From ca6e271a54ae78bb81d3b76940ae1708a0f3a21f Mon Sep 17 00:00:00 2001 From: Johannes Braun <29555657+joBr99@users.noreply.github.com> Date: Sun, 22 Feb 2026 00:45:35 +0100 Subject: [PATCH] add documentation for standalone version --- .github/workflows/docs-standalone-release.yml | 25 ++++ docs-standalone/_assets/user.css | 80 ++++++++++ docs-standalone/cards.md | 137 ++++++++++++++++++ docs-standalone/configuration.md | 61 ++++++++ docs-standalone/connection-modes.md | 45 ++++++ docs-standalone/entities.md | 77 ++++++++++ docs-standalone/getting-started.md | 55 +++++++ docs-standalone/index.md | 38 +++++ docs-standalone/mkdocs.yml | 59 ++++++++ docs-standalone/screensaver.md | 57 ++++++++ docs-standalone/troubleshooting.md | 63 ++++++++ 11 files changed, 697 insertions(+) create mode 100644 .github/workflows/docs-standalone-release.yml create mode 100644 docs-standalone/_assets/user.css create mode 100644 docs-standalone/cards.md create mode 100644 docs-standalone/configuration.md create mode 100644 docs-standalone/connection-modes.md create mode 100644 docs-standalone/entities.md create mode 100644 docs-standalone/getting-started.md create mode 100644 docs-standalone/index.md create mode 100644 docs-standalone/mkdocs.yml create mode 100644 docs-standalone/screensaver.md create mode 100644 docs-standalone/troubleshooting.md diff --git a/.github/workflows/docs-standalone-release.yml b/.github/workflows/docs-standalone-release.yml new file mode 100644 index 00000000..067bf494 --- /dev/null +++ b/.github/workflows/docs-standalone-release.yml @@ -0,0 +1,25 @@ +name: docs-standalone-ci + +on: + workflow_dispatch: + push: + branches: + - main + paths: + - docs-standalone/** + - .github/workflows/docs-standalone-release.yml + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + - uses: actions/setup-python@v6 + with: + python-version: 3.x + - run: pip install mkdocs-material mike + - run: git config --global user.name Docs deploy + - run: git config --global user.email docs@dummy.bot.com + - run: mike deploy --config-file docs-standalone/mkdocs.yml --push --update-aliases standalone diff --git a/docs-standalone/_assets/user.css b/docs-standalone/_assets/user.css new file mode 100644 index 00000000..1106a6e9 --- /dev/null +++ b/docs-standalone/_assets/user.css @@ -0,0 +1,80 @@ +/*.md-header__button.md-logo img { + width: unset; +}*/ + +.md-main__inner { + margin-top: unset; +} + +.md-nav__title { + display: none; +} + +/*.md-header,*/ .md-footer { + background-color: #333333; +} + +.md-footer__inner.md-grid { + display: none; +} + +.md-sidebar { + padding-top: 0px; +} + +/*.md-sidebar.md-sidebar--primary { + position: unset; +}*/ + +.md-sidebar.md-sidebar--secondary { + padding-top: 10px; +} + +.md-sidebar.md-sidebar--primary .md-sidebar__scrollwrap { + /*overflow-y: unset;*/ + padding-right: 1px; + border-right: 1px solid #adadad; +} + +.md-sidebar.md-sidebar--primary .md-sidebar__inner { + /*border-right: 1px solid #adadad;*/ + padding-bottom: 30px; +} +.md-sidebar.md-sidebar--secondary .md-sidebar__inner { + border-left: 1px solid #adadad; +} + +.md-nav__item .md-nav__list { + padding-left: 10px; +} + +.md-content { + margin-top: 25px; + /*border-left: 1px solid #adadad; + border-right: 1px solid #adadad;*/ +} + +.md-top { + display: none; +} + +.md-typeset hr { + border-bottom: 1px solid #adadad; +} + +.md-typeset h1, +.md-typeset h2, +.md-typeset h3, +.md-typeset h4, +.md-typeset h5 { + font-weight: bold; +} + +.md-typeset table:not([class]) td:not(:last-child), +.md-typeset table:not([class]) th:not(:last-child) { + border-right: .05rem solid var(--md-typeset-table-color); +} + +ol li::marker { + font-weight: bold; +} \ No newline at end of file diff --git a/docs-standalone/cards.md b/docs-standalone/cards.md new file mode 100644 index 00000000..3a64fcf0 --- /dev/null +++ b/docs-standalone/cards.md @@ -0,0 +1,137 @@ +# Cards + +## Supported card types + +- `cardEntities` +- `cardGrid` +- `cardQR` +- `cardPower` +- `cardMedia` +- `cardThermo` +- `cardAlarm` +- `cardUnlock` + +## Common card keys + +key | required | type | description +-- | -- | -- | -- +`type` | yes | string | Card type. +`title` | no | string | Card title. +`key` | no | string | Navigation key used by `navigate.`. + +## `cardEntities` and `cardGrid` + +```yaml +- type: cardEntities + title: Main + key: main + entities: + - entity: light.kitchen + - entity: navigate.settings + icon: mdi:cog +``` + +- `entities` is required. +- `cardGrid` auto-switches to `cardGrid2` if more than 6 entities are present. + +## `cardQR` + +```yaml +- type: cardQR + title: Guest WiFi + qrCode: "WIFI:S:myssid;T:WPA;P:mypassword;;" + entities: + - entity: iText.myssid + name: SSID + icon: mdi:wifi +``` + +Keys: + +- `qrCode` optional (default value exists, but set it explicitly) +- supports optional `entity` / `entities` + +## `cardPower` + +```yaml +- type: cardPower + title: Energy + entities: + - entity: sensor.house_power + - entity: delete + - entity: sensor.solar_power +``` + +Notes: + +- `entities` is required. +- `speed` key is accepted in config but currently not applied by the renderer. + +## `cardMedia` + +```yaml +- type: cardMedia + title: Living Room + entity: media_player.living_room + entities: + - entity: light.ambient + - entity: switch.tv_bias_light +``` + +Notes: + +- Main media entity must exist (`entity` or first generated entity). +- Additional `entities` are rendered as action buttons on the bottom row. + +## `cardThermo` + +```yaml +- type: cardThermo + title: Heating + entity: climate.downstairs + supported_modes: ["heat", "off"] +``` + +Keys: + +- `entity` required +- `supported_modes` optional (filters shown HVAC mode buttons) + +## `cardAlarm` + +```yaml +- type: cardAlarm + title: House Alarm + entity: alarm_control_panel.house + supported_modes: ["arm_home", "arm_away", "arm_night"] +``` + +Keys: + +- `entity` required +- `supported_modes` optional + +## `cardUnlock` + +```yaml +- type: cardUnlock + title: Admin + pin: 1234 + destination: navigate.admin +``` + +Keys: + +- `pin` required +- `destination` required + +Typical target in `hiddenCards`: + +```yaml +hiddenCards: + - type: cardGrid + key: admin + title: Admin + entities: + - entity: switch.maintenance_mode +``` diff --git a/docs-standalone/configuration.md b/docs-standalone/configuration.md new file mode 100644 index 00000000..178f5ac9 --- /dev/null +++ b/docs-standalone/configuration.md @@ -0,0 +1,61 @@ +# Configuration + +The runtime reads one YAML file (default: `./panels.yaml`, add-on mode: `/config/panels.yaml`). + +## Top-level keys + +key | required | type | default | description +-- | -- | -- | -- | -- +`nspanels` | yes | object | none | Map of panel definitions. +`home_assistant_address` | recommended | string | none | Home Assistant base URL. In add-on mode it is auto-filled as `http://supervisor` if missing. +`home_assistant_token` | recommended | string | none | Long-lived token or Supervisor token. +`mqtt_server` | required in MQTT mode | string | from env | MQTT host. +`mqtt_port` | required in MQTT mode | int | from env | MQTT port. +`mqtt_username` | required in MQTT mode | string | from env | MQTT username. +`mqtt_password` | required in MQTT mode | string | from env | MQTT password. +`use_ha_api` | optional | any | absent | If present, MQTT input mode is disabled and HA event mode is used. +`timeZone` | optional | string | `Europe/Berlin` | Global fallback for panel `timeZone`. +`hiddenCards` | optional | list | `[]` | Global fallback for panel `hiddenCards`. + +## Panel keys (`nspanels.`) + +key | required | type | default | description +-- | -- | -- | -- | -- +`panelRecvTopic` | yes | string | none | Receive channel for panel events. +`panelSendTopic` | yes | string | none | Send channel for panel commands. +`locale` | yes | string | none | Locale used for translations and date formatting. +`timeZone` | recommended | string | from top-level `timeZone` | Time zone for clock. +`timeFormat` | yes | string | none | Python `strftime` format. +`dateFormat` | yes | string | none | Babel date format (example: `full`, `medium`). +`model` | optional | string | `eu` | Panel model (`eu`, `us-p`, `us-l`). +`temp_unit` | optional | string | `celsius` | Thermostat card unit (`celsius` or `fahrenheit`). +`sleepTimeout` | optional | int | `20` | Seconds before screensaver. +`sleepBrightness` | optional | int or entity_id | `10` | Screensaver brightness. +`screenBrightness` | optional | int or entity_id | `100` | Active-screen brightness. +`sleepTracking` | optional | entity_id | none | Forces sleep brightness to 0 when entity state matches `sleepTrackingZones`. +`sleepTrackingZones` | optional | list | `["not_home", "off"]` | States that trigger forced dimming. +`sleepOverride` | optional | object | none | Override sleep brightness when entity is `on`/`true`/`home`. +`defaultBackgroundColor` | optional | string | `ha-dark` | `ha-dark` or `black`. +`featExperimentalSliders` | optional | int | `0` | Forwarded in dimmode command. +`defaultCard` | optional | string | none | Default card when leaving screensaver (`navigate.`). +`screensaver` | yes | object | none | Screensaver definition. +`cards` | yes | list | none | Top-level cards. +`hiddenCards` | optional | list | `[]` | Hidden cards addressable through `navigate.`. + +## Brightness behavior + +- Integer values are used directly. +- Entity values read Home Assistant state and cast to number. +- List/schedule style brightness is not supported in this rewrite. + +Example: + +```yaml +sleepBrightness: input_number.nspanel_sleep +screenBrightness: input_number.nspanel_awake +sleepTracking: person.john +sleepTrackingZones: ["not_home", "off"] +sleepOverride: + entity: light.bedroom + brightness: 30 +``` diff --git a/docs-standalone/connection-modes.md b/docs-standalone/connection-modes.md new file mode 100644 index 00000000..198cbf8c --- /dev/null +++ b/docs-standalone/connection-modes.md @@ -0,0 +1,45 @@ +# Connection Modes + +The rewrite supports two panel input/output modes. + +## 1) MQTT mode (default) + +Enabled when: + +- `mqtt_server` is configured +- `use_ha_api` is not present + +Behavior: + +- Subscribes to every panel `panelRecvTopic` +- Expects JSON payload containing `CustomRecv` +- Publishes commands to `panelSendTopic` + +Example receive payload: + +```json +{"CustomRecv":"event,startup,54,eu"} +``` + +## 2) Home Assistant API mode (`use_ha_api`) + +Enabled when key `use_ha_api` exists in config. + +Behavior: + +- Subscribes to HA event `esphome.nspanel.data` +- Routes events by `device_id` (must match configured `panelRecvTopic`) +- Sends panel commands by calling Home Assistant service: + - `_nspanelui_api_call` + +Service payload shape: + +```yaml +data: "...panel command..." +command: 2 +``` + +## Common to both modes + +- Home Assistant websocket connection is used for entity state cache and service calls. +- UI actions (button presses, sliders, mode selects) are translated to Home Assistant service calls. diff --git a/docs-standalone/entities.md b/docs-standalone/entities.md new file mode 100644 index 00000000..939e5d2f --- /dev/null +++ b/docs-standalone/entities.md @@ -0,0 +1,77 @@ +# Entities + +Entities are used in cards and screensaver lists. + +## Entity keys + +key | required | type | description +-- | -- | -- | -- +`entity` | yes | string | Home Assistant entity id, or internal entity (`navigate.*`, `delete`, `iText.*`). +`name` | no | string | Display name override. +`icon` | no | string or map | Icon override (`mdi:*`), optionally per state. +`color` | no | `[r,g,b]` or map | Color override, optionally per state. +`value` | no | string | Value override. +`font` | no | string | Icon font variant (`small`, `medium`, `medium-icon`, `large`). +`status` | no | string | Extra status entity for `navigate.*` items. +`effectList` | no | list | Custom light effect list for detail popup. +`attribute` | no | string | Weather attribute to display. +`day` | no | int | Weather daily forecast index. +`hour` | no | int | Weather hourly forecast index. +`unit` | no | string | Value suffix. + +## Supported Home Assistant domains + +- `switch` +- `input_boolean` +- `automation` +- `lock` +- `input_text` +- `input_select` +- `select` +- `light` +- `fan` +- `button` +- `input_button` +- `scene` +- `script` +- `number` +- `input_number` +- `timer` +- `alarm_control_panel` +- `vacuum` +- `media_player` +- `sun` +- `person` +- `climate` +- `cover` +- `sensor` +- `binary_sensor` +- `weather` + +## Internal entities + +- `navigate.`: Navigate to card with matching `key`. +- `navigate.UP`: Navigate back. +- `delete`: Placeholder/empty slot. +- `iText.`: Static text entry. + +## Template-based values + +The rewrite supports Home Assistant template rendering for selected fields when prefixed with `ha:`: + +- `icon: "ha:{{ ... }}"` +- `color: "ha:{{ ... }}"` (must evaluate to JSON RGB list) +- `value: "ha:{{ ... }}"` +- `qrCode: "ha:{{ ... }}"` + +Example: + +```yaml +- entity: light.kitchen + icon: + "on": mdi:lightbulb + "off": mdi:lightbulb-outline + color: + "on": [255, 210, 90] + "off": [80, 120, 170] +``` diff --git a/docs-standalone/getting-started.md b/docs-standalone/getting-started.md new file mode 100644 index 00000000..86bc753d --- /dev/null +++ b/docs-standalone/getting-started.md @@ -0,0 +1,55 @@ +# Getting Started + +## Home Assistant add-on mode + +In add-on mode, the container startup script: + +- reads MQTT credentials from Home Assistant service discovery +- sets `CONFIG_FILE=/config/panels.yaml` +- creates `/config/panels.yaml` from the bundled example if it does not exist + +Relevant files: + +- `nspanel-lovelace-ui/rootfs/usr/bin/mqtt-manager/run.sh` +- `nspanel-lovelace-ui/config.yaml` + +## Minimal `panels.yaml` + +Start with one panel: + +```yaml +home_assistant_address: "http://supervisor" +home_assistant_token: "SUPERVISOR_TOKEN_OR_LONG_LIVED_TOKEN" + +nspanels: + kitchen: + panelRecvTopic: "tele/tasmota_kitchen/RESULT" + panelSendTopic: "cmnd/tasmota_kitchen/CustomSend" + locale: "en_US" + timeZone: "Europe/Berlin" + timeFormat: "%H:%M" + dateFormat: "full" + screensaver: + entities: + - entity: weather.home + cards: + - type: cardEntities + title: Main + entities: + - entity: light.kitchen + - entity: switch.coffee_machine +``` + +## Important notes + +- `cards` and `screensaver` are required per panel. +- `timeFormat`, `dateFormat`, and `locale` should be set per panel. +- `panelRecvTopic` / `panelSendTopic` are required. + +## Running standalone (outside HA add-on) + +If you run this container/process outside Supervisor: + +- provide `home_assistant_address` and `home_assistant_token` in YAML +- provide MQTT values in YAML (`mqtt_server`, `mqtt_port`, `mqtt_username`, `mqtt_password`) or environment +- set `CONFIG_FILE` if the config is not `./panels.yaml` diff --git a/docs-standalone/index.md b/docs-standalone/index.md new file mode 100644 index 00000000..72bd5386 --- /dev/null +++ b/docs-standalone/index.md @@ -0,0 +1,38 @@ +# Overview + +This documentation covers the standalone rewrite located in `nspanel-lovelace-ui/`. + +It is a Python backend that: + +- receives panel input (MQTT mode or Home Assistant API mode) +- reads Home Assistant state through the websocket API +- renders cards and screensaver pages +- sends panel commands back to the device + +This docs set is intentionally separate from the AppDaemon docs in `docs/`. + +## Rewrite location + +- Add-on package: `nspanel-lovelace-ui/` +- Runtime code: `nspanel-lovelace-ui/rootfs/usr/bin/mqtt-manager/` +- Example panel config: `nspanel-lovelace-ui/rootfs/usr/bin/mqtt-manager/panels.yaml.example` + +## What is supported + +- `cardEntities` +- `cardGrid` (auto-switches to `cardGrid2` when needed) +- `cardQR` +- `cardPower` +- `cardMedia` +- `cardThermo` +- `cardAlarm` +- `cardUnlock` +- screensaver with status icons and weather forecast entities + +## Runtime model + +1. Load `panels.yaml`. +2. Resolve MQTT and Home Assistant connection settings. +3. Create one thread per panel. +4. Listen for events and state changes. +5. Re-render active pages and detail popups when relevant entities change. diff --git a/docs-standalone/mkdocs.yml b/docs-standalone/mkdocs.yml new file mode 100644 index 00000000..e37217e5 --- /dev/null +++ b/docs-standalone/mkdocs.yml @@ -0,0 +1,59 @@ +site_name: NsPanel Lovelace UI Standalone Docs +site_description: Documentation for the standalone/Home Assistant add-on rewrite in nspanel-lovelace-ui. +site_author: Johannes Braun +site_url: https://jobr99.github.io/nspanel-lovelace-ui + +repo_name: jobr99/nspanel-lovelace-ui +repo_url: https://github.com/jobr99/nspanel-lovelace-ui +edit_uri: "" + +copyright: "Copyright © 2026 Johannes Braun" + +docs_dir: . + +theme: + name: material + palette: + accent: blue + font: + text: "arial, sans-serif" + code: monospace + features: + - navigation.indexes + - navigation.sections + - navigation.top + - navigation.tracking + - navigation.expand + - search.highlight + - search.share + - search.suggest + +extra_css: + - _assets/user.css + +markdown_extensions: + - admonition + - def_list + - attr_list + - pymdownx.tilde + - pymdownx.details + - pymdownx.superfences + - pymdownx.magiclink + - toc: + permalink: true + - codehilite: + guess_lang: false + +plugins: + - search: + lang: en + +nav: + - "Overview": index.md + - "Getting Started": getting-started.md + - "Configuration": configuration.md + - "Screensaver": screensaver.md + - "Cards": cards.md + - "Entities": entities.md + - "Connection Modes": connection-modes.md + - "Troubleshooting": troubleshooting.md diff --git a/docs-standalone/screensaver.md b/docs-standalone/screensaver.md new file mode 100644 index 00000000..ed57892b --- /dev/null +++ b/docs-standalone/screensaver.md @@ -0,0 +1,57 @@ +# Screensaver + +`screensaver` is a required object in each panel config. + +## Keys + +key | required | type | default | description +-- | -- | -- | -- | -- +`type` | no | string | `screensaver` | Layout type (`screensaver` / `screensaver2`). +`entities` | yes* | list | none | Screensaver entities. +`entity` | yes* | string | none | Single-entity shortcut. +`statusIcon1` | no | object | none | Left status icon near date. +`statusIcon2` | no | object | none | Right status icon near date. +`doubleTapToUnlock` | no | bool | `false` | Requires double tap when leaving screensaver. +`sleepTimeout` | no | int | panel `sleepTimeout` | Per-screensaver timeout override. + +`*` Provide at least one of `entity` or `entities`. + +## Screensaver entities + +Screensaver entities use the same entity format as other cards. + +For `weather.` you can also use: + +- `attribute` (default `temperature`) +- `day` (daily forecast index) +- `hour` (hourly forecast index) +- `unit` (suffix, default `°C` for temperature-like attributes) + +## Example + +```yaml +screensaver: + type: screensaver + doubleTapToUnlock: true + sleepTimeout: 30 + statusIcon1: + entity: binary_sensor.front_door + icon: + "on": mdi:door-open + "off": mdi:door-closed + font: medium-icon + statusIcon2: + entity: sensor.outdoor_temperature + icon: mdi:thermometer + entities: + - entity: weather.home + attribute: temperature + - entity: weather.home + day: 1 + attribute: temperature + - entity: weather.home + day: 2 + attribute: temperature + - entity: sensor.indoor_temperature + icon: mdi:home-thermometer +``` diff --git a/docs-standalone/troubleshooting.md b/docs-standalone/troubleshooting.md new file mode 100644 index 00000000..44336cbd --- /dev/null +++ b/docs-standalone/troubleshooting.md @@ -0,0 +1,63 @@ +# Troubleshooting + +## Config does not load + +Symptoms: + +- no panel output +- log shows YAML parse error or file missing + +Checks: + +1. Confirm `CONFIG_FILE` path. +2. Validate YAML syntax. +3. Ensure required per-panel keys exist: `panelRecvTopic`, `panelSendTopic`, `locale`, `timeFormat`, `dateFormat`, `screensaver`, `cards`. + +## MQTT not connected + +Symptoms: + +- log repeats MQTT connection retry + +Checks: + +1. Verify `mqtt_server`, `mqtt_port`, `mqtt_username`, `mqtt_password`. +2. Verify panel publishes on the same topic as `panelRecvTopic`. +3. Verify payload includes `CustomRecv` JSON key. + +## Home Assistant websocket not connected + +Symptoms: + +- log repeatedly waits for websocket/auth + +Checks: + +1. Verify `home_assistant_address` and `home_assistant_token`. +2. In add-on mode, verify Supervisor token access is available. +3. Confirm HA is reachable from container network. + +## Card does not open or navigate + +Checks: + +1. For `navigate.`, confirm target card has matching `key`. +2. For `cardUnlock`, confirm `destination` and `pin` are set. +3. Confirm card `type` is one of the implemented types. + +## Brightness behaves unexpectedly + +Checks: + +1. If using entity-based brightness, verify entity state is numeric. +2. Avoid list-based brightness schedules in this rewrite (not supported). +3. Review interaction between `sleepTracking`, `sleepTrackingZones`, and `sleepOverride`. + +## Useful logs to look for + +- `Config file not found` +- `Error while parsing YAML file` +- `Connected to MQTT Server` +- `Home Assistant auth OK` +- `card type ... not implemented` +- `Not implemented: