v0.8.30-beta - depends_on in sjablonen, en vijftien domotica-apps
All checks were successful
Deploy server-up (dev) / deploy (push) Successful in 13m41s
All checks were successful
Deploy server-up (dev) / deploy (push) Successful in 13m41s
- 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 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
This commit is contained in:
parent
42bd87047a
commit
b54e7003e8
49 changed files with 1798 additions and 6 deletions
39
CHANGELOG.md
39
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
|
# v0.8.20-beta — Prometheus startte niet, en 23 apps erbij
|
||||||
|
|
||||||
**Prometheus stond kapot in de catalogus.** Het sjabloon koppelde een lege map op
|
**Prometheus stond kapot in de catalogus.** Het sjabloon koppelde een lege map op
|
||||||
|
|
|
||||||
|
|
@ -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. |
|
| **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. |
|
| **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. |
|
| **Eigen IP per stack** | Met macvlan of ipvlan krijgt een app een eigen adres in je LAN in plaats van poorten op de host. |
|
||||||
|
|
|
||||||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
0.8.20-beta
|
0.8.30-beta
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,12 @@
|
||||||
"categories": [
|
"categories": [
|
||||||
"monitoring",
|
"monitoring",
|
||||||
"communicatie"
|
"communicatie"
|
||||||
|
],
|
||||||
|
"depends_on": [
|
||||||
|
{
|
||||||
|
"app": "prometheus",
|
||||||
|
"reason": "Alertmanager verwerkt de alarmen die Prometheus opwerpt; los draaiend krijgt hij er nooit een."
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"variables": [
|
"variables": [
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,12 @@
|
||||||
},
|
},
|
||||||
"categories": [
|
"categories": [
|
||||||
"monitoring"
|
"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": [
|
"variables": [
|
||||||
|
|
|
||||||
14
apps/appdaemon/files/compose.yaml
Normal file
14
apps/appdaemon/files/compose.yaml
Normal file
|
|
@ -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
|
||||||
106
apps/appdaemon/template.json
Normal file
106
apps/appdaemon/template.json
Normal file
|
|
@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -19,6 +19,12 @@
|
||||||
"categories": [
|
"categories": [
|
||||||
"monitoring",
|
"monitoring",
|
||||||
"beheer"
|
"beheer"
|
||||||
|
],
|
||||||
|
"depends_on": [
|
||||||
|
{
|
||||||
|
"app": "prometheus",
|
||||||
|
"reason": "Levert meetwaarden per container waar Prometheus ze komt ophalen."
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"variables": [
|
"variables": [
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,12 @@
|
||||||
"categories": [
|
"categories": [
|
||||||
"documenten",
|
"documenten",
|
||||||
"productiviteit"
|
"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": [
|
"variables": [
|
||||||
|
|
|
||||||
14
apps/domoticz/files/compose.yaml
Normal file
14
apps/domoticz/files/compose.yaml
Normal file
|
|
@ -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
|
||||||
65
apps/domoticz/template.json
Normal file
65
apps/domoticz/template.json
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
11
apps/double-take/files/compose.yaml
Normal file
11
apps/double-take/files/compose.yaml
Normal file
|
|
@ -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
|
||||||
66
apps/double-take/template.json
Normal file
66
apps/double-take/template.json
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
34
apps/dsmr-reader/files/compose.yaml
Normal file
34
apps/dsmr-reader/files/compose.yaml
Normal file
|
|
@ -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
|
||||||
114
apps/dsmr-reader/template.json
Normal file
114
apps/dsmr-reader/template.json
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
14
apps/emqx/files/compose.yaml
Normal file
14
apps/emqx/files/compose.yaml
Normal file
|
|
@ -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
|
||||||
76
apps/emqx/template.json
Normal file
76
apps/emqx/template.json
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
14
apps/go2rtc/files/compose.yaml
Normal file
14
apps/go2rtc/files/compose.yaml
Normal file
|
|
@ -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
|
||||||
74
apps/go2rtc/template.json
Normal file
74
apps/go2rtc/template.json
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
15
apps/matter-hub/files/compose.yaml
Normal file
15
apps/matter-hub/files/compose.yaml
Normal file
|
|
@ -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
|
||||||
97
apps/matter-hub/template.json
Normal file
97
apps/matter-hub/template.json
Normal file
|
|
@ -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'"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
12
apps/matter-server/files/compose.yaml
Normal file
12
apps/matter-server/files/compose.yaml
Normal file
|
|
@ -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
|
||||||
65
apps/matter-server/template.json
Normal file
65
apps/matter-server/template.json
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -17,6 +17,12 @@
|
||||||
},
|
},
|
||||||
"categories": [
|
"categories": [
|
||||||
"monitoring"
|
"monitoring"
|
||||||
|
],
|
||||||
|
"depends_on": [
|
||||||
|
{
|
||||||
|
"app": "prometheus",
|
||||||
|
"reason": "Levert meetwaarden waar Prometheus ze komt ophalen. Zonder Prometheus meet hij in het luchtledige."
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"variables": [
|
"variables": [
|
||||||
|
|
|
||||||
17
apps/openhab/files/compose.yaml
Normal file
17
apps/openhab/files/compose.yaml
Normal file
|
|
@ -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
|
||||||
67
apps/openhab/template.json
Normal file
67
apps/openhab/template.json
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
12
apps/openwakeword/files/compose.yaml
Normal file
12
apps/openwakeword/files/compose.yaml
Normal file
|
|
@ -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
|
||||||
87
apps/openwakeword/template.json
Normal file
87
apps/openwakeword/template.json
Normal file
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
12
apps/piper/files/compose.yaml
Normal file
12
apps/piper/files/compose.yaml
Normal file
|
|
@ -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
|
||||||
80
apps/piper/template.json
Normal file
80
apps/piper/template.json
Normal file
|
|
@ -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."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
12
apps/rtl433/files/compose.yaml
Normal file
12
apps/rtl433/files/compose.yaml
Normal file
|
|
@ -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
|
||||||
85
apps/rtl433/template.json
Normal file
85
apps/rtl433/template.json
Normal file
|
|
@ -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`."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
13
apps/snapserver/files/compose.yaml
Normal file
13
apps/snapserver/files/compose.yaml
Normal file
|
|
@ -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
|
||||||
73
apps/snapserver/template.json
Normal file
73
apps/snapserver/template.json
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -17,6 +17,16 @@
|
||||||
"categories": [
|
"categories": [
|
||||||
"downloaden",
|
"downloaden",
|
||||||
"media"
|
"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": [
|
"variables": [
|
||||||
|
|
|
||||||
13
apps/traccar/files/compose.yaml
Normal file
13
apps/traccar/files/compose.yaml
Normal file
|
|
@ -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
|
||||||
68
apps/traccar/template.json
Normal file
68
apps/traccar/template.json
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
12
apps/whisper/files/compose.yaml
Normal file
12
apps/whisper/files/compose.yaml
Normal file
|
|
@ -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
|
||||||
96
apps/whisper/template.json
Normal file
96
apps/whisper/template.json
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -17,6 +17,12 @@
|
||||||
},
|
},
|
||||||
"categories": [
|
"categories": [
|
||||||
"domotica"
|
"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": [
|
"variables": [
|
||||||
|
|
|
||||||
|
|
@ -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
|
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.
|
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
|
**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:
|
base64 van 24 bytes — 32 tekens. Wil de app iets anders, zeg dat er dan bij:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1334,6 +1334,46 @@ def _gekozen_app_netwerken(body: dict, standaard: str) -> list[str]:
|
||||||
return [standaard] if verbinden else []
|
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,
|
def _ip_mapping(net: dict, net_naam: str, gevraagd: dict,
|
||||||
eigen=()) -> tuple[dict, str, int]:
|
eigen=()) -> tuple[dict, str, int]:
|
||||||
"""Controleer een mapping container → adres, en vul lege adressen aan.
|
"""Controleer een mapping container → adres, en vul lege adressen aan.
|
||||||
|
|
@ -1479,6 +1519,7 @@ def api_store_preview():
|
||||||
metadata=meta,
|
metadata=meta,
|
||||||
fields=flds,
|
fields=flds,
|
||||||
services=diensten,
|
services=diensten,
|
||||||
|
depends_on=_afhankelijkheden_met_status(meta),
|
||||||
preview_files=preview_files,
|
preview_files=preview_files,
|
||||||
# Backwards-compat voor de oude UI:
|
# Backwards-compat voor de oude UI:
|
||||||
env_vars=[], images=[], ports=[],
|
env_vars=[], images=[], ports=[],
|
||||||
|
|
|
||||||
|
|
@ -71,9 +71,33 @@ def metadata(d: Path) -> dict:
|
||||||
"kind": t.get("kind", "compose"),
|
"kind": t.get("kind", "compose"),
|
||||||
"format": "boilerplate",
|
"format": "boilerplate",
|
||||||
"draft": bool(md.get("draft")),
|
"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 ──────────────────────────────────
|
# ── Variable schema → Server Up form fields ──────────────────────────────────
|
||||||
|
|
||||||
def fields(d: Path) -> list[dict]:
|
def fields(d: Path) -> list[dict]:
|
||||||
|
|
|
||||||
|
|
@ -1461,6 +1461,30 @@ tailwind.config = {
|
||||||
<template x-if="install.format === 'boilerplate' && !install.loading">
|
<template x-if="install.format === 'boilerplate' && !install.loading">
|
||||||
<div class="space-y-3">
|
<div class="space-y-3">
|
||||||
|
|
||||||
|
<!-- Wat deze app nodig heeft en nog niet draait. Advies, geen
|
||||||
|
blokkade: je kunt de broker of Home Assistant net zo goed op een
|
||||||
|
andere machine hebben staan. -->
|
||||||
|
<div x-show="ontbrekendeAfhankelijkheden().length"
|
||||||
|
class="rounded-xl border border-wr/40 bg-wr/5 px-3.5 py-3 space-y-2">
|
||||||
|
<div class="flex items-center gap-2 text-xs font-bold text-wr">
|
||||||
|
<span class="mdi mdi-alert-outline"></span>
|
||||||
|
<span x-text="t('depends_on_missing')">Deze app heeft nog iets nodig</span>
|
||||||
|
</div>
|
||||||
|
<template x-for="d in ontbrekendeAfhankelijkheden()" :key="d.app">
|
||||||
|
<div class="flex items-start gap-2.5">
|
||||||
|
<span class="min-w-0 flex-1">
|
||||||
|
<span class="text-sm font-semibold text-tx dark:text-tx-dark" x-text="d.app"></span>
|
||||||
|
<span x-show="d.reason" class="block text-[11px] text-t2 dark:text-t2-dark leading-snug"
|
||||||
|
x-text="d.reason"></span>
|
||||||
|
</span>
|
||||||
|
<button type="button" class="btn-sm shrink-0" @click="installeerAfhankelijkheid(d)">
|
||||||
|
<span class="mdi mdi-download-outline"></span>
|
||||||
|
<span x-text="t('depends_on_install')">Eerst installeren</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Stapindicator; klikbaar om terug te springen -->
|
<!-- Stapindicator; klikbaar om terug te springen -->
|
||||||
<div class="flex items-center gap-1 overflow-x-auto pb-1" x-show="!onePage">
|
<div class="flex items-center gap-1 overflow-x-auto pb-1" x-show="!onePage">
|
||||||
<template x-for="(s, i) in wizardSteps()" :key="s.id">
|
<template x-for="(s, i) in wizardSteps()" :key="s.id">
|
||||||
|
|
@ -2815,6 +2839,20 @@ function app() {
|
||||||
this.install.connect_apps = d.connect_default !== false;
|
this.install.connect_apps = d.connect_default !== false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// Wat dit sjabloon nodig heeft en nog niet draait. De backend heeft de
|
||||||
|
// status er al bij gezet; hier blijft alleen het filteren over.
|
||||||
|
ontbrekendeAfhankelijkheden() {
|
||||||
|
return (this.install.depends_on || []).filter(d => !d.installed);
|
||||||
|
},
|
||||||
|
// Deze modal sluiten en die van de benodigde app openen. openInstall()
|
||||||
|
// vervangt install helemaal, dus er blijft niets van de vorige staan.
|
||||||
|
async installeerAfhankelijkheid(d) {
|
||||||
|
for (const [repoId, lijst] of Object.entries(this.storeStacks || {})) {
|
||||||
|
const st = (lijst || []).find(x => x.dir === d.app);
|
||||||
|
if (st) { await this.openInstall(st, repoId); return; }
|
||||||
|
}
|
||||||
|
this.toast(this.t('depends_on_not_in_store', {app: d.app}), 'er');
|
||||||
|
},
|
||||||
// Adressen van al geïnstalleerde apps die bij dit veld passen. Een veld met
|
// Adressen van al geïnstalleerde apps die bij dit veld passen. Een veld met
|
||||||
// {"connect": {"app": "mosquitto", "scheme": "mqtt", "port": 1883}} levert
|
// {"connect": {"app": "mosquitto", "scheme": "mqtt", "port": 1883}} levert
|
||||||
// mqtt://<containernaam>:1883 op voor elke geïnstalleerde Mosquitto.
|
// mqtt://<containernaam>:1883 op voor elke geïnstalleerde Mosquitto.
|
||||||
|
|
@ -2954,7 +2992,7 @@ function app() {
|
||||||
envVars: [], images: [], envOverrides: {}, imageTags: {},
|
envVars: [], images: [], envOverrides: {}, imageTags: {},
|
||||||
fields: [], values: {}, preview_files: {},
|
fields: [], values: {}, preview_files: {},
|
||||||
step: 0, tab: 'compose', editing: false, composeText: '', envText: '',
|
step: 0, tab: 'compose', editing: false, composeText: '', envText: '',
|
||||||
network: '', ip: '', ips: {}, services: []
|
network: '', ip: '', ips: {}, services: [], depends_on: []
|
||||||
};
|
};
|
||||||
this.modal = 'install';
|
this.modal = 'install';
|
||||||
this.fieldInfo = null;
|
this.fieldInfo = null;
|
||||||
|
|
@ -2990,6 +3028,7 @@ function app() {
|
||||||
}
|
}
|
||||||
this.install.values = init;
|
this.install.values = init;
|
||||||
this.install.preview_files = d.preview_files || {};
|
this.install.preview_files = d.preview_files || {};
|
||||||
|
this.install.depends_on = d.depends_on || [];
|
||||||
this.install.step = 0;
|
this.install.step = 0;
|
||||||
this.revealed = {};
|
this.revealed = {};
|
||||||
this.ipCheck = {};
|
this.ipCheck = {};
|
||||||
|
|
|
||||||
|
|
@ -347,5 +347,8 @@
|
||||||
"ip_per_container": "Address per container",
|
"ip_per_container": "Address per container",
|
||||||
"ip_per_container_hint": "Only give a container its own address if you want to reach it from outside. The rest keep their port on the host.",
|
"ip_per_container_hint": "Only give a container its own address if you want to reach it from outside. The rest keep their port on the host.",
|
||||||
"port_on_host": "port on the host",
|
"port_on_host": "port on the host",
|
||||||
"appdata_dir": "Appdata directory"
|
"appdata_dir": "Appdata directory",
|
||||||
|
"depends_on_missing": "This app still needs something",
|
||||||
|
"depends_on_install": "Install first",
|
||||||
|
"depends_on_not_in_store": "'{app}' is not in the store"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -347,5 +347,8 @@
|
||||||
"ip_per_container": "Adres per container",
|
"ip_per_container": "Adres per container",
|
||||||
"ip_per_container_hint": "Geef alleen de containers een eigen adres die je van buitenaf wilt bereiken. De rest houdt zijn poort op de host.",
|
"ip_per_container_hint": "Geef alleen de containers een eigen adres die je van buitenaf wilt bereiken. De rest houdt zijn poort op de host.",
|
||||||
"port_on_host": "poort op de host",
|
"port_on_host": "poort op de host",
|
||||||
"appdata_dir": "Appdata-map"
|
"appdata_dir": "Appdata-map",
|
||||||
|
"depends_on_missing": "Deze app heeft nog iets nodig",
|
||||||
|
"depends_on_install": "Eerst installeren",
|
||||||
|
"depends_on_not_in_store": "'{app}' staat niet in de store"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,23 @@ check('één groep: geen kop', c.stepGroups('basis')[0].showHeader === false);
|
||||||
c.install.fields.push(veld('c','basis',{group:'Tweede'}));
|
c.install.fields.push(veld('c','basis',{group:'Tweede'}));
|
||||||
check('twee groepen: wel koppen', c.stepGroups('basis').every(g => g.showHeader));
|
check('twee groepen: wel koppen', c.stepGroups('basis').every(g => g.showHeader));
|
||||||
|
|
||||||
|
// ── Afhankelijkheden ────────────────────────────────────────────────────────
|
||||||
|
// De melding hoort alleen te verschijnen voor wat er níét draait, en te
|
||||||
|
// verdwijnen zodra het er wel is.
|
||||||
|
c.install = {format:'boilerplate', loading:false, fields:[], values:{}, step:0,
|
||||||
|
depends_on: [
|
||||||
|
{app:'mosquitto', reason:'MQTT-broker', installed:false},
|
||||||
|
{app:'loki', reason:'logopslag', installed:true, stacks:['loki']},
|
||||||
|
]};
|
||||||
|
check('alleen het ontbrekende wordt gemeld', c.ontbrekendeAfhankelijkheden().length === 1);
|
||||||
|
check('en dat is mosquitto', c.ontbrekendeAfhankelijkheden()[0].app === 'mosquitto');
|
||||||
|
c.install.depends_on[0].installed = true;
|
||||||
|
check('niets meer te melden zodra alles draait',
|
||||||
|
c.ontbrekendeAfhankelijkheden().length === 0);
|
||||||
|
c.install.depends_on = [];
|
||||||
|
check('een app zonder afhankelijkheden meldt niets',
|
||||||
|
c.ontbrekendeAfhankelijkheden().length === 0);
|
||||||
|
|
||||||
// ── Sleutelformaten ─────────────────────────────────────────────────────────
|
// ── Sleutelformaten ─────────────────────────────────────────────────────────
|
||||||
// Een willekeurige string is niet genoeg: Laravel wil `base64:` ervoor, Homarr
|
// Een willekeurige string is niet genoeg: Laravel wil `base64:` ervoor, Homarr
|
||||||
// en LibreChat willen hexadecimaal van een vaste lengte. In het verkeerde
|
// en LibreChat willen hexadecimaal van een vaste lengte. In het verkeerde
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,80 @@ def test_koppelvelden_verwijzen_naar_bestaande_apps():
|
||||||
assert doel in apps, f"{d.name}/{f['name']} verwijst naar '{doel}'"
|
assert doel in apps, f"{d.name}/{f['name']} verwijst naar '{doel}'"
|
||||||
|
|
||||||
|
|
||||||
|
# ── Afhankelijkheden tussen apps ─────────────────────────────────────────────
|
||||||
|
# Een `connect`-veld wijst naar een andere app, maar zegt niet dát je die nodig
|
||||||
|
# hebt. Zigbee2MQTT zonder MQTT-broker start prima en doet niets; `depends_on`
|
||||||
|
# maakt dat zichtbaar vóór het installeren.
|
||||||
|
|
||||||
|
def _apps():
|
||||||
|
return sorted(d for d in (WORTEL / "apps").iterdir() if d.is_dir())
|
||||||
|
|
||||||
|
|
||||||
|
def _deps(d):
|
||||||
|
return bp.metadata(d).get("depends_on") or []
|
||||||
|
|
||||||
|
|
||||||
|
def test_afhankelijkheden_verwijzen_naar_bestaande_apps():
|
||||||
|
namen = {d.name for d in _apps()}
|
||||||
|
for d in _apps():
|
||||||
|
for dep in _deps(d):
|
||||||
|
assert dep["app"] in namen, f"{d.name} hangt af van '{dep['app']}'"
|
||||||
|
|
||||||
|
|
||||||
|
def test_elke_afhankelijkheid_heeft_een_reden():
|
||||||
|
"""Een waarschuwing zonder uitleg is een waarschuwing die je wegklikt."""
|
||||||
|
for d in _apps():
|
||||||
|
for dep in _deps(d):
|
||||||
|
assert dep["reason"], f"{d.name} → {dep['app']}: geen reden opgegeven"
|
||||||
|
|
||||||
|
|
||||||
|
def test_geen_app_hangt_van_zichzelf_af():
|
||||||
|
for d in _apps():
|
||||||
|
assert d.name not in [x["app"] for x in _deps(d)], d.name
|
||||||
|
|
||||||
|
|
||||||
|
def test_geen_kringetjes():
|
||||||
|
"""A heeft B nodig en B heeft A nodig levert een melding op die je nooit
|
||||||
|
kunt wegwerken."""
|
||||||
|
graaf = {d.name: [x["app"] for x in _deps(d)] for d in _apps()}
|
||||||
|
bezocht: set[str] = set()
|
||||||
|
|
||||||
|
def loop(naam, pad):
|
||||||
|
if naam in pad:
|
||||||
|
raise AssertionError(f"kringetje: {' → '.join(pad + [naam])}")
|
||||||
|
if naam in bezocht:
|
||||||
|
return
|
||||||
|
bezocht.add(naam)
|
||||||
|
for volgende in graaf.get(naam, []):
|
||||||
|
loop(volgende, pad + [naam])
|
||||||
|
|
||||||
|
for naam in graaf:
|
||||||
|
loop(naam, [])
|
||||||
|
|
||||||
|
|
||||||
|
def test_korte_schrijfwijze_wordt_uitgeklapt(tmp_path):
|
||||||
|
"""Externe repo's hoeven niets van deze sleutel te weten; `["mosquitto"]`
|
||||||
|
moet net zo goed werken als de volledige vorm."""
|
||||||
|
import json as _json
|
||||||
|
d = tmp_path / "app"
|
||||||
|
(d / "files").mkdir(parents=True)
|
||||||
|
(d / "template.json").write_text(_json.dumps({
|
||||||
|
"kind": "compose",
|
||||||
|
"metadata": {"name": "x", "description": "y", "tags": ["z"],
|
||||||
|
"depends_on": ["mosquitto", {"app": "loki", "reason": "omdat"}]},
|
||||||
|
"variables": [],
|
||||||
|
}), encoding="utf-8")
|
||||||
|
(d / "files" / "compose.yaml").write_text("services: {}\n", encoding="utf-8")
|
||||||
|
assert bp.metadata(d)["depends_on"] == [
|
||||||
|
{"app": "mosquitto", "reason": ""},
|
||||||
|
{"app": "loki", "reason": "omdat"},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def test_zonder_depends_on_een_lege_lijst():
|
||||||
|
assert bp.metadata(WORTEL / "apps" / "vaultwarden")["depends_on"] == []
|
||||||
|
|
||||||
|
|
||||||
# ── Endpoint ─────────────────────────────────────────────────────────────────
|
# ── Endpoint ─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
def test_connectable_endpoint(client, env, monkeypatch):
|
def test_connectable_endpoint(client, env, monkeypatch):
|
||||||
|
|
@ -140,3 +214,37 @@ def test_connectable_endpoint(client, env, monkeypatch):
|
||||||
def test_connectable_zonder_stacks(client):
|
def test_connectable_zonder_stacks(client):
|
||||||
login(client)
|
login(client)
|
||||||
assert client.get("/api/apps/connectable").get_json()["apps"] == []
|
assert client.get("/api/apps/connectable").get_json()["apps"] == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_preview_meldt_wat_er_nog_ontbreekt(client, env, monkeypatch):
|
||||||
|
"""De installatiemodal moet vóór het installeren kunnen tonen wat er mist."""
|
||||||
|
import json as _json
|
||||||
|
from core import git
|
||||||
|
csrf = login(client)
|
||||||
|
bron = git.cache_dir("server-up") / "apps" / "z2m"
|
||||||
|
(bron / "files").mkdir(parents=True)
|
||||||
|
(bron / "template.json").write_text(_json.dumps({
|
||||||
|
"kind": "compose",
|
||||||
|
"metadata": {"name": "Zigbee2MQTT", "description": "test", "tags": ["mqtt"],
|
||||||
|
"depends_on": [{"app": "mosquitto", "reason": "broker nodig"},
|
||||||
|
{"app": "loki", "reason": "logs"}]},
|
||||||
|
"variables": [{"title": "Algemeen", "items": [
|
||||||
|
{"name": "service_name", "type": "str", "title": "Naam",
|
||||||
|
"default": "z2m", "required": True}]}],
|
||||||
|
}), encoding="utf-8")
|
||||||
|
(bron / "files" / "compose.yaml").write_text(
|
||||||
|
"services:\n << service_name >>:\n image: x\n", encoding="utf-8")
|
||||||
|
|
||||||
|
# Alleen Mosquitto draait al.
|
||||||
|
stack = env["lib"] / "mqtt"
|
||||||
|
stack.mkdir(parents=True)
|
||||||
|
(stack / "docker-compose.yml").write_text("services:\n a:\n image: x\n")
|
||||||
|
(stack / ".serverup.json").write_text(_json.dumps({"source": "mosquitto"}))
|
||||||
|
|
||||||
|
d = client.post("/api/store/preview", json={"stack": "z2m", "repo_id": "server-up"},
|
||||||
|
headers={"X-CSRF-Token": csrf}).get_json()
|
||||||
|
deps = {x["app"]: x for x in d["depends_on"]}
|
||||||
|
assert deps["mosquitto"]["installed"] is True
|
||||||
|
assert deps["mosquitto"]["stacks"] == ["mqtt"]
|
||||||
|
assert deps["loki"]["installed"] is False
|
||||||
|
assert deps["loki"]["reason"] == "logs"
|
||||||
|
|
|
||||||
|
|
@ -307,7 +307,14 @@ SPEC = [
|
||||||
image="mrusse08/soularr:latest",
|
image="mrusse08/soularr:latest",
|
||||||
omschrijving="Laat Lidarr zoeken via Soulseek (slskd) voor albums die op de gewone indexers niet te vinden zijn.",
|
omschrijving="Laat Lidarr zoeken via Soulseek (slskd) voor albums die op de gewone indexers niet te vinden zijn.",
|
||||||
tags=["muziek", "downloaden"], cats=["downloaden", "media"],
|
tags=["muziek", "downloaden"], cats=["downloaden", "media"],
|
||||||
poorten=[], data=True, config_pad="/data", sectie="Muziek"),
|
poorten=[], data=True, config_pad="/data", sectie="Muziek",
|
||||||
|
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."}]),
|
||||||
dict(dir="neutarr", naam="NeutArr", icon="huntarr",
|
dict(dir="neutarr", naam="NeutArr", icon="huntarr",
|
||||||
image="iampuid0/neutarr:latest",
|
image="iampuid0/neutarr:latest",
|
||||||
omschrijving="Zoekt gericht naar ontbrekende afleveringen en naar wat beter kan. Opvolger van Huntarr, dat in februari 2026 offline ging na een reeks lekken; dit is de fork van de laatste schone versie.",
|
omschrijving="Zoekt gericht naar ontbrekende afleveringen en naar wat beter kan. Opvolger van Huntarr, dat in februari 2026 offline ging na een reeks lekken; dit is de fork van de laatste schone versie.",
|
||||||
|
|
@ -586,6 +593,9 @@ def schrijf_los(app):
|
||||||
"icon": {"provider": "selfhst", "id": app["icon"]},
|
"icon": {"provider": "selfhst", "id": app["icon"]},
|
||||||
"version": {"name": "latest"},
|
"version": {"name": "latest"},
|
||||||
"categories": app["cats"],
|
"categories": app["cats"],
|
||||||
|
# Wat deze app nodig heeft om iets te doen; de installatiemodal
|
||||||
|
# waarschuwt als het er nog niet is.
|
||||||
|
**({"depends_on": app["depends_on"]} if app.get("depends_on") else {}),
|
||||||
},
|
},
|
||||||
"variables": _velden(app),
|
"variables": _velden(app),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue