From b54e7003e88cb4871059ab410500d349331f492f Mon Sep 17 00:00:00 2001 From: Ramon Date: Sat, 1 Aug 2026 04:58:50 +0200 Subject: [PATCH] v0.8.30-beta - depends_on in sjablonen, en vijftien domotica-apps - Nieuwe metadata-sleutel depends_on: een sjabloon kan zeggen welke andere app het nodig heeft en waarom. Het installatiescherm toont dat voor het invullen, met een knop naar dat sjabloon. Advies, geen blokkade -- de broker of Home Assistant kan net zo goed op een andere machine staan - De reden is verplicht; een waarschuwing zonder uitleg klik je weg. De korte vorm ["mosquitto"] werkt ook, voor sjablonen uit externe repo's - Toegepast op acht sjablonen waar het gemis onzichtbaar was: zigbee2mqtt, alloy, alertmanager, node-exporter, cadvisor, collabora, double-take, soularr. Niet op element, open-webui, exportarr, unpackerr en onlyoffice: die werken met meerdere alternatieven, en depends_on kent geen "een van deze" - Vijftien domotica-apps, van 12 naar 27 in die categorie: Piper, Whisper en openWakeWord (spraakbediening van Home Assistant, tot nu toe volledig afwezig), Matter Server, Matter Hub, AppDaemon, go2rtc, Double Take, Domoticz, openHAB, DSMR-reader (P1-poort slimme meter), rtl_433 (433 MHz sensoren naar MQTT), Traccar, Snapcast en EMQX - Catalogus van 241 naar 256 apps; alle 285 images gecontroleerd Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy --- CHANGELOG.md | 39 +++++++++ README.md | 2 +- VERSION | 2 +- apps/alertmanager/template.json | 6 ++ apps/alloy/template.json | 6 ++ apps/appdaemon/files/compose.yaml | 14 ++++ apps/appdaemon/template.json | 106 ++++++++++++++++++++++++ apps/cadvisor/template.json | 6 ++ apps/collabora/template.json | 6 ++ apps/domoticz/files/compose.yaml | 14 ++++ apps/domoticz/template.json | 65 +++++++++++++++ apps/double-take/files/compose.yaml | 11 +++ apps/double-take/template.json | 66 +++++++++++++++ apps/dsmr-reader/files/compose.yaml | 34 ++++++++ apps/dsmr-reader/template.json | 114 ++++++++++++++++++++++++++ apps/emqx/files/compose.yaml | 14 ++++ apps/emqx/template.json | 76 +++++++++++++++++ apps/go2rtc/files/compose.yaml | 14 ++++ apps/go2rtc/template.json | 74 +++++++++++++++++ apps/matter-hub/files/compose.yaml | 15 ++++ apps/matter-hub/template.json | 97 ++++++++++++++++++++++ apps/matter-server/files/compose.yaml | 12 +++ apps/matter-server/template.json | 65 +++++++++++++++ apps/node-exporter/template.json | 6 ++ apps/openhab/files/compose.yaml | 17 ++++ apps/openhab/template.json | 67 +++++++++++++++ apps/openwakeword/files/compose.yaml | 12 +++ apps/openwakeword/template.json | 87 ++++++++++++++++++++ apps/piper/files/compose.yaml | 12 +++ apps/piper/template.json | 80 ++++++++++++++++++ apps/rtl433/files/compose.yaml | 12 +++ apps/rtl433/template.json | 85 +++++++++++++++++++ apps/snapserver/files/compose.yaml | 13 +++ apps/snapserver/template.json | 73 +++++++++++++++++ apps/soularr/template.json | 10 +++ apps/traccar/files/compose.yaml | 13 +++ apps/traccar/template.json | 68 +++++++++++++++ apps/whisper/files/compose.yaml | 12 +++ apps/whisper/template.json | 96 ++++++++++++++++++++++ apps/zigbee2mqtt/template.json | 6 ++ docs/apps-maken.md | 24 ++++++ server-up/app.py | 41 +++++++++ server-up/core/boilerplates.py | 24 ++++++ server-up/templates/index.html | 41 ++++++++- server-up/translations/en.json | 5 +- server-up/translations/nl.json | 5 +- tests/js/menu.test.js | 17 ++++ tests/test_connect.py | 108 ++++++++++++++++++++++++ tools/arr_sjablonen.py | 12 ++- 49 files changed, 1798 insertions(+), 6 deletions(-) create mode 100644 apps/appdaemon/files/compose.yaml create mode 100644 apps/appdaemon/template.json create mode 100644 apps/domoticz/files/compose.yaml create mode 100644 apps/domoticz/template.json create mode 100644 apps/double-take/files/compose.yaml create mode 100644 apps/double-take/template.json create mode 100644 apps/dsmr-reader/files/compose.yaml create mode 100644 apps/dsmr-reader/template.json create mode 100644 apps/emqx/files/compose.yaml create mode 100644 apps/emqx/template.json create mode 100644 apps/go2rtc/files/compose.yaml create mode 100644 apps/go2rtc/template.json create mode 100644 apps/matter-hub/files/compose.yaml create mode 100644 apps/matter-hub/template.json create mode 100644 apps/matter-server/files/compose.yaml create mode 100644 apps/matter-server/template.json create mode 100644 apps/openhab/files/compose.yaml create mode 100644 apps/openhab/template.json create mode 100644 apps/openwakeword/files/compose.yaml create mode 100644 apps/openwakeword/template.json create mode 100644 apps/piper/files/compose.yaml create mode 100644 apps/piper/template.json create mode 100644 apps/rtl433/files/compose.yaml create mode 100644 apps/rtl433/template.json create mode 100644 apps/snapserver/files/compose.yaml create mode 100644 apps/snapserver/template.json create mode 100644 apps/traccar/files/compose.yaml create mode 100644 apps/traccar/template.json create mode 100644 apps/whisper/files/compose.yaml create mode 100644 apps/whisper/template.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a07c66..251d7ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,42 @@ +# v0.8.30-beta — Sjablonen kunnen zeggen wat ze nodig hebben, en vijftien domotica-apps + +**Een app kon niet zeggen dat hij een andere nodig had.** Het `connect`-veld +wijst naar een andere app en vult een adres in, maar zegt niets over noodzaak. +Daardoor kon je Zigbee2MQTT installeren zonder MQTT-broker, Alertmanager zonder +Prometheus en Grafana Alloy zonder Loki. Alle drie starten ze, doen niets, en de +reden staat nergens. + +Sjablonen kunnen dat nu wél zeggen, met `depends_on` in de metadata. Het +installatiescherm toont vóór het invullen wat er ontbreekt, met de reden erbij en +een knop die je meteen naar dat sjabloon brengt. **Advies, geen blokkade** — je +kunt de broker of Home Assistant net zo goed op een andere machine hebben staan. +De reden is verplicht: een waarschuwing zonder uitleg klik je weg. + +Meteen toegepast op acht sjablonen waar het gemis tot nu toe onzichtbaar was: +Zigbee2MQTT, Alloy, Alertmanager, node-exporter, cAdvisor, Collabora, Double Take +en Soularr. Bewust níét op Element, open-webui, Exportarr, Unpackerr en ONLYOFFICE: +die werken met meerdere alternatieven, en `depends_on` kent geen "een van deze". + +**Vijftien domotica-apps.** Van 12 naar 27 in die categorie — vooral het spul dat +*om* Home Assistant heen hoort: + +- **Stemassistent**, tot nu toe volledig afwezig: Piper (tekst naar spraak), + Whisper (spraak naar tekst) en openWakeWord (het activeerwoord). Samen maken ze + de spraakbediening van HA compleet zonder dat er iets naar een clouddienst gaat. +- **Matter Server** en **Matter Hub**, plus **AppDaemon** voor automatiseringen in + Python +- **go2rtc** (camerastreams) en **Double Take** (gezichtsherkenning op Frigate) +- **Domoticz** en **openHAB** als alternatief voor Home Assistant zelf +- Voor de Nederlandse opstelling: **DSMR-reader** leest de P1-poort van je slimme + meter uit, **rtl_433** vangt de 433 MHz-sensoren van weerstations en regenmeters + op en zet ze op MQTT +- **Traccar** (GPS-tracking), **Snapcast** (audio door het hele huis) en **EMQX** + (MQTT-broker met webinterface) + +Drie daarvan hebben een fysiek apparaat nodig — een P1-kabel, een SDR-stick, een +Zigbee-dongle. Die krijgen een veld met uitleg over hoe je het juiste pad vindt, +in plaats van een gok die stilzwijgend faalt. + # v0.8.20-beta — Prometheus startte niet, en 23 apps erbij **Prometheus stond kapot in de catalogus.** Het sjabloon koppelde een lege map op diff --git a/README.md b/README.md index 4f4b7f0..7b33b89 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ IP-adres in je netwerk geven. | | | |---|---| -| **App-catalogus** | 241 kant-en-klare apps, ingedeeld in categorieën met kleur. Zoeken, filteren en installeren met een formulier in plaats van YAML. | +| **App-catalogus** | 256 kant-en-klare apps, ingedeeld in categorieën met kleur. Zoeken, filteren en installeren met een formulier in plaats van YAML. | | **Stacks beheren** | Starten, stoppen, bijwerken en herstarten — per stack of per losse container, met logs en live CPU-/geheugengebruik. | | **Apps koppelen** | Stacks komen op een gedeeld netwerk, zodat ze elkaar op naam bereiken. Een veld dat naar een andere app verwijst toont een keuzelijst met wat je al draait. | | **Eigen IP per stack** | Met macvlan of ipvlan krijgt een app een eigen adres in je LAN in plaats van poorten op de host. | diff --git a/VERSION b/VERSION index 3c2e9ad..a65aeb3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.8.20-beta +0.8.30-beta diff --git a/apps/alertmanager/template.json b/apps/alertmanager/template.json index 5097de6..d452254 100644 --- a/apps/alertmanager/template.json +++ b/apps/alertmanager/template.json @@ -18,6 +18,12 @@ "categories": [ "monitoring", "communicatie" + ], + "depends_on": [ + { + "app": "prometheus", + "reason": "Alertmanager verwerkt de alarmen die Prometheus opwerpt; los draaiend krijgt hij er nooit een." + } ] }, "variables": [ diff --git a/apps/alloy/template.json b/apps/alloy/template.json index b9f1916..5045d9e 100644 --- a/apps/alloy/template.json +++ b/apps/alloy/template.json @@ -17,6 +17,12 @@ }, "categories": [ "monitoring" + ], + "depends_on": [ + { + "app": "loki", + "reason": "Alloy verzamelt logs en stuurt ze door. Zonder Loki om ze te bewaren gaan ze meteen weer verloren." + } ] }, "variables": [ diff --git a/apps/appdaemon/files/compose.yaml b/apps/appdaemon/files/compose.yaml new file mode 100644 index 0000000..e0ef300 --- /dev/null +++ b/apps/appdaemon/files/compose.yaml @@ -0,0 +1,14 @@ +services: + << service_name >>: + image: acockburn/appdaemon:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - HA_URL=<< ha_url >> + - TOKEN=<< ha_token >> + - DASH_URL=<< dash_url >> + volumes: + - << appdata_dir >>/<< service_name >>:/conf + ports: + - "<< port >>:5050" + restart: unless-stopped diff --git a/apps/appdaemon/template.json b/apps/appdaemon/template.json new file mode 100644 index 0000000..2362d4a --- /dev/null +++ b/apps/appdaemon/template.json @@ -0,0 +1,106 @@ +{ + "kind": "compose", + "metadata": { + "name": "AppDaemon", + "description": "Automatiseringen voor Home Assistant in Python in plaats van YAML. Voor logica die met de ingebouwde automatiseringen onhandig wordt.", + "tags": [ + "domotica", + "automatisering", + "python" + ], + "icon": { + "provider": "selfhst", + "id": "appdaemon" + }, + "version": { + "name": "latest" + }, + "categories": [ + "domotica", + "ontwikkeling" + ], + "depends_on": [ + { + "app": "home-assistant", + "reason": "Dit is een dienst die Home Assistant aanroept; los draaiend doet hij niets." + } + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "appdaemon", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 5050, + "required": true + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "ha_url", + "type": "str", + "title": "Adres van Home Assistant", + "default": "http://homeassistant:8123", + "required": true, + "connect": { + "app": "home-assistant", + "scheme": "http", + "port": 8123 + }, + "help": "Waar AppDaemon Home Assistant bereikt." + }, + { + "name": "dash_url", + "type": "str", + "title": "Eigen adres", + "default": "http://localhost:5050", + "required": true, + "description": "Waar het dashboard van AppDaemon zelf op staat" + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "ha_token", + "type": "str", + "title": "Toegangstoken van Home Assistant", + "default": "", + "required": true, + "secret": true, + "eigen_invoer": true, + "description": "Maak er een aan onder je profiel in Home Assistant" + } + ] + } + ] +} diff --git a/apps/cadvisor/template.json b/apps/cadvisor/template.json index 35d3f80..532a879 100644 --- a/apps/cadvisor/template.json +++ b/apps/cadvisor/template.json @@ -19,6 +19,12 @@ "categories": [ "monitoring", "beheer" + ], + "depends_on": [ + { + "app": "prometheus", + "reason": "Levert meetwaarden per container waar Prometheus ze komt ophalen." + } ] }, "variables": [ diff --git a/apps/collabora/template.json b/apps/collabora/template.json index 652761f..9a4cd54 100644 --- a/apps/collabora/template.json +++ b/apps/collabora/template.json @@ -18,6 +18,12 @@ "categories": [ "documenten", "productiviteit" + ], + "depends_on": [ + { + "app": "nextcloud-aio", + "reason": "Collabora is de bewerker; de bestanden en de gebruikers komen uit Nextcloud. Los draaiend heb je niets om te openen." + } ] }, "variables": [ diff --git a/apps/domoticz/files/compose.yaml b/apps/domoticz/files/compose.yaml new file mode 100644 index 0000000..660d654 --- /dev/null +++ b/apps/domoticz/files/compose.yaml @@ -0,0 +1,14 @@ +services: + << service_name >>: + image: domoticz/domoticz:stable + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - WWW_PORT=8080 + - SSL_PORT=6144 + volumes: + - << appdata_dir >>/<< service_name >>:/opt/domoticz/userdata + ports: + - "<< port >>:8080" + - "<< port_ssl >>:6144" + restart: unless-stopped diff --git a/apps/domoticz/template.json b/apps/domoticz/template.json new file mode 100644 index 0000000..be3c4d3 --- /dev/null +++ b/apps/domoticz/template.json @@ -0,0 +1,65 @@ +{ + "kind": "compose", + "metadata": { + "name": "Domoticz", + "description": "Lichtgewicht domoticasysteem dat op bescheiden hardware draait, met veel ondersteuning voor oudere protocollen. Let op: Heb je een USB-stick voor Z-Wave of RFXCOM, geef die dan door onder `devices` in het compose-bestand.", + "tags": [ + "domotica", + "automatisering" + ], + "icon": { + "provider": "selfhst", + "id": "domoticz" + }, + "version": { + "name": "latest" + }, + "categories": [ + "domotica" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "domoticz", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8219, + "required": true, + "description": "Standaard 8080; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "port_ssl", + "type": "int", + "title": "Beveiligde poort", + "default": 6144, + "required": true + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + } + ] +} diff --git a/apps/double-take/files/compose.yaml b/apps/double-take/files/compose.yaml new file mode 100644 index 0000000..9fc02b1 --- /dev/null +++ b/apps/double-take/files/compose.yaml @@ -0,0 +1,11 @@ +services: + << service_name >>: + image: jakowenko/double-take:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + volumes: + - << appdata_dir >>/<< service_name >>:/.storage + ports: + - "<< port >>:3000" + restart: unless-stopped diff --git a/apps/double-take/template.json b/apps/double-take/template.json new file mode 100644 index 0000000..4828bb5 --- /dev/null +++ b/apps/double-take/template.json @@ -0,0 +1,66 @@ +{ + "kind": "compose", + "metadata": { + "name": "Double Take", + "description": "Herkent gezichten in de beelden die Frigate doorgeeft, en meldt aan Home Assistant wie er voor de deur staat.", + "tags": [ + "camera", + "gezichtsherkenning", + "domotica" + ], + "icon": { + "provider": "selfhst", + "id": "double-take" + }, + "version": { + "name": "latest" + }, + "categories": [ + "domotica", + "beveiliging" + ], + "depends_on": [ + { + "app": "frigate", + "reason": "Double Take verwerkt de beelden die Frigate aanlevert; zonder Frigate krijgt het niets binnen." + } + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "doubletake", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8224, + "required": true, + "description": "Standaard 3000; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + } + ] +} diff --git a/apps/dsmr-reader/files/compose.yaml b/apps/dsmr-reader/files/compose.yaml new file mode 100644 index 0000000..5c79bc6 --- /dev/null +++ b/apps/dsmr-reader/files/compose.yaml @@ -0,0 +1,34 @@ +services: + << service_name >>: + image: xirixiz/dsmr-reader-docker:latest + container_name: << service_name >> + environment: + - DJANGO_TIME_ZONE=<< timezone >> + - DJANGO_SECRET_KEY=<< secret_key >> + - DJANGO_DATABASE_HOST=<< service_name >>-db + - DJANGO_DATABASE_NAME=dsmrreader + - DJANGO_DATABASE_USER=dsmrreader + - DJANGO_DATABASE_PASSWORD=<< db_password >> + - DSMR_USER=<< admin_user >> + - DSMR_PASSWORD=<< admin_password >> + - DSMRREADER_REMOTE_DATALOGGER_INPUT_METHOD=serial + - DSMRREADER_REMOTE_DATALOGGER_SERIAL_PORT=/dev/ttyUSB0 + volumes: + - << appdata_dir >>/<< service_name >>:/app/backups + ports: + - "<< port >>:80" + depends_on: + - << service_name >>-db + devices: + - << p1_apparaat >>:/dev/ttyUSB0 + restart: unless-stopped + << service_name >>-db: + image: postgres:16-alpine + container_name: << service_name >>-db + environment: + - POSTGRES_DB=dsmrreader + - POSTGRES_USER=dsmrreader + - POSTGRES_PASSWORD=<< db_password >> + volumes: + - << appdata_dir >>/<< service_name >>-db:/var/lib/postgresql/data + restart: unless-stopped diff --git a/apps/dsmr-reader/template.json b/apps/dsmr-reader/template.json new file mode 100644 index 0000000..c1487b7 --- /dev/null +++ b/apps/dsmr-reader/template.json @@ -0,0 +1,114 @@ +{ + "kind": "compose", + "metadata": { + "name": "DSMR-reader", + "description": "Leest de P1-poort van je slimme meter uit en houdt verbruik, teruglevering en gasstanden bij, met grafieken per dag en per jaar.", + "tags": [ + "energie", + "slimme-meter", + "p1" + ], + "icon": { + "provider": "selfhst", + "id": "dsmr-reader" + }, + "version": { + "name": "latest" + }, + "categories": [ + "domotica", + "gezin" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "dsmrreader", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8221, + "required": true, + "description": "Standaard 80; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "p1_apparaat", + "type": "str", + "title": "P1-kabel", + "default": "/dev/ttyUSB0", + "required": true, + "description": "Het apparaat van je P1-kabel op de host", + "help": "Zoek het met `ls -l /dev/serial/by-id/`. Gebruik bij voorkeur dat pad in plaats van /dev/ttyUSB0: dat nummer kan na een herstart bij een ander apparaat horen." + }, + { + "name": "admin_user", + "type": "str", + "title": "Gebruikersnaam", + "default": "admin", + "required": true + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "db_password", + "type": "str", + "title": "Databasewachtwoord", + "default": "", + "required": true, + "secret": true, + "generate": "auto", + "description": "Wordt automatisch ingevuld en in .env bewaard" + }, + { + "name": "secret_key", + "type": "str", + "title": "Django-sleutel", + "default": "", + "required": true, + "secret": true, + "generate": "auto" + }, + { + "name": "admin_password", + "type": "str", + "title": "Wachtwoord", + "default": "", + "required": true, + "secret": true, + "eigen_invoer": true + } + ] + } + ] +} diff --git a/apps/emqx/files/compose.yaml b/apps/emqx/files/compose.yaml new file mode 100644 index 0000000..a872612 --- /dev/null +++ b/apps/emqx/files/compose.yaml @@ -0,0 +1,14 @@ +services: + << service_name >>: + image: emqx/emqx:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + volumes: + - << appdata_dir >>/<< service_name >>:/opt/emqx/data + - << appdata_dir >>/<< service_name >>-log:/opt/emqx/log + ports: + - "<< port_mqtt >>:1883" + - "<< port >>:18083" + - "<< port_ws >>:8083" + restart: unless-stopped diff --git a/apps/emqx/template.json b/apps/emqx/template.json new file mode 100644 index 0000000..e183f8b --- /dev/null +++ b/apps/emqx/template.json @@ -0,0 +1,76 @@ +{ + "kind": "compose", + "metadata": { + "name": "EMQX", + "description": "MQTT-broker met een webinterface, regels en clustering. Zwaarder dan Mosquitto, maar je ziet wat er langskomt. Let op: Het standaardaccount is admin met wachtwoord public — wijzig dat meteen na de eerste keer inloggen.", + "tags": [ + "mqtt", + "broker", + "domotica" + ], + "icon": { + "provider": "selfhst", + "id": "emqx" + }, + "version": { + "name": "latest" + }, + "categories": [ + "domotica", + "netwerk" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "emqx", + "required": true + }, + { + "name": "port_mqtt", + "type": "int", + "title": "MQTT-poort", + "default": 1884, + "required": true, + "description": "Standaard 1883; hier verplaatst omdat Mosquitto die al gebruikt" + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8223, + "required": true, + "description": "Standaard 18083; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "port_ws", + "type": "int", + "title": "Websocket-poort", + "default": 8227, + "required": true, + "description": "Standaard 8083; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + } + ] +} diff --git a/apps/go2rtc/files/compose.yaml b/apps/go2rtc/files/compose.yaml new file mode 100644 index 0000000..bb53870 --- /dev/null +++ b/apps/go2rtc/files/compose.yaml @@ -0,0 +1,14 @@ +services: + << service_name >>: + image: alexxit/go2rtc:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + volumes: + - << appdata_dir >>/<< service_name >>:/config + ports: + - "<< port >>:1984" + - "<< port_rtsp >>:8554" + - "<< port_webrtc >>:8555" + - "<< port_webrtc >>:8555/udp" + restart: unless-stopped diff --git a/apps/go2rtc/template.json b/apps/go2rtc/template.json new file mode 100644 index 0000000..a618f1d --- /dev/null +++ b/apps/go2rtc/template.json @@ -0,0 +1,74 @@ +{ + "kind": "compose", + "metadata": { + "name": "go2rtc", + "description": "Zet camerastreams om naar een formaat dat je browser aankan, met bijna geen vertraging. Werkt los, en zit ook in Frigate ingebouwd. Let op: De camera's zet je in go2rtc.yaml in de configuratiemap.", + "tags": [ + "camera", + "streaming", + "domotica" + ], + "icon": { + "provider": "selfhst", + "id": "go2rtc" + }, + "version": { + "name": "latest" + }, + "categories": [ + "domotica", + "media" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "go2rtc", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 1984, + "required": true + }, + { + "name": "port_rtsp", + "type": "int", + "title": "RTSP-poort", + "default": 8228, + "required": true, + "description": "Standaard 8554; hier verplaatst omdat Frigate die al gebruikt" + }, + { + "name": "port_webrtc", + "type": "int", + "title": "WebRTC-poort", + "default": 8555, + "required": true + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + } + ] +} diff --git a/apps/matter-hub/files/compose.yaml b/apps/matter-hub/files/compose.yaml new file mode 100644 index 0000000..a8deb87 --- /dev/null +++ b/apps/matter-hub/files/compose.yaml @@ -0,0 +1,15 @@ +services: + << service_name >>: + image: ghcr.io/t0bst4r/home-assistant-matter-hub:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - HAMH_HOME_ASSISTANT_URL=<< ha_url >> + - HAMH_HOME_ASSISTANT_ACCESS_TOKEN=<< ha_token >> + - HAMH_LOG_LEVEL=info + volumes: + - << appdata_dir >>/<< service_name >>:/data + ports: + - "<< port >>:8482" + network_mode: host + restart: unless-stopped diff --git a/apps/matter-hub/template.json b/apps/matter-hub/template.json new file mode 100644 index 0000000..84e90bb --- /dev/null +++ b/apps/matter-hub/template.json @@ -0,0 +1,97 @@ +{ + "kind": "compose", + "metadata": { + "name": "Matter Hub", + "description": "Biedt je Home Assistant-apparaten aan als Matter-bridge, zodat Alexa, Google Home en Apple Home ze zien. Let op: Draait op het netwerk van de host, want Matter-apparaten vinden elkaar via uitzendingen op je LAN.", + "tags": [ + "matter", + "domotica", + "bridge" + ], + "icon": { + "provider": "selfhst", + "id": "matter" + }, + "version": { + "name": "latest" + }, + "categories": [ + "domotica" + ], + "depends_on": [ + { + "app": "home-assistant", + "reason": "Dit is een dienst die Home Assistant aanroept; los draaiend doet hij niets." + } + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "matterhub", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8482, + "required": true + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "ha_url", + "type": "str", + "title": "Adres van Home Assistant", + "default": "http://homeassistant:8123", + "required": true, + "connect": { + "app": "home-assistant", + "scheme": "http", + "port": 8123 + }, + "help": "Het adres waarop de bridge Home Assistant bereikt." + } + ] + }, + { + "title": "Toegang", + "items": [ + { + "name": "ha_token", + "type": "str", + "title": "Toegangstoken van Home Assistant", + "default": "", + "required": true, + "secret": true, + "eigen_invoer": true, + "description": "Maak er een aan onder je profiel, onderaan bij 'Langlopende toegangstokens'" + } + ] + } + ] +} diff --git a/apps/matter-server/files/compose.yaml b/apps/matter-server/files/compose.yaml new file mode 100644 index 0000000..2a7d75a --- /dev/null +++ b/apps/matter-server/files/compose.yaml @@ -0,0 +1,12 @@ +services: + << service_name >>: + image: ghcr.io/home-assistant-libs/python-matter-server:stable + container_name: << service_name >> + environment: + - TZ=<< timezone >> + volumes: + - << appdata_dir >>/<< service_name >>:/data + ports: + - "<< port >>:5580" + network_mode: host + restart: unless-stopped diff --git a/apps/matter-server/template.json b/apps/matter-server/template.json new file mode 100644 index 0000000..044ce85 --- /dev/null +++ b/apps/matter-server/template.json @@ -0,0 +1,65 @@ +{ + "kind": "compose", + "metadata": { + "name": "Matter Server", + "description": "Laat Home Assistant met Matter-apparaten praten. Draait als aparte dienst omdat het een eigen Thread- en Wi-Fi-stack meebrengt. Let op: Draait op het netwerk van de host: Matter en Thread werken met uitzendingen over IPv6, en die komen een Docker-bridge niet uit.", + "tags": [ + "matter", + "thread", + "domotica" + ], + "icon": { + "provider": "selfhst", + "id": "matter" + }, + "version": { + "name": "latest" + }, + "categories": [ + "domotica" + ], + "depends_on": [ + { + "app": "home-assistant", + "reason": "Dit is een dienst die Home Assistant aanroept; los draaiend doet hij niets." + } + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "matterserver", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Websocket-poort", + "default": 5580, + "required": true, + "description": "Hier maakt Home Assistant verbinding mee" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + } + ] +} diff --git a/apps/node-exporter/template.json b/apps/node-exporter/template.json index 4a4e54d..e04a768 100644 --- a/apps/node-exporter/template.json +++ b/apps/node-exporter/template.json @@ -17,6 +17,12 @@ }, "categories": [ "monitoring" + ], + "depends_on": [ + { + "app": "prometheus", + "reason": "Levert meetwaarden waar Prometheus ze komt ophalen. Zonder Prometheus meet hij in het luchtledige." + } ] }, "variables": [ diff --git a/apps/openhab/files/compose.yaml b/apps/openhab/files/compose.yaml new file mode 100644 index 0000000..e5e9465 --- /dev/null +++ b/apps/openhab/files/compose.yaml @@ -0,0 +1,17 @@ +services: + << service_name >>: + image: openhab/openhab:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + - OPENHAB_HTTP_PORT=8080 + - OPENHAB_HTTPS_PORT=8443 + - EXTRA_JAVA_OPTS=-Duser.timezone=<< timezone >> + volumes: + - << appdata_dir >>/<< service_name >>:/openhab/conf + - << appdata_dir >>/<< service_name >>-userdata:/openhab/userdata + - << appdata_dir >>/<< service_name >>-addons:/openhab/addons + ports: + - "<< port >>:8080" + - "<< port_https >>:8443" + restart: unless-stopped diff --git a/apps/openhab/template.json b/apps/openhab/template.json new file mode 100644 index 0000000..74e5ed4 --- /dev/null +++ b/apps/openhab/template.json @@ -0,0 +1,67 @@ +{ + "kind": "compose", + "metadata": { + "name": "openHAB", + "description": "Domoticasysteem met ruim vierhonderd koppelingen en een eigen regeltaal. Zwaarder dan Home Assistant, maar krachtiger in complexe opstellingen.", + "tags": [ + "domotica", + "automatisering", + "java" + ], + "icon": { + "provider": "selfhst", + "id": "openhab" + }, + "version": { + "name": "latest" + }, + "categories": [ + "domotica" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "openhab", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8220, + "required": true, + "description": "Standaard 8080; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "port_https", + "type": "int", + "title": "HTTPS-poort", + "default": 8229, + "required": true, + "description": "Standaard 8443; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + } + ] +} diff --git a/apps/openwakeword/files/compose.yaml b/apps/openwakeword/files/compose.yaml new file mode 100644 index 0000000..09a8787 --- /dev/null +++ b/apps/openwakeword/files/compose.yaml @@ -0,0 +1,12 @@ +services: + << service_name >>: + image: rhasspy/wyoming-openwakeword:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + volumes: + - << appdata_dir >>/<< service_name >>:/data + command: --preload-model << activeerwoord >> + ports: + - "<< port >>:10400" + restart: unless-stopped diff --git a/apps/openwakeword/template.json b/apps/openwakeword/template.json new file mode 100644 index 0000000..ee001d8 --- /dev/null +++ b/apps/openwakeword/template.json @@ -0,0 +1,87 @@ +{ + "kind": "compose", + "metadata": { + "name": "openWakeWord", + "description": "Luistert naar het activeerwoord waarmee je een gesprek met Home Assistant begint, zonder dat er iets meeluistert bij een ander.", + "tags": [ + "spraak", + "domotica", + "wyoming" + ], + "icon": { + "provider": "selfhst", + "id": "home-assistant" + }, + "version": { + "name": "latest" + }, + "categories": [ + "domotica", + "ai" + ], + "depends_on": [ + { + "app": "home-assistant", + "reason": "Dit is een dienst die Home Assistant aanroept; los draaiend doet hij niets." + } + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "openwakeword", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Wyoming-poort", + "default": 10400, + "required": true, + "description": "Hier maakt Home Assistant verbinding mee" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "activeerwoord", + "type": "enum", + "title": "Activeerwoord", + "default": "ok_nabu", + "required": true, + "config": { + "options": [ + "ok_nabu", + "hey_jarvis", + "alexa", + "hey_mycroft", + "hey_rhasspy" + ] + } + } + ] + } + ] +} diff --git a/apps/piper/files/compose.yaml b/apps/piper/files/compose.yaml new file mode 100644 index 0000000..0af08fe --- /dev/null +++ b/apps/piper/files/compose.yaml @@ -0,0 +1,12 @@ +services: + << service_name >>: + image: rhasspy/wyoming-piper:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + volumes: + - << appdata_dir >>/<< service_name >>:/data + command: --voice << stem >> + ports: + - "<< port >>:10200" + restart: unless-stopped diff --git a/apps/piper/template.json b/apps/piper/template.json new file mode 100644 index 0000000..ef1f544 --- /dev/null +++ b/apps/piper/template.json @@ -0,0 +1,80 @@ +{ + "kind": "compose", + "metadata": { + "name": "Piper", + "description": "Zet tekst om in spraak, op je eigen server. Home Assistant praat hiermee terug zonder dat er iets naar een clouddienst gaat.", + "tags": [ + "spraak", + "domotica", + "wyoming" + ], + "icon": { + "provider": "selfhst", + "id": "home-assistant" + }, + "version": { + "name": "latest" + }, + "categories": [ + "domotica", + "ai" + ], + "depends_on": [ + { + "app": "home-assistant", + "reason": "Dit is een dienst die Home Assistant aanroept; los draaiend doet hij niets." + } + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "piper", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Wyoming-poort", + "default": 10200, + "required": true, + "description": "Hier maakt Home Assistant verbinding mee" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "stem", + "type": "str", + "title": "Stem", + "default": "nl_BE-nathalie-medium", + "required": true, + "description": "Bijvoorbeeld nl_BE-nathalie-medium of en_US-lessac-medium", + "help": "De stem wordt bij de eerste start gedownload. Nederlandse stemmen beginnen met nl_NL of nl_BE; het achtervoegsel (low, medium, high) bepaalt kwaliteit tegen snelheid." + } + ] + } + ] +} diff --git a/apps/rtl433/files/compose.yaml b/apps/rtl433/files/compose.yaml new file mode 100644 index 0000000..e16296d --- /dev/null +++ b/apps/rtl433/files/compose.yaml @@ -0,0 +1,12 @@ +services: + << service_name >>: + image: hertzg/rtl_433:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + volumes: + - << appdata_dir >>/<< service_name >>:/etc/rtl_433 + command: -F "mqtt://<< mqtt_host >>,retain=1,devices=rtl_433[/model][/id]" -M time -M protocol + devices: + - << sdr_apparaat >>:/dev/bus/usb + restart: unless-stopped diff --git a/apps/rtl433/template.json b/apps/rtl433/template.json new file mode 100644 index 0000000..4226321 --- /dev/null +++ b/apps/rtl433/template.json @@ -0,0 +1,85 @@ +{ + "kind": "compose", + "metadata": { + "name": "rtl_433", + "description": "Vangt de signalen op van draadloze sensoren op 433 MHz — weerstations, regenmeters, deursensoren — en zet ze op MQTT.", + "tags": [ + "sensoren", + "433mhz", + "mqtt", + "domotica" + ], + "icon": { + "provider": "selfhst", + "id": "rtl433" + }, + "version": { + "name": "latest" + }, + "categories": [ + "domotica" + ], + "depends_on": [ + { + "app": "mosquitto", + "reason": "rtl_433 publiceert alles wat het opvangt naar een MQTT-broker; zonder broker verdwijnen de metingen." + } + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "rtl433", + "required": true + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "mqtt_host", + "type": "str", + "title": "MQTT-broker", + "default": "mosquitto:1883", + "required": true, + "connect": { + "app": "mosquitto", + "scheme": "", + "port": 1883 + }, + "help": "Waar de opgevangen metingen naartoe gaan." + }, + { + "name": "sdr_apparaat", + "type": "str", + "title": "SDR-stick", + "default": "/dev/bus/usb", + "required": true, + "description": "De USB-bus waar je RTL-SDR-ontvanger op zit", + "help": "De hele USB-bus doorgeven werkt, maar geeft de container toegang tot elk USB-apparaat. Wil je dat niet, zoek dan het pad van juist deze stick met `lsusb`." + } + ] + } + ] +} diff --git a/apps/snapserver/files/compose.yaml b/apps/snapserver/files/compose.yaml new file mode 100644 index 0000000..61d18ba --- /dev/null +++ b/apps/snapserver/files/compose.yaml @@ -0,0 +1,13 @@ +services: + << service_name >>: + image: saiyato/snapserver:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + volumes: + - << appdata_dir >>/<< service_name >>:/etc/snapserver + ports: + - "<< port >>:1704" + - "<< port_control >>:1705" + - "<< port_web >>:1780" + restart: unless-stopped diff --git a/apps/snapserver/template.json b/apps/snapserver/template.json new file mode 100644 index 0000000..021bb65 --- /dev/null +++ b/apps/snapserver/template.json @@ -0,0 +1,73 @@ +{ + "kind": "compose", + "metadata": { + "name": "Snapcast", + "description": "Speelt muziek gelijk af door het hele huis: elke speaker loopt op de milliseconde synchroon, ook op verschillende apparaten. Let op: De bronnen zet je in snapserver.conf in de configuratiemap. Op elke speaker draai je een snapclient.", + "tags": [ + "muziek", + "multiroom", + "audio" + ], + "icon": { + "provider": "selfhst", + "id": "snapcast" + }, + "version": { + "name": "latest" + }, + "categories": [ + "domotica", + "media" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "snapserver", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Streampoort", + "default": 1704, + "required": true + }, + { + "name": "port_control", + "type": "int", + "title": "Besturingspoort", + "default": 1705, + "required": true + }, + { + "name": "port_web", + "type": "int", + "title": "Webinterface", + "default": 1780, + "required": true + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + } + ] +} diff --git a/apps/soularr/template.json b/apps/soularr/template.json index fa6b46a..61dd8c3 100644 --- a/apps/soularr/template.json +++ b/apps/soularr/template.json @@ -17,6 +17,16 @@ "categories": [ "downloaden", "media" + ], + "depends_on": [ + { + "app": "lidarr", + "reason": "Soularr pakt de gaten op die Lidarr aangeeft; zonder Lidarr weet het niet waarnaar het moet zoeken." + }, + { + "app": "slskd", + "reason": "Het zoeken zelf gebeurt via Soulseek, waarvoor slskd de verbinding maakt." + } ] }, "variables": [ diff --git a/apps/traccar/files/compose.yaml b/apps/traccar/files/compose.yaml new file mode 100644 index 0000000..6493f48 --- /dev/null +++ b/apps/traccar/files/compose.yaml @@ -0,0 +1,13 @@ +services: + << service_name >>: + image: traccar/traccar:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + volumes: + - << appdata_dir >>/<< service_name >>:/opt/traccar/data + - << appdata_dir >>/<< service_name >>-logs:/opt/traccar/logs + ports: + - "<< port >>:8082" + - "<< port_osmand >>:5055" + restart: unless-stopped diff --git a/apps/traccar/template.json b/apps/traccar/template.json new file mode 100644 index 0000000..0ba4867 --- /dev/null +++ b/apps/traccar/template.json @@ -0,0 +1,68 @@ +{ + "kind": "compose", + "metadata": { + "name": "Traccar", + "description": "Serverkant voor GPS-tracking: ontvangt posities van telefoons en trackers, met kaarten, routes en geofences.", + "tags": [ + "gps", + "tracking", + "kaart" + ], + "icon": { + "provider": "selfhst", + "id": "traccar" + }, + "version": { + "name": "latest" + }, + "categories": [ + "domotica", + "gezin" + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "traccar", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Webinterface", + "default": 8225, + "required": true, + "description": "Standaard 8082; hier verplaatst omdat die poort al bezet is" + }, + { + "name": "port_osmand", + "type": "int", + "title": "OsmAnd-poort", + "default": 8226, + "required": true, + "description": "Waar telefoons hun positie naartoe sturen; standaard 5055, hier verplaatst omdat Jellyseerr die al gebruikt" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + } + ] +} diff --git a/apps/whisper/files/compose.yaml b/apps/whisper/files/compose.yaml new file mode 100644 index 0000000..15f90fa --- /dev/null +++ b/apps/whisper/files/compose.yaml @@ -0,0 +1,12 @@ +services: + << service_name >>: + image: rhasspy/wyoming-whisper:latest + container_name: << service_name >> + environment: + - TZ=<< timezone >> + volumes: + - << appdata_dir >>/<< service_name >>:/data + command: --model << model >> --language << taal >> + ports: + - "<< port >>:10300" + restart: unless-stopped diff --git a/apps/whisper/template.json b/apps/whisper/template.json new file mode 100644 index 0000000..c9088a4 --- /dev/null +++ b/apps/whisper/template.json @@ -0,0 +1,96 @@ +{ + "kind": "compose", + "metadata": { + "name": "Whisper", + "description": "Zet spraak om in tekst. De oorkant van de stembediening van Home Assistant, volledig lokaal.", + "tags": [ + "spraak", + "domotica", + "wyoming", + "transcriptie" + ], + "icon": { + "provider": "selfhst", + "id": "home-assistant" + }, + "version": { + "name": "latest" + }, + "categories": [ + "domotica", + "ai" + ], + "depends_on": [ + { + "app": "home-assistant", + "reason": "Dit is een dienst die Home Assistant aanroept; los draaiend doet hij niets." + } + ] + }, + "variables": [ + { + "title": "Algemeen", + "items": [ + { + "name": "service_name", + "type": "str", + "title": "Servicenaam", + "default": "whisper", + "required": true + }, + { + "name": "port", + "type": "int", + "title": "Wyoming-poort", + "default": 10300, + "required": true, + "description": "Hier maakt Home Assistant verbinding mee" + }, + { + "name": "appdata_dir", + "type": "str", + "title": "Appdata-map", + "default": "/opt/serverup/appdata", + "required": true, + "description": "Basismap voor de gegevens van deze app" + }, + { + "name": "timezone", + "type": "str", + "title": "Tijdzone", + "default": "Europe/Amsterdam", + "required": true + } + ] + }, + { + "title": "Instellingen", + "items": [ + { + "name": "model", + "type": "enum", + "title": "Model", + "default": "base", + "required": true, + "config": { + "options": [ + "tiny", + "base", + "small", + "medium", + "large-v3" + ] + }, + "description": "Groter is nauwkeuriger en trager; base is een goed begin" + }, + { + "name": "taal", + "type": "str", + "title": "Taal", + "default": "nl", + "required": true + } + ] + } + ] +} diff --git a/apps/zigbee2mqtt/template.json b/apps/zigbee2mqtt/template.json index 51130ba..f69a51f 100644 --- a/apps/zigbee2mqtt/template.json +++ b/apps/zigbee2mqtt/template.json @@ -17,6 +17,12 @@ }, "categories": [ "domotica" + ], + "depends_on": [ + { + "app": "mosquitto", + "reason": "Zigbee2MQTT publiceert alles naar een MQTT-broker. Zonder broker start het wel, maar komt er niets aan bij Home Assistant." + } ] }, "variables": [ diff --git a/docs/apps-maken.md b/docs/apps-maken.md index cc8c22d..aa8d7cf 100644 --- a/docs/apps-maken.md +++ b/docs/apps-maken.md @@ -373,6 +373,30 @@ containernamen zonder. Het wachtwoord is een veld met `"secret": true` en belandt in plaats van in het compose-bestand. Vergeet `depends_on` niet, anders start de app vóór zijn database en valt hij om op de eerste verbinding. +**Een app die een andere nodig heeft.** Een `connect`-veld wijst naar een andere +app en vult een adres in, maar zegt niet dát je die nodig hebt. Zigbee2MQTT +zonder MQTT-broker start prima en doet niets. Zeg het daarom expliciet, in +`metadata`: + +```json +"depends_on": [ + {"app": "mosquitto", + "reason": "Zigbee2MQTT publiceert alles naar een MQTT-broker. Zonder broker start het wel, maar komt er niets aan."} +] +``` + +Het installatiescherm toont vóór het invullen wat er nog ontbreekt, met een knop +die je meteen naar dat sjabloon brengt. **Het is advies, geen blokkade** — je kunt +de broker net zo goed op een andere machine hebben staan. + +De reden is verplicht: een waarschuwing zonder uitleg is een waarschuwing die +mensen wegklikken. Gebruik het alleen waar het écht klopt. `depends_on` kent geen +"een van deze", dus bij een app die met Nextcloud óf Seafile werkt laat je het +weg; een halve waarheid is daar erger dan geen. + +`["mosquitto"]` zonder reden mag ook — die korte vorm is er voor sjablonen uit +externe repo's, die niets van deze sleutel hoeven te weten. + **Sleutels in een bepaald formaat.** `"generate": "auto"` maakt url-veilige base64 van 24 bytes — 32 tekens. Wil de app iets anders, zeg dat er dan bij: diff --git a/server-up/app.py b/server-up/app.py index f51b6d4..d4f1f68 100644 --- a/server-up/app.py +++ b/server-up/app.py @@ -1334,6 +1334,46 @@ def _gekozen_app_netwerken(body: dict, standaard: str) -> list[str]: return [standaard] if verbinden else [] +def _geinstalleerde_bronnen() -> dict[str, list[str]]: + """Per app-sjabloon de stacks die eruit geïnstalleerd zijn. + + `api_connectable` leidt hetzelfde af uit `.serverup.json`, maar draait daar + een `docker compose ps` per stack overheen om de containernamen op te halen. + Dat is te traag voor een controle die bij elk openen van de installatiemodal + langskomt; hier is alleen de bron nodig. + """ + uit: dict[str, list[str]] = {} + try: + lib = Path(cfg.load()["LIBRARY_DIR"]).resolve() + except Exception: + return uit + if not lib.is_dir(): + return uit + for d in sorted(lib.iterdir()): + if not d.is_dir() or d.name.startswith("."): + continue + mf = d / ".serverup.json" + if not mf.exists(): + continue + try: + bron = (json.loads(mf.read_text("utf-8")) or {}).get("source") or "" + except Exception: + continue + if bron: + uit.setdefault(bron, []).append(d.name) + return uit + + +def _afhankelijkheden_met_status(meta: dict) -> list[dict]: + """De depends_on van een sjabloon, aangevuld met wat er al draait.""" + bronnen = _geinstalleerde_bronnen() + uit = [] + for dep in meta.get("depends_on") or []: + stacks = bronnen.get(dep["app"], []) + uit.append({**dep, "installed": bool(stacks), "stacks": stacks}) + return uit + + def _ip_mapping(net: dict, net_naam: str, gevraagd: dict, eigen=()) -> tuple[dict, str, int]: """Controleer een mapping container → adres, en vul lege adressen aan. @@ -1479,6 +1519,7 @@ def api_store_preview(): metadata=meta, fields=flds, services=diensten, + depends_on=_afhankelijkheden_met_status(meta), preview_files=preview_files, # Backwards-compat voor de oude UI: env_vars=[], images=[], ports=[], diff --git a/server-up/core/boilerplates.py b/server-up/core/boilerplates.py index a6976ca..3f83098 100644 --- a/server-up/core/boilerplates.py +++ b/server-up/core/boilerplates.py @@ -71,9 +71,33 @@ def metadata(d: Path) -> dict: "kind": t.get("kind", "compose"), "format": "boilerplate", "draft": bool(md.get("draft")), + "depends_on": _afhankelijkheden(md.get("depends_on")), } +def _afhankelijkheden(waarde) -> list[dict]: + """Welke andere apps heeft dit sjabloon nodig, en waarom? + + Een `connect`-veld wijst naar een andere app en vult een adres in, maar zegt + niets over noodzaak. Zigbee2MQTT zonder MQTT-broker start prima en doet + niets — en de reden staat nergens. Hiermee kan het sjabloon dat wél zeggen. + + Zowel `["mosquitto"]` als `[{"app": "mosquitto", "reason": "…"}]` mag; de + korte vorm is voor sjablonen uit externe repo's, die niets van deze sleutel + hoeven te weten. + """ + uit: list[dict] = [] + for item in (waarde or []): + if isinstance(item, str): + item = {"app": item} + if not isinstance(item, dict): + continue + app = str(item.get("app") or "").strip() + if app: + uit.append({"app": app, "reason": str(item.get("reason") or "").strip()}) + return uit + + # ── Variable schema → Server Up form fields ────────────────────────────────── def fields(d: Path) -> list[dict]: diff --git a/server-up/templates/index.html b/server-up/templates/index.html index 296c611..e331f6b 100644 --- a/server-up/templates/index.html +++ b/server-up/templates/index.html @@ -1461,6 +1461,30 @@ tailwind.config = {