iobroker.zeptrion 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Stefan Bühler
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,302 @@
1
+ # ioBroker.zeptrion
2
+
3
+ ![Logo](admin/zeptrion.png)
4
+
5
+ [![NPM version](https://img.shields.io/npm/v/iobroker.zeptrion.svg)](https://www.npmjs.com/package/iobroker.zeptrion)
6
+ [![Downloads](https://img.shields.io/npm/dm/iobroker.zeptrion.svg)](https://www.npmjs.com/package/iobroker.zeptrion)
7
+ [![Tests](https://github.com/bueste/ioBroker.zeptrion/workflows/Test%20and%20Release/badge.svg)](https://github.com/bueste/ioBroker.zeptrion/actions)
8
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
9
+
10
+ Adapter für Feller **zeptrion / zApp** WLAN-Aktoren (WLAN-Nebenstelle 4K = zApp-Gateway,
11
+ WLAN-Zwischenmodul 2K = zApp-Booster) für Licht- und Storensteuerung, basierend auf der
12
+ zrap Webservice API (Feller-Dokument 10.ZEPAPI-E.1612 / Version 1.0, Firmware ab 01.08.18).
13
+
14
+ > Vor der Store-Veröffentlichung muss noch die Autor-E-Mail-Adresse
15
+ > in `package.json` eingetragen werden (Platzhalter CHANGE_ME@example.com).
16
+
17
+ ## Funktionsumfang
18
+
19
+ - **Kanalsteuerung** (`zrap/chctrl`): on/off/stop/toggle, open/close, move_open/move_close,
20
+ dim_up/dim_down inkl. zeitgesteuerter Varianten (`_t` in ms), sowie Szenen
21
+ recall_s1-4 / store_s1-4 / delete_s1-4 - als einzelne Buttons UND als freies
22
+ `command`-Textfeld.
23
+ - **Kanalzustand** (`zrap/chscan` als periodischer Resync + `zrap/chnotify` als
24
+ Long-Poll-Push für nahezu Echtzeit-Updates) und **Kanalbeschreibung** (`zrap/chdes`,
25
+ read/write: Name, Gruppe, Icon, Typ, Kategorie).
26
+ - **Geräteinformationen** (`zrap/id`): Hardware-/Software-/Bootloader-Version, Seriennummer,
27
+ Systemname, Gerätetyp.
28
+ - **Signalstärke** (`zrap/rssi`, gepollt).
29
+ - **Netzwerkstatus** (`zrap/net`, read-only): SSID, IP, MAC, Modus, Verschlüsselung,
30
+ Maske, Gateway.
31
+ - **Systembefehle** (`zrap/sys`): Neustart, Werksreset, Zurücksetzen in Access-Point-Modus.
32
+ - **Standort** (`zrap/loc`), **NTP-Konfiguration** (`zrap/ntp`) und **Datum/Zeit**
33
+ (`zrap/date`) inkl. Ein-Klick-Synchronisation der Geräte-Uhrzeit mit dem ioBroker-Host.
34
+ - **mDNS-Discovery** (Kapitel 4 der API-Doku): durchsucht das lokale Netz nach
35
+ zeptrion-Geräten und übernimmt Funde deaktiviert in die Konfigurationstabelle
36
+ (Discovery kombiniert mit manueller Kontrolle/Aktivierung).
37
+ - **Sammelbefehle für Hagelalarm**: `control.closeAllShutters` / `openAllShutters` /
38
+ `stopAllShutters` steuern alle konfigurierten Kanäle über alle aktiven Geräte gleichzeitig
39
+ - dank Multicast-Bündelung (siehe unten) als je EIN Request pro Gerät, nicht pro Kanal.
40
+ - **Multicast-Befehlsbündelung**: Kanalbefehle desselben Geräts, die innerhalb von 50ms
41
+ eintreffen, werden automatisch zu einem einzigen `zrap/chctrl`-Multicast-POST gebündelt
42
+ (Kapitel 3.6.5 der API-Doku) statt mehrerer sequentieller Einzelrequests.
43
+ - **Storen-Positionsschätzung** (optional, `posEstimate`): da die Hardware laut Doku für
44
+ Storenkanäle praktisch immer `-1` (unbekannt) liefert, kann pro Gerät eine
45
+ Motor-Laufzeit hinterlegt werden; der Adapter schätzt daraus die Position anhand
46
+ Bewegungsrichtung und verstrichener Zeit (Best Effort, kein Hardware-Feedback,
47
+ manuell kalibrierbar).
48
+ - **Smartfront-Unterstützung** (optional, `zapi/smartfront/*`): Temperatur/Helligkeit/
49
+ Luftfeuchtigkeit auslesen, LED-Hintergrundfarbe setzen (nur für Geräte mit
50
+ angeschlossenem Feller-Smartfront-Taster, Checkbox in der Konfiguration).
51
+ - Robustes Error-Handling: unterscheidet ECONNREFUSED/Timeout/DNS-Fehler, Backoff bei
52
+ wiederholten Fehlern, pro Gerät und global sichtbarer Verbindungsstatus. mDNS-Discovery
53
+ ist zusätzlich gegen Exceptions durch fremde/kaputte Netzwerkpakete abgesichert.
54
+
55
+ Nicht implementiert (siehe "Bekannte Einschränkungen"): Schreibzugriff auf `zrap/net`
56
+ (WLAN-Zugangsdaten ändern), `zrap/scheduler`, Smartbutton-Webhook-Programmierung
57
+ (`zapi/smartbt/*`).
58
+
59
+ ## Installation
60
+
61
+ ### a) Lokal/manuell (vor Store-Veröffentlichung)
62
+
63
+ ```bash
64
+ cd /opt/iobroker/node_modules
65
+ mkdir iobroker.zeptrion
66
+ # Dateien dieses Pakets hierhin kopieren
67
+ cd iobroker.zeptrion
68
+ npm install --production
69
+
70
+ cd /opt/iobroker
71
+ iobroker upload zeptrion
72
+ iobroker add zeptrion
73
+ ```
74
+
75
+ ### b) Über den ioBroker Adapter-Store (nach erfolgter Veröffentlichung)
76
+
77
+ Admin-Oberfläche -> Adapter -> "zeptrion" suchen -> Installieren.
78
+
79
+ ## Konfiguration
80
+
81
+ - **HTTP Timeout**: Timeout pro Request an ein Gerät (Default 4000 ms).
82
+ - **Discovery-Button**: durchsucht das lokale Netz per mDNS (Service-Type `_zapp._tcp`,
83
+ Fallback `_http._tcp` für Firmware < 01.08.xx anhand des Hostname-Musters
84
+ `zapp-YYWWNNNN`). Neu gefundene Geräte werden **deaktiviert** in die Tabelle
85
+ übernommen - Zeile danach prüfen, ID/Name vergeben, Kanalzahl kontrollieren
86
+ (3340-4-x = 4 Kanäle, 3340-2-x = 2 Kanäle) und aktivieren. mDNS funktioniert nur
87
+ innerhalb des gleichen Netzsegments/VLANs.
88
+ - **Geräte-Tabelle** (auch komplett manuell befüllbar, ohne Discovery):
89
+ - `Aktiv`, `ID` (a-z 0-9 _ -), `Bezeichnung`, `IP-Adresse/Hostname`,
90
+ `Kanäle` (1-4), `Art` (Storen/Licht/unbekannt - steuert die ioBroker-Objektrollen,
91
+ siehe unten), `Laufzeit Storenmotor` (Sekunden, 0=deaktiviert - schaltet
92
+ `posEstimate` frei, siehe unten, gilt als Standard für alle Kanäle),
93
+ `Laufzeit/Kanal` (optional, kommagetrennt, z.B. `22,28` - überschreibt die
94
+ Standard-Laufzeit einzeln je Kanal; nützlich bei 2K-Geräten, deren beide
95
+ Kanäle unterschiedliche Motor-Laufzeiten haben; leere Einträge fallen auf
96
+ die Standard-Laufzeit zurück), `Smartfront` (Checkbox, nur bei angeschlossenem
97
+ Feller-Smartfront-Taster aktivieren), `Poll (s)` (Default 30, für RSSI +
98
+ periodischen chscan-Resync; die eigentlichen Kanalupdates laufen über den
99
+ chnotify-Long-Poll unabhängig davon).
100
+
101
+ ## Objektbaum pro Gerät (`zeptrion.0.<id>`)
102
+
103
+ ```
104
+ <id>.info.connection / lastError / hw / sw / boot / sn / sys / type / oen / rssi / refresh
105
+ <id>.network.ssid / ip / mac / mode / enc / mask / gw / bssid (read-only)
106
+ <id>.system.reboot / unlock / factoryDefault / networkDefault (Buttons; factoryDefault erfordert unlock binnen 30s)
107
+ <id>.location.name (read/write)
108
+ <id>.ntp.url / per (read/write)
109
+ <id>.date.rfc1123 / tz / dst / syncNow (read/write + Button)
110
+
111
+ <id>.channels.chN.val Kanalzustand 0-100 / -1 (roher Hardwarewert)
112
+ <id>.channels.chN.posEstimate nur bei Art=Storen: Software-Positionsschätzung
113
+ 0=zu/100=offen, auch manuell schreibbar (Kalibrierung)
114
+ <id>.channels.chN.name / group / icon / type / cat Kanalbeschreibung (read/write)
115
+ <id>.channels.chN.command freies Kommando (String)
116
+ <id>.channels.chN.stop / on / off / toggle / open / close /
117
+ move_open / move_close / dim_up / dim_down (Buttons)
118
+ <id>.channels.chN.recall_s1..4 / store_s1..4 / delete_s1..4 (Buttons)
119
+
120
+ <id>.smartfront.temp / lux / hum nur wenn "Smartfront" aktiviert (read)
121
+ <id>.smartfront.ledState aktueller LED-Status als JSON (read)
122
+ <id>.smartfront.ledSet LED(s) setzen, JSON-Array (write)
123
+ ```
124
+
125
+ Global:
126
+
127
+ ```
128
+ info.connection mind. ein Gerät erreichbar
129
+ control.closeAllShutters Button: ALLE konfigurierten Kanäle -> "close"
130
+ control.openAllShutters Button: ALLE konfigurierten Kanäle -> "open"
131
+ control.stopAllShutters Button: ALLE konfigurierten Kanäle -> "stop"
132
+ ```
133
+
134
+ ## Objekt-Rollen und "Art" (kind)
135
+
136
+ Die zrap-API selbst unterscheidet nicht zwischen Licht- und Storenkanal - das steckt
137
+ allein in der Verkabelung/im Aktor. Damit Visualisierungen (VIS, evtl. spätere
138
+ ioBroker.iot/Alexa-Anbindung) Kanäle trotzdem sinnvoll klassifizieren können, kann pro
139
+ Gerät die "Art" gesetzt werden:
140
+
141
+ | Art | `<ch>.val` Rolle | `stop`/`open`/`close` Rolle |
142
+ |---|---|---|
143
+ | Storen/Rolladen | `level.blind` | `button.stop` / `button.open.blind` / `button.close.blind` |
144
+ | Licht | `level.dimmer` | generisch `button` |
145
+ | unbekannt (Default) | `value` | generisch `button` |
146
+
147
+ Wichtig: `level.blind` täuscht **keine** echte Positionsrückmeldung vor - laut Feller-Doku
148
+ liefert `chscan`/`chnotify` für einen Storenkanal so gut wie immer `-1` (unbekannt), da die
149
+ Hardware selbst keine Lamellenposition zurückmeldet. Die Rolle verbessert nur die
150
+ Erkennung durch VIS-Widgets, der Zahlenwert bleibt i.d.R. uninformativ.
151
+
152
+ ## Hagelalarm-Nutzung
153
+
154
+ ```javascript
155
+ // JavaScript-Adapter Beispiel
156
+ on({id: 'wetter.0.warnungen.hagel', val: true}, function () {
157
+ setState('zeptrion.0.control.closeAllShutters', true);
158
+ });
159
+ ```
160
+
161
+ Fehler bei einzelnen Geräten (offline etc.) unterbrechen die übrigen Kanäle nicht -
162
+ jeder fehlgeschlagene Kanal wird einzeln geloggt und in `<id>.info.lastError` vermerkt.
163
+
164
+ ## Bekannte Einschränkungen / bewusste Entscheidungen
165
+
166
+ - **Smartbutton-Webhook-Programmierung** (`zapi/smartbt/prgm`/`prgn`/`prgs`) ist nicht
167
+ implementiert: dabei ruft der Taster bei Tastendruck direkt eine URL auf ioBroker auf
168
+ (echtes Push, ganz ohne Polling). Das würde einen eingehenden HTTP-Server im Adapter
169
+ voraussetzen, den es aktuell nicht gibt - eine grössere Architekturerweiterung, kein
170
+ kleiner Zusatz. Bleibt als möglicher zukünftiger Ausbauschritt dokumentiert.
171
+ - **Schreibzugriff auf `zrap/net`** ist nicht implementiert - WLAN-Zugangsdaten eines
172
+ Aktors per Skript zu ändern ist riskant (Verbindungsverlust, Reboot nötig). Kann bei
173
+ Bedarf ergänzt werden.
174
+ - **Scheduler (`zrap/scheduler`)** und die **zeptrionAir-Smartfront-Services**
175
+ (`zapi/smartfront/*`, `zapi/smartbt/*`) sind nicht implementiert, da für den
176
+ Storen-/Hagel-Use-Case nicht relevant. Die vorhandene `zrapGet`/`zrapPost`-Struktur
177
+ in `main.js` lässt sich leicht erweitern.
178
+ - `chctrl` liefert laut Doku HTTP 302 ohne Body - Redirects werden bewusst nicht verfolgt
179
+ (`maxRedirects: 0`), um unnötige Zusatzrequests zu vermeiden.
180
+ - Bei wiederholten Fehlern eines Geräts wird das Poll-Intervall bis maximal das
181
+ 5-fache verlängert (einfacher Backoff).
182
+
183
+ ## Entwicklung / Tests
184
+
185
+ ```bash
186
+ npm install
187
+ npm run lint
188
+ npm test # Package-Konsistenz + Unit-Tests
189
+ npm run test:integration # startet echten js-controller (dauert länger)
190
+ ```
191
+
192
+ ## Veröffentlichung im ioBroker Adapter-Store
193
+
194
+ Kurzer Fahrplan (Details: https://github.com/ioBroker/ioBroker.docs/blob/master/docs/de/dev/adaptercreation.md):
195
+
196
+ 1. Autor-E-Mail (`CHANGE_ME@example.com`) in `package.json` eintragen.
197
+ 2. Eigenes öffentliches GitHub-Repository `ioBroker.zeptrion` anlegen, Code pushen.
198
+ 3. `npx @iobroker/adapter-checker` (bzw. https://adapter-check.iobroker.in/) gegen das
199
+ Repository laufen lassen und alle Fehler/Warnungen bereinigen.
200
+ 4. Ersten Release-Tag setzen (`v0.1.0`), CI-Workflow veröffentlicht bei Bedarf automatisch
201
+ auf npm (Secret `NPM_TOKEN` in den Repo-Settings hinterlegen) oder manuell `npm publish`.
202
+ 5. Pull Request gegen `ioBroker/ioBroker.repositories` (`sources-dist.json`, Eintrag unter
203
+ `latest`) erstellen.
204
+ 6. Nach Review/Merge erscheint der Adapter im Adapter-Store; nach ausreichender Stabilität
205
+ und positiven Bewertungen kann später ein Antrag auf Aufnahme in den `stable`-Zweig
206
+ gestellt werden.
207
+
208
+ ## Changelog
209
+
210
+ ### 0.7.0 (2026-07-10)
211
+ - Skalierung für 20+ Geräte: paralleles Setup, Poll-Jitter, Duplikat-Erkennung
212
+ - Strikte Startup-Validierung jeder konfigurierten Geräte-Zeile
213
+ - CSV-Massenimport (eigener Konfig-Tab) mit Zeilen-Validierung und Auto-ID
214
+ - FIX: Positionsschätzung nach Stopp während Endlagenfahrt korrekt
215
+ - FIX: Adapter-Timer-Cleanup (this.clearTimeout), führende Nullen in chdes-Codes bleiben erhalten
216
+
217
+ ### 0.6.0 (2026-07-10)
218
+ - Auto-ID aus Host, Geräte-Test-Button (Erreichbarkeit + zeptrion-Verifikation + Kanalzahl-Prüfung)
219
+ - Kanal-Objektnamen aus dem Gerät (chdes), neues Icon, Geräte-Icons
220
+
221
+ ### 0.5.1 (2026-07-10)
222
+ - KRITISCHER FIX: XML-Parser übersprang die Nutzdaten wegen des XML-Deklarations-Keys - alle GET-Werte blieben in 0.5.0 null
223
+
224
+ ### 0.5.0 (2026-07-07)
225
+ - setPosition: zeitbasierte %-Anfahrt für Storen (Chunking wegen 32s-API-Limit, Referenzfahrt bei unbekannter Position)
226
+ - tiltOpen/tiltClose: Lamellen-Kipp-Impulse (konfigurierbare Impulsdauer)
227
+ - calibrate: Positionsschätzung ohne Fahrt setzen
228
+
229
+ ### 0.4.0 (2026-07-07) - Security- & Qualitäts-Härtung
230
+ - **Verriegelter Werksreset**: `system.factoryDefault` funktioniert nur noch innerhalb
231
+ von 30s nach Setzen von `system.unlock` - ein einzelner versehentlicher setState aus
232
+ Script/VIS kann das Gerät nicht mehr plätten.
233
+ - **Crashsicheres onStateChange**: der komplette Handler (inkl. der Sammelbefehle) läuft
234
+ jetzt in einer zentralen Fehlerbehandlung - keine Unhandled Promise Rejections mehr
235
+ möglich.
236
+ - **Eingabevalidierung**: Kanalbeschreibung (32/32/24/4/4 Bytes UTF-8), Standort (32),
237
+ NTP-URL (32) und NTP-Intervall (0-255) werden vor dem Senden geprüft; klare
238
+ Fehlermeldung statt HTTP-400 vom Gerät. Umlaute zählen korrekt als 2 Bytes.
239
+ - **Adapter-verwaltete Timer** (`this.setTimeout`) überall - automatische Aufräumung
240
+ beim Unload gemäss ioBroker-Guidelines.
241
+ - **Verbindungs-Ökonomie**: solange der chnotify-Long-Poll gesund läuft, wird der
242
+ redundante chscan-Resync nur noch bei jedem 5. Poll ausgeführt (schont die
243
+ schwachen Embedded-Webserver der Unterputzaktoren).
244
+ - **chnotify abschaltbar** (Experten-Tab) für Umgebungen mit Verbindungsproblemen.
245
+ - **Admin-UI neu**: Tabs (Geräte/Experten), durchgängig EN+DE, Eingabe-Validatoren
246
+ (ID-Muster, Host-Muster), Tooltips an jeder Spalte, Sicherheitshinweis.
247
+ - ESLint auf Flat Config (v9) migriert, Lint läuft sauber durch; Smoke-Tests für
248
+ Kommando-Validierung, Byte-Limits, Positionsmathematik und Multicast-Body.
249
+
250
+ ### 0.3.0 (2026-07-07)
251
+ - Kanalbefehle desselben Geräts werden innerhalb eines 50ms-Fensters automatisch zu
252
+ einem einzigen Multicast-POST an `/zrap/chctrl` gebündelt statt sequentiell einzeln
253
+ gesendet - insbesondere `control.closeAllShutters` (Hagelalarm) profitiert davon
254
+ massiv (ein Request pro Gerät statt einer pro Kanal).
255
+ - Optionale zeitbasierte Storen-Positionsschätzung (`posEstimate`) anhand konfigurierbarer
256
+ Motor-Laufzeit, da die Hardware selbst keine Position zurückmeldet.
257
+ - Optionale Smartfront-Unterstützung (`zapi/smartfront/*`): Temperatur/Helligkeit/
258
+ Feuchtigkeit auslesen, LED-Hintergrundfarbe setzen.
259
+ - Rollen-Korrektur: `level.blind` sitzt jetzt auf der Positionsschätzung statt auf dem
260
+ rohen (meist -1) Hardwarewert.
261
+
262
+ ### 0.2.0 (2026-07-07)
263
+ - Kanalzustände werden jetzt primär über `zrap/chnotify` (Long-Poll) nahezu in
264
+ Echtzeit aktualisiert statt nur per Intervall-Polling; `chscan`-Poll bleibt als
265
+ periodischer Resync/Fallback erhalten.
266
+ - Zusätzliches Sicherheitsnetz (Busy-Window, 5s) verhindert, dass ein zeitgleicher
267
+ chscan-Resync einen gerade gesendeten Bewegungsbefehl mit einem veralteten Wert
268
+ überschreibt.
269
+ - mDNS-Discovery-Handler gegen Exceptions durch fremde/kaputte Netzwerkpakete
270
+ abgesichert (try/catch je Service-Event statt nur um die Subscription herum).
271
+ - Neues Geräte-Feld "Art" (Storen/Licht/unbekannt) steuert Standard-Objektrollen
272
+ (`level.blind`, `button.stop`, `button.open.blind`, `button.close.blind` bzw.
273
+ `level.dimmer`) für bessere VIS-/Smart-Home-Integration.
274
+ - Strukturierte `native`-Metadaten (Host, Kanalnummer, Art) an Geräte-/Kanal-Objekten.
275
+
276
+ ### 0.1.0 (2026-07-07)
277
+ - Erste Version: Kanalsteuerung, Kanalzustand/-beschreibung, Geräte-/Netzwerkinfo,
278
+ Systembefehle, Standort/NTP/Datum, Sammelbefehle für Hagelalarm, mDNS-Discovery.
279
+
280
+ ## License
281
+
282
+ MIT License
283
+
284
+ Copyright (c) 2026 Stefan Bühler
285
+
286
+ Permission is hereby granted, free of charge, to any person obtaining a copy
287
+ of this software and associated documentation files (the "Software"), to deal
288
+ in the Software without restriction, including without limitation the rights
289
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
290
+ copies of the Software, and to permit persons to whom the Software is
291
+ furnished to do so, subject to the following conditions:
292
+
293
+ The above copyright notice and this permission notice shall be included in all
294
+ copies or substantial portions of the Software.
295
+
296
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
297
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
298
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
299
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
300
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
301
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
302
+ SOFTWARE.
@@ -0,0 +1,245 @@
1
+ {
2
+ "type": "tabs",
3
+ "items": {
4
+ "tabDevices": {
5
+ "type": "panel",
6
+ "label": { "en": "Devices", "de": "Geräte" },
7
+ "items": {
8
+ "_infoHeader": {
9
+ "type": "staticText",
10
+ "text": {
11
+ "en": "Feller zeptrion / zApp WLAN actuators (WLAN-Nebenstelle 4K, WLAN-Zwischenmodul 2K). Host = IP address or mDNS name (e.g. zapp-14250034.local).",
12
+ "de": "Feller zeptrion / zApp WLAN-Aktoren (WLAN-Nebenstelle 4K, WLAN-Zwischenmodul 2K). Host = IP-Adresse oder mDNS-Name (z.B. zapp-14250034.local)."
13
+ },
14
+ "sm": 12
15
+ },
16
+ "discoverBtn": {
17
+ "newLine": true,
18
+ "type": "sendTo",
19
+ "command": "discover",
20
+ "jsonData": "{}",
21
+ "variant": "contained",
22
+ "label": {
23
+ "en": "🔍 Scan network for zeptrion devices (mDNS, ~4s)",
24
+ "de": "🔍 Netzwerk nach zeptrion-Geräten durchsuchen (mDNS, ca. 4s)"
25
+ },
26
+ "showProcess": true,
27
+ "sm": 12, "md": 6
28
+ },
29
+ "testBtn": {
30
+ "type": "sendTo",
31
+ "command": "testDevices",
32
+ "jsonData": "{}",
33
+ "variant": "outlined",
34
+ "label": {
35
+ "en": "🔎 Test configured devices (reachable? really zeptrion?)",
36
+ "de": "🔎 Konfigurierte Geräte testen (erreichbar? wirklich zeptrion?)"
37
+ },
38
+ "showProcess": true,
39
+ "sm": 12, "md": 6
40
+ },
41
+ "_discoverHint": {
42
+ "type": "staticText",
43
+ "text": {
44
+ "en": "Found devices are added DISABLED to the table below. Close and reopen this dialog after scanning, then verify each row (name, channel count, kind) and enable it. mDNS only works within the same network segment / VLAN.",
45
+ "de": "Gefundene Geräte werden DEAKTIVIERT in die Tabelle übernommen. Dialog nach der Suche schliessen und neu öffnen, dann jede Zeile prüfen (Name, Kanalzahl, Art) und aktivieren. mDNS funktioniert nur im gleichen Netzsegment/VLAN."
46
+ },
47
+ "sm": 12
48
+ },
49
+ "devices": {
50
+ "newLine": true,
51
+ "type": "table",
52
+ "label": { "en": "Devices", "de": "Geräte" },
53
+ "sm": 12,
54
+ "items": [
55
+ {
56
+ "type": "checkbox",
57
+ "attr": "enabled",
58
+ "title": { "en": "Active", "de": "Aktiv" },
59
+ "default": true,
60
+ "width": "5%"
61
+ },
62
+ {
63
+ "type": "text",
64
+ "attr": "id",
65
+ "title": "ID",
66
+ "tooltip": { "en": "Leave empty = auto-generated from host. Only a-z, 0-9, _ and -", "de": "Leer lassen = wird automatisch aus dem Host erzeugt. Nur a-z, 0-9, _ und -" },
67
+ "validator": "!data.id || /^[a-zA-Z0-9_-]+$/.test(data.id)",
68
+ "validatorErrorText": { "en": "Only a-z, 0-9, _ and - (or leave empty)", "de": "Nur a-z, 0-9, _ und - (oder leer lassen)" },
69
+ "width": "10%"
70
+ },
71
+ {
72
+ "type": "text",
73
+ "attr": "name",
74
+ "title": { "en": "Label", "de": "Bezeichnung" },
75
+ "width": "14%"
76
+ },
77
+ {
78
+ "type": "text",
79
+ "attr": "host",
80
+ "title": { "en": "IP address / hostname", "de": "IP-Adresse / Hostname" },
81
+ "validator": "!data.host || /^[a-zA-Z0-9.\\-]+$/.test(data.host)",
82
+ "validatorErrorText": { "en": "Invalid host (no protocol, no spaces)", "de": "Ungültiger Host (kein Protokoll, keine Leerzeichen)" },
83
+ "width": "16%"
84
+ },
85
+ {
86
+ "type": "number",
87
+ "attr": "channels",
88
+ "title": { "en": "Channels", "de": "Kanäle" },
89
+ "tooltip": { "en": "3340-4-x = 4, 3340-2-x = 2", "de": "3340-4-x = 4, 3340-2-x = 2" },
90
+ "min": 1, "max": 4, "default": 1,
91
+ "width": "6%"
92
+ },
93
+ {
94
+ "type": "select",
95
+ "attr": "kind",
96
+ "title": { "en": "Kind", "de": "Art" },
97
+ "tooltip": { "en": "Controls ioBroker object roles for VIS/smart home integrations", "de": "Steuert ioBroker-Objektrollen für VIS/Smart-Home-Integrationen" },
98
+ "options": [
99
+ { "value": "unknown", "label": { "en": "unknown/mixed", "de": "unbekannt/gemischt" } },
100
+ { "value": "blind", "label": { "en": "Blinds/shutters", "de": "Storen/Rolladen" } },
101
+ { "value": "light", "label": { "en": "Light", "de": "Licht" } }
102
+ ],
103
+ "default": "unknown",
104
+ "width": "12%"
105
+ },
106
+ {
107
+ "type": "number",
108
+ "attr": "travelTimeSec",
109
+ "title": { "en": "Motor travel (s)", "de": "Motor-Laufzeit (s)" },
110
+ "tooltip": {
111
+ "en": "Default travel time in seconds, used for all channels unless overridden per-channel below. 0 = position estimation and setPosition disabled. Only relevant for kind=Blinds.",
112
+ "de": "Standard-Laufzeit in Sekunden, gilt für alle Kanäle, sofern nicht rechts pro Kanal überschrieben. 0 = Positionsschätzung und setPosition deaktiviert. Nur relevant bei Art=Storen."
113
+ },
114
+ "min": 0, "max": 300, "default": 0,
115
+ "width": "8%"
116
+ },
117
+ {
118
+ "type": "text",
119
+ "attr": "travelTimeSecCh",
120
+ "title": { "en": "Travel/ch (s)", "de": "Laufzeit/Kanal (s)" },
121
+ "tooltip": {
122
+ "en": "Optional: comma-separated per-channel override, one value per channel in order (e.g. '22,28' for a 2K device where channel 1 and 2 have different motor travel times). Empty entries fall back to 'Motor travel (s)'. Leave the whole field empty to use the same value for all channels.",
123
+ "de": "Optional: Kommagetrennte Laufzeit pro Kanal, ein Wert je Kanal in Reihenfolge (z.B. '22,28' für ein 2K-Gerät, bei dem Kanal 1 und 2 unterschiedliche Motor-Laufzeiten haben). Leere Einträge verwenden 'Motor-Laufzeit (s)'. Ganzes Feld leer lassen = gleicher Wert für alle Kanäle."
124
+ },
125
+ "validator": "!data.travelTimeSecCh || /^\\s*\\d*\\s*(,\\s*\\d*\\s*){0,3}$/.test(data.travelTimeSecCh)",
126
+ "validatorErrorText": { "en": "Comma-separated numbers only, max 4 values (e.g. '22,28')", "de": "Nur kommagetrennte Zahlen, max. 4 Werte (z.B. '22,28')" },
127
+ "width": "9%"
128
+ },
129
+ {
130
+ "type": "number",
131
+ "attr": "tiltTimeMs",
132
+ "title": { "en": "Tilt pulse (ms)", "de": "Kipp-Impuls (ms)" },
133
+ "tooltip": {
134
+ "en": "Short move pulse for tilting raffstore lamellas via tiltOpen/tiltClose (typically 300-800ms). 0 = disabled. Only relevant for kind=Blinds.",
135
+ "de": "Kurzer Fahr-Impuls zum Schrägstellen von Rafflamellen via tiltOpen/tiltClose (typisch 300-800ms). 0 = deaktiviert. Nur relevant bei Art=Storen."
136
+ },
137
+ "min": 0, "max": 5000, "default": 0,
138
+ "width": "8%"
139
+ },
140
+ {
141
+ "type": "checkbox",
142
+ "attr": "smartfront",
143
+ "title": "Smartfront",
144
+ "tooltip": {
145
+ "en": "Only enable if a Feller Smartfront (920-330x.xx.ZS/.ZU) is attached: adds temperature/brightness/humidity sensors and LED control",
146
+ "de": "Nur aktivieren, wenn ein Feller-Smartfront (920-330x.xx.ZS/.ZU) montiert ist: ergänzt Temperatur/Helligkeit/Feuchte-Sensoren und LED-Steuerung"
147
+ },
148
+ "default": false,
149
+ "width": "8%"
150
+ },
151
+ {
152
+ "type": "number",
153
+ "attr": "pollInterval",
154
+ "title": "Poll (s)",
155
+ "tooltip": {
156
+ "en": "Interval for RSSI + periodic resync. Real-time channel updates come via long-poll independently.",
157
+ "de": "Intervall für RSSI + periodischen Resync. Echtzeit-Kanalupdates kommen unabhängig davon per Long-Poll."
158
+ },
159
+ "min": 5, "max": 3600, "default": 30,
160
+ "width": "7%"
161
+ }
162
+ ]
163
+ }
164
+ }
165
+ },
166
+ "tabImport": {
167
+ "type": "panel",
168
+ "label": { "en": "CSV import", "de": "CSV-Import" },
169
+ "items": {
170
+ "_csvHelp": {
171
+ "type": "staticText",
172
+ "text": {
173
+ "en": "Bulk-add devices. One line per device, semicolon separated (recommended if using the last column, since it contains commas):\nhost;name;channels;kind;travel_s;tilt_ms;smartfront;poll_s;travel_s_per_channel\nOnly host is mandatory. kind: blind/light/unknown (also: storen, licht). smartfront: 1/0. travel_s_per_channel (optional): comma-separated per-channel override, e.g. '22,28' for a 2K device with different travel times, empty = use travel_s for all channels. Lines starting with # are ignored, a header line 'host;...' is skipped.\nExample:\n10.195.36.116;Storen Büro;2;blind;22;500;0;30;22,28\n10.195.36.117;Storen Wohnen;2;storen;25",
174
+ "de": "Geräte in Serie anlegen. Eine Zeile pro Gerät, Semikolon getrennt (empfohlen bei Nutzung der letzten Spalte, da diese Kommas enthält):\nhost;name;kanäle;art;laufzeit_s;kipp_ms;smartfront;poll_s;laufzeit_kanal_s\nNur host ist Pflicht. art: blind/light/unknown (auch: storen, licht). smartfront: 1/0. laufzeit_kanal_s (optional): kommagetrennte Laufzeit pro Kanal, z.B. '22,28' für ein 2K-Gerät mit unterschiedlichen Laufzeiten, leer = laufzeit_s für alle Kanäle. Zeilen mit # werden ignoriert, eine Kopfzeile 'host;...' wird übersprungen.\nBeispiel:\n10.195.36.116;Storen Büro;2;blind;22;500;0;30;22,28\n10.195.36.117;Storen Wohnen;2;storen;25"
175
+ },
176
+ "sm": 12
177
+ },
178
+ "csvText": {
179
+ "newLine": true,
180
+ "type": "text",
181
+ "label": { "en": "CSV lines", "de": "CSV-Zeilen" },
182
+ "minRows": 8,
183
+ "maxRows": 20,
184
+ "trim": false,
185
+ "noClearButton": true,
186
+ "sm": 12
187
+ },
188
+ "importBtn": {
189
+ "newLine": true,
190
+ "type": "sendTo",
191
+ "command": "importCsv",
192
+ "jsonData": "{\"csv\": ${JSON.stringify(data.csvText)}}",
193
+ "variant": "contained",
194
+ "label": { "en": "⬆️ Import (validates every line)", "de": "⬆️ Importieren (validiert jede Zeile)" },
195
+ "showProcess": true,
196
+ "sm": 12, "md": 5
197
+ },
198
+ "_importHint": {
199
+ "type": "staticText",
200
+ "text": {
201
+ "en": "Valid lines are added ENABLED, invalid lines are reported and skipped. Duplicate hosts are rejected. After import the adapter restarts - close and reopen this dialog to see the new table rows.",
202
+ "de": "Gültige Zeilen werden AKTIVIERT übernommen, ungültige gemeldet und übersprungen. Doppelte Hosts werden abgelehnt. Nach dem Import startet der Adapter neu - Dialog schliessen und neu öffnen, um die neuen Tabellenzeilen zu sehen."
203
+ },
204
+ "sm": 12
205
+ }
206
+ }
207
+ },
208
+ "tabExpert": {
209
+ "type": "panel",
210
+ "label": { "en": "Expert", "de": "Experten" },
211
+ "items": {
212
+ "requestTimeout": {
213
+ "type": "number",
214
+ "label": { "en": "HTTP timeout (ms)", "de": "HTTP Timeout (ms)" },
215
+ "help": {
216
+ "en": "Timeout per request to a device (does not apply to the chnotify long-poll, which uses a fixed 35s).",
217
+ "de": "Timeout pro Request an ein Gerät (gilt nicht für den chnotify-Long-Poll, der fix 35s verwendet)."
218
+ },
219
+ "min": 500, "max": 30000, "default": 4000,
220
+ "sm": 12, "md": 4
221
+ },
222
+ "useNotify": {
223
+ "newLine": true,
224
+ "type": "checkbox",
225
+ "label": { "en": "Use chnotify long-poll (near real-time updates)", "de": "chnotify-Long-Poll verwenden (nahezu Echtzeit-Updates)" },
226
+ "help": {
227
+ "en": "Keeps one HTTP connection per device permanently open (device answers within 30s at the latest). Disable only if devices show connection problems; channel states then update only at the poll interval.",
228
+ "de": "Hält dauerhaft eine HTTP-Verbindung pro Gerät offen (Gerät antwortet spätestens nach 30s). Nur deaktivieren, falls Geräte Verbindungsprobleme zeigen; Kanalzustände aktualisieren dann nur noch im Poll-Intervall."
229
+ },
230
+ "default": true,
231
+ "sm": 12, "md": 8
232
+ },
233
+ "_safetyHint": {
234
+ "newLine": true,
235
+ "type": "staticText",
236
+ "text": {
237
+ "en": "⚠️ Safety: the factory reset button (system.factoryDefault) is interlocked - it only works within 30s after setting system.unlock. This prevents accidental wipes from scripts/VIS.",
238
+ "de": "⚠️ Sicherheit: der Werksreset-Button (system.factoryDefault) ist verriegelt - er funktioniert nur innerhalb von 30s nach Setzen von system.unlock. Das verhindert versehentliches Löschen durch Scripts/VIS."
239
+ },
240
+ "sm": 12
241
+ }
242
+ }
243
+ }
244
+ }
245
+ }
Binary file