iobroker.esphome 0.3.2 → 0.4.1
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/CHANGELOG_OLD.md +8 -0
- package/README.md +13 -11
- package/admin/index_m.html +30 -39
- package/admin/words.js +4 -1
- package/io-package.json +27 -26
- package/main.js +252 -43
- package/package.json +1 -1
package/CHANGELOG_OLD.md
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
# Older changes
|
|
2
|
+
## 0.2.4 (2021-08-24)
|
|
3
|
+
* (DutchmanNL) Version of ESPHome Dashboard updated to 2021.8
|
|
4
|
+
* (DutchmanNL) Add option if config of ESPHome device should be shown as states (default = FALSE, safes 8 states for each sensor)
|
|
5
|
+
|
|
6
|
+
## 0.2.3 (2021-06-29)
|
|
7
|
+
* (Jey-Cee) Bugfix : Light component state not changed [#74](https://github.com/DrozmotiX/ioBroker.esphome/issues/74)
|
|
8
|
+
* (DutchmanNL) Update compatibility to version 1.19.4 of ESPHome Dashboard
|
|
9
|
+
|
|
2
10
|
## 0.2.2 (2021-06-24)
|
|
3
11
|
* (DutchmanNL) [!!! Breaking !!!] Make YAML file persistent, backup your configuration before updating ! solves [#57](https://github.com/DrozmotiX/ioBroker.esphome/issues/57)
|
|
4
12
|
* (DutchmanNL) Update ESPHome Dashboard to 1.18.0, requires Python >=3.7 (and ensure <4.0!)
|
package/README.md
CHANGED
|
@@ -112,29 +112,31 @@ If you like my work, please consider a personal donation
|
|
|
112
112
|
### __WORK IN PROGRESS__
|
|
113
113
|
* (DutchmanNL)
|
|
114
114
|
-->
|
|
115
|
+
### 0.4.1 (2023-11-05)
|
|
116
|
+
* (DutchmanNL) Bugfix: Password / connection issues in previous beta resolves #179
|
|
117
|
+
* (DutchmanNL) Bugfix: Allow individual API password or encryption keys for devices, resolves #174
|
|
118
|
+
* (DutchmanNL) Support ESPHome device Encryption Key (you should migrate from API password to Encryption Key ! resolves #152)
|
|
119
|
+
|
|
120
|
+
### 0.4.0 (2023-11-03)
|
|
121
|
+
* (DutchmanNL) Added cleanup capability for unused channels & states after initialisation of device, resolves #39
|
|
122
|
+
* (DutchmanNL) Added button to info channel which allows to delete all offline devices from adapter tree. resolves #39
|
|
123
|
+
* (DutchmanNL) [Breaking] Backup strategy changed, requires [BackitUp v2.9.1](https://github.com/simatec/ioBroker.backitup) and activate option for ESPHome, fixes #129
|
|
124
|
+
|
|
115
125
|
### 0.3.2 (2023-11-01)
|
|
116
126
|
* (DutchmanNL) Improved error handling if devices are not reachable/disconnected
|
|
117
|
-
* (DutchmanNL) Bugfix: Allow control of brightness and color for light component,
|
|
127
|
+
* (DutchmanNL) Bugfix: Allow control of brightness and color for light component, resolves #173
|
|
118
128
|
|
|
119
129
|
### 0.3.1 (2023-10-31)
|
|
120
|
-
* (DutchmanNL) Bugfix: Show online state of ESP Device correctly,
|
|
130
|
+
* (DutchmanNL) Bugfix: Show online state of ESP Device correctly, resolves #106
|
|
121
131
|
|
|
122
132
|
### 0.3.0 (2023-10-31) - Bugfixes & Improvements
|
|
123
133
|
* (Dutchman & SimonFischer04) Several Bugfixes
|
|
124
134
|
* (SimonFischer04) Support type "select device"
|
|
125
135
|
* (DutchmanNL) ESPHome dashboard default disabled
|
|
126
136
|
* (SimonFischer04) Migrate to @2colors/esphome-native-api
|
|
127
|
-
* (DutchmanNL) Automatically create needed directories,
|
|
137
|
+
* (DutchmanNL) Automatically create needed directories, resolves #168
|
|
128
138
|
* (SimonFischer04) Migrate usage of python to new structure, should solve all ESPHome Dashboard related installation issues
|
|
129
139
|
|
|
130
|
-
### 0.2.4 (2021-08-24)
|
|
131
|
-
* (DutchmanNL) Version of ESPHome Dashboard updated to 2021.8
|
|
132
|
-
* (DutchmanNL) Add option if config of ESPHome device should be shown as states (default = FALSE, safes 8 states for each sensor)
|
|
133
|
-
|
|
134
|
-
### 0.2.3 (2021-06-29)
|
|
135
|
-
* (Jey-Cee) Bugfix : Light component state not changed [#74](https://github.com/DrozmotiX/ioBroker.esphome/issues/74)
|
|
136
|
-
* (DutchmanNL) Update compatibility to version 1.19.4 of ESPHome Dashboard
|
|
137
|
-
|
|
138
140
|
## License
|
|
139
141
|
MIT License
|
|
140
142
|
|
package/admin/index_m.html
CHANGED
|
@@ -88,15 +88,23 @@
|
|
|
88
88
|
console.log('Return of all devices : ' + JSON.stringify(_devices));
|
|
89
89
|
|
|
90
90
|
let text = '';
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
91
|
+
text += `
|
|
92
|
+
|
|
93
|
+
<p class="translate">You can either choose to use the Device Encryption Key (preferred) or API-Password (legacy)</p>
|
|
94
|
+
<p class="translate">When Encryption Key is provided, API-Password will be ignored</p>
|
|
95
|
+
<div class="input-field ip col s8">
|
|
96
|
+
<label for="device-ip"></label><input placeholder="192.168.0.100" class="center" id="device-ip" type="text"/>
|
|
97
|
+
<span class="translate">IP</span>
|
|
98
|
+
</div>
|
|
99
|
+
<div class="input-field pass col s8">
|
|
100
|
+
<label for="deviceEncryptionKey"></label><input class="center" id="deviceEncryptionKey" type="password"/>
|
|
101
|
+
<span class="translate">deviceEncryptionKey</span>
|
|
102
|
+
</div>
|
|
103
|
+
<div class="input-field pass col s8">
|
|
104
|
+
<label for="device-pass"></label><input class="center" id="device-pass" type="password"/>
|
|
105
|
+
<span class="translate">device-pass</span>
|
|
106
|
+
</div>`;
|
|
107
|
+
|
|
100
108
|
$(`#edit_device_container`).html(text);
|
|
101
109
|
});
|
|
102
110
|
}
|
|
@@ -190,7 +198,8 @@
|
|
|
190
198
|
console.log('Add device button executed');
|
|
191
199
|
messageObj = {
|
|
192
200
|
'device-ip': $('#device-ip').val(),
|
|
193
|
-
'device-pass': encryptManuell(secret, $('#device-pass').val())
|
|
201
|
+
'device-pass': encryptManuell(secret, $('#device-pass').val()),
|
|
202
|
+
'deviceEncryptionKey': encryptManuell(secret, $('#deviceEncryptionKey').val())
|
|
194
203
|
};
|
|
195
204
|
sendTo(null, 'addDevice', messageObj, (data) => {
|
|
196
205
|
console.log('Message from backend : ' + data);
|
|
@@ -210,7 +219,8 @@
|
|
|
210
219
|
messageObj = {
|
|
211
220
|
'device-ip': $('#device-ip').val(),
|
|
212
221
|
// 'device-pass': decryptManuell(secret, $('#device-pass').val())
|
|
213
|
-
'device-pass': encryptManuell(secret, $('#device-pass').val())
|
|
222
|
+
'device-pass': encryptManuell(secret, $('#device-pass').val()),
|
|
223
|
+
'deviceEncryptionKey': encryptManuell(secret, $('#deviceEncryptionKey').val())
|
|
214
224
|
};
|
|
215
225
|
sendTo(null, 'addDevice', messageObj, (data) => {
|
|
216
226
|
console.log('Message from backend : ' + data);
|
|
@@ -305,31 +315,6 @@
|
|
|
305
315
|
<input type="text" class="value" disabled="true" id="ESPHomeDashboardPort" />
|
|
306
316
|
<label for="ESPHomeDashboardPort" class="translate">ESPHomeDashboardPort</label>
|
|
307
317
|
</div>
|
|
308
|
-
|
|
309
|
-
<!-- <div class="input-field col s4">-->
|
|
310
|
-
<!-- <input placeholder="localhost" class="center" id="device-ip" type="text" id="ESPHomeDashboardEnabled" />-->
|
|
311
|
-
<!-- <span class="translate">ESPHome Dashboard IP</span>-->
|
|
312
|
-
<!-- </div>-->
|
|
313
|
-
<!-- <div class="input-field col s4">-->
|
|
314
|
-
<!-- <input type="number" class="value" id="ESPHomeDashboardPort" />-->
|
|
315
|
-
<!-- <span class="translate">Port</span>-->
|
|
316
|
-
<!-- </div>-->
|
|
317
|
-
<!-- <div class="input-field col s2">-->
|
|
318
|
-
<!-- <input type="checkbox" class="value" id="currentYearWeeks" />-->
|
|
319
|
-
<!-- <span class="translate">Week</span>-->
|
|
320
|
-
<!-- </div>-->
|
|
321
|
-
<!-- <div class="input-field col s2">-->
|
|
322
|
-
<!-- <input type="checkbox" class="value" id="currentYearMonth" />-->
|
|
323
|
-
<!-- <span class="translate">Month</span>-->
|
|
324
|
-
<!-- </div>-->
|
|
325
|
-
<!-- <div class="input-field col s2">-->
|
|
326
|
-
<!-- <input type="checkbox" class="value" id="currentYearQuarter" />-->
|
|
327
|
-
<!-- <span class="translate">Quarter</span>-->
|
|
328
|
-
<!-- </div>-->
|
|
329
|
-
<!-- <div class="input-field col s2">-->
|
|
330
|
-
<!-- <input type="checkbox" class="value" id="currentYearPrevious" />-->
|
|
331
|
-
<!-- <span class="translate">Previous</span>-->
|
|
332
|
-
<!-- </div>-->
|
|
333
318
|
</div>
|
|
334
319
|
|
|
335
320
|
<div class="row center">
|
|
@@ -407,11 +392,17 @@
|
|
|
407
392
|
<div class="modal-content">
|
|
408
393
|
<h5 class="translate center">Add device manually</h5>
|
|
409
394
|
<div class="row center">
|
|
410
|
-
<
|
|
411
|
-
|
|
395
|
+
<p class="translate">You can either choose to use the Device Encryption Key (preferred) or API-Password (legacy)</p>
|
|
396
|
+
<p class="translate">When Encryption Key is provided, API-Password will be ignored</p>
|
|
397
|
+
<div class="input-field ip col s8">
|
|
398
|
+
<label for="device-ip"></label><input placeholder="192.168.0.100" class="center" id="device-ip" type="text"/>
|
|
412
399
|
<span class="translate">IP</span>
|
|
413
400
|
</div>
|
|
414
|
-
<div class="input-field pass col
|
|
401
|
+
<div class="input-field pass col s8">
|
|
402
|
+
<label for="deviceEncryptionKey"></label><input class="center" id="deviceEncryptionKey" type="password"/>
|
|
403
|
+
<span class="translate">deviceEncryptionKey</span>
|
|
404
|
+
</div>
|
|
405
|
+
<div class="input-field pass col s8">
|
|
415
406
|
<label for="device-pass"></label><input class="center" id="device-pass" type="password"/>
|
|
416
407
|
<span class="translate">device-pass</span>
|
|
417
408
|
</div>
|
package/admin/words.js
CHANGED
|
@@ -10,6 +10,8 @@ systemDictionary = {
|
|
|
10
10
|
'Connected': { 'en': 'Connected', 'de': 'Verbunden', 'ru': 'Подключено', 'pt': 'Conectado', 'nl': 'Verbonden', 'fr': 'Lié', 'it': 'Collegato', 'es': 'Conectado', 'pl': 'Połączony', 'zh-cn': '连接的'},
|
|
11
11
|
'Delete': { 'en': 'Delete', 'de': 'Löschen', 'ru': 'Удалить', 'pt': 'Excluir', 'nl': 'Verwijderen', 'fr': 'Effacer', 'it': 'Elimina', 'es': 'Borrar', 'pl': 'Usuń', 'zh-cn': '删除'},
|
|
12
12
|
'Devices can be added manually or by autodiscovery': {'en': 'Devices can be added manually or by autodiscovery', 'de': 'Geräte können manuell oder durch die automatische Erkennung hinzugefügt werden', 'ru': 'Устройства можно добавлять вручную или с помощью автообнаружения', 'pt': 'Os dispositivos podem ser adicionados manualmente ou por autodiscovery', 'nl': 'Apparaten kunnen handmatig of door autodiscovery worden toegevoegd', 'fr': 'Les appareils peuvent être ajoutés manuellement ou par découverte automatique', 'it': 'I dispositivi possono essere aggiunti manualmente o tramite rilevamento automatico', 'es': 'Los dispositivos se pueden agregar manualmente o por descubrimiento automático', 'pl': 'Urządzenia można dodawać ręcznie lub przez automatyczne wykrywanie', 'zh-cn': '可以手动添加设备或通过自动发现添加设备'},
|
|
13
|
+
'You can either choose to use the Device Encryption Key (preferred) or API-Password (legacy)': {'en': 'You can either choose to use the Device Encryption Key (preferred) or API-Password (legacy)', 'de': 'Sie können entweder den Geräteverschlüsselungsschlüssel (bevorzugt) oder das API-Passwort (alt) verwenden.', 'ru': 'Вы можете использовать либо ключ шифрования устройства (предпочтительно), либо пароль API (устаревший вариант).', 'pt': 'Você pode optar por usar a chave de criptografia do dispositivo (preferencial) ou a senha da API (legado)', 'nl': 'U kunt ervoor kiezen om de Device Encryption Key (bij voorkeur) of het API-wachtwoord (verouderd) te gebruiken', 'fr': "Vous pouvez choisir d'utiliser la clé de chiffrement de l'appareil (de préférence) ou le mot de passe API (ancien)", 'it': 'Puoi scegliere di utilizzare la chiave di crittografia del dispositivo (preferita) o la password API (legacy)', 'es': 'Puede optar por utilizar la clave de cifrado del dispositivo (preferida) o la contraseña API (heredada)', 'pl': 'Możesz wybrać użycie klucza szyfrowania urządzenia (preferowany) lub hasła API (starsza wersja)', 'zh-cn': '您可以选择使用设备加密密钥(首选)或 API 密码(旧版)'},
|
|
14
|
+
'When Encryption Key is provided, API-Password will be ignored': {'en': 'When Encryption Key is provided, API-Password will be ignored', 'de': 'Wenn der Verschlüsselungsschlüssel bereitgestellt wird, wird das API-Passwort ignoriert', 'ru': 'Если предоставлен ключ шифрования, пароль API будет игнорироваться.', 'pt': 'Quando a chave de criptografia for fornecida, a senha da API será ignorada', 'nl': 'Wanneer de coderingssleutel wordt opgegeven, wordt het API-wachtwoord genegeerd', 'fr': 'Lorsque la clé de cryptage est fournie, le mot de passe API sera ignoré', 'it': 'Quando viene fornita la chiave di crittografia, la password API verrà ignorata', 'es': 'Cuando se proporciona la clave de cifrado, se ignorará la contraseña API', 'pl': 'Po podaniu klucza szyfrowania hasło API zostanie zignorowane', 'zh-cn': '当提供加密密钥时,API-密码将被忽略'},
|
|
13
15
|
'ESPHomeDashboardEnabled': { 'en': 'Enable built-in ESPHome dashboard', 'de': 'Aktiviere das integrierte ESPHome-Dashboard', 'ru': 'Включить встроенный ESPHome Dashboard', 'pt': 'Ativar painel ESPHome integrado', 'nl': 'Schakel het ingebouwde ESPHome-dashboard in', 'fr': 'Activer le tableau de bord ESPHome intégré', 'it': 'Abilita il dashboard ESPHome integrato', 'es': 'Habilitar el panel de control ESPHome integrado', 'pl': 'Włącz wbudowany pulpit nawigacyjny ESPHome', 'zh-cn': '启用内置ESPHome仪表板'},
|
|
14
16
|
'ESPHome_Dashboard_Generic_info': { 'en': 'Here you can enable / disable the ESPHome dashboard hosted by ioBroker. A separate installation of ESPHome is not required!', 'de': 'Hier wird das von ioBroker bereitgestellt ESPHome-Dashboard aktiviert / deaktiviert. Eine separate Installation von ESPHome ist nicht erforderlich!', 'ru': 'Здесь вы можете включить / отключить панель управления ESPHome, запущенную ioBroker-ом. Устанавливать дополнительно ESPhome не нужно!', 'pt': 'Aqui você pode ativar / desativar o painel ESPHome hospedado por ioBroker. ', 'nl': 'Hier kunt u het ESPHome-dashboard dat wordt gehost door ioBroker in- / uitschakelen. Een seperate installatie is niet noodzakelijk!', 'fr': 'Ici, vous pouvez activer / désactiver le tableau de bord ESPHome hébergé par ioBroker. ', 'it': 'Qui puoi abilitare / disabilitare la dashboard ESPHome ospitata da ioBroker. ', 'es': 'Aquí puede habilitar / deshabilitar el panel de ESPHome alojado por ioBroker. ', 'pl': 'Tutaj możesz włączyć / wyłączyć pulpit nawigacyjny ESPHome obsługiwany przez ioBroker. ', 'zh-cn': '您可以在此处启用/禁用ioBroker托管的ESPHome仪表板。'},
|
|
15
17
|
'ESPHome_Dashboard_IP_info': { 'en': 'Please provide the IP address where the ESPHome dashboard is located (ioBroker or already existing instance).', 'de': 'Bitte die IP-Adresse angeben, unter der sich das ESPHome-Dashboard befindet (ioBroker oder bereits vorhandene ESPHome Instanz).', 'ru': 'Укажите IP-адрес, на котором расположена панель управления ESPHome (ioBroker или уже существующий экземпляр?)', 'pt': 'Forneça o endereço IP onde o ESPHome Dashboard está localizado (ioBroker ou instância já existente?)', 'nl': 'IP-adres op waar het ESPHome-dashboard zich bevindt (ioBroker of een reeds bestaande instantie?)', 'fr': "Veuillez fournir l'adresse IP où se trouve le tableau de bord ESPHome (ioBroker ou instance déjà existante?)", 'it': "Fornisci l'indirizzo IP in cui si trova ESPHome Dashboard (ioBroker o istanza già esistente?)", 'es': 'Proporcione la dirección IP donde se encuentra el panel de ESPHome (¿ioBroker o una instancia ya existente?)', 'pl': 'Podaj adres IP, pod którym znajduje się pulpit nawigacyjny ESPHome (ioBroker czy już istniejąca instancja?)', 'zh-cn': '请提供ESPHome仪表板所在的IP地址(ioBroker或已经存在的实例?)'},
|
|
@@ -20,6 +22,7 @@ systemDictionary = {
|
|
|
20
22
|
'IP-Address': { 'en': 'IP Address', 'de': 'IP-Adresse', 'ru': 'IP адрес', 'pt': 'Endereço de IP', 'nl': 'IP adres', 'fr': 'Adresse IP', 'it': 'Indirizzo IP', 'es': 'Dirección IP', 'pl': 'Adres IP', 'zh-cn': 'IP地址'},
|
|
21
23
|
'Name': { 'en': 'Name', 'de': 'Name', 'ru': 'Имя', 'pt': 'Nome', 'nl': 'Naam', 'fr': 'Nom', 'it': 'Nome', 'es': 'Nombre', 'pl': 'Nazwa', 'zh-cn': '姓名'},
|
|
22
24
|
'Show configuration as states': { 'en': 'Show configuration as states', 'de': 'Konfiguration als Zustände anzeigen', 'ru': 'Показать конфигурацию как состояния', 'pt': 'Mostrar configuração como estados', 'nl': 'Configuratie weergeven als toestanden', 'fr': "Afficher la configuration sous forme d'états", 'it': 'Mostra configurazione come stati', 'es': 'Mostrar configuración como estados', 'pl': 'Pokaż konfigurację jako stany', 'zh-cn': '将配置显示为状态'},
|
|
23
|
-
'device-pass': { 'en': 'Password',
|
|
25
|
+
'device-pass': { 'en': 'Device API Password (legacy)', 'de': 'Passwort', 'ru': 'Пароль', 'pt': 'Senha', 'nl': 'Wachtwoord', 'fr': 'Mot de passe', 'it': "Parola d'ordine", 'es': 'Contraseña', 'pl': 'Hasło', 'zh-cn': '密码'},
|
|
26
|
+
'deviceEncryptionKey': { 'en': 'Device EncryptionKey (preferred)', 'de': 'Geräteverschlüsselungsschlüssel (bevorzugt)', 'ru': 'Ключ шифрования устройства (предпочтительно)', 'pt': 'Chave de criptografia do dispositivo (preferencial)', 'nl': 'Apparaatcoderingssleutel (bij voorkeur)', 'fr': "Clé de chiffrement de l'appareil (de préférence)", 'it': 'Chiave di crittografia del dispositivo (preferita)', 'es': 'Clave de cifrado del dispositivo (preferida)', 'pl': 'Klucz szyfrowania urządzenia (preferowany)', 'zh-cn': '设备加密密钥(首选)'},
|
|
24
27
|
'reconnect interval': { 'en': 'Reconnect Interval', 'de': 'Intervall für erneutes Verbinden', 'ru': 'Интервал повторного соединения', 'pt': 'intervalo de reconexão', 'nl': 'interval voor opnieuw verbinden', 'fr': 'intervalle de reconnexion', 'it': "ricollegare l'intervallo", 'es': 'intervalo de reconexión', 'pl': 'interwał ponownego łączenia', 'zh-cn': '重新连接间隔'},
|
|
25
28
|
};
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "esphome",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.4.1",
|
|
5
5
|
"news": {
|
|
6
|
+
"0.4.1": {
|
|
7
|
+
"en": "Bugfix: Password / connection issues in previous beta resolves #179\nBugfix: Allow individual API password or encryption keys for devices, resolves #174\nSupport ESPHome device Encryption Key (you should migrate from API password to Encryption Key ! resolves #152)",
|
|
8
|
+
"de": "Bugfix: Passwort / Verbindungsprobleme in vorherigen beta löst #179\nBugfix: Lassen Sie individuelle API-Passwort oder Verschlüsselungsschlüssel für Geräte, löst #174\nSupport ESPHome Gerät Verschlüsselungsschlüssel (Sie sollten von API-Passwort zu Verschlüsselungsschlüssel migrieren! löst #152)",
|
|
9
|
+
"ru": "Bugfix: Пароль / проблемы соединения в предыдущей бета-версии решает #179\nBugfix: Разрешить индивидуальные API-пароль или ключи шифрования для устройств, решает #174\nПоддержка ESPHome устройства Encryption Key (вы должны migrate от API-пароль для Encryption Key! решает #152)",
|
|
10
|
+
"pt": "Bugfix: Problemas de senha / conexão no beta anterior resolve #179\nBugfix: Permitir senha API individual ou chaves de criptografia para dispositivos, resolve #174\nSuporte ESPHome dispositivo Encryption Key (você deve migrar da senha API para Encryption Key! resolve #152)",
|
|
11
|
+
"nl": "Vertaling:\nBugfix: Sta individuele API wachtwoord of encryptie sleutels voor apparatuur, vaststellen\nSteun ESPHome apparatuur encryption Key (je moet migreren van API wachtwoord naar Encryption Key! Vertaling:",
|
|
12
|
+
"fr": "Bugfix: Mot de passe / problèmes de connexion dans la bêta précédente résout #179\nBugfix: Permettre un mot de passe ou des clés de chiffrement de l'API pour les appareils, résout #174\nSupport ESPHome périphérique Clé de chiffrement (vous devriez migrer de l'API mot de passe à la clé de chiffrement ! résout #152)",
|
|
13
|
+
"it": "Bugfix: Password / problemi di connessione nella precedente beta risolve #179\nBugfix: Consentire singole password API o chiavi di crittografia per i dispositivi, risolve #174\nSupporto dispositivo ESPHome chiave di crittografia (si dovrebbe migrare da password API a chiave di crittografia! risolve #152)",
|
|
14
|
+
"es": "Bugfix: Problemas de contraseña / conexión en beta anterior resuelve #179\nBugfix: Permitir contraseña o claves de cifrado individuales de API para dispositivos, resuelve #174\nSoporte ESPHome dispositivo clave de cifrado (debe migrar desde contraseña de API a clave de cifrado! resuelve #152)",
|
|
15
|
+
"pl": "Bugfix: Password / Problemy połączenia w poprzednich beta rozwiązały numer #179\nBugfix: Allow indywidualny API password lub klucze szyfrujące dla urządzeń, rozwiązał numer #174\nWsparcie ESPHome: Encryption Key (you powinien wyemigrować z hasła API do Encryption Key ! Rozwiązanie #152",
|
|
16
|
+
"uk": "Помилки: Пароль / питання з'єднання у попередніх бета-рішеннях #179\nПомилки: Дозволити індивідуальний пароль API або ключі шифрування для пристроїв, вирішує #174\nПідтримка ESPHome пристрій шифрування ключа (Ви повинні мигратувати від API пароля до ключа шифрування ! розчини #152)",
|
|
17
|
+
"zh-cn": "Bugfix:在前几批被盗用词/联系问题\nBugfix: 允许个人的通用或加密装置的关键,第174号行动\n支持ESPHome装置的加密关键(you应从API密码移到恩加密的关键! 第152号决议)"
|
|
18
|
+
},
|
|
19
|
+
"0.4.0": {
|
|
20
|
+
"en": "Added cleanup capability for unused channels & states after initialisation of device, resolves #39\nAdded button to info channel which allows to delete all offline devices from adapter tree. resolves #39\n[Breaking] Backup strategy changed, requires [BackitUp v2.9.1](https://github.com/simatec/ioBroker.backitup) and activate option for ESPHome, fixes #129",
|
|
21
|
+
"de": "Zusätzliche Reinigungsfähigkeit für ungenutzte Kanäle & Zustände nach der Initialisierung des Geräts, löst #39\nZusätzlicher Button zum Info-Kanal, der alle Offline-Geräte aus dem Adapterbaum löschen kann. löst #39\n[Breaking] Backup-Strategie geändert, erfordert [BackitUp v2.9.1](https://github.com/simatec/ioBroker.backitup) und aktiviert Option für ESPHome, repariert #129",
|
|
22
|
+
"ru": "Добавлена возможность очистки неиспользуемых каналов и государств после инициализации устройства, решает #39\nДобавлена кнопка к информационному каналу, что позволяет удалить все оффлайн устройства из дерева адаптера. решает #39\n[Breaking] Стратегия резервного копирования изменена, требует [BackitUp v2.9.1](https://github.com/simatec/ioBroker.backitup) и активировать вариант для ESPHome, исправлений #129",
|
|
23
|
+
"pt": "Adicionado capacidade de limpeza para canais não utilizados & estados após a inicialização do dispositivo, resolve #39\nAdicionado botão para info canal que permite excluir todos os dispositivos off-line da árvore do adaptador. resolve #39\n[Breaking] Estratégia de backup alterada, requer [BackitUp v2.9.1](https://github.com/simatec/ioBroker.backitup) e opção ativa para ESPHome, correções #129",
|
|
24
|
+
"nl": "Vervoegde schoonmaak capaciteit voor onbruikbare kanalen apparaat na de initialisatie van 39\nKnop toegevoegd aan info kanaal dat alle offline apparaten van adapter boom laat verwijderen. 39\nOndersteuningsstrategie veranderde, vereist [Backitup v2.9.1, htps:com/simateioBroker, en tactiveer de optie van 12 uur",
|
|
25
|
+
"fr": "Ajout d'une capacité de nettoyage pour les canaux non utilisés & états après l'initialisation du dispositif, résout #39\nAjout du bouton sur le canal d'info qui permet de supprimer tous les périphériques hors ligne de l'arbre d'adaptateur. résolution #39\n[Breaking] La stratégie de sauvegarde a changé, nécessite [BackitUp v2.9.1](https://github.com/simatec/ioBroker.backitup) et l'option active pour ESPHome, corrige #129",
|
|
26
|
+
"it": "Aggiunta funzionalità di pulizia per canali e stati non utilizzati dopo l'inizializzazione del dispositivo, risolve #39\nPulsante aggiunto al canale info che consente di eliminare tutti i dispositivi offline dall'albero dell'adattatore. risolve #39\n[Breaking] La strategia di backup è cambiata, richiede [BackitUp v2.9.1](https://github.com/simatec/ioBroker.backitup) e attiva l'opzione per ESPHome, corregge #129",
|
|
27
|
+
"es": "Capacidad de limpieza agregada para canales no utilizados \" estados después de la inicialización del dispositivo, resuelve #39\nSe agregó botón a canal de información que permite eliminar todos los dispositivos fuera de línea del árbol del adaptador. resuelve #39\n[Breaking] La estrategia de respaldo cambió, requiere [BackitUp v2.9.1](https://github.com/simatec/ioBroker.backitup) y activar la opción para ESPHome, fija #129",
|
|
28
|
+
"pl": "Po zainicjowaniu możliwości usuwania nieużywanych kanałów i stanów po inicjalizacji urządzenia, rozwiązał #39\nNaciśnięty przycisk do kanału informacyjnego, który umożliwia usunięcie wszystkich urządzeń offline z drzewa adapterowego. Rozwiązanie #39\n(Po zmianie strategii Backupa, wymaga od BOATUTUp v2.9.1(https:/github.com/simatec/ioBroker.backitup) i aktywacji opcji dla ESPHome, naprawa #129",
|
|
29
|
+
"uk": "Додано можливість очищення каналів і станів після ініціалізації пристрою, вирішує #39\nДодано кнопку на інформаційний канал, який дозволяє видалити всі offline пристрої з дерева адаптера. розчини #39\n[Breaking] Стратегія резервного копіювання змінено, вимагає [BackitUp v2.9.1](https://github.com/simatec/ioBroker.backitup) і активувати варіант для ESPHome, фіксує #129",
|
|
30
|
+
"zh-cn": "在装置初始化后增加无用渠道和各州的清洁能力,第39号决定\n添加但道托顿以电器,使所有线装置能够从适应树中删除。 行动39\n[Breaking] Backup战略改变,要求[BackitUp v2.9.1](http://github.com/simatec/ioBroker.backitup)和“ESPHome”的主动选择,第129号行动。"
|
|
31
|
+
},
|
|
6
32
|
"0.3.2": {
|
|
7
33
|
"en": "Improved error handling if devices are not reachable/disconnected\nBugfix: Allow control of brightness and color for light component, fixes #173",
|
|
8
34
|
"de": "Verbesserte Fehlerbehandlung, wenn Geräte nicht erreichbar/vernetzt sind\nBugfix: Erlauben Sie die Kontrolle von Helligkeit und Farbe für die Lichtkomponente, fixiert #173",
|
|
@@ -65,30 +91,6 @@
|
|
|
65
91
|
"es": "Corrección de error: el estado del componente de luz no ha cambiado [# 74] (https://github.com/DrozmotiX/ioBroker.esphome/issues/74)\nActualizar la compatibilidad a la versión 1.19.4 de ESPHome Dashboard",
|
|
66
92
|
"pl": "Poprawka błędu: stan lekkiego komponentu nie uległ zmianie [#74](https://github.com/DrozmotiX/ioBroker.esphome/issues/74)\nZaktualizuj kompatybilność do wersji 1.19.4 ESPHome Dashboard",
|
|
67
93
|
"zh-cn": "修正:轻组件状态没有改变 [#74](https://github.com/DrozmotiX/ioBroker.esphome/issues/74)\n更新与 ESPHome Dashboard 1.19.4 版的兼容性"
|
|
68
|
-
},
|
|
69
|
-
"0.2.2": {
|
|
70
|
-
"en": "[!!! Breaking !!!] Make YAML file persistent, backup your configuration before updating ! solves [#57](https://github.com/DrozmotiX/ioBroker.esphome/issues/57)\nUpdate ESPHome Dashboard to 1.18.0, requires Python >=3.7 (and ensure <4.0!)\nBugfix : Reconnect to devices without autodiscovery / MDNS-Broadcast in network, solves [#66](https://github.com/DrozmotiX/ioBroker.esphome/issues/66)",
|
|
71
|
-
"de": "[!!! Breaking !!!] Machen Sie die YAML-Datei persistent, sichern Sie Ihre Konfiguration vor dem Update! löst [#57](https://github.com/DrozmotiX/ioBroker.esphome/issues/57)\nAktualisieren Sie das ESPHome-Dashboard auf 1.18.0, erfordert Python >=3.7 (und stellen Sie sicher <4.0!)\nBugfix : Reconnect zu Geräten ohne Autodiscovery / MDNS-Broadcast im Netzwerk, behebt [#66](https://github.com/DrozmotiX/ioBroker.esphome/issues/66)",
|
|
72
|
-
"ru": "[!!! Ломаю !!!] Сделайте файл YAML постоянным, сделайте резервную копию конфигурации перед обновлением! решает [# 57] (https://github.com/DrozmotiX/ioBroker.esphome/issues/57)\nОбновите ESPHome Dashboard до 1.18.0, требуется Python> = 3.7 (и убедитесь, что <4.0!)\nИсправление: повторное подключение к устройствам без автообнаружения / MDNS-трансляции в сети, решает [# 66] (https://github.com/DrozmotiX/ioBroker.esphome/issues/66)",
|
|
73
|
-
"pt": "[!!! Quebrando !!!] Torne o arquivo YAML persistente, faça backup de sua configuração antes de atualizar! resolve [# 57] (https://github.com/DrozmotiX/ioBroker.esphome/issues/57)\nAtualize o painel ESPHome para 1.18.0, requer Python> = 3.7 (e garanta <4.0!)\nCorreção de bug: reconectar a dispositivos sem autodiscovery / MDNS-Broadcast na rede, resolve [# 66] (https://github.com/DrozmotiX/ioBroker.esphome/issues/66)",
|
|
74
|
-
"nl": "[!!! Breaking !!!] Maak het YAML-bestand persistent, maak een back-up van uw configuratie voordat u deze bijwerkt! lost [#57](https://github.com/DrozmotiX/ioBroker.esphome/issues/57) op\nUpdate ESPHome Dashboard naar 1.18.0, vereist Python >=3.7 (en zorg voor <4.0!)\nBugfix: opnieuw verbinding maken met apparaten zonder autodiscovery / MDNS-uitzending in netwerk, lost [#66](https://github.com/DrozmotiX/ioBroker.esphome/issues/66) op",
|
|
75
|
-
"fr": "[!!! Breaking !!!] Rendez le fichier YAML persistant, sauvegardez votre configuration avant de mettre à jour ! résout [#57](https://github.com/DrozmotiX/ioBroker.esphome/issues/57)\nMettez à jour ESPHome Dashboard vers 1.18.0, nécessite Python >=3.7 (et assurez-vous <4.0 !)\nCorrection de bug : se reconnecter aux appareils sans découverte automatique / MDNS-Broadcast en réseau, résout [#66](https://github.com/DrozmotiX/ioBroker.esphome/issues/66)",
|
|
76
|
-
"it": "[!!! Breaking !!!] Rendi persistente il file YAML, esegui il backup della configurazione prima di aggiornare! risolve [#57](https://github.com/DrozmotiX/ioBroker.esphome/issues/57)\nAggiorna ESPHome Dashboard a 1.18.0, richiede Python >=3.7 (e assicurati <4.0!)\nBugfix: riconnettersi ai dispositivi senza autodiscovery / MDNS-Broadcast in rete, risolve [#66] (https://github.com/DrozmotiX/ioBroker.esphome/issues/66)",
|
|
77
|
-
"es": "[!!! ¡¡¡Rompiendo !!!] ¡Haga que el archivo YAML sea persistente, haga una copia de seguridad de su configuración antes de actualizar! resuelve [# 57] (https://github.com/DrozmotiX/ioBroker.esphome/issues/57)\nActualice ESPHome Dashboard a 1.18.0, requiere Python> = 3.7 (¡y asegúrese de <4.0!)\nCorrección de error: vuelva a conectarse a dispositivos sin detección automática / MDNS-Broadcast en la red, resuelve [# 66] (https://github.com/DrozmotiX/ioBroker.esphome/issues/66)",
|
|
78
|
-
"pl": "[!!! Breaking !!!] Utrwal plik YAML, wykonaj kopię zapasową konfiguracji przed aktualizacją! rozwiązuje [#57](https://github.com/DrozmotiX/ioBroker.esphome/issues/57)\nZaktualizuj pulpit nawigacyjny ESPHome do wersji 1.18.0, wymaga Pythona >=3.7 (i upewnij się, że <4.0!)\nBugfix: Połącz się ponownie z urządzeniami bez automatycznego wykrywania / MDNS-Broadcast w sieci, rozwiązuje [#66](https://github.com/DrozmotiX/ioBroker.esphome/issues/66)",
|
|
79
|
-
"zh-cn": "[!!!打破 !!!] 使 YAML 文件持久化,更新前备份您的配置!解决 [#57](https://github.com/DrozmotiX/ioBroker.esphome/issues/57)\n将 ESPHome Dashboard 更新到 1.18.0,需要 Python >=3.7(并确保 <4.0!)\n修正:在网络中没有自动发现/MDNS-Broadcast 的情况下重新连接到设备,解决[#66](https://github.com/DrozmotiX/ioBroker.esphome/issues/66)"
|
|
80
|
-
},
|
|
81
|
-
"0.2.1-1": {
|
|
82
|
-
"en": "add cover component\nadd transitionLength for lights",
|
|
83
|
-
"de": "Abdeckungskomponente hinzufügen\nÜbergangslänge für Lichter hinzufügen",
|
|
84
|
-
"ru": "добавить компонент обложки\nдобавить transitionLength для огней",
|
|
85
|
-
"pt": "adicionar componente de capa\nadicionar comprimento de transição para luzes",
|
|
86
|
-
"nl": "voeg een omslagcomponent toe\nvoeg transitionLength toe voor lichten",
|
|
87
|
-
"fr": "ajouter un composant de couverture\najouter une longueur de transition pour les lumières",
|
|
88
|
-
"it": "aggiungi il componente di copertina\naggiungi TransitionLength per le luci",
|
|
89
|
-
"es": "agregar componente de portada\nagregar transiciónLength para luces",
|
|
90
|
-
"pl": "dodaj komponent okładki\ndodaj długość przejścia dla świateł",
|
|
91
|
-
"zh-cn": "添加封面组件\n为灯光添加transitionLength"
|
|
92
94
|
}
|
|
93
95
|
},
|
|
94
96
|
"title": "Control ESPHome managed devices",
|
|
@@ -145,7 +147,6 @@
|
|
|
145
147
|
"dsn": "https://52227cfa250b49e99b1f28408273402c@sentry.iobroker.net/122"
|
|
146
148
|
}
|
|
147
149
|
},
|
|
148
|
-
"dataFolder": "esphome.%INSTANCE%",
|
|
149
150
|
"localLink": "http://%ESPHomeDashboardIP%:%ESPHomeDashboardPort%",
|
|
150
151
|
"adminTab": {
|
|
151
152
|
"link": "http://%ESPHomeDashboardIP%:%ESPHomeDashboardPort%",
|
package/main.js
CHANGED
|
@@ -14,8 +14,10 @@ const stateAttr = require(__dirname + '/lib/stateAttr.js'); // Load attribute li
|
|
|
14
14
|
const disableSentry = false; // Ensure to set to true during development!
|
|
15
15
|
const warnMessages = {}; // Store warn messages to avoid multiple sending to sentry
|
|
16
16
|
const fs = require('fs');
|
|
17
|
+
const {clearTimeout} = require('timers');
|
|
17
18
|
const client = {};
|
|
18
|
-
|
|
19
|
+
const resetTimers = {}; // Memory allocation for all running timers
|
|
20
|
+
let reconnectInterval, apiPass, autodiscovery, dashboardProcess, createConfigStates;
|
|
19
21
|
|
|
20
22
|
class Esphome extends utils.Adapter {
|
|
21
23
|
|
|
@@ -58,7 +60,11 @@ class Esphome extends utils.Adapter {
|
|
|
58
60
|
|
|
59
61
|
// Start MDNS discovery when enabled
|
|
60
62
|
if (autodiscovery) {
|
|
61
|
-
|
|
63
|
+
if (resetTimers['autodiscovery']) resetTimers['autodiscovery'] = clearTimeout(resetTimers['autodiscovery']);
|
|
64
|
+
this.log.info(`Adapter ready, automatic Device Discovery will be acticated in 30 seconds.`);
|
|
65
|
+
resetTimers['autodiscovery'] = setTimeout(async () => {
|
|
66
|
+
this.deviceDiscovery(); // Start MDNS autodiscovery
|
|
67
|
+
}, (30000));
|
|
62
68
|
} else {
|
|
63
69
|
this.log.warn(`Auto Discovery disabled, new devices (or IP changes) will NOT be detected automatically!`);
|
|
64
70
|
}
|
|
@@ -70,6 +76,21 @@ class Esphome extends utils.Adapter {
|
|
|
70
76
|
this.log.info(`Native Integration of ESPHome Dashboard disabled `);
|
|
71
77
|
}
|
|
72
78
|
|
|
79
|
+
// Create & Subscribe to button handling offline Device cleanup
|
|
80
|
+
this.extendObjectAsync('esphome.0.info.deviceCleanup',
|
|
81
|
+
{
|
|
82
|
+
'type': 'state',
|
|
83
|
+
'common': {
|
|
84
|
+
'role': 'button',
|
|
85
|
+
'name': 'Device or service connected',
|
|
86
|
+
'type': 'boolean',
|
|
87
|
+
'read': false,
|
|
88
|
+
'write': true,
|
|
89
|
+
'def': false
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
this.subscribeStates('esphome.0.info.deviceCleanup');
|
|
93
|
+
|
|
73
94
|
} catch (e) {
|
|
74
95
|
this.log.error(`[Adapter start] Fatal error occurred ${e}`);
|
|
75
96
|
}
|
|
@@ -154,7 +175,7 @@ class Esphome extends utils.Adapter {
|
|
|
154
175
|
|
|
155
176
|
// Get basic data of known devices and start reading data
|
|
156
177
|
for (const i in knownDevices) {
|
|
157
|
-
this.connectDevices(knownDevices[i].native.ip,
|
|
178
|
+
this.connectDevices(knownDevices[i].native.ip, knownDevices[i].native.passWord, knownDevices[i].native.encryptionKey ? knownDevices[i].native.encryptionKey : '');
|
|
158
179
|
}
|
|
159
180
|
} catch (e) {
|
|
160
181
|
this.sendSentry(`[tryKnownDevices] ${e}`);
|
|
@@ -165,7 +186,7 @@ class Esphome extends utils.Adapter {
|
|
|
165
186
|
deviceDiscovery() {
|
|
166
187
|
try {
|
|
167
188
|
|
|
168
|
-
this.log.info(`
|
|
189
|
+
this.log.info(`Automatic device Discovery started, new devices (or IP changes) will be detected automatically`);
|
|
169
190
|
discovery = new Discovery();
|
|
170
191
|
|
|
171
192
|
discovery.on('info', async (message) => {
|
|
@@ -173,7 +194,13 @@ class Esphome extends utils.Adapter {
|
|
|
173
194
|
this.log.debug(`Discovery message ${JSON.stringify(message)}`);
|
|
174
195
|
if (this.deviceInfo[message.address] == null) {
|
|
175
196
|
this.log.info(`[AutoDiscovery] New ESPHome device found at IP ${message.address}, trying to initialize`);
|
|
176
|
-
|
|
197
|
+
//ToDo: Add default Encryption Key
|
|
198
|
+
// Only run autodiscovery if device is unknown yet
|
|
199
|
+
if (!this.deviceInfo[message.address]
|
|
200
|
+
&& this.deviceInfo[message.address].connectError === false
|
|
201
|
+
&& !this.deviceInfo[message.address] && this.deviceInfo[message.address].connecting) {
|
|
202
|
+
this.connectDevices(`${message.address}`, apiPass, '');
|
|
203
|
+
}
|
|
177
204
|
}
|
|
178
205
|
} catch (e) {
|
|
179
206
|
this.log.error(`[deviceDiscovery handler] ${e}`);
|
|
@@ -188,42 +215,80 @@ class Esphome extends utils.Adapter {
|
|
|
188
215
|
/**
|
|
189
216
|
* Handle Socket connections
|
|
190
217
|
* @param {string} host IP adress of device
|
|
191
|
-
* @param {string
|
|
218
|
+
* @param {string} deviceApiPass Native API credentials
|
|
219
|
+
* @param {string} deviceEncryptionKey Encryption Key credentials
|
|
192
220
|
*/
|
|
193
|
-
connectDevices(host,
|
|
221
|
+
connectDevices(host, deviceApiPass, deviceEncryptionKey) {
|
|
194
222
|
try {
|
|
195
223
|
// const host = espDevices[device].ip;
|
|
196
224
|
this.log.info(`Try to connect to ${host}`);
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
225
|
+
|
|
226
|
+
// Cancel process if connection try is already in progress
|
|
227
|
+
if (this.deviceInfo[host] && this.deviceInfo[host].connecting) return;
|
|
228
|
+
|
|
229
|
+
// Clear any existing memory information for this device
|
|
230
|
+
delete this.deviceInfo[host];
|
|
231
|
+
|
|
232
|
+
// Reserve basic memory information for this device
|
|
233
|
+
this.deviceInfo[host] = {
|
|
234
|
+
connected : false,
|
|
235
|
+
connecting : true,
|
|
236
|
+
connectionError : false,
|
|
237
|
+
initialized: false,
|
|
238
|
+
ip : host
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
if (!deviceEncryptionKey || deviceEncryptionKey === '') {
|
|
242
|
+
client[host] = new Client({
|
|
243
|
+
host: host,
|
|
244
|
+
clientInfo: `${this.host}`,
|
|
245
|
+
clearSession: true,
|
|
246
|
+
initializeDeviceInfo: true,
|
|
247
|
+
initializeListEntities: true,
|
|
248
|
+
initializeSubscribeStates: false,
|
|
249
|
+
// initializeSubscribeLogs: false, //ToDo: Make configurable by adapter settings
|
|
250
|
+
reconnect: true,
|
|
251
|
+
reconnectInterval: reconnectInterval,
|
|
252
|
+
pingInterval: 15000, //ToDo: Make configurable by adapter settings
|
|
253
|
+
pingAttempts: 3,
|
|
254
|
+
password : this.decrypt(deviceApiPass)
|
|
255
|
+
// port: espDevices[device].port //ToDo: Make configurable by adapter settings
|
|
256
|
+
});
|
|
257
|
+
} else {
|
|
258
|
+
client[host] = new Client({
|
|
259
|
+
host: host,
|
|
260
|
+
clientInfo: `${this.host}`,
|
|
261
|
+
clearSession: true,
|
|
262
|
+
initializeDeviceInfo: true,
|
|
263
|
+
initializeListEntities: true,
|
|
264
|
+
initializeSubscribeStates: false,
|
|
265
|
+
// initializeSubscribeLogs: false, //ToDo: Make configurable by adapter settings
|
|
266
|
+
reconnect: true,
|
|
267
|
+
reconnectInterval: reconnectInterval,
|
|
268
|
+
pingInterval: 15000, //ToDo: Make configurable by adapter settings
|
|
269
|
+
pingAttempts: 3,
|
|
270
|
+
encryptionKey: this.decrypt(deviceEncryptionKey)
|
|
271
|
+
// port: espDevices[device].port //ToDo: Make configurable by adapter settings
|
|
272
|
+
});
|
|
273
|
+
}
|
|
213
274
|
|
|
214
275
|
// Connection listener
|
|
215
276
|
client[host].on('connected', async () => {
|
|
216
277
|
try {
|
|
217
278
|
// Clear any existing memory information for this device
|
|
218
279
|
delete this.deviceInfo[host];
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
280
|
+
if (!this.deviceInfo[host]) {
|
|
281
|
+
this.deviceInfo[host] = {
|
|
282
|
+
connected : false,
|
|
283
|
+
connecting : true,
|
|
284
|
+
connectionError : false,
|
|
285
|
+
initialized: false,
|
|
286
|
+
ip : host
|
|
287
|
+
};
|
|
288
|
+
} else {
|
|
289
|
+
this.deviceInfo[host].connected = true;
|
|
290
|
+
this.deviceInfo[host].connecting = false;
|
|
291
|
+
}
|
|
227
292
|
this.log.info(`ESPHome client ${host} connected`);
|
|
228
293
|
// Clear possible present warn messages for device from previous connection
|
|
229
294
|
delete warnMessages[host];
|
|
@@ -232,10 +297,18 @@ class Esphome extends utils.Adapter {
|
|
|
232
297
|
}
|
|
233
298
|
});
|
|
234
299
|
|
|
235
|
-
client[host].on('disconnected', () => {
|
|
300
|
+
client[host].on('disconnected', async () => {
|
|
236
301
|
try {
|
|
237
302
|
if (this.deviceInfo[host].deviceName != null) {
|
|
238
|
-
this.
|
|
303
|
+
await this.stateSetCreate(`${this.deviceInfo[host].deviceName}.info._online`, `Online state`, false);
|
|
304
|
+
|
|
305
|
+
// Check all created states in memory if their are related to this device
|
|
306
|
+
for (const state in this.createdStatesDetails) {
|
|
307
|
+
// Remove states from cache
|
|
308
|
+
if (state.split('.')[0] === this.deviceInfo[host].deviceName) {
|
|
309
|
+
delete this.createdStatesDetails[state];
|
|
310
|
+
}
|
|
311
|
+
}
|
|
239
312
|
|
|
240
313
|
// Cache relevant data before clearing memory space of device
|
|
241
314
|
const cacheDeviceInformation = {
|
|
@@ -249,6 +322,7 @@ class Esphome extends utils.Adapter {
|
|
|
249
322
|
// Reserve basic memory information for this device
|
|
250
323
|
this.deviceInfo[host] = {
|
|
251
324
|
connected : false,
|
|
325
|
+
connecting: false,
|
|
252
326
|
connectionError : true,
|
|
253
327
|
deviceName : cacheDeviceInformation.deviceName,
|
|
254
328
|
deviceInfoName : cacheDeviceInformation.deviceInfoName,
|
|
@@ -266,6 +340,12 @@ class Esphome extends utils.Adapter {
|
|
|
266
340
|
client[host].on('initialized', () => {
|
|
267
341
|
this.log.info(`ESPHome client ${this.deviceInfo[host].deviceInfoName} on ip ${host} initialized`);
|
|
268
342
|
this.deviceInfo[host].initialized = true;
|
|
343
|
+
|
|
344
|
+
// Start timer to cleanup unneeded objects
|
|
345
|
+
if (resetTimers[host]) resetTimers[host] = clearTimeout(resetTimers[host]);
|
|
346
|
+
resetTimers[host] = setTimeout(async () => {
|
|
347
|
+
await this.objectCleanup(host);
|
|
348
|
+
}, (10000));
|
|
269
349
|
});
|
|
270
350
|
|
|
271
351
|
// Log message listener
|
|
@@ -286,12 +366,18 @@ class Esphome extends utils.Adapter {
|
|
|
286
366
|
// Store device information into memory
|
|
287
367
|
const deviceName = this.replaceAll(deviceInfo.macAddress, `:`, ``);
|
|
288
368
|
this.deviceInfo[host] = {
|
|
369
|
+
adapterObjects : {
|
|
370
|
+
channels : []
|
|
371
|
+
},
|
|
289
372
|
ip: host,
|
|
373
|
+
connectError : false,
|
|
374
|
+
connected : true,
|
|
290
375
|
mac: deviceInfo.macAddress,
|
|
291
376
|
deviceInfo: deviceInfo,
|
|
292
377
|
deviceName: deviceName,
|
|
293
378
|
deviceInfoName: deviceInfo.name,
|
|
294
|
-
passWord:
|
|
379
|
+
passWord: deviceApiPass,
|
|
380
|
+
encryptionKey: deviceEncryptionKey,
|
|
295
381
|
};
|
|
296
382
|
|
|
297
383
|
// Store MAC & IP relation, delete possible existing entry before
|
|
@@ -314,7 +400,8 @@ class Esphome extends utils.Adapter {
|
|
|
314
400
|
name: this.deviceInfo[host].deviceInfoName,
|
|
315
401
|
mac: deviceInfo.macAddress,
|
|
316
402
|
deviceName: deviceName,
|
|
317
|
-
passWord:
|
|
403
|
+
passWord: deviceApiPass,
|
|
404
|
+
encryptionKey: deviceEncryptionKey
|
|
318
405
|
},
|
|
319
406
|
});
|
|
320
407
|
|
|
@@ -368,6 +455,11 @@ class Esphome extends utils.Adapter {
|
|
|
368
455
|
native: {},
|
|
369
456
|
});
|
|
370
457
|
|
|
458
|
+
// Cache created channel in device memory
|
|
459
|
+
if (!this.deviceInfo[host].adapterObjects.channels.includes(`${this.namespace}.${this.deviceInfo[host].deviceName}.${entity.type}`)) {
|
|
460
|
+
this.deviceInfo[host].adapterObjects.channels.push(`${this.namespace}.${this.deviceInfo[host].deviceName}.${entity.type}`);
|
|
461
|
+
}
|
|
462
|
+
|
|
371
463
|
// Create state specific channel by id
|
|
372
464
|
await this.extendObjectAsync(`${this.deviceInfo[host].deviceName}.${entity.type}.${entity.id}`, {
|
|
373
465
|
type: 'channel',
|
|
@@ -377,6 +469,11 @@ class Esphome extends utils.Adapter {
|
|
|
377
469
|
native: {},
|
|
378
470
|
});
|
|
379
471
|
|
|
472
|
+
// Cache created channel in device memory
|
|
473
|
+
if (!this.deviceInfo[host].adapterObjects.channels.includes(`${this.namespace}.${this.deviceInfo[host].deviceName}.${entity.type}.${entity.id}`)) {
|
|
474
|
+
this.deviceInfo[host].adapterObjects.channels.push(`${this.namespace}.${this.deviceInfo[host].deviceName}.${entity.type}.${entity.id}`);
|
|
475
|
+
}
|
|
476
|
+
|
|
380
477
|
//Check if config channel should be created
|
|
381
478
|
if (!createConfigStates) {
|
|
382
479
|
// Delete folder structure if already present
|
|
@@ -397,6 +494,12 @@ class Esphome extends utils.Adapter {
|
|
|
397
494
|
},
|
|
398
495
|
native: {},
|
|
399
496
|
});
|
|
497
|
+
|
|
498
|
+
// Cache created channel in device memory
|
|
499
|
+
if (!this.deviceInfo[host].adapterObjects.channels.includes(`${this.namespace}.${this.deviceInfo[host].deviceName}.${entity.type}.${entity.id}.config`)) {
|
|
500
|
+
this.deviceInfo[host].adapterObjects.channels.push(`${this.namespace}.${this.deviceInfo[host].deviceName}.${entity.type}.${entity.id}.config`);
|
|
501
|
+
}
|
|
502
|
+
|
|
400
503
|
// Handle Entity JSON structure and write related config channel data
|
|
401
504
|
await this.TraverseJson(entity.config, `${this.deviceInfo[host].deviceName}.${entity.type}.${entity.id}.config`);
|
|
402
505
|
}
|
|
@@ -492,13 +595,13 @@ class Esphome extends utils.Adapter {
|
|
|
492
595
|
|
|
493
596
|
|
|
494
597
|
} catch (e) {
|
|
495
|
-
this.log.error(`Connection issue for ${entity.name} ${e}`);
|
|
598
|
+
this.log.error(`Connection issue for ${entity.name} ${e} | ${e.stack}`);
|
|
496
599
|
}
|
|
497
600
|
|
|
498
601
|
});
|
|
499
602
|
|
|
500
603
|
// Connection data handler
|
|
501
|
-
client[host].on('error', (error) => {
|
|
604
|
+
client[host].on('error', async (error) => {
|
|
502
605
|
try {
|
|
503
606
|
|
|
504
607
|
// Reserve memory space for connection error if not already exist
|
|
@@ -517,24 +620,42 @@ class Esphome extends utils.Adapter {
|
|
|
517
620
|
if (!this.deviceInfo[host].connectError) {
|
|
518
621
|
this.log.error(optimisedError);
|
|
519
622
|
this.deviceInfo[host].connectError = true;
|
|
623
|
+
await this.stateSetCreate(`${this.deviceInfo[host].deviceName}.info._online`, `Online state`, false);
|
|
624
|
+
}
|
|
625
|
+
} else if (error.message.includes('EHOSTUNREACH')) {
|
|
626
|
+
optimisedError = `Client ${host} unreachable !`;
|
|
627
|
+
if (!this.deviceInfo[host].connectError) {
|
|
628
|
+
this.log.error(optimisedError);
|
|
629
|
+
this.deviceInfo[host].connectError = true;
|
|
630
|
+
await this.stateSetCreate(`${this.deviceInfo[host].deviceName}.info._online`, `Online state`, false);
|
|
520
631
|
}
|
|
521
632
|
} else if (error.message.includes('Invalid password')) {
|
|
522
633
|
optimisedError = `Client ${host} incorrect password !`;
|
|
523
634
|
if (!this.deviceInfo[host].connectError) {
|
|
524
635
|
this.log.error(optimisedError);
|
|
525
636
|
this.deviceInfo[host].connectError = true;
|
|
637
|
+
await this.stateSetCreate(`${this.deviceInfo[host].deviceName}.info._online`, `Online state`, false);
|
|
638
|
+
}
|
|
639
|
+
} else if (error.message.includes('Encryption expected')) {
|
|
640
|
+
optimisedError = `Client ${host} requires encryption key which has not been provided, please enter encryption key in adapter settings for this device !`;
|
|
641
|
+
if (!this.deviceInfo[host].connectError) {
|
|
642
|
+
this.log.error(optimisedError);
|
|
643
|
+
this.deviceInfo[host].connectError = true;
|
|
644
|
+
await this.stateSetCreate(`${this.deviceInfo[host].deviceName}.info._online`, `Online state`, false);
|
|
526
645
|
}
|
|
527
646
|
} else if (error.message.includes('ECONNRESET')) {
|
|
528
647
|
optimisedError = `Client ${host} Connection Lost, will reconnect automatically when device is available!`;
|
|
529
648
|
if (!this.deviceInfo[host].connectError) {
|
|
530
649
|
this.log.warn(optimisedError);
|
|
531
650
|
this.deviceInfo[host].connectError = true;
|
|
651
|
+
await this.stateSetCreate(`${this.deviceInfo[host].deviceName}.info._online`, `Online state`, false);
|
|
532
652
|
}
|
|
533
653
|
} else if (error.message.includes('timeout')) {
|
|
534
654
|
optimisedError = `Client ${host} Timeout, will reconnect automatically when device is available!`;
|
|
535
655
|
if (!this.deviceInfo[host].connectError) {
|
|
536
656
|
this.log.warn(optimisedError);
|
|
537
657
|
this.deviceInfo[host].connectError = true;
|
|
658
|
+
await this.stateSetCreate(`${this.deviceInfo[host].deviceName}.info._online`, `Online state`, false);
|
|
538
659
|
}
|
|
539
660
|
} else if (error.message.includes('ECONNREFUSED')) {
|
|
540
661
|
optimisedError = `Client ${host} not yet ready to connect, will try again!`;
|
|
@@ -573,7 +694,7 @@ class Esphome extends utils.Adapter {
|
|
|
573
694
|
}
|
|
574
695
|
|
|
575
696
|
} catch (e) {
|
|
576
|
-
this.log.error(`ESP device error for ${host}`);
|
|
697
|
+
this.log.error(`ESP device error for ${host} | ${e} | ${e.stack}`);
|
|
577
698
|
}
|
|
578
699
|
}
|
|
579
700
|
|
|
@@ -672,6 +793,8 @@ class Esphome extends utils.Adapter {
|
|
|
672
793
|
// Check if state contains value
|
|
673
794
|
if (transitionLength) {
|
|
674
795
|
this.deviceInfo[host][entity.id].states.transitionLength = transitionLength.val;
|
|
796
|
+
// Run create state routine to ensure state is cached in memory
|
|
797
|
+
await this.stateSetCreate(`${this.deviceInfo[host].deviceName}.${entity.type}.${entity.id}.transitionLength`, `${stateName} of ${entity.config.name}`, transitionLength.val, `s`, writable);
|
|
675
798
|
} else { // Else just create it
|
|
676
799
|
await this.stateSetCreate(`${this.deviceInfo[host].deviceName}.${entity.type}.${entity.id}.transitionLength`, `${stateName} of ${entity.config.name}`, 0, `s`, writable);
|
|
677
800
|
this.deviceInfo[host][entity.id].states.transitionLength = 0;
|
|
@@ -948,6 +1071,8 @@ class Esphome extends utils.Adapter {
|
|
|
948
1071
|
onUnload(callback) {
|
|
949
1072
|
try {
|
|
950
1073
|
this.log.debug(JSON.stringify(this.deviceInfo));
|
|
1074
|
+
|
|
1075
|
+
// Set all online states to false
|
|
951
1076
|
for (const device in this.deviceInfo) {
|
|
952
1077
|
|
|
953
1078
|
// Ensure all known online states are set to false
|
|
@@ -962,9 +1087,12 @@ class Esphome extends utils.Adapter {
|
|
|
962
1087
|
this.log.debug(`[onUnload] ${JSON.stringify(e)}`);
|
|
963
1088
|
}
|
|
964
1089
|
}
|
|
965
|
-
|
|
966
|
-
|
|
1090
|
+
|
|
1091
|
+
// Ensure all possible running timers are cleared
|
|
1092
|
+
for (const timer in resetTimers) {
|
|
1093
|
+
if (resetTimers[timer]) resetTimers[timer] = clearTimeout(resetTimers[timer]);
|
|
967
1094
|
}
|
|
1095
|
+
|
|
968
1096
|
try {
|
|
969
1097
|
if (dashboardProcess) {
|
|
970
1098
|
dashboardProcess.kill('SIGTERM', {
|
|
@@ -1028,8 +1156,7 @@ class Esphome extends utils.Adapter {
|
|
|
1028
1156
|
} else {
|
|
1029
1157
|
this.log.info(`Valid IP address received`);
|
|
1030
1158
|
this.messageResponse[obj.message['device-ip']] = obj;
|
|
1031
|
-
|
|
1032
|
-
await this.connectDevices(obj.message['device-ip'], apiPass);
|
|
1159
|
+
await this.connectDevices(obj.message['device-ip'], obj.message['device-pass'], obj.message['deviceEncryptionKey']);
|
|
1033
1160
|
}
|
|
1034
1161
|
break;
|
|
1035
1162
|
}
|
|
@@ -1079,6 +1206,17 @@ class Esphome extends utils.Adapter {
|
|
|
1079
1206
|
try {
|
|
1080
1207
|
if (state && state.ack === false) {
|
|
1081
1208
|
const device = id.split('.');
|
|
1209
|
+
|
|
1210
|
+
try {
|
|
1211
|
+
// Verify if trigger is related to device-cleanup
|
|
1212
|
+
if (id.split('.')[3] === 'deviceCleanup'){
|
|
1213
|
+
await this.offlineDeviceCleanup();
|
|
1214
|
+
return;
|
|
1215
|
+
}
|
|
1216
|
+
} catch (e) {
|
|
1217
|
+
// Skip action
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1082
1220
|
const deviceIP = this.deviceStateRelation[device[2]].ip;
|
|
1083
1221
|
|
|
1084
1222
|
// Handle Switch State
|
|
@@ -1226,13 +1364,84 @@ class Esphome extends utils.Adapter {
|
|
|
1226
1364
|
});
|
|
1227
1365
|
|
|
1228
1366
|
// Set online state to false, will be set to true at successfully connected
|
|
1229
|
-
this.
|
|
1367
|
+
await this.stateSetCreate(`${_devices.rows[currDevice].id}.info._online`, `Online state`, false);
|
|
1230
1368
|
}
|
|
1231
1369
|
|
|
1232
1370
|
} catch (e) {
|
|
1233
1371
|
this.log.error(`[resetOnlineState] ${e}`);
|
|
1234
1372
|
}
|
|
1235
1373
|
}
|
|
1374
|
+
|
|
1375
|
+
async objectCleanup(ip){
|
|
1376
|
+
try {
|
|
1377
|
+
this.log.debug(`[objectCleanup] Starting channel and state cleanup for ${this.deviceInfo[ip].deviceName} | ${ip} | ${this.deviceInfo[ip].ip}`);
|
|
1378
|
+
|
|
1379
|
+
// Cancel cleanup operation in case device is not connected anymore
|
|
1380
|
+
if (this.deviceInfo[ip].connectionError || !this.deviceInfo[ip].connected) return;
|
|
1381
|
+
|
|
1382
|
+
// Set parameters for object view to only include objects within adapter namespace
|
|
1383
|
+
const params = {
|
|
1384
|
+
startkey : `${this.namespace}.${this.deviceInfo[ip].deviceName}.`,
|
|
1385
|
+
endkey : `${this.namespace}.\u9999`,
|
|
1386
|
+
};
|
|
1387
|
+
|
|
1388
|
+
// Get all current channels
|
|
1389
|
+
const _channels = await this.getObjectViewAsync('system', 'channel', params);
|
|
1390
|
+
// List all found channels & compare with memory, delete unneeded channels
|
|
1391
|
+
for (const currDevice in _channels.rows) {
|
|
1392
|
+
// @ts-ignore
|
|
1393
|
+
if (!this.deviceInfo[ip].adapterObjects.channels.includes(_channels.rows[currDevice].id)
|
|
1394
|
+
&& _channels.rows[currDevice].id.split('.')[2] === this.deviceInfo[ip].deviceName){
|
|
1395
|
+
this.log.debug(`[objectCleanup] Unknown Channel found, delete ${_channels.rows[currDevice].id}`);
|
|
1396
|
+
await this.delObjectAsync(_channels.rows[currDevice].id, {recursive: true});
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
// Get all current states in adapter tree
|
|
1401
|
+
const _states = await this.getObjectViewAsync('system', 'state', params);
|
|
1402
|
+
// List all found states & compare with memory, delete unneeded states
|
|
1403
|
+
for (const currDevice in _states.rows) {
|
|
1404
|
+
if (!this.createdStatesDetails[_states.rows[currDevice].id.replace(`esphome.0.`, ``)]
|
|
1405
|
+
&& _states.rows[currDevice].id.split('.')[2] === this.deviceInfo[ip].deviceName){
|
|
1406
|
+
this.log.debug(`[objectCleanup] Unknown State found, delete ${_states.rows[currDevice].id}`);
|
|
1407
|
+
// await this.delObjectAsync(_states.rows[currDevice].id);
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
} catch (e) {
|
|
1412
|
+
this.log.error(`[objectCleanup] Fatal error ${e} | ${e.stack}`);
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
async offlineDeviceCleanup () {
|
|
1417
|
+
this.log.info(`Offline Device cleanup started`);
|
|
1418
|
+
|
|
1419
|
+
try {
|
|
1420
|
+
|
|
1421
|
+
// Get an overview of all current devices known by adapter
|
|
1422
|
+
const knownDevices = await this.getDevicesAsync();
|
|
1423
|
+
console.log(`KnownDevices: ${knownDevices}`);
|
|
1424
|
+
|
|
1425
|
+
// Loop to all devices, check if online state = TRUE otherwise delete device
|
|
1426
|
+
for (const device in knownDevices){
|
|
1427
|
+
|
|
1428
|
+
// Get online value
|
|
1429
|
+
const online = await this.getStateAsync(`${knownDevices[device]._id}.info._online`);
|
|
1430
|
+
if (!online || !online.val){
|
|
1431
|
+
this.log.info(`Offline device ${knownDevices[device]._id.split('.')[2]} expected on ip ${knownDevices[device].native.ip} removed`);
|
|
1432
|
+
await this.delObjectAsync(knownDevices[device]._id, {recursive: true});
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
if (!knownDevices) return; // exit function if no known device are detected
|
|
1438
|
+
if (knownDevices.length > 0) this.log.info(`Try to contact ${knownDevices.length} known devices`);
|
|
1439
|
+
} catch (e) {
|
|
1440
|
+
this.log.error(`[offlineDeviceCleanup] Fatal error occurred, cannot cleanup offline devices ${e} | ${e.stack}`);
|
|
1441
|
+
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1236
1445
|
}
|
|
1237
1446
|
|
|
1238
1447
|
if (require.main !== module) {
|