Compare commits

...

2 commits

Author SHA1 Message Date
96bbb3602a sample2, show grid cost 2025-12-15 07:34:50 +02:00
7347636311 add token for token auth 2025-12-15 07:34:30 +02:00
2 changed files with 18 additions and 4 deletions

View file

@ -14,7 +14,7 @@ API_TOKEN = "d0vA6CsrY69N3JAOGtuZMEb9QpbJWPcoxhxRyBXZn8SIisB3weLKjMZwQRo8c2k9BRD
w42_state = panel.rx(None) w42_state = panel.rx(None)
# TODO: must pass token, otherwise subscription should fail # TODO: must pass token, otherwise subscription should fail
attach_w42_state(rx_var=w42_state, system_id=SYSTEM_ID) attach_w42_state(rx_var=w42_state, system_id=SYSTEM_ID, token=API_TOKEN)
state_as_text = panel.bind(lambda s: f"W42 State:\n\n```\n{json.dumps(s, indent=2)}\n```\n\nReplace this with some awesome visuals", w42_state) state_as_text = panel.bind(lambda s: f"W42 State:\n\n```\n{json.dumps(s, indent=2)}\n```\n\nReplace this with some awesome visuals", w42_state)
@ -39,6 +39,9 @@ class Configuration(BaseModel):
location_lat: float = 0.0 location_lat: float = 0.0
location_lon: float = 0.0 location_lon: float = 0.0
class Stats(BaseModel):
grid_cost_total: float = 0.0
class SystemState(BaseModel): class SystemState(BaseModel):
load_forecast: LoadForecast = LoadForecast() load_forecast: LoadForecast = LoadForecast()
pv_forecast: PvForecast = PvForecast() pv_forecast: PvForecast = PvForecast()
@ -47,6 +50,7 @@ class SystemState(BaseModel):
buy_prices: list[float] = [] buy_prices: list[float] = []
output: Output | None = None output: Output | None = None
config: Configuration = Configuration() config: Configuration = Configuration()
stats: Stats = Stats()
state: SystemState = panel.rx(lambda s: SystemState.model_validate(s) if s else SystemState())(w42_state) state: SystemState = panel.rx(lambda s: SystemState.model_validate(s) if s else SystemState())(w42_state)
@ -178,11 +182,16 @@ async def process_config_change(_btn):
config_submit = panel.widgets.Button(name="Update Configuration", button_type="primary", width=200) config_submit = panel.widgets.Button(name="Update Configuration", button_type="primary", width=200)
config_submit.on_click(process_config_change) config_submit.on_click(process_config_change)
def summary(state: SystemState) -> str:
total_cost = state.stats.grid_cost_total
return f"## Summary\n\nGrid {'cost' if total_cost > 0 else 'income'} total: {abs(state.stats.grid_cost_total):.2f} ZAR"
_ = panel.template.FastListTemplate( _ = panel.template.FastListTemplate(
title="Sample W42 App", title="Sample W42 App",
sidebar=[panel.pane.Markdown("This is a sample sidebar.")], sidebar=[panel.pane.Markdown("This is a sample sidebar.")],
main=[ main=[
# panel.pane.Markdown(state_as_text, sizing_mode='stretch_width'), # panel.pane.Markdown(state_as_text, sizing_mode='stretch_width'),
panel.pane.Markdown(panel.rx(summary)(state), sizing_mode='stretch_width'),
panel.pane.ECharts( panel.pane.ECharts(
load_fc_chart_rx, load_fc_chart_rx,
sizing_mode='stretch_width', sizing_mode='stretch_width',

View file

@ -8,7 +8,7 @@ from websockets.asyncio.client import connect
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def attach_w42_state(rx_var: panel.rx, system_id: str): def attach_w42_state(rx_var: panel.rx, system_id: str, token: str):
WS_URL = "ws://localhost:8000/ws/systems" # TODO: make configurable WS_URL = "ws://localhost:8000/ws/systems" # TODO: make configurable
@ -23,12 +23,17 @@ def attach_w42_state(rx_var: panel.rx, system_id: str):
logger.info(f"Connected to {WS_URL}") logger.info(f"Connected to {WS_URL}")
send_response = await websocket.send(json.dumps({ send_response = await websocket.send(json.dumps({
"action": "subscribe", "action": "subscribe",
"system_id": system_id "system_id": system_id,
"token": token
})) }))
logger.info(f"Subscribed to system {system_id}, waiting for messages..., send_response={send_response}") logger.info(f"Subscribed to system {system_id}, waiting for messages..., send_response={send_response}")
async for message in websocket: async for message in websocket:
as_json = json.loads(message) as_json = json.loads(message)
rx_var.rx.value = as_json['change']['state'] if as_json.get('error'):
logger.error(f"Error from websocket: {as_json['error']}")
rx_var.rx.value = as_json
else:
rx_var.rx.value = as_json['change']['state']
except ConnectionClosed: except ConnectionClosed:
if must_reconnect: if must_reconnect:
logger.info("connection closed, retrying...") logger.info("connection closed, retrying...")