Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions apps/predbat/tests/test_web_if.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,23 @@
import shutil
import tempfile
from components import Components
from web_helper import get_plan_renderer_js


def test_plan_renderer_renders_batch_controls():
"""
Ensure the plan renderer exposes the batch selection controls and syncs
the runtime batch state.
"""
renderer_js = get_plan_renderer_js()
assert "predbatSelectedTimeOverrides" in renderer_js
assert "setSelectedTimeOverrides(getSelectedTimeOverrides())" in renderer_js
assert "openDropdown(dropdownId)" in renderer_js
assert "Batch select" in renderer_js
assert "Cancel Batch" in renderer_js
assert "batch-select-action" in renderer_js
assert "cancel-batch" in renderer_js
assert "querySelectorAll('a.batch-select-action, a.cancel-batch')" in renderer_js
Comment on lines +17 to +33


def run_test_web_if(my_predbat):
Expand Down Expand Up @@ -240,6 +257,16 @@ def run_test_web_if(my_predbat):
print("ERROR: Unexpected response from /plan_override: {} - {}".format(res.status_code, res.text))
failed = 1

print("Test POST /plan_override with multiple times")
address = "http://127.0.0.1:5052/plan_override"
data = {"time": "00:00,01:00", "action": "Manual Demand"}
res = requests.post(address, data=data)
if res.status_code in [200]:
accessed_endpoints.add(("POST", "/plan_override"))
else:
print("ERROR: Unexpected response from /plan_override with multiple times: {} - {}".format(res.status_code, res.text))
failed = 1

Comment on lines +260 to +269
# Test /rate_override POST
print("Test POST /rate_override")
address = "http://127.0.0.1:5052/rate_override"
Expand Down
59 changes: 36 additions & 23 deletions apps/predbat/web.py
Original file line number Diff line number Diff line change
Expand Up @@ -4144,6 +4144,14 @@ async def html_api_login(self, request):

return response

def _parse_override_times(self, time_str):
"""
Split a comma-separated override time string into individual values.
"""
if not time_str:
return []
return [item.strip() for item in time_str.split(",") if item.strip()]

async def html_rate_override(self, request):
"""
Handle POST request for rate overrides
Expand Down Expand Up @@ -4250,33 +4258,38 @@ async def html_plan_override(self, request):
if not time_str or not action:
return web.json_response({"success": False, "message": "Missing required parameters"}, status=400)

now_utc = self.now_utc
override_time = get_override_time_from_string(now_utc, time_str, self.plan_interval_minutes)
if not override_time:
time_values = self._parse_override_times(time_str)
if not time_values:
return web.json_response({"success": False, "message": "Invalid time format"}, status=400)

minutes_from_now = (override_time - now_utc).total_seconds() / 60
if minutes_from_now >= 48 * 60:
return web.json_response({"success": False, "message": "Override time must be within 48 hours from now."}, status=400)

selection_option = "{}".format(override_time.strftime("%a %H:%M"))
clear_option = "[{}]".format(override_time.strftime("%a %H:%M"))
if action == "Clear":
await self.base.async_manual_select("manual_demand", selection_option)
await self.base.async_manual_select("manual_demand", clear_option)
else:
if action == "Manual Demand":
now_utc = self.now_utc
for time_value in time_values:
override_time = get_override_time_from_string(now_utc, time_value, self.plan_interval_minutes)
if not override_time:
return web.json_response({"success": False, "message": "Invalid time format"}, status=400)

minutes_from_now = (override_time - now_utc).total_seconds() / 60
if minutes_from_now >= 48 * 60:
return web.json_response({"success": False, "message": "Override time must be within 48 hours from now."}, status=400)

selection_option = "{}".format(override_time.strftime("%a %H:%M"))
clear_option = "[{}]".format(override_time.strftime("%a %H:%M"))
if action == "Clear":
await self.base.async_manual_select("manual_demand", selection_option)
elif action == "Manual Charge":
await self.base.async_manual_select("manual_charge", selection_option)
elif action == "Manual Export":
await self.base.async_manual_select("manual_export", selection_option)
elif action == "Manual Freeze Charge":
await self.base.async_manual_select("manual_freeze_charge", selection_option)
elif action == "Manual Freeze Export":
await self.base.async_manual_select("manual_freeze_export", selection_option)
await self.base.async_manual_select("manual_demand", clear_option)
else:
return web.json_response({"success": False, "message": "Unknown action"}, status=400)
if action == "Manual Demand":
await self.base.async_manual_select("manual_demand", selection_option)
elif action == "Manual Charge":
await self.base.async_manual_select("manual_charge", selection_option)
elif action == "Manual Export":
await self.base.async_manual_select("manual_export", selection_option)
elif action == "Manual Freeze Charge":
await self.base.async_manual_select("manual_freeze_charge", selection_option)
elif action == "Manual Freeze Export":
await self.base.async_manual_select("manual_freeze_export", selection_option)
else:
return web.json_response({"success": False, "message": "Unknown action"}, status=400)

# Refresh plan
self.base.update_pending = True
Expand Down
Loading
Loading