iobroker.homewizard 0.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 krobi <krobi@power-dreams.com>
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,190 @@
1
+ # ioBroker.homewizard
2
+
3
+ [![npm version](https://img.shields.io/npm/v/iobroker.homewizard)](https://www.npmjs.com/package/iobroker.homewizard)
4
+ ![Node](https://img.shields.io/badge/node-%3E%3D20-brightgreen)
5
+ ![TypeScript](https://img.shields.io/badge/TypeScript-strict-blue)
6
+ [![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
7
+ [![npm downloads](https://img.shields.io/npm/dt/iobroker.homewizard)](https://www.npmjs.com/package/iobroker.homewizard)
8
+ ![Installations](https://iobroker.live/badges/homewizard-installed.svg)
9
+ [![Ko-fi](https://img.shields.io/badge/Ko--fi-Support-ff5e5b?logo=ko-fi)](https://ko-fi.com/krobipd)
10
+ [![PayPal](https://img.shields.io/badge/Donate-PayPal-blue.svg)](https://paypal.me/krobipd)
11
+
12
+ <img src="https://raw.githubusercontent.com/krobipd/ioBroker.homewizard/main/admin/homewizard.svg" width="100" />
13
+
14
+ Real-time energy monitoring from HomeWizard devices via API v2 with WebSocket push (~1 update/second).
15
+
16
+ ---
17
+
18
+ ## Features
19
+
20
+ - **WebSocket push** for real-time energy data (~1 update per second)
21
+ - **Automatic device discovery** via mDNS (zero configuration)
22
+ - **Hue-style pairing** — press the button on the device to connect
23
+ - **Multi-device support** — manage all HomeWizard devices in one adapter instance
24
+ - **Battery control** — manage HomeWizard Plug-In Batteries (mode, permissions)
25
+ - **System control** — LED brightness, cloud toggle, reboot, identify
26
+ - **REST fallback** — automatic polling when WebSocket is unavailable
27
+
28
+ ---
29
+
30
+ ## Requirements
31
+
32
+ - **Node.js >= 20**
33
+ - **ioBroker js-controller >= 7.0.0**
34
+ - **ioBroker Admin >= 7.6.20**
35
+ - **HomeWizard device with API v2 support** (firmware 4.x+ with local API enabled)
36
+
37
+ ---
38
+
39
+ ## Supported Devices
40
+
41
+ | Device | Product Type | WebSocket | Battery Control |
42
+ |--------|-------------|-----------|-----------------|
43
+ | P1 Meter | HWE-P1 | Yes | Yes (as controller) |
44
+ | kWh Meter 1-Phase | HWE-KWH1 / SDM230 | Yes | Yes (as controller) |
45
+ | kWh Meter 3-Phase | HWE-KWH3 / SDM630 | Yes | Yes (as controller) |
46
+ | Plug-In Battery | HWE-BAT | Yes | Controlled via P1/kWh |
47
+
48
+ > **Note:** Energy Socket (HWE-SKT) and Watermeter (HWE-WTR) only support API v1 and are not yet supported. Support will be added when HomeWizard releases API v2 for these devices.
49
+
50
+ ---
51
+
52
+ ## Configuration
53
+
54
+ Devices are added via the **pairing mode**, not manually:
55
+
56
+ 1. Open the **Objects** tab in ioBroker Admin
57
+ 2. Set `homewizard.0.startPairing` to `true`
58
+ 3. **Press the physical button** on your HomeWizard device within 60 seconds
59
+ 4. The device is discovered automatically and appears in the adapter settings
60
+
61
+ The Admin UI shows all paired devices. You can update the IP address if a device gets a new one.
62
+
63
+ ---
64
+
65
+ ## State Tree
66
+
67
+ ```
68
+ homewizard.0.
69
+ ├── info.connection — Overall connection status (bool)
70
+ ├── startPairing — Activate pairing mode (button)
71
+ └── {productType}_{serial}/ — e.g. hwe-p1_5c2fafaabbcc
72
+ ├── info/
73
+ │ ├── productName — Device name (string)
74
+ │ ├── productType — Product type (string)
75
+ │ ├── firmware — Firmware version (string)
76
+ │ ├── connected — WebSocket connection status (bool)
77
+ │ ├── wifi_rssi_db — WiFi signal strength (number, dB)
78
+ │ └── uptime_s — Device uptime (number, s)
79
+ ├── power_w — Total power (number, W)
80
+ ├─�� power_l1_w .. l3_w — Power per phase (number, W)
81
+ ├── voltage_l1_v .. l3_v — Voltage per phase (number, V)
82
+ ├── current_l1_a .. l3_a — Current per phase (number, A)
83
+ ├── frequency_hz — Grid frequency (number, Hz)
84
+ ├── energy_import_kwh — Total import (number, kWh)
85
+ ├── energy_import_t1..t4_kwh — Import per tariff (number, kWh)
86
+ ├── energy_export_kwh — Total export (number, kWh)
87
+ ├── energy_export_t1..t4_kwh — Export per tariff (number, kWh)
88
+ ├── tariff — Active tariff (number)
89
+ ├── quality/ — Power quality counters
90
+ │ ├── voltage_sag_l1..l3_count
91
+ │ ├── voltage_swell_l1..l3_count
92
+ │ ├── power_fail_count
93
+ │ └── long_power_fail_count
94
+ ├── external/ — External meters (gas, water, heat)
95
+ │ └── {type}_{id}/
96
+ │ ├── value — Meter reading (number)
97
+ │ ���── unit — Unit (string)
98
+ │ └── timestamp — Last update (string)
99
+ ├── battery/ — Battery control (if batteries connected)
100
+ │ ├── mode — zero / to_full / standby (string, R/W)
101
+ │ ├── permissions — JSON array (string, R/W)
102
+ │ ├── battery_count — Connected batteries (number)
103
+ │ ├── power_w — Battery power (number, W)
104
+ │ ├── target_power_w — Target power (number, W)
105
+ │ ├── max_consumption_w — Max consumption (number, W)
106
+ │ └── max_production_w — Max production (number, W)
107
+ └── system/ — System settings
108
+ ├── cloud_enabled — Cloud communication (bool, R/W)
109
+ ├── status_led_brightness_pct — LED brightness 0-100 (number, R/W)
110
+ ├── api_v1_enabled — Legacy API v1 (bool, R/W)
111
+ ├── reboot — Reboot device (button)
112
+ └── identify — Blink LED (button)
113
+ ```
114
+
115
+ > States are created dynamically based on what the device reports. Not all devices have all states.
116
+
117
+ ---
118
+
119
+ ## Troubleshooting
120
+
121
+ ### Device not found during pairing
122
+ - Make sure the device is on the same network/VLAN as the ioBroker server
123
+ - Verify that **local API** is enabled in the HomeWizard app (Settings > Meters > your device > Local API)
124
+ - Check that multicast/mDNS traffic is not blocked by your router/firewall
125
+
126
+ ### WebSocket keeps disconnecting
127
+ - Check WiFi signal strength (`info.wifi_rssi_db`) — consider moving the device closer to the router
128
+ - The adapter automatically reconnects with exponential backoff and falls back to REST polling
129
+
130
+ ### Token invalid after factory reset
131
+ - Remove the device from the adapter settings and pair again
132
+
133
+ ---
134
+
135
+ ## Changelog
136
+
137
+ ### 0.1.0 (2026-04-04)
138
+ - Initial release
139
+ - HomeWizard API v2 with Bearer Token authentication
140
+ - WebSocket push for real-time energy data
141
+ - mDNS device discovery
142
+ - Hue-style multi-device pairing
143
+ - Battery control and system settings
144
+ - REST fallback when WebSocket unavailable
145
+
146
+ Older changelog: [CHANGELOG.md](CHANGELOG.md)
147
+
148
+ ---
149
+
150
+ ## Support
151
+
152
+ - [ioBroker Forum](https://forum.iobroker.net/)
153
+ - [GitHub Issues](https://github.com/krobipd/ioBroker.homewizard/issues)
154
+
155
+ ### Support Development
156
+
157
+ This adapter is free and open source. If you find it useful, consider buying me a coffee:
158
+
159
+ [![Ko-fi](https://img.shields.io/badge/Ko--fi-Support-ff5e5b?style=for-the-badge&logo=ko-fi)](https://ko-fi.com/krobipd)
160
+ [![PayPal](https://img.shields.io/badge/Donate-PayPal-blue.svg?style=for-the-badge)](https://paypal.me/krobipd)
161
+
162
+ ---
163
+
164
+ ## License
165
+
166
+ MIT License
167
+
168
+ Copyright (c) 2026 krobi <krobi@power-dreams.com>
169
+
170
+ Permission is hereby granted, free of charge, to any person obtaining a copy
171
+ of this software and associated documentation files (the "Software"), to deal
172
+ in the Software without restriction, including without limitation the rights
173
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
174
+ copies of the Software, and to permit persons to whom the Software is
175
+ furnished to do so, subject to the following conditions:
176
+
177
+ The above copyright notice and this permission notice shall be included in all
178
+ copies or substantial portions of the Software.
179
+
180
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
181
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
182
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
183
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
184
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
185
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
186
+ SOFTWARE.
187
+
188
+ ---
189
+
190
+ *Developed with assistance from Claude.ai*
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
2
+ <circle cx="50" cy="50" r="48" fill="#00B4D8" stroke="#0077B6" stroke-width="2"/>
3
+ <path d="M30 65 L50 25 L70 65" fill="none" stroke="#FFFFFF" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
4
+ <line x1="38" y1="50" x2="62" y2="50" stroke="#FFFFFF" stroke-width="6" stroke-linecap="round"/>
5
+ <line x1="50" y1="65" x2="50" y2="80" stroke="#FFFFFF" stroke-width="6" stroke-linecap="round"/>
6
+ </svg>
@@ -0,0 +1,16 @@
1
+ {
2
+ "headerDevices": "Gekoppelte Geräte",
3
+ "devicesInfo": "Geräte werden automatisch über den Pairing-Modus hinzugefügt. Verwende den Datenpunkt 'startPairing' im Objekte-Tab, um ein neues Gerät zu koppeln. Die IP-Adresse kann hier aktualisiert werden, falls sich diese ändert.",
4
+ "labelDevices": "Geräte",
5
+ "colProductName": "Name",
6
+ "colProductType": "Typ",
7
+ "colSerial": "Seriennummer",
8
+ "colIP": "IP-Adresse",
9
+ "colToken": "Token",
10
+ "headerPairing": "Kopplung",
11
+ "pairingInfo": "Um ein neues Gerät hinzuzufügen: Setze den Datenpunkt 'startPairing' auf true und drücke dann innerhalb von 60 Sekunden den physischen Knopf am HomeWizard-Gerät. Das Gerät wird automatisch erkannt und zur Liste hinzugefügt.",
12
+ "supportHeader": "Unterstützung",
13
+ "aboutInfo": "Dieser Adapter ist kostenlos und Open Source. Wenn er dir nützlich ist, erwäge die Entwicklung zu unterstützen:",
14
+ "donateKofi": "Ko-fi",
15
+ "donatePaypal": "PayPal"
16
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "headerDevices": "Paired Devices",
3
+ "devicesInfo": "Devices are added automatically via the pairing mode. Use the 'startPairing' data point in the Objects tab to pair a new device. You can update the IP address here if a device gets a new one.",
4
+ "labelDevices": "Devices",
5
+ "colProductName": "Name",
6
+ "colProductType": "Type",
7
+ "colSerial": "Serial",
8
+ "colIP": "IP Address",
9
+ "colToken": "Token",
10
+ "headerPairing": "Pairing",
11
+ "pairingInfo": "To add a new device: Set the 'startPairing' data point to true, then press the physical button on your HomeWizard device within 60 seconds. The device will be discovered automatically and added to the list above.",
12
+ "supportHeader": "Support",
13
+ "aboutInfo": "This adapter is free and open source. If you find it useful, consider supporting the development:",
14
+ "donateKofi": "Ko-fi",
15
+ "donatePaypal": "PayPal"
16
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "headerDevices": "Dispositivos emparejados",
3
+ "devicesInfo": "Los dispositivos se añaden automáticamente a través del modo de emparejamiento. Usa el punto de datos 'startPairing' en la pestaña Objetos para emparejar un nuevo dispositivo. La dirección IP se puede actualizar aquí si cambia.",
4
+ "labelDevices": "Dispositivos",
5
+ "colProductName": "Nombre",
6
+ "colProductType": "Tipo",
7
+ "colSerial": "Número de serie",
8
+ "colIP": "Dirección IP",
9
+ "colToken": "Token",
10
+ "headerPairing": "Emparejamiento",
11
+ "pairingInfo": "Para añadir un dispositivo: establece el punto de datos 'startPairing' en true y luego presiona el botón físico en tu dispositivo HomeWizard dentro de 60 segundos. El dispositivo se descubrirá automáticamente.",
12
+ "supportHeader": "Apoyo",
13
+ "aboutInfo": "Este adaptador es gratuito y de código abierto. Si te resulta útil, considera apoyar el desarrollo:",
14
+ "donateKofi": "Ko-fi",
15
+ "donatePaypal": "PayPal"
16
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "headerDevices": "Appareils appairés",
3
+ "devicesInfo": "Les appareils sont ajoutés automatiquement via le mode d'appairage. Utilisez le point de données 'startPairing' dans l'onglet Objets pour appairer un nouvel appareil. L'adresse IP peut être mise à jour ici si elle change.",
4
+ "labelDevices": "Appareils",
5
+ "colProductName": "Nom",
6
+ "colProductType": "Type",
7
+ "colSerial": "Numéro de série",
8
+ "colIP": "Adresse IP",
9
+ "colToken": "Jeton",
10
+ "headerPairing": "Appairage",
11
+ "pairingInfo": "Pour ajouter un appareil : définissez le point de données 'startPairing' sur true, puis appuyez sur le bouton physique de votre appareil HomeWizard dans les 60 secondes. L'appareil sera découvert automatiquement.",
12
+ "supportHeader": "Soutien",
13
+ "aboutInfo": "Cet adaptateur est gratuit et open source. Si vous le trouvez utile, envisagez de soutenir le développement :",
14
+ "donateKofi": "Ko-fi",
15
+ "donatePaypal": "PayPal"
16
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "headerDevices": "Dispositivi associati",
3
+ "devicesInfo": "I dispositivi vengono aggiunti automaticamente tramite la modalità di associazione. Usa il punto dati 'startPairing' nella scheda Oggetti per associare un nuovo dispositivo. L'indirizzo IP può essere aggiornato qui se cambia.",
4
+ "labelDevices": "Dispositivi",
5
+ "colProductName": "Nome",
6
+ "colProductType": "Tipo",
7
+ "colSerial": "Numero di serie",
8
+ "colIP": "Indirizzo IP",
9
+ "colToken": "Token",
10
+ "headerPairing": "Associazione",
11
+ "pairingInfo": "Per aggiungere un dispositivo: imposta il punto dati 'startPairing' su true, poi premi il pulsante fisico sul dispositivo HomeWizard entro 60 secondi. Il dispositivo verrà scoperto automaticamente.",
12
+ "supportHeader": "Supporto",
13
+ "aboutInfo": "Questo adattatore è gratuito e open source. Se lo trovi utile, considera di supportare lo sviluppo:",
14
+ "donateKofi": "Ko-fi",
15
+ "donatePaypal": "PayPal"
16
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "headerDevices": "Gekoppelde apparaten",
3
+ "devicesInfo": "Apparaten worden automatisch toegevoegd via de koppelmodus. Gebruik het datapunt 'startPairing' in het tabblad Objecten om een nieuw apparaat te koppelen. Het IP-adres kan hier worden bijgewerkt als dit verandert.",
4
+ "labelDevices": "Apparaten",
5
+ "colProductName": "Naam",
6
+ "colProductType": "Type",
7
+ "colSerial": "Serienummer",
8
+ "colIP": "IP-adres",
9
+ "colToken": "Token",
10
+ "headerPairing": "Koppelen",
11
+ "pairingInfo": "Om een apparaat toe te voegen: zet het datapunt 'startPairing' op true en druk vervolgens binnen 60 seconden op de fysieke knop op je HomeWizard-apparaat. Het apparaat wordt automatisch gevonden en toegevoegd.",
12
+ "supportHeader": "Ondersteuning",
13
+ "aboutInfo": "Deze adapter is gratis en open source. Als je het nuttig vindt, overweeg dan de ontwikkeling te steunen:",
14
+ "donateKofi": "Ko-fi",
15
+ "donatePaypal": "PayPal"
16
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "headerDevices": "Sparowane urządzenia",
3
+ "devicesInfo": "Urządzenia są dodawane automatycznie przez tryb parowania. Użyj punktu danych 'startPairing' w zakładce Obiekty, aby sparować nowe urządzenie. Adres IP można zaktualizować tutaj, jeśli się zmieni.",
4
+ "labelDevices": "Urządzenia",
5
+ "colProductName": "Nazwa",
6
+ "colProductType": "Typ",
7
+ "colSerial": "Numer seryjny",
8
+ "colIP": "Adres IP",
9
+ "colToken": "Token",
10
+ "headerPairing": "Parowanie",
11
+ "pairingInfo": "Aby dodać urządzenie: ustaw punkt danych 'startPairing' na true, a następnie naciśnij fizyczny przycisk na urządzeniu HomeWizard w ciągu 60 sekund. Urządzenie zostanie wykryte automatycznie.",
12
+ "supportHeader": "Wsparcie",
13
+ "aboutInfo": "Ten adapter jest darmowy i otwartoźródłowy. Jeśli uważasz go za przydatny, rozważ wsparcie rozwoju:",
14
+ "donateKofi": "Ko-fi",
15
+ "donatePaypal": "PayPal"
16
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "headerDevices": "Dispositivos emparelhados",
3
+ "devicesInfo": "Os dispositivos são adicionados automaticamente através do modo de emparelhamento. Use o ponto de dados 'startPairing' na aba Objetos para emparelhar um novo dispositivo. O endereço IP pode ser atualizado aqui se mudar.",
4
+ "labelDevices": "Dispositivos",
5
+ "colProductName": "Nome",
6
+ "colProductType": "Tipo",
7
+ "colSerial": "Número de série",
8
+ "colIP": "Endereço IP",
9
+ "colToken": "Token",
10
+ "headerPairing": "Emparelhamento",
11
+ "pairingInfo": "Para adicionar um dispositivo: defina o ponto de dados 'startPairing' como true e pressione o botão físico no dispositivo HomeWizard dentro de 60 segundos. O dispositivo será descoberto automaticamente.",
12
+ "supportHeader": "Apoio",
13
+ "aboutInfo": "Este adaptador é gratuito e de código aberto. Se você achar útil, considere apoiar o desenvolvimento:",
14
+ "donateKofi": "Ko-fi",
15
+ "donatePaypal": "PayPal"
16
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "headerDevices": "Сопряженные устройства",
3
+ "devicesInfo": "Устройства добавляются автоматически через режим сопряжения. Используйте точку данных 'startPairing' на вкладке объектов для добавления нового устройства. IP-адрес можно обновить здесь, если он изменился.",
4
+ "labelDevices": "Устройства",
5
+ "colProductName": "Имя",
6
+ "colProductType": "Тип",
7
+ "colSerial": "Серийный номер",
8
+ "colIP": "IP-адрес",
9
+ "colToken": "Токен",
10
+ "headerPairing": "Сопряжение",
11
+ "pairingInfo": "Чтобы добавить устройство: установите точку данных 'startPairing' в true, затем нажмите физическую кнопку на устройстве HomeWizard в течение 60 секунд. Устройство будет обнаружено автоматически.",
12
+ "supportHeader": "Поддержка",
13
+ "aboutInfo": "Этот адаптер бесплатный и с открытым исходным кодом. Если он вам полезен, рассмотрите поддержку разработки:",
14
+ "donateKofi": "Ko-fi",
15
+ "donatePaypal": "PayPal"
16
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "headerDevices": "Сполучені пристрої",
3
+ "devicesInfo": "Пристрої додаються автоматично через режим сполучення. Використовуйте точку даних 'startPairing' на вкладці Об'єкти для сполучення нового пристрою. IP-адресу можна оновити тут, якщо вона змінилася.",
4
+ "labelDevices": "Пристрої",
5
+ "colProductName": "Назва",
6
+ "colProductType": "Тип",
7
+ "colSerial": "Серійний номер",
8
+ "colIP": "IP-адреса",
9
+ "colToken": "Токен",
10
+ "headerPairing": "Сполучення",
11
+ "pairingInfo": "Щоб додати пристрій: встановіть точку даних 'startPairing' на true, потім натисніть фізичну кнопку на пристрої HomeWizard протягом 60 секунд. Пристрій буде виявлено автоматично.",
12
+ "supportHeader": "Підтримка",
13
+ "aboutInfo": "Цей адаптер безкоштовний і з відкритим кодом. Якщо він вам корисний, розгляньте підтримку розробки:",
14
+ "donateKofi": "Ko-fi",
15
+ "donatePaypal": "PayPal"
16
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "headerDevices": "已配对设备",
3
+ "devicesInfo": "设备通过配对模式自动添加。使用对象选项卡中的 'startPairing' 数据点来配对新设备。如果设备的 IP 地址发生变化,可以在此处更新。",
4
+ "labelDevices": "设备",
5
+ "colProductName": "名称",
6
+ "colProductType": "类型",
7
+ "colSerial": "序列号",
8
+ "colIP": "IP 地址",
9
+ "colToken": "令牌",
10
+ "headerPairing": "配对",
11
+ "pairingInfo": "要添加新设备:将 'startPairing' 数据点设置为 true,然后在 60 秒内按下 HomeWizard 设备上的物理按钮。设备将被自动发现并添加到上面的列表中。",
12
+ "supportHeader": "支持",
13
+ "aboutInfo": "此适配器免费且开源。如果您觉得有用,请考虑支持开发:",
14
+ "donateKofi": "Ko-fi",
15
+ "donatePaypal": "PayPal"
16
+ }
@@ -0,0 +1,99 @@
1
+ {
2
+ "i18n": true,
3
+ "type": "panel",
4
+ "items": {
5
+ "_headerDevices": {
6
+ "type": "header",
7
+ "text": "headerDevices",
8
+ "size": 3
9
+ },
10
+ "_devicesInfo": {
11
+ "type": "staticText",
12
+ "text": "devicesInfo",
13
+ "style": { "fontSize": 14, "marginBottom": 16 }
14
+ },
15
+ "devices": {
16
+ "type": "table",
17
+ "label": "labelDevices",
18
+ "sm": 12,
19
+ "items": [
20
+ {
21
+ "type": "text",
22
+ "attr": "productName",
23
+ "title": "colProductName",
24
+ "width": "20%",
25
+ "readOnly": true
26
+ },
27
+ {
28
+ "type": "text",
29
+ "attr": "productType",
30
+ "title": "colProductType",
31
+ "width": "15%",
32
+ "readOnly": true
33
+ },
34
+ {
35
+ "type": "text",
36
+ "attr": "serial",
37
+ "title": "colSerial",
38
+ "width": "20%",
39
+ "readOnly": true
40
+ },
41
+ {
42
+ "type": "text",
43
+ "attr": "ip",
44
+ "title": "colIP",
45
+ "width": "20%"
46
+ },
47
+ {
48
+ "type": "text",
49
+ "attr": "token",
50
+ "title": "colToken",
51
+ "width": "25%",
52
+ "readOnly": true
53
+ }
54
+ ],
55
+ "noDelete": false
56
+ },
57
+ "_headerPairing": {
58
+ "newLine": true,
59
+ "type": "header",
60
+ "text": "headerPairing",
61
+ "size": 4
62
+ },
63
+ "_pairingInfo": {
64
+ "type": "staticText",
65
+ "text": "pairingInfo",
66
+ "style": { "fontSize": 14, "marginBottom": 16 }
67
+ },
68
+ "_supportHeader": {
69
+ "newLine": true,
70
+ "type": "header",
71
+ "text": "supportHeader",
72
+ "size": 5
73
+ },
74
+ "_aboutInfo": {
75
+ "type": "staticText",
76
+ "text": "aboutInfo",
77
+ "xs": 12, "sm": 12, "md": 12, "lg": 12, "xl": 12,
78
+ "style": { "fontSize": 14, "marginBottom": 16 }
79
+ },
80
+ "_kofiLink": {
81
+ "type": "staticLink",
82
+ "href": "https://ko-fi.com/krobipd",
83
+ "label": "donateKofi",
84
+ "button": true,
85
+ "variant": "outlined",
86
+ "color": "primary",
87
+ "xs": 12, "sm": 6, "md": 4, "lg": 4, "xl": 4
88
+ },
89
+ "_paypalLink": {
90
+ "type": "staticLink",
91
+ "href": "https://paypal.me/krobipd",
92
+ "label": "donatePaypal",
93
+ "button": true,
94
+ "variant": "outlined",
95
+ "color": "primary",
96
+ "xs": 12, "sm": 6, "md": 4, "lg": 4, "xl": 4
97
+ }
98
+ }
99
+ }
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var discovery_exports = {};
30
+ __export(discovery_exports, {
31
+ HomeWizardDiscovery: () => HomeWizardDiscovery
32
+ });
33
+ module.exports = __toCommonJS(discovery_exports);
34
+ var import_bonjour_service = __toESM(require("bonjour-service"));
35
+ class HomeWizardDiscovery {
36
+ bonjour = null;
37
+ browser = null;
38
+ log;
39
+ /**
40
+ * @param log Logger interface
41
+ * @param log.debug Debug log function
42
+ * @param log.warn Warning log function
43
+ */
44
+ constructor(log) {
45
+ this.log = log;
46
+ }
47
+ /**
48
+ * Start scanning for HomeWizard devices
49
+ *
50
+ * @param callback Called for each discovered device
51
+ */
52
+ start(callback) {
53
+ this.stop();
54
+ this.bonjour = new import_bonjour_service.default();
55
+ this.log.debug("mDNS: browsing for _hwenergy._tcp");
56
+ this.browser = this.bonjour.find(
57
+ { type: "hwenergy", protocol: "tcp" },
58
+ (service) => {
59
+ const device = this.parseService(service);
60
+ if (device) {
61
+ this.log.debug(
62
+ `mDNS: found ${device.name} (${device.productType}) at ${device.ip}`
63
+ );
64
+ callback(device);
65
+ }
66
+ }
67
+ );
68
+ }
69
+ /** Stop scanning */
70
+ stop() {
71
+ if (this.browser) {
72
+ this.browser.stop();
73
+ this.browser = null;
74
+ }
75
+ if (this.bonjour) {
76
+ this.bonjour.destroy();
77
+ this.bonjour = null;
78
+ }
79
+ }
80
+ /**
81
+ * Parse a Bonjour service into a DiscoveredDevice
82
+ *
83
+ * @param service Bonjour service record
84
+ */
85
+ parseService(service) {
86
+ var _a, _b, _c, _d, _e, _f, _g;
87
+ const ip = (_a = service.addresses) == null ? void 0 : _a.find((addr) => addr.includes("."));
88
+ if (!ip) {
89
+ this.log.debug(`mDNS: no IPv4 address for ${service.name}`);
90
+ return null;
91
+ }
92
+ const txt = service.txt;
93
+ const productType = (_c = (_b = txt == null ? void 0 : txt.product_type) != null ? _b : txt == null ? void 0 : txt.type) != null ? _c : "unknown";
94
+ const serial = (_e = (_d = txt == null ? void 0 : txt.serial) != null ? _d : service.name) != null ? _e : "unknown";
95
+ const name = (_g = (_f = txt == null ? void 0 : txt.product_name) != null ? _f : service.name) != null ? _g : productType;
96
+ return { ip, productType, serial, name };
97
+ }
98
+ }
99
+ // Annotate the CommonJS export names for ESM import in node:
100
+ 0 && (module.exports = {
101
+ HomeWizardDiscovery
102
+ });
103
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/lib/discovery.ts"],
4
+ "sourcesContent": ["import Bonjour, { type Service } from \"bonjour-service\";\nimport type { DiscoveredDevice } from \"./types\";\n\n/** Callback for discovered devices */\nexport type DiscoveryCallback = (device: DiscoveredDevice) => void;\n\n/**\n * mDNS discovery for HomeWizard Energy devices.\n * Browses for `_hwenergy._tcp` services on the local network.\n */\nexport class HomeWizardDiscovery {\n private bonjour: Bonjour | null = null;\n private browser: ReturnType<Bonjour[\"find\"]> | null = null;\n private readonly log: {\n debug: (msg: string) => void;\n warn: (msg: string) => void;\n };\n\n /**\n * @param log Logger interface\n * @param log.debug Debug log function\n * @param log.warn Warning log function\n */\n constructor(log: {\n debug: (msg: string) => void;\n warn: (msg: string) => void;\n }) {\n this.log = log;\n }\n\n /**\n * Start scanning for HomeWizard devices\n *\n * @param callback Called for each discovered device\n */\n start(callback: DiscoveryCallback): void {\n this.stop();\n\n this.bonjour = new Bonjour();\n this.log.debug(\"mDNS: browsing for _hwenergy._tcp\");\n\n this.browser = this.bonjour.find(\n { type: \"hwenergy\", protocol: \"tcp\" },\n (service: Service) => {\n const device = this.parseService(service);\n if (device) {\n this.log.debug(\n `mDNS: found ${device.name} (${device.productType}) at ${device.ip}`,\n );\n callback(device);\n }\n },\n );\n }\n\n /** Stop scanning */\n stop(): void {\n if (this.browser) {\n this.browser.stop();\n this.browser = null;\n }\n if (this.bonjour) {\n this.bonjour.destroy();\n this.bonjour = null;\n }\n }\n\n /**\n * Parse a Bonjour service into a DiscoveredDevice\n *\n * @param service Bonjour service record\n */\n private parseService(service: Service): DiscoveredDevice | null {\n // IPv4 address\n const ip = service.addresses?.find((addr) => addr.includes(\".\"));\n if (!ip) {\n this.log.debug(`mDNS: no IPv4 address for ${service.name}`);\n return null;\n }\n\n // TXT records contain product_type, serial, etc.\n const txt = service.txt as Record<string, string> | undefined;\n const productType = txt?.product_type ?? txt?.type ?? \"unknown\";\n const serial = txt?.serial ?? service.name ?? \"unknown\";\n const name = txt?.product_name ?? service.name ?? productType;\n\n return { ip, productType, serial, name };\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6BAAsC;AAU/B,MAAM,oBAAoB;AAAA,EACvB,UAA0B;AAAA,EAC1B,UAA8C;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUjB,YAAY,KAGT;AACD,SAAK,MAAM;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,UAAmC;AACvC,SAAK,KAAK;AAEV,SAAK,UAAU,IAAI,uBAAAA,QAAQ;AAC3B,SAAK,IAAI,MAAM,mCAAmC;AAElD,SAAK,UAAU,KAAK,QAAQ;AAAA,MAC1B,EAAE,MAAM,YAAY,UAAU,MAAM;AAAA,MACpC,CAAC,YAAqB;AACpB,cAAM,SAAS,KAAK,aAAa,OAAO;AACxC,YAAI,QAAQ;AACV,eAAK,IAAI;AAAA,YACP,eAAe,OAAO,IAAI,KAAK,OAAO,WAAW,QAAQ,OAAO,EAAE;AAAA,UACpE;AACA,mBAAS,MAAM;AAAA,QACjB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,OAAa;AACX,QAAI,KAAK,SAAS;AAChB,WAAK,QAAQ,KAAK;AAClB,WAAK,UAAU;AAAA,IACjB;AACA,QAAI,KAAK,SAAS;AAChB,WAAK,QAAQ,QAAQ;AACrB,WAAK,UAAU;AAAA,IACjB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,aAAa,SAA2C;AAxElE;AA0EI,UAAM,MAAK,aAAQ,cAAR,mBAAmB,KAAK,CAAC,SAAS,KAAK,SAAS,GAAG;AAC9D,QAAI,CAAC,IAAI;AACP,WAAK,IAAI,MAAM,6BAA6B,QAAQ,IAAI,EAAE;AAC1D,aAAO;AAAA,IACT;AAGA,UAAM,MAAM,QAAQ;AACpB,UAAM,eAAc,sCAAK,iBAAL,YAAqB,2BAAK,SAA1B,YAAkC;AACtD,UAAM,UAAS,sCAAK,WAAL,YAAe,QAAQ,SAAvB,YAA+B;AAC9C,UAAM,QAAO,sCAAK,iBAAL,YAAqB,QAAQ,SAA7B,YAAqC;AAElD,WAAO,EAAE,IAAI,aAAa,QAAQ,KAAK;AAAA,EACzC;AACF;",
6
+ "names": ["Bonjour"]
7
+ }