diff --git a/poetry.lock b/poetry.lock index 00bdfb7..be34cdc 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3919,4 +3919,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "3eea7c38b9b21441000ab9996329c2efae52464c698b013df5debffd3af5e7e3" +content-hash = "8f3d473f12e66f997137dab2288517897944a71f63adfb47c4c9104af1a2e7ff" diff --git a/pyproject.toml b/pyproject.toml index 31f3f81..b79d4ea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,7 @@ jupyterlab = "^4.4.10" pandas-stubs = "^2.3.2.250926" websockets = "^15.0.1" pydantic = "^2.12.4" +httpx = "^0.28.1" [tool.poetry.group.dev.dependencies] pytest = "^8.3.3" pytest-cov = "^5.0.0" diff --git a/sample2.py b/sample2.py index 7829d8e..fc25d90 100644 --- a/sample2.py +++ b/sample2.py @@ -6,8 +6,15 @@ from pydantic import BaseModel from watt42_viewlib import attach_w42_state +panel.extension('echarts', 'ace', 'jsoneditor') + +SYSTEM_ID = "79476e53-dea6-44fa-976c-eff6260baeb6" +API_TOKEN = "d0vA6CsrY69N3JAOGtuZMEb9QpbJWPcoxhxRyBXZn8SIisB3weLKjMZwQRo8c2k9BRDtK0qHYnsvUMnqeO7Xog" + w42_state = panel.rx(None) -attach_w42_state(rx_var=w42_state, system_id="79476e53-dea6-44fa-976c-eff6260baeb6") + +# TODO: must pass token, otherwise subscription should fail +attach_w42_state(rx_var=w42_state, system_id=SYSTEM_ID) 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) @@ -27,6 +34,11 @@ class LoadForecast(BaseModel): at: datetime = datetime.now() slots: list[float] = [] +class Configuration(BaseModel): + inverter_sid: str = "" + location_lat: float = 0.0 + location_lon: float = 0.0 + class SystemState(BaseModel): load_forecast: LoadForecast = LoadForecast() pv_forecast: PvForecast = PvForecast() @@ -34,6 +46,7 @@ class SystemState(BaseModel): sell_prices: list[float] = [] buy_prices: list[float] = [] output: Output | None = None + config: Configuration = Configuration() state: SystemState = panel.rx(lambda s: SystemState.model_validate(s) if s else SystemState())(w42_state) @@ -139,10 +152,34 @@ prices_chart_rx = panel.rx(prices_chart)(state) datetime_fmt = "%Y-%m-%d %H:%M:%S" -value = w42_state.rx.value +config_editor = panel.widgets.JSONEditor(value=state.config.model_dump(), mode='form', height=200, width=400, menu=False) + +SCRIPT_ID = "23a6d15a-f7e3-4ff1-b3c1-94d297c972c9" + +async def process_config_change(_btn): + from httpx import AsyncClient + async with AsyncClient() as client: + response = await client.post( + f"http://localhost:8000/api/scripts/{SCRIPT_ID}/execute?system_guid={SYSTEM_ID}", + json={ + 'signal': 'update_config', + 'request_body': config_editor.value, + }, + headers={ + "Content-Type": "application/json", + "x-api-token": API_TOKEN + } + ) + print(f"Config update response: {response.status_code} - {response.text}") + + +# _ = panel.rx(process_config_change)(config_editor.value) + +config_submit = panel.widgets.Button(name="Update Configuration", button_type="primary", width=200) +config_submit.on_click(process_config_change) _ = panel.template.FastListTemplate( - title="Sample W42 View App", + title="Sample W42 App", sidebar=[panel.pane.Markdown("This is a sample sidebar.")], main=[ # panel.pane.Markdown(state_as_text, sizing_mode='stretch_width'), @@ -157,6 +194,7 @@ _ = panel.template.FastListTemplate( height=300 ), w42_state, + panel.Column(config_editor, config_submit, sizing_mode='stretch_width'), panel.pane.Markdown(panel.bind(lambda s: f"State at {s.now.strftime(datetime_fmt)}, Load Forecast Time: {s.load_forecast.at}", state), sizing_mode='stretch_width'), ], ).servable()