homebridge-plugin-klares4 1.1.0

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.
Files changed (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +203 -0
  3. package/config.schema.json +206 -0
  4. package/dist/accessories/cover-accessory.d.ts +21 -0
  5. package/dist/accessories/cover-accessory.d.ts.map +1 -0
  6. package/dist/accessories/cover-accessory.js +128 -0
  7. package/dist/accessories/cover-accessory.js.map +1 -0
  8. package/dist/accessories/light-accessory.d.ts +16 -0
  9. package/dist/accessories/light-accessory.d.ts.map +1 -0
  10. package/dist/accessories/light-accessory.js +78 -0
  11. package/dist/accessories/light-accessory.js.map +1 -0
  12. package/dist/accessories/scenario-accessory.d.ts +13 -0
  13. package/dist/accessories/scenario-accessory.d.ts.map +1 -0
  14. package/dist/accessories/scenario-accessory.js +55 -0
  15. package/dist/accessories/scenario-accessory.js.map +1 -0
  16. package/dist/accessories/sensor-accessory.d.ts +24 -0
  17. package/dist/accessories/sensor-accessory.d.ts.map +1 -0
  18. package/dist/accessories/sensor-accessory.js +128 -0
  19. package/dist/accessories/sensor-accessory.js.map +1 -0
  20. package/dist/accessories/thermostat-accessory.d.ts +21 -0
  21. package/dist/accessories/thermostat-accessory.d.ts.map +1 -0
  22. package/dist/accessories/thermostat-accessory.js +215 -0
  23. package/dist/accessories/thermostat-accessory.js.map +1 -0
  24. package/dist/accessories/zone-accessory.d.ts +18 -0
  25. package/dist/accessories/zone-accessory.d.ts.map +1 -0
  26. package/dist/accessories/zone-accessory.js +99 -0
  27. package/dist/accessories/zone-accessory.js.map +1 -0
  28. package/dist/index.d.ts +4 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +7 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/platform.d.ts +69 -0
  33. package/dist/platform.d.ts.map +1 -0
  34. package/dist/platform.js +345 -0
  35. package/dist/platform.js.map +1 -0
  36. package/dist/settings.d.ts +3 -0
  37. package/dist/settings.d.ts.map +1 -0
  38. package/dist/settings.js +6 -0
  39. package/dist/settings.js.map +1 -0
  40. package/dist/types.d.ts +82 -0
  41. package/dist/types.d.ts.map +1 -0
  42. package/dist/types.js +3 -0
  43. package/dist/types.js.map +1 -0
  44. package/dist/websocket-client.d.ts +57 -0
  45. package/dist/websocket-client.d.ts.map +1 -0
  46. package/dist/websocket-client.js +991 -0
  47. package/dist/websocket-client.js.map +1 -0
  48. package/package.json +64 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Paolo Trivi
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,203 @@
1
+ # homebridge-plugin-klares4
2
+
3
+ [![npm version](https://badge.fury.io/js/homebridge-plugin-klares4.svg)](https://badge.fury.io/js/homebridge-plugin-klares4)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ Plugin completo per sistemi Ksenia Lares4 che integra zone di sicurezza, luci, tapparelle, termostati e sensori ambientali in un'unica soluzione per Homebridge.
7
+
8
+ ## ✨ Caratteristiche
9
+
10
+ - 🔐 **Zone di Sicurezza**: Sensori di contatto per porte e finestre
11
+ - 💡 **Controllo Luci**: Accensione/spegnimento di tutte le luci del sistema
12
+ - 🪟 **Tapparelle Intelligenti**: Controllo percentuale con timing configurabile
13
+ - 🌡️ **Termostati**: Controllo temperatura e modalità riscaldamento/raffreddamento
14
+ - 📊 **Sensori Ambientali**: Temperatura, umidità e luminosità in tempo reale
15
+ - 🔄 **Aggiornamenti Real-time**: Connessione WebSocket con riconnessione automatica
16
+ - ⚙️ **Configurazione UI**: Interfaccia grafica completa in Homebridge UI
17
+ - 🎯 **Personalizzazione**: Nomi personalizzati ed esclusione selettiva di entità
18
+
19
+ ## 📋 Prerequisiti
20
+
21
+ - Homebridge >= 1.6.0
22
+ - Node.js >= 14.18.1
23
+ - Sistema Ksenia Lares4 con accesso WebSocket abilitato
24
+
25
+ ## 🚀 Installazione
26
+
27
+ ### Tramite Homebridge UI (Consigliato)
28
+
29
+ 1. Apri Homebridge UI
30
+ 2. Vai su **Plugins**
31
+ 3. Cerca `homebridge-plugin-klares4`
32
+ 4. Clicca **Install**
33
+ 5. Configura il plugin tramite l'interfaccia grafica
34
+
35
+ ### Tramite npm
36
+
37
+ ```bash
38
+ npm install -g homebridge-plugin-klares4
39
+ ```
40
+
41
+ ## ⚙️ Configurazione
42
+
43
+ ### Configurazione Base
44
+
45
+ Il plugin può essere configurato completamente tramite l'interfaccia grafica di Homebridge UI. I parametri obbligatori sono:
46
+
47
+ - **Nome Plugin**: Nome che apparirà nei log
48
+ - **Indirizzo IP**: IP del sistema Ksenia Lares4
49
+ - **Sender ID**: Identificativo univoco per la connessione WebSocket
50
+ - **PIN Sistema**: PIN di accesso al sistema Lares4
51
+
52
+ ### Configurazione Manuale (config.json)
53
+
54
+ ```json
55
+ {
56
+ "platforms": [
57
+ {
58
+ "platform": "Lares4Complete",
59
+ "name": "Klares4",
60
+ "ip": "192.168.1.100",
61
+ "sender": "homebridge",
62
+ "pin": "123456",
63
+ "maxSeconds": 30,
64
+ "reconnectInterval": 5000,
65
+ "heartbeatInterval": 30000,
66
+ "debug": false,
67
+ "excludeZones": ["1", "5"],
68
+ "excludeOutputs": ["2", "7"],
69
+ "excludeSensors": ["3"],
70
+ "customNames": {
71
+ "zones": {
72
+ "1": "Porta Principale",
73
+ "2": "Finestra Cucina"
74
+ },
75
+ "outputs": {
76
+ "9": "Luce Sala Custom",
77
+ "1": "Tapparella Studio"
78
+ },
79
+ "sensors": {
80
+ "1": "Termometro Sala"
81
+ }
82
+ }
83
+ }
84
+ ]
85
+ }
86
+ ```
87
+
88
+ ### Parametri di Configurazione
89
+
90
+ | Parametro | Tipo | Default | Descrizione |
91
+ | ------------------- | -------- | ------------ | ------------------------------- |
92
+ | `name` | string | "Klares4" | Nome del plugin |
93
+ | `ip` | string | obbligatorio | Indirizzo IP del sistema Lares4 |
94
+ | `sender` | string | "homebridge" | ID univoco per WebSocket |
95
+ | `pin` | string | obbligatorio | PIN di accesso |
96
+ | `maxSeconds` | number | 30 | Tempo max tapparelle (secondi) |
97
+ | `reconnectInterval` | number | 5000 | Intervallo riconnessione (ms) |
98
+ | `heartbeatInterval` | number | 30000 | Intervallo heartbeat (ms) |
99
+ | `debug` | boolean | false | Logging dettagliato |
100
+ | `excludeZones` | string[] | [] | Zone da escludere |
101
+ | `excludeOutputs` | string[] | [] | Output da escludere |
102
+ | `excludeSensors` | string[] | [] | Sensori da escludere |
103
+ | `customNames` | object | {} | Nomi personalizzati |
104
+
105
+ ## 🏠 Tipi di Accessori Supportati
106
+
107
+ ### Zone di Sicurezza
108
+
109
+ - **Tipo HomeKit**: Contact Sensor
110
+ - **Stati**: Aperto/Chiuso, Bypass
111
+ - **Aggiornamenti**: Real-time via WebSocket
112
+
113
+ ### Luci
114
+
115
+ - **Tipo HomeKit**: Lightbulb
116
+ - **Controllo**: On/Off
117
+ - **Feedback**: Stato real-time
118
+
119
+ ### Tapparelle
120
+
121
+ - **Tipo HomeKit**: Window Covering
122
+ - **Controllo**: Percentuale (0-100%)
123
+ - **Comandi**: Su/Giù/Stop
124
+ - **Timing**: Configurabile tramite `maxSeconds`
125
+
126
+ ### Termostati
127
+
128
+ - **Tipo HomeKit**: Thermostat
129
+ - **Modalità**: Off/Heat/Cool
130
+ - **Controllo**: Temperatura target
131
+ - **Sensori**: Temperatura corrente
132
+
133
+ ### Sensori Ambientali
134
+
135
+ - **Tipi HomeKit**: Temperature/Humidity/Light Sensor
136
+ - **Dati**: Temperatura, Umidità, Luminosità
137
+ - **Aggiornamenti**: Real-time
138
+
139
+ ## 🔧 Risoluzione Problemi
140
+
141
+ ### Connessione WebSocket
142
+
143
+ Se il plugin non riesce a connettersi:
144
+
145
+ 1. Verifica che l'IP sia corretto
146
+ 2. Controlla che il PIN sia valido
147
+ 3. Assicurati che il sistema Lares4 accetti connessioni WebSocket
148
+ 4. Verifica che la porta 443 (HTTPS) o 80 (HTTP) sia accessibile
149
+
150
+ ### Debug
151
+
152
+ Abilita il debug logging per diagnosi dettagliate:
153
+
154
+ ```json
155
+ {
156
+ "debug": true
157
+ }
158
+ ```
159
+
160
+ ### Serial Number Warning
161
+
162
+ Il warning "Serial Number characteristic must have a length of more than 1 character" è stato risolto nelle versioni recenti. Assicurati di avere l'ultima versione del plugin.
163
+
164
+ ### Tapparelle non Responsive
165
+
166
+ Se le tapparelle non rispondono correttamente:
167
+
168
+ 1. Verifica il parametro `maxSeconds`
169
+ 2. Controlla che i comandi up, down, alt siano supportati dal sistema
170
+ 3. Testa prima con movimenti completi (0% o 100%)
171
+
172
+ ## 📊 Monitoraggio
173
+
174
+ Il plugin fornisce log dettagliati per monitorare:
175
+
176
+ - Stato connessione WebSocket
177
+ - Comandi inviati e ricevuti
178
+ - Aggiornamenti entità
179
+ - Errori e riconnessioni
180
+
181
+ ## 🤝 Contributi
182
+
183
+ I contributi sono benvenuti! Per contribuire:
184
+
185
+ 1. Fork del repository
186
+ 2. Crea un branch per la tua feature
187
+ 3. Commit delle modifiche
188
+ 4. Push al branch
189
+ 5. Apri una Pull Request
190
+
191
+ ## 📄 Licenza
192
+
193
+ Questo progetto è rilasciato sotto licenza MIT.
194
+
195
+ ## 🔗 Link Utili
196
+
197
+ - [Homebridge](https://homebridge.io/)
198
+ - [Homebridge UI](https://github.com/homebridge/homebridge-config-ui-x)
199
+ - [Ksenia Security](https://www.ksenia.it/)
200
+
201
+ ---
202
+
203
+ **Nota**: Questo progetto non è affiliato con Ksenia Security S.p.A. È un progetto open source sviluppato dalla comunità.
@@ -0,0 +1,206 @@
1
+ {
2
+ "pluginAlias": "Lares4Complete",
3
+ "pluginType": "platform",
4
+ "singular": true,
5
+ "headerDisplay": "Plugin per il sistema di allarme Ksenia Lares4",
6
+ "footerDisplay": "Per maggiori informazioni visita [GitHub](https://github.com/paolo-trivi/homebridge-plugin-klares4)",
7
+ "schema": {
8
+ "type": "object",
9
+ "properties": {
10
+ "name": {
11
+ "title": "Nome Piattaforma",
12
+ "type": "string",
13
+ "default": "Lares4",
14
+ "required": true
15
+ },
16
+ "ip": {
17
+ "title": "Indirizzo IP",
18
+ "type": "string",
19
+ "format": "ipv4",
20
+ "placeholder": "192.168.1.100",
21
+ "required": true
22
+ },
23
+ "port": {
24
+ "title": "Porta",
25
+ "type": "integer",
26
+ "default": 443,
27
+ "minimum": 1,
28
+ "maximum": 65535,
29
+ "required": true
30
+ },
31
+ "https": {
32
+ "title": "Usa HTTPS",
33
+ "type": "boolean",
34
+ "default": true
35
+ },
36
+ "sender": {
37
+ "title": "Sender ID",
38
+ "type": "string",
39
+ "default": "homebridge",
40
+ "required": true
41
+ },
42
+ "pin": {
43
+ "title": "PIN Sistema",
44
+ "type": "string",
45
+ "required": true
46
+ },
47
+ "debug": {
48
+ "title": "Debug Mode",
49
+ "type": "boolean",
50
+ "default": false
51
+ },
52
+ "maxSeconds": {
53
+ "title": "Timeout Massimo (secondi)",
54
+ "type": "integer",
55
+ "default": 30,
56
+ "minimum": 5,
57
+ "maximum": 300
58
+ },
59
+ "reconnectInterval": {
60
+ "title": "Intervallo Riconnessione (ms)",
61
+ "type": "integer",
62
+ "default": 5000,
63
+ "minimum": 1000,
64
+ "maximum": 60000
65
+ },
66
+ "heartbeatInterval": {
67
+ "title": "Intervallo Heartbeat (ms)",
68
+ "type": "integer",
69
+ "default": 30000,
70
+ "minimum": 10000,
71
+ "maximum": 300000
72
+ },
73
+ "excludeZones": {
74
+ "title": "Zone da Escludere",
75
+ "type": "array",
76
+ "items": {
77
+ "type": "string"
78
+ }
79
+ },
80
+ "excludeOutputs": {
81
+ "title": "Output da Escludere",
82
+ "type": "array",
83
+ "items": {
84
+ "type": "string"
85
+ }
86
+ },
87
+ "excludeSensors": {
88
+ "title": "Sensori da Escludere",
89
+ "type": "array",
90
+ "items": {
91
+ "type": "string"
92
+ }
93
+ }
94
+ }
95
+ },
96
+ "layout": [
97
+ {
98
+ "type": "section",
99
+ "title": "Configurazione Connessione",
100
+ "expandable": true,
101
+ "expanded": true,
102
+ "items": [
103
+ "name",
104
+ "ip",
105
+ "port",
106
+ "https",
107
+ "sender",
108
+ "pin"
109
+ ]
110
+ },
111
+ {
112
+ "type": "section",
113
+ "title": "Opzioni Avanzate",
114
+ "expandable": true,
115
+ "expanded": false,
116
+ "items": [
117
+ "debug",
118
+ "maxSeconds",
119
+ "reconnectInterval",
120
+ "heartbeatInterval"
121
+ ]
122
+ },
123
+ {
124
+ "type": "section",
125
+ "title": "Esclusioni Dispositivi",
126
+ "expandable": true,
127
+ "expanded": true,
128
+ "items": [
129
+ {
130
+ "type": "help",
131
+ "helpvalue": "<div class='alert alert-primary'><h5>📋 Come Escludere Dispositivi</h5><ol><li><strong>Avvia il plugin una volta</strong> per scoprire tutti i dispositivi</li><li><strong>Controlla il file</strong> <code>~/.homebridge/klares4-devices.json</code></li><li><strong>Copia gli ID</strong> dei dispositivi che NON vuoi vedere in HomeKit</li><li><strong>Incollali</strong> nei campi sottostanti</li><li><strong>Riavvia Homebridge</strong></li></ol></div>"
132
+ },
133
+ {
134
+ "type": "help",
135
+ "helpvalue": "<div class='alert alert-info'><h5>💡 Suggerimento</h5><p>Puoi aprire il file <code>klares4-devices.json</code> con un editor di testo per vedere tutti i dispositivi disponibili con i loro ID e nomi.</p><p><strong>Esempio di contenuto del file:</strong></p><pre>{\n \"outputs\": [\n {\"id\": \"18\", \"name\": \"Riscaldamento Sala\"},\n {\"id\": \"31\", \"name\": \"Sirena Esterna\"},\n ...\n ]\n}</pre></div>"
136
+ },
137
+ {
138
+ "key": "excludeOutputs",
139
+ "type": "array",
140
+ "orderable": false,
141
+ "buttonText": "➕ Aggiungi Output da Escludere",
142
+ "items": [
143
+ {
144
+ "type": "div",
145
+ "displayFlex": true,
146
+ "flex-direction": "row",
147
+ "items": [
148
+ {
149
+ "key": "excludeOutputs[]",
150
+ "flex": "1 1 50px",
151
+ "notitle": true,
152
+ "placeholder": "ID Output (es: 18 per Riscaldamento Sala)",
153
+ "description": "Inserisci l'ID numerico dell'output da escludere"
154
+ }
155
+ ]
156
+ }
157
+ ]
158
+ },
159
+ {
160
+ "key": "excludeZones",
161
+ "type": "array",
162
+ "orderable": false,
163
+ "buttonText": "➕ Aggiungi Zona da Escludere",
164
+ "items": [
165
+ {
166
+ "type": "div",
167
+ "displayFlex": true,
168
+ "flex-direction": "row",
169
+ "items": [
170
+ {
171
+ "key": "excludeZones[]",
172
+ "flex": "1 1 50px",
173
+ "notitle": true,
174
+ "placeholder": "ID Zona (es: 18 per Finestra Studio)",
175
+ "description": "Inserisci l'ID numerico della zona da escludere"
176
+ }
177
+ ]
178
+ }
179
+ ]
180
+ },
181
+ {
182
+ "key": "excludeSensors",
183
+ "type": "array",
184
+ "orderable": false,
185
+ "buttonText": "➕ Aggiungi Sensore da Escludere",
186
+ "items": [
187
+ {
188
+ "type": "div",
189
+ "displayFlex": true,
190
+ "flex-direction": "row",
191
+ "items": [
192
+ {
193
+ "key": "excludeSensors[]",
194
+ "flex": "1 1 50px",
195
+ "notitle": true,
196
+ "placeholder": "ID Sensore (es: 1 per Term. Sala)",
197
+ "description": "Inserisci l'ID numerico del sensore da escludere"
198
+ }
199
+ ]
200
+ }
201
+ ]
202
+ }
203
+ ]
204
+ }
205
+ ]
206
+ }
@@ -0,0 +1,21 @@
1
+ import type { CharacteristicValue, PlatformAccessory } from 'homebridge';
2
+ import type { Lares4Platform } from '../platform';
3
+ import type { KseniaDevice } from '../types';
4
+ export declare class CoverAccessory {
5
+ private readonly platform;
6
+ private readonly accessory;
7
+ private service;
8
+ private device;
9
+ private targetPosition;
10
+ private currentPosition;
11
+ private positionState;
12
+ private maxSeconds;
13
+ constructor(platform: Lares4Platform, accessory: PlatformAccessory);
14
+ setTargetPosition(value: CharacteristicValue): Promise<void>;
15
+ getTargetPosition(): Promise<CharacteristicValue>;
16
+ getCurrentPosition(): Promise<CharacteristicValue>;
17
+ getPositionState(): Promise<CharacteristicValue>;
18
+ private simulateMovement;
19
+ updateStatus(newDevice: KseniaDevice): void;
20
+ }
21
+ //# sourceMappingURL=cover-accessory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cover-accessory.d.ts","sourceRoot":"","sources":["../../src/accessories/cover-accessory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAW,MAAM,YAAY,CAAC;AAClF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,qBAAa,cAAc;IASnB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAT9B,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,cAAc,CAAa;IACnC,OAAO,CAAC,eAAe,CAAa;IACpC,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,UAAU,CAAS;gBAGN,QAAQ,EAAE,cAAc,EACxB,SAAS,EAAE,iBAAiB;IAwC3C,iBAAiB,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAgC5D,iBAAiB,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAIjD,kBAAkB,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAIlD,gBAAgB,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAItD,OAAO,CAAC,gBAAgB;IAiCxB,YAAY,CAAC,SAAS,EAAE,YAAY,GAAG,IAAI;CA4B9C"}
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CoverAccessory = void 0;
4
+ class CoverAccessory {
5
+ constructor(platform, accessory) {
6
+ this.platform = platform;
7
+ this.accessory = accessory;
8
+ this.targetPosition = 0;
9
+ this.currentPosition = 0;
10
+ this.positionState = 2; // 2 = stopped
11
+ this.device = accessory.context.device;
12
+ this.currentPosition = this.device.status?.position || 0;
13
+ this.targetPosition = this.device.status?.position || 0;
14
+ this.maxSeconds = this.platform.config.maxSeconds || 30;
15
+ // Imposta le informazioni dell'accessorio
16
+ this.accessory.getService(this.platform.Service.AccessoryInformation)
17
+ .setCharacteristic(this.platform.Characteristic.Manufacturer, 'Ksenia')
18
+ .setCharacteristic(this.platform.Characteristic.Model, 'Lares4 Cover')
19
+ .setCharacteristic(this.platform.Characteristic.SerialNumber, this.device.id)
20
+ .setCharacteristic(this.platform.Characteristic.FirmwareRevision, '2.0.0');
21
+ // Ottieni o crea il servizio WindowCovering
22
+ this.service = this.accessory.getService(this.platform.Service.WindowCovering)
23
+ || this.accessory.addService(this.platform.Service.WindowCovering);
24
+ this.service.setCharacteristic(this.platform.Characteristic.Name, this.device.name);
25
+ // Imposta gli handlers per le caratteristiche
26
+ this.service.getCharacteristic(this.platform.Characteristic.CurrentPosition)
27
+ .onGet(this.getCurrentPosition.bind(this));
28
+ this.service.getCharacteristic(this.platform.Characteristic.PositionState)
29
+ .onGet(this.getPositionState.bind(this));
30
+ this.service.getCharacteristic(this.platform.Characteristic.TargetPosition)
31
+ .onSet(this.setTargetPosition.bind(this))
32
+ .onGet(this.getTargetPosition.bind(this));
33
+ // Inizializza i valori delle caratteristiche con valori sicuri
34
+ const safeCurrentPosition = isNaN(this.currentPosition) ? 0 : this.currentPosition;
35
+ const safeTargetPosition = isNaN(this.targetPosition) ? 0 : this.targetPosition;
36
+ this.service.setCharacteristic(this.platform.Characteristic.CurrentPosition, safeCurrentPosition);
37
+ this.service.setCharacteristic(this.platform.Characteristic.TargetPosition, safeTargetPosition);
38
+ this.service.setCharacteristic(this.platform.Characteristic.PositionState, this.positionState);
39
+ }
40
+ async setTargetPosition(value) {
41
+ const targetPosition = value;
42
+ if (targetPosition === this.currentPosition) {
43
+ return; // Nessun movimento necessario
44
+ }
45
+ this.targetPosition = targetPosition;
46
+ try {
47
+ // Determina lo stato del movimento
48
+ if (targetPosition > this.currentPosition) {
49
+ this.positionState = 1; // Opening
50
+ }
51
+ else {
52
+ this.positionState = 0; // Closing
53
+ }
54
+ // Aggiorna lo stato del movimento
55
+ this.service.updateCharacteristic(this.platform.Characteristic.PositionState, this.positionState);
56
+ await this.platform.wsClient?.moveCover(this.device.id, targetPosition);
57
+ this.platform.log.info(`🪟 ${this.device.name}: Movimento a ${targetPosition}%`);
58
+ // Simula il movimento graduale
59
+ this.simulateMovement(targetPosition);
60
+ }
61
+ catch (error) {
62
+ this.platform.log.error(`❌ Errore controllo tapparella ${this.device.name}:`, error);
63
+ throw new this.platform.api.hap.HapStatusError(-70402 /* this.platform.api.hap.HAPStatus.SERVICE_COMMUNICATION_FAILURE */);
64
+ }
65
+ }
66
+ async getTargetPosition() {
67
+ return isNaN(this.targetPosition) ? 0 : this.targetPosition;
68
+ }
69
+ async getCurrentPosition() {
70
+ return isNaN(this.currentPosition) ? 0 : this.currentPosition;
71
+ }
72
+ async getPositionState() {
73
+ return this.positionState;
74
+ }
75
+ simulateMovement(targetPosition) {
76
+ const startPosition = this.currentPosition;
77
+ const distance = Math.abs(targetPosition - startPosition);
78
+ const direction = targetPosition > startPosition ? 1 : -1;
79
+ const stepSize = this.platform.config.coverStepSize || 5; // % per step (configurabile)
80
+ const totalTime = (distance / 100) * (this.maxSeconds * 1000); // Tempo totale basato su maxSeconds
81
+ const stepTime = totalTime / (distance / stepSize); // Tempo per step calcolato
82
+ let currentStep = 0;
83
+ const totalSteps = Math.ceil(distance / stepSize);
84
+ const moveInterval = setInterval(() => {
85
+ currentStep++;
86
+ if (currentStep >= totalSteps) {
87
+ // Movimento completato
88
+ this.currentPosition = targetPosition;
89
+ this.positionState = 2; // Stopped
90
+ this.service.updateCharacteristic(this.platform.Characteristic.CurrentPosition, this.currentPosition);
91
+ this.service.updateCharacteristic(this.platform.Characteristic.PositionState, this.positionState);
92
+ this.platform.log.debug(`🪟 ${this.device.name}: Movimento completato a ${targetPosition}%`);
93
+ clearInterval(moveInterval);
94
+ }
95
+ else {
96
+ // Movimento in corso
97
+ this.currentPosition = Math.min(100, Math.max(0, startPosition + (direction * stepSize * currentStep)));
98
+ this.service.updateCharacteristic(this.platform.Characteristic.CurrentPosition, this.currentPosition);
99
+ }
100
+ }, stepTime);
101
+ }
102
+ // Metodo per aggiornare lo stato dall'esterno (aggiornamenti real-time)
103
+ updateStatus(newDevice) {
104
+ this.device = newDevice;
105
+ if (this.device.status?.position !== this.currentPosition) {
106
+ this.currentPosition = this.device.status?.position || 0;
107
+ this.targetPosition = this.device.status?.position || 0;
108
+ // Aggiorna le caratteristiche
109
+ this.service.updateCharacteristic(this.platform.Characteristic.CurrentPosition, this.currentPosition);
110
+ this.service.updateCharacteristic(this.platform.Characteristic.TargetPosition, this.targetPosition);
111
+ }
112
+ // Aggiorna lo stato del movimento
113
+ switch (this.device.status?.state) {
114
+ case 'opening':
115
+ this.positionState = 1;
116
+ break;
117
+ case 'closing':
118
+ this.positionState = 0;
119
+ break;
120
+ default:
121
+ this.positionState = 2; // stopped
122
+ }
123
+ this.service.updateCharacteristic(this.platform.Characteristic.PositionState, this.positionState);
124
+ this.platform.log.debug(`🔄 Aggiornato stato tapparella ${this.device.name}: ${this.currentPosition}%`);
125
+ }
126
+ }
127
+ exports.CoverAccessory = CoverAccessory;
128
+ //# sourceMappingURL=cover-accessory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cover-accessory.js","sourceRoot":"","sources":["../../src/accessories/cover-accessory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { CharacteristicValue, PlatformAccessory } from 'homebridge';
2
+ import type { Lares4Platform } from '../platform';
3
+ import type { KseniaDevice } from '../types';
4
+ export declare class LightAccessory {
5
+ private readonly platform;
6
+ private readonly accessory;
7
+ private service;
8
+ private device;
9
+ constructor(platform: Lares4Platform, accessory: PlatformAccessory);
10
+ setOn(value: CharacteristicValue): Promise<void>;
11
+ getOn(): Promise<CharacteristicValue>;
12
+ setBrightness(value: CharacteristicValue): Promise<void>;
13
+ getBrightness(): Promise<CharacteristicValue>;
14
+ updateStatus(newDevice: KseniaDevice): void;
15
+ }
16
+ //# sourceMappingURL=light-accessory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"light-accessory.d.ts","sourceRoot":"","sources":["../../src/accessories/light-accessory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAW,MAAM,YAAY,CAAC;AAClF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,qBAAa,cAAc;IAKnB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAL9B,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,MAAM,CAAe;gBAGR,QAAQ,EAAE,cAAc,EACxB,SAAS,EAAE,iBAAiB;IA8B3C,KAAK,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAahD,KAAK,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAIrC,aAAa,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBxD,aAAa,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAKnD,YAAY,CAAC,SAAS,EAAE,YAAY,GAAG,IAAI;CAY9C"}