iobroker.al-ko 0.2.2 → 0.2.3

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/README.md CHANGED
@@ -54,7 +54,19 @@ Es handelt sich um ein Community-Projekt, und AL-KO bietet **keinen Support** da
54
54
 
55
55
  ## Changelog
56
56
 
57
- ## Changelog
57
+ ### 0.2.3 (2025-10-22)
58
+
59
+ **Deutsch:**
60
+ - WebSocket-Stabilität deutlich verbessert:
61
+ - Heartbeat (Ping/Pong) alle **120 Sekunden** mit **30 Sekunden** Timeout
62
+ - Bei fehlendem Pong oder Fehlern wird die Verbindung **aktiv beendet**, damit ein sauberer **Reconnect** erfolgt
63
+ - Entfernt: „Silence-Watchdog“, damit es in längeren Ruhephasen (z. B. nachts) **keine unnötigen Reconnects** gibt
64
+
65
+ **English:**
66
+ - Improved WebSocket stability:
67
+ - Heartbeat (ping/pong) every **120 seconds** with **30 seconds** timeout
68
+ - If pong is missing or errors occur, the socket is **terminated** to trigger a clean **reconnect**
69
+ - Removed the **silence watchdog** to avoid unnecessary reconnects during long idle periods (e.g., at night)
58
70
 
59
71
 
60
72
  ### 0.2.2 (2025-10-20)
package/io-package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "al-ko",
4
- "version": "0.2.2",
4
+ "version": "0.2.3",
5
5
  "tier": 3,
6
6
  "titleLang": {
7
7
  "en": "AL-KO",
@@ -33,6 +33,19 @@
33
33
  "Hubert Zechner <hubertiob@posteo.at>"
34
34
  ],
35
35
  "news": {
36
+ "0.2.3": {
37
+ " en": "Improved WebSocket stability: Added heartbeat (ping/pong) every 120 seconds with 30 seconds timeout. If no pong or an error occurs, the socket is closed and reconnected automatically. Removed the silence watchdog to avoid unnecessary reconnects during long idle phases (e.g., at night).",
38
+ "de": "WebSocket-Stabilität verbessert: Heartbeat (Ping/Pong) alle 120 Sekunden mit 30 Sekunden Timeout hinzugefügt. Bei fehlendem Pong oder Fehlern wird die Verbindung geschlossen und automatisch neu verbunden. Der Silence-Watchdog wurde entfernt, um unnötige Reconnects während längerer Ruhephasen (z. B. nachts) zu vermeiden.",
39
+ "ru": "Улучшена стабильность WebSocket: добавлен Heartbeat (ping/pong) каждые 120 секунд с тайм-аутом 30 секунд. При отсутствии pong или ошибках соединение закрывается и автоматически восстанавливается. Удалён watchdog тишины, чтобы избежать ненужных переподключений во время долгих периодов бездействия (например, ночью).",
40
+ "pt": "Melhorada a estabilidade do WebSocket: Adicionado heartbeat (ping/pong) a cada 120 segundos com tempo limite de 30 segundos. Se não houver pong ou ocorrer um erro, o socket é fechado e reconectado automaticamente. Removido o watchdog de silêncio para evitar reconexões desnecessárias durante longos períodos de inatividade (por exemplo, à noite).",
41
+ "nl": "Verbeterde WebSocket-stabiliteit: Heartbeat (ping/pong) toegevoegd elke 120 seconden met een timeout van 30 seconden. Als er geen pong of een fout optreedt, wordt de socket gesloten en automatisch opnieuw verbonden. De stilte-watchdog is verwijderd om onnodige reconnects tijdens langere inactieve periodes (bijv. 's nachts) te voorkomen.",
42
+ "fr": "Stabilité WebSocket améliorée : ajout d'un heartbeat (ping/pong) toutes les 120 secondes avec un délai d'attente de 30 secondes. En cas d'absence de pong ou d'erreur, la connexion est fermée et reconnectée automatiquement. Le watchdog de silence a été supprimé afin d'éviter des reconnexions inutiles lors de longues périodes d'inactivité (par exemple, la nuit).",
43
+ "it": "Migliorata la stabilità del WebSocket: aggiunto heartbeat (ping/pong) ogni 120 secondi con timeout di 30 secondi. Se manca il pong o si verifica un errore, la connessione viene chiusa e riconnessa automaticamente. Rimosso il watchdog del silenzio per evitare riconnessioni inutili durante lunghi periodi di inattività (ad esempio, di notte).",
44
+ "es": "Mejorada la estabilidad del WebSocket: se añadió un heartbeat (ping/pong) cada 120 segundos con un tiempo de espera de 30 segundos. Si no hay pong o ocurre un error, el socket se cierra y se reconecta automáticamente. Se eliminó el watchdog de silencio para evitar reconexiones innecesarias durante largos períodos de inactividad (por ejemplo, por la noche).",
45
+ "pl": "Poprawiona stabilność WebSocket: dodano heartbeat (ping/pong) co 120 sekund z limitem czasu 30 sekund. W przypadku braku pong lub błędu połączenie jest zamykane i automatycznie ponownie nawiązywane. Usunięto watchdog ciszy, aby uniknąć niepotrzebnych ponownych połączeń podczas długich okresów bezczynności (np. w nocy).",
46
+ "uk": "Покращено стабільність WebSocket: додано heartbeat (ping/pong) кожні 120 секунд із тайм-аутом 30 секунд. Якщо pong не надходить або виникає помилка, з'єднання закривається та автоматично відновлюється. Видалено watchdog тиші, щоб уникнути непотрібних повторних підключень під час тривалих періодів бездіяльності (наприклад, уночі).",
47
+ "zh-cn": "改进了 WebSocket 稳定性:每 120 秒添加一次心跳 (ping/pong),超时 30 秒。如果没有收到 pong 或发生错误,连接将关闭并自动重新连接。移除了静默监视程序,以避免在长时间空闲期间(例如夜间)不必要的重新连接。"
48
+ },
36
49
  "0.2.2": {
37
50
  "en": "Prepared for the first npm release. Synchronized versions between io-package.json and package.json. Added npm metadata and publication configuration. Minor internal adjustments for improved compatibility.",
38
51
  "de": "Für die erste npm-Veröffentlichung vorbereitet. Versionen zwischen io-package.json und package.json synchronisiert. npm-Metadaten und Veröffentlichungskonfiguration hinzugefügt. Kleine interne Anpassungen zur verbesserten Kompatibilität.",
@@ -45,60 +58,8 @@
45
58
  "pl": "Przygotowano do pierwszego wydania npm. Zsynchronizowano wersje między io-package.json i package.json. Dodano metadane npm i konfigurację publikacji. Drobne poprawki wewnętrzne dla lepszej kompatybilności.",
46
59
  "uk": "Підготовлено до першого випуску npm. Синхронізовано версії між io-package.json і package.json. Додано метадані npm та конфігурацію публікації. Невеликі внутрішні покращення для кращої сумісності.",
47
60
  "zh-cn": "为首次 npm 发布做好准备。同步 io-package.json 与 package.json 之间的版本。添加了 npm 元数据和发布配置。进行了少量内部改进以提高兼容性。"
48
- },
49
- "0.2.1": {
50
- "en": "Added option in Admin UI to enable or disable WebSocket message logging (wsDebug). This allows toggling incoming WebSocket message logs directly in the adapter configuration. Minor internal improvements.",
51
- "de": "Neue Option in der Admin-UI zum Aktivieren oder Deaktivieren des WebSocket-Nachrichten-Loggings (wsDebug). Das Logging eingehender WebSocket-Nachrichten kann nun direkt in der Adapter-Konfiguration gesteuert werden. Kleine interne Verbesserungen.",
52
- "ru": "Добавлена опция в интерфейсе администратора для включения или отключения логирования сообщений WebSocket (wsDebug). Теперь можно управлять логированием входящих сообщений WebSocket прямо в настройках адаптера. Незначительные внутренние улучшения.",
53
- "pt": "Adicionada opção na interface de administração para ativar ou desativar o registro de mensagens WebSocket (wsDebug). Agora é possível alternar o registro de mensagens diretamente na configuração do adaptador. Pequenas melhorias internas.",
54
- "nl": "Optie toegevoegd in de Admin UI om het loggen van WebSocket-berichten in of uit te schakelen (wsDebug). Hiermee kun je inkomende berichten direct in de adapterconfiguratie beheren. Kleine interne verbeteringen.",
55
- "fr": "Ajout d'une option dans l'interface d'administration pour activer ou désactiver la journalisation des messages WebSocket (wsDebug). Permet de basculer l'enregistrement des messages directement depuis la configuration de l'adaptateur. Améliorations internes mineures.",
56
- "it": "Aggiunta un'opzione nell'interfaccia di amministrazione per abilitare o disabilitare il logging dei messaggi WebSocket (wsDebug). Ora è possibile gestire i log direttamente nella configurazione dell'adattatore. Piccoli miglioramenti interni.",
57
- "es": "Se agregó una opción en la interfaz de administración para habilitar o deshabilitar el registro de mensajes WebSocket (wsDebug). Ahora se puede activar o desactivar directamente desde la configuración del adaptador. Pequeñas mejoras internas.",
58
- "pl": "Dodano opcję w interfejsie administratora do włączania lub wyłączania logowania wiadomości WebSocket (wsDebug). Można teraz sterować logowaniem bezpośrednio w konfiguracji adaptera. Drobne ulepszenia wewnętrzne.",
59
- "uk": "Додано опцію в інтерфейсі адміністратора для ввімкнення або вимкнення журналювання повідомлень WebSocket (wsDebug). Тепер можна керувати логуванням безпосередньо в налаштуваннях адаптера. Незначні внутрішні покращення.",
60
- "zh-cn": "在管理界面中添加了启用或禁用 WebSocket 消息日志记录 (wsDebug) 的选项。现在可以在适配器配置中直接切换日志记录。进行了少量内部改进。"
61
- },
62
- "0.2.0": {
63
- "en": "Migrated to ESLint 9 (Flat-Config) and updated development dependencies",
64
- "de": "Migration auf ESLint 9 (Flat-Config) und Aktualisierung der Entwicklungsabhängigkeiten",
65
- "ru": "Переход на ESLint 9 (Flat-Config) и обновлены зависимости для разработки",
66
- "pt": "Migrado para ESLint 9 (Flat-Config) e dependências de desenvolvimento atualizadas",
67
- "nl": "Gemigreerd naar ESLint 9 (Flat-Config) en ontwikkelafhankelijkheden bijgewerkt",
68
- "fr": "Migration vers ESLint 9 (Flat-Config) et mise à jour des dépendances de développement",
69
- "it": "Migrazione a ESLint 9 (Flat-Config) e aggiornate le dipendenze di sviluppo",
70
- "es": "Migrado a ESLint 9 (Flat-Config) y actualizadas las dependencias de desarrollo",
71
- "pl": "Migracja do ESLint 9 (Flat-Config) i aktualizacja zależności deweloperskich",
72
- "uk": "Міграція на ESLint 9 (Flat-Config) та оновлено залежності розробки",
73
- "zh-cn": "迁移到 ESLint 9(Flat-Config)并更新开发依赖项"
74
- },
75
- "0.1.2": {
76
- "en": "Improved admin UI config and fixed adapter-check issues",
77
- "de": "Verbesserte Admin-UI-Konfiguration und behobene Adapter-Check-Fehler",
78
- "ru": "Улучшена конфигурация админ-интерфейса и исправлены ошибки adapter-check",
79
- "pt": "Configuração da interface de administração melhorada e problemas do adapter-check corrigidos",
80
- "nl": "Verbeterde admin UI-configuratie en adapter-checkproblemen opgelost",
81
- "fr": "Configuration de l'interface d'administration améliorée et correction des problèmes d'adapter-check",
82
- "it": "Configurazione dell'interfaccia di amministrazione migliorata e risolti i problemi di adapter-check",
83
- "es": "Configuración de la interfaz de administración mejorada y problemas de verificación del adaptador corregidos",
84
- "pl": "Ulepszona konfiguracja interfejsu administratora i naprawione błędy adapter-check",
85
- "uk": "Покращена конфігурація інтерфейсу адміністратора та виправлені помилки adapter-check",
86
- "zh-cn": "改进了管理界面配置并修复了适配器检查问题"
87
- },
88
- "0.1.1": {
89
- "en": "Initial release",
90
- "de": "Erste Version",
91
- "ru": "Первая версия",
92
- "pt": "Versão inicial",
93
- "nl": "Eerste versie",
94
- "fr": "Première version",
95
- "it": "Prima versione",
96
- "es": "Primera versión",
97
- "pl": "Pierwsza wersja",
98
- "uk": "Перша версія",
99
- "zh-cn": "初始版本"
100
61
  }
101
- },
62
+ },
102
63
  "keywords": [
103
64
  "al-ko",
104
65
  "Robolinho",
@@ -110,7 +71,6 @@
110
71
  "adminUI": {
111
72
  "config": "json"
112
73
  },
113
- "license": "MIT",
114
74
  "licenseInformation": {
115
75
  "type": "free",
116
76
  "license": "MIT",
package/main.js CHANGED
@@ -31,7 +31,9 @@ class AlKoAdapter extends utils.Adapter {
31
31
  this.adapterSetStates = new Set();
32
32
  this.pendingPushes = new Set();
33
33
  this.webSockets = {}; // offene WebSocket-Verbindungen pro Gerät
34
- this.reconnectTimeouts = {}; // hier speichern wir alle offenen Reconnect-Timeouts
34
+ this.reconnectTimeouts = {}; // offene Reconnect-Timeouts
35
+ this.pingIntervals = {}; // Ping-Intervalle pro Gerät
36
+ this.pongTimeouts = {}; // Timeout-Überwachung nach Ping
35
37
 
36
38
  this._stopRequested = false;
37
39
 
@@ -97,6 +99,7 @@ class AlKoAdapter extends utils.Adapter {
97
99
 
98
100
  this.log.info("✅ Login erfolgreich");
99
101
  }
102
+
100
103
  async refreshAuth() {
101
104
  if (!this.refreshToken || Date.now() >= this.tokenExpiresAt - 60000) {
102
105
  this.log.info("🔄 Erneuere Access-Token…");
@@ -206,8 +209,32 @@ class AlKoAdapter extends utils.Adapter {
206
209
  const url = `wss://socket.al-ko.com/v1?Authorization=${this.accessToken}&thingName=${deviceId}`;
207
210
  const ws = new WebSocket(url);
208
211
 
212
+ ws.isAlive = true;
213
+
209
214
  ws.on("open", () => {
210
215
  this.log.info(`🔗 WebSocket verbunden für Gerät: ${deviceId}`);
216
+
217
+ // PING-Mechanismus (alle 120 Sekunden)
218
+ this.pingIntervals[deviceId] = setInterval(() => {
219
+ if (ws.readyState === WebSocket.OPEN) {
220
+ ws.ping();
221
+ ws.isAlive = false;
222
+
223
+ this.pongTimeouts[deviceId] = setTimeout(() => {
224
+ if (!ws.isAlive) {
225
+ this.log.warn(
226
+ `💤 Keine Pong-Antwort von ${deviceId} → Verbindung wird beendet`,
227
+ );
228
+ ws.terminate();
229
+ }
230
+ }, 30_000); // 30 Sekunden Zeit für Pong
231
+ }
232
+ }, 120_000); // 120 Sekunden Ping-Intervall
233
+ });
234
+
235
+ ws.on("pong", () => {
236
+ ws.isAlive = true;
237
+ clearTimeout(this.pongTimeouts[deviceId]);
211
238
  });
212
239
 
213
240
  ws.on("message", async (msg) => {
@@ -242,7 +269,8 @@ class AlKoAdapter extends utils.Adapter {
242
269
  this.log.warn(
243
270
  `⚠️ WebSocket geschlossen für ${deviceId}, erneuter Versuch in 10s`,
244
271
  );
245
- // Timeout merken, damit wir ihn im onUnload wieder aufräumen können
272
+ clearInterval(this.pingIntervals[deviceId]);
273
+ clearTimeout(this.pongTimeouts[deviceId]);
246
274
  this.reconnectTimeouts[deviceId] = setTimeout(
247
275
  () => this.connectWebSocket(deviceId),
248
276
  10000,
@@ -251,6 +279,10 @@ class AlKoAdapter extends utils.Adapter {
251
279
 
252
280
  ws.on("error", (err) => {
253
281
  this.log.error(`❌ WebSocket-Fehler (${deviceId}): ${err.message}`);
282
+ // Falls kein 'close' folgt, aktiv terminieren, damit Reconnect greift
283
+ try {
284
+ ws.terminate();
285
+ } catch {}
254
286
  });
255
287
 
256
288
  this.webSockets[deviceId] = ws;
@@ -565,22 +597,29 @@ class AlKoAdapter extends utils.Adapter {
565
597
  clearInterval(this.tokenInterval);
566
598
  }
567
599
 
568
- // offene Reconnect-Timeouts aufräumen
569
600
  for (const t of Object.values(this.reconnectTimeouts)) {
570
601
  try {
571
602
  clearTimeout(t);
572
- } catch {
573
- // intentionally empty
574
- }
603
+ } catch {}
604
+ }
605
+
606
+ for (const t of Object.values(this.pingIntervals)) {
607
+ try {
608
+ clearInterval(t);
609
+ } catch {}
610
+ }
611
+
612
+ for (const t of Object.values(this.pongTimeouts)) {
613
+ try {
614
+ clearTimeout(t);
615
+ } catch {}
575
616
  }
576
617
 
577
618
  // offene WebSockets schließen
578
619
  for (const ws of Object.values(this.webSockets)) {
579
620
  try {
580
621
  ws.close();
581
- } catch {
582
- // intentionally empty
583
- }
622
+ } catch {}
584
623
  }
585
624
 
586
625
  this.log.info("Adapter gestoppt.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.al-ko",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Adapter for communication with Al-Ko garden tools",
5
5
  "author": {
6
6
  "name": "Hubertiob",
@@ -23,7 +23,7 @@
23
23
  ],
24
24
  "repository": {
25
25
  "type": "git",
26
- "url": "https://github.com/zechnerhubert/ioBroker.al-ko.git"
26
+ "url": "git+https://github.com/zechnerhubert/ioBroker.al-ko.git"
27
27
  },
28
28
  "bugs": {
29
29
  "url": "https://github.com/zechnerhubert/ioBroker.al-ko/issues"
@@ -44,15 +44,15 @@
44
44
  "README.md"
45
45
  ],
46
46
  "scripts": {
47
- "test:js": "mocha --config test/mocharc.custom.json \"{!(node_modules|test)/**/*.test.js,*.test.js,test/**/test!(PackageFiles|Startup).js}\"",
48
- "test:package": "mocha test/package --exit",
49
- "test:integration": "mocha test/integration --exit",
50
- "test": "npm run test:js && npm run test:package",
51
- "check": "tsc --noEmit -p tsconfig.check.json",
52
- "lint": "eslint main.js lib/ --ext .js",
53
- "lint:fix": "eslint main.js lib/ --ext .js --fix",
54
- "translate": "translate-adapter",
55
- "release": "release-script"
47
+ "test:js": "mocha --config test/mocharc.custom.json \"{!(node_modules|test)/**/*.test.js,*.test.js,test/**/test!(PackageFiles|Startup).js}\"",
48
+ "test:package": "mocha test/package --exit",
49
+ "test:integration": "mocha test/integration --exit",
50
+ "test": "npm run test:js && npm run test:package",
51
+ "check": "tsc --noEmit -p tsconfig.check.json",
52
+ "lint": "eslint main.js lib/ admin/jsonConfig.json --ext .js,.json",
53
+ "lint:fix": "eslint main.js lib/ admin/jsonConfig.json --ext .js,.json --fix",
54
+ "translate": "translate-adapter",
55
+ "release": "release-script"
56
56
  },
57
57
  "dependencies": {
58
58
  "@iobroker/adapter-core": "^3.3.2",
@@ -60,35 +60,35 @@
60
60
  "ws": "^8.18.0"
61
61
  },
62
62
  "devDependencies": {
63
- "@alcalzone/release-script": "^3.8.0",
64
- "@alcalzone/release-script-plugin-iobroker": "^3.7.2",
65
- "@alcalzone/release-script-plugin-license": "^3.7.0",
66
- "@alcalzone/release-script-plugin-manual-review": "^3.7.0",
67
- "@iobroker/adapter-dev": "^1.5.0",
68
- "@iobroker/testing": "^5.1.1",
69
- "@tsconfig/node20": "^20.1.6",
70
- "@types/chai": "^4.3.20",
71
- "@types/chai-as-promised": "^7.1.8",
72
- "@types/mocha": "^10.0.10",
73
- "@types/node": "^24.6.1",
74
- "@types/proxyquire": "^1.3.31",
75
- "@types/sinon": "^17.0.4",
76
- "@types/sinon-chai": "^4.0.0",
77
- "@eslint/js": "^9.14.0",
78
- "@iobroker/eslint-config": "^1.5.0",
79
- "chai": "^4.5.0",
80
- "chai-as-promised": "^7.1.2",
81
- "eslint": "^9.14.0",
82
- "mocha": "^11.7.2",
83
- "prettier": "^3.3.3",
84
- "proxyquire": "^2.1.3",
85
- "sinon": "^21.0.0",
86
- "sinon-chai": "^4.0.1",
87
- "typescript": "~5.0.4",
88
- "typescript-eslint": "^8.8.0"
89
- },
90
- "publishConfig": {
91
- "access": "public"
92
- },
63
+ "@alcalzone/release-script": "^3.8.0",
64
+ "@alcalzone/release-script-plugin-iobroker": "^3.7.2",
65
+ "@alcalzone/release-script-plugin-license": "^3.7.0",
66
+ "@alcalzone/release-script-plugin-manual-review": "^3.7.0",
67
+ "@iobroker/adapter-dev": "^1.5.0",
68
+ "@iobroker/testing": "^5.1.1",
69
+ "@tsconfig/node20": "^20.1.6",
70
+ "@types/chai": "^4.3.20",
71
+ "@types/chai-as-promised": "^7.1.8",
72
+ "@types/mocha": "^10.0.10",
73
+ "@types/node": "^24.6.1",
74
+ "@types/proxyquire": "^1.3.31",
75
+ "@types/sinon": "^17.0.4",
76
+ "@types/sinon-chai": "^4.0.0",
77
+ "@eslint/js": "^9.14.0",
78
+ "@iobroker/eslint-config": "^1.5.0",
79
+ "chai": "^4.5.0",
80
+ "chai-as-promised": "^7.1.2",
81
+ "eslint": "^9.14.0",
82
+ "mocha": "^11.7.2",
83
+ "prettier": "^3.3.3",
84
+ "proxyquire": "^2.1.3",
85
+ "sinon": "^21.0.0",
86
+ "sinon-chai": "^4.0.1",
87
+ "typescript": "~5.0.4",
88
+ "typescript-eslint": "^8.8.0"
89
+ },
90
+ "publishConfig": {
91
+ "access": "public"
92
+ },
93
93
  "readmeFilename": "README.md"
94
94
  }