UX-13 P3: Simple view and Batteries screen
- Batteries: one card per battery with On/Off, the mode list (cheap hours and selling greyed out until OPT-11 P3), level, and Now / Today / Why lines built in homeview.py. Replaces the OPT-11 P1 minimal cards and uses the existing pack_use / pack_mode actions and store keys. - An Off battery the peak limit still needs says so with its figure; no line shows 0 W beside moving power (OPT-11 P1 test F2). Today says "Not planned yet" until OPT-11 P3/P4. - Home's plan leaves Off batteries out, except for the peak limit. - Settings opens on Simple: the layout's simple fields with an applies chip and a note, plus the battery switches and modes. Installer is one tap. - English and Dutch words in app/ui_text; test_batteries_screen.py; browser check tools/ux13_browser_check.py (CHECK=1 ux13_screenshots.sh); new and changed screenshots only. No control, allocator, arbiter or command module changed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UBtqPrG1mDLXzTEBnhEkkV
This commit is contained in:
@@ -2,7 +2,9 @@
|
||||
headless browser check. `python3 tools/ux13_demo.py STATE PORT [HOST]`
|
||||
|
||||
STATE is running, shadow, alarm, new (P4) or setup (UX-15's setup-only
|
||||
mode, P5). The controller is the shipped `Controller`
|
||||
mode, P5). P3 adds the battery-mode states in `P3`: modes (on, B on Leftover
|
||||
solar), off (B switched off), off_peak (B off but giving for the peak limit),
|
||||
refusal (A refuses to give power) and maint (A in its monthly cycle). The controller is the shipped `Controller`
|
||||
with its readings set by hand (two batteries, solar, today's prices in the
|
||||
mockup's shape, trading on). Nothing here talks to Home Assistant or to an
|
||||
inverter: `/action` changes only this fixture. Used for the P1 render check
|
||||
@@ -34,8 +36,9 @@ sys.path.insert(0, os.path.join(HERE, "tools"))
|
||||
|
||||
from aiohttp import web as aioweb # noqa: E402
|
||||
|
||||
from app import homeview, web # noqa: E402
|
||||
from app import homeview, packmode, web # noqa: E402
|
||||
from app.main import Controller # noqa: E402
|
||||
from app.maintenance import DRAIN # noqa: E402
|
||||
from app.setuponly import SetupOnly # noqa: E402
|
||||
from app.peakguard import PeakDecision # noqa: E402
|
||||
from app.price import PricePoint, PriceProduct, PriceRead # noqa: E402
|
||||
@@ -231,8 +234,14 @@ OPTS = {"meter_entity": "sensor.grid", "meter_source": "off",
|
||||
"max_w": 2500, "capacity_kwh": 5.4}]}
|
||||
|
||||
|
||||
# UX-13 P3: the battery-mode states, each with battery modes on.
|
||||
P3 = ("modes", "off", "off_peak", "refusal", "maint")
|
||||
|
||||
|
||||
def controller(state):
|
||||
opts = dict(OPTS, shadow_mode="on" if state == "shadow" else "off")
|
||||
if state in P3:
|
||||
opts["battery_modes_enabled"] = True
|
||||
c = Controller(opts, Hass(), Store(), Pub(), stop=asyncio.Event())
|
||||
c.auto = True
|
||||
now = datetime.now(timezone.utc)
|
||||
@@ -255,6 +264,29 @@ def controller(state):
|
||||
c.pv_w = 3900.0
|
||||
if state == "alarm":
|
||||
c.inverters[0].sign_wd.tripped = True
|
||||
if state in P3:
|
||||
a, b = c.inverters
|
||||
b.store_set(packmode.MODE_KEY, packmode.LEFTOVER_SOLAR)
|
||||
if state in ("off", "off_peak"):
|
||||
b.store_set(packmode.USE_KEY, False)
|
||||
b.batt = 0.0
|
||||
if state == "off_peak":
|
||||
# A cloudy evening: the house takes 6 kW and the peak limit needs
|
||||
# both batteries, so B gives 0.5 kW although it is switched off.
|
||||
c.pv_w, c.grid = 0.0, 3490.0
|
||||
a.batt, b.batt = 2000.0, 510.0
|
||||
c.peak_guard = PeakDecision(engaged=True, floor_w=2500.0,
|
||||
ceiling_w=3500.0, ceiling_from="cap",
|
||||
projected_w=3600.0)
|
||||
if state == "refusal":
|
||||
# A is at its cut-out level and refuses: asked 0 W, B takes over.
|
||||
c.pv_w, c.grid = 0.0, 5.0
|
||||
a.soc, a.batt, a.refused = 9.0, -4.0, 1
|
||||
b.batt = 1210.0
|
||||
if state == "maint":
|
||||
c.maints[0].store.set("phase", DRAIN) # MAINT-05: A's own key
|
||||
c.pv_w, c.grid = 0.0, 0.0
|
||||
a.batt, b.batt = 2000.0, 0.0
|
||||
return c
|
||||
|
||||
|
||||
@@ -290,6 +322,7 @@ async def main(state, port, host="127.0.0.1"):
|
||||
p1_net_entity="sensor.grid", price_provider="generic_dayahead",
|
||||
peak_forecast_entity="sensor.peak_forecast",
|
||||
shadow_mode=c.o.get("shadow_mode", "off"),
|
||||
battery_modes_enabled=state in P3,
|
||||
inverters=[dict(i, bms_soc_floor=10)
|
||||
for i in OPTS["inverters"]])
|
||||
runner = aioweb.AppRunner(web.build_app(c, Supervisor(stored)))
|
||||
|
||||
Reference in New Issue
Block a user