iobroker.autodarts 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/io-package.json +27 -27
- package/lib/adapter-config.d.ts +4 -1
- package/lib/httpHelper.js +43 -0
- package/lib/httpHelper.test.js +171 -0
- package/lib/throw.js +20 -8
- package/lib/trafficLight.js +7 -7
- package/lib/visit.js +5 -4
- package/main.js +105 -179
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -59,6 +59,19 @@ In the adapter settings, enter:
|
|
|
59
59
|
<!--
|
|
60
60
|
### **WORK IN PROGRESS**
|
|
61
61
|
-->
|
|
62
|
+
### 0.3.2 (2025-12-27)
|
|
63
|
+
- (DrozmotiX) **ENHANCED**: Fixed all TypeScript type errors by adding proper type definitions for config properties
|
|
64
|
+
- (DrozmotiX) **ENHANCED**: Refactored HTTP request handling - created reusable httpHelper module to eliminate code duplication
|
|
65
|
+
- (DrozmotiX) **ENHANCED**: Converted HTTP callback-based requests to async/await pattern for better error handling
|
|
66
|
+
- (DrozmotiX) **ENHANCED**: Improved connection state logging - now logs when connection is restored after being offline
|
|
67
|
+
- (DrozmotiX) **ENHANCED**: Standardized async/await usage across all state change handlers for consistency
|
|
68
|
+
- (DrozmotiX) **FIXED**: Removed unused error variable in fetchVersion method
|
|
69
|
+
- (DrozmotiX) **FIXED**: Added proper error type checking in fetchConfig to prevent runtime errors
|
|
70
|
+
- (DrozmotiX) **TESTING**: Added comprehensive unit tests for httpHelper module covering success, timeout, and error scenarios
|
|
71
|
+
|
|
72
|
+
### 0.3.1 (2025-12-27)
|
|
73
|
+
- Changed: Object creation now uses extendObjectAsync with proper roles and types instead of setObjectNotExistsAsync.
|
|
74
|
+
|
|
62
75
|
### 0.3.0 (2025-12-26)
|
|
63
76
|
- Added traffic light datapoints (`status.trafficLightColor`, `status.trafficLightState`) mapped from Board Manager status (`Throw` / `Takeout` / connection errors).
|
|
64
77
|
- Refactored code: visit handling, throw handling (triple / bull) and traffic light logic moved to separate modules.
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "autodarts",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.2",
|
|
5
5
|
"news": {
|
|
6
|
+
"0.3.2": {
|
|
7
|
+
"en": "**ENHANCED**: Fixed all TypeScript type errors by adding proper type definitions for config properties\n**ENHANCED**: Refactored HTTP request handling - created reusable httpHelper module to eliminate code duplication\n**ENHANCED**: Converted HTTP callback-based requests to async/await pattern for better error handling\n**ENHANCED**: Improved connection state logging - now logs when connection is restored after being offline\n**ENHANCED**: Standardized async/await usage across all state change handlers for consistency\n**FIXED**: Removed unused error variable in fetchVersion method\n**FIXED**: Added proper error type checking in fetchConfig to prevent runtime errors\n**TESTING**: Added comprehensive unit tests for httpHelper module covering success, timeout, and error scenarios",
|
|
8
|
+
"de": "**ENHANCED**: Alle TypeScript-Typfehler behoben, indem richtige Typendefinitionen für config-Eigenschaften hinzugefügt wurden\n**ENHANCED**: Refactored HTTP Request Handling - erstelltes wiederverwendbares httpHelper Modul zur Beseitigung der Codevervielfachung\n**ENHANCED**: Konvertierte HTTP-Requests auf async/await-Muster für eine bessere Fehlerbehandlung\n**ENHANCED**: Verbesserte Verbindungszustandsprotokollierung - protokolliert nun, wenn die Verbindung nach Offline wiederhergestellt wird\n**ENHANCED**: Standardisierte async/await Nutzung über alle State Change-Handler für Konsistenz\n**FIXED**: Ungenutzte Fehlervariable in fetchVersion Methode entfernt\n**FIXED**: Es wurde eine ordnungsgemäße Fehlersuche im fetchConfig hinzugefügt, um Laufzeitfehler zu verhindern\n**TESTING**: Ergänzende Unit-Tests für das httpHelper-Modul für Erfolgs-, Timeout- und Fehlerszenarien",
|
|
9
|
+
"ru": "** УСТАНОВЛЕНО**: исправлены все ошибки типа TypeScript путем добавления правильных определений типа для свойств конфигурации\n**УДАЛЕН**: Рефакторированная обработка HTTP-запросов - создан многоразовый модуль httpHelper для устранения дублирования кода\n** УВЕДОМЛЕН**: преобразованные HTTP-запросы на основе обратного вызова для улучшения обработки ошибок\n** ВОССТАНОВЛЕНИЕ**: Улучшенная регистрация состояния соединения - теперь журналы, когда соединение восстанавливается после автономного подключения\n** УСТАНОВЛЕНО**: Стандартизированное использование асинхронизации/ожиданий для всех обработчиков изменений состояния\n**FIXED**: Удаление неиспользуемой переменной ошибки в методе fetchVersion\n**FIXED**: добавлена правильная проверка типа ошибки в fetchConfig для предотвращения ошибок во время выполнения\n** Тестирование**: добавлены комплексные единичные тесты для модуля httpHelper, охватывающие сценарии успеха, тайм-аута и ошибок",
|
|
10
|
+
"pt": "**Enhanced**: Corrigido todos os erros de tipo TypeScript adicionando definições de tipo adequadas para as propriedades de configuração\n**ENHANCED**: Refactored HTTP request handling - created reutilizable httpHelper module to elimine code duplication\n**ENHANCED**: Requisições baseadas em callback HTTP convertidas para o padrão assync/await para melhor manipulação de erros\n**Enhanced**: Registro melhorado do estado da conexão - agora registra quando a conexão é restaurada após estar offline\n**ENHANCED**: Uso padrão de assync/await em todos os manipuladores de mudança de estado para consistência\n**FIXED**: Variável de erro não utilizada removida no método fetchVersion\n**FIXED**: Adicionado o tipo de erro correto verificando no fetchConfig para evitar erros de execução\n**TESTING**: Adicionados testes unitários abrangentes para o módulo httpHelper cobrindo cenários de sucesso, tempo e erro",
|
|
11
|
+
"nl": "**ENHANCED**: Fixed all TypeScript type fouten door het toevoegen van juiste type definities voor config eigenschappen\n**ENHANKELIJK**: Refactored HTTP request handling - herbruikbare httpHelper module gemaakt om code duplicatie te elimineren\n**ENHANCED**: Converted HTTP callback-gebaseerde verzoeken om async/wacht patroon voor betere foutafhandeling\n**ENHANCED**: Verbeterde verbindingstoestand logging - nu logt wanneer de verbinding wordt hersteld na offline zijn\n** ANTWOORD**: Gestandaardiseerd async/wacht gebruik in alle state change handlers voor consistentie\n** VAST**: Verwijderde ongebruikte fout variabele in fetchVersie methode\n** VAST**: Toegevoegd juiste fout type controleren in fetchConfig om runtime fouten te voorkomen\n**TESTING**: Toegevoegd uitgebreide unit testen voor httpHelper module over succes, timeout, en fout scenario's",
|
|
12
|
+
"fr": "**ENHANCED**: Correction de toutes les erreurs de type TypeScript en ajoutant des définitions de type appropriées pour les propriétés de configuration\n**ENHANDED**: Refactored HTTP request handling - créé module httpHelper réutilisable pour éliminer la duplication de code\n**ENHANCED**: Converti les requêtes basées sur le callback HTTP en modèle async/attendit pour une meilleure gestion des erreurs\n**ENHANCED**: Amélioration de l'enregistrement d'état de connexion - logs maintenant lorsque la connexion est restaurée après être hors ligne\n**CHANGE**: utilisation normalisée async/attendue dans tous les gestionnaires de changement d'état pour une cohérence\n**FIXED**: Supprimé la variable d'erreur inutilisée dans la méthode fetchVersion\n**FIXED**: Ajout d'une vérification de type d'erreur dans fetchConfig pour prévenir les erreurs d'exécution\n**TESTING**: Ajout de tests unitaires complets pour le module httpHelper couvrant les scénarios de succès, de délai et d'erreur",
|
|
13
|
+
"it": "**ENHANCED**: Risolto tutti gli errori di tipo TypeScript aggiungendo definizioni di tipo corrette per proprietà di configurazione\n**ENHANCED**: Refactored HTTP request handling - creato modulo httpHelper riutilizzabile per eliminare la duplicazione di codice\n**ENHANCED**: Le richieste basate su callback HTTP convertite in un modello asinc/aspettato per una migliore gestione degli errori\n**ENHANCED**: Registrazione dello stato di connessione migliorata - ora i log quando la connessione viene ripristinata dopo essere offline\n**ENHANCED**: Uso standardizzato asinc/aspettato in tutti i maneggiatori di cambio di stato per consistenza\n**FIXED**: Rimossa variabile di errore non utilizzata nel metodo fetchVersion\n**FIXED**: Aggiunta il corretto tipo di errore di controllo in fetchConfig per evitare errori runtime\n**TESTING**: Aggiunti test unitari completi per il modulo httpHelper che copre il successo, il timeout e gli scenari di errore",
|
|
14
|
+
"es": "**ENHANCED**: Arregla todos los errores tipo TipoScript añadiendo definiciones adecuadas para propiedades de configuración\n**ENHANCED**: Refactored HTTP request handling - creó el módulo httpHelper reutilizable para eliminar la duplicación de códigos\n**ENHANCED**: Solicitudes convertidas basadas en llamadas HTTP a async/await patrón para un mejor manejo de errores\n**ENHANCED**: Mejora de la conexión de registro de estado - ahora registros cuando la conexión se restaura después de estar fuera de línea\n**ENHANCED**: El uso estandarizado async/await en todos los manejadores del cambio estatal para la consistencia\n**FIXED**: Retire la variable de error no utilizado en el método fetchVersion\n**FIXED**: Añadido el tipo de error correcto en fetchConfig para evitar errores de tiempo de ejecución\n** Notas**: Se agregaron pruebas de unidad completas para el módulo httpHelper que abarcan el éxito, el tiempo y los escenarios de error",
|
|
15
|
+
"pl": "* *ENHANCED* *: Naprawiono wszystkie błędy typu TypeScript poprzez dodanie właściwych definicji typów dla właściwości konfiguracyjnych \n* *ENHANCED* *: Refactored HTTP request handling - created realisable httpHelper module to elimination code duplication \n* *ENHANCED* *: Konwertowany HTTP połączeń backback prośby async / czekać wzór dla lepszej obsługi błędów \n* *ENHANCED* *: Ulepszone logowanie stanu połączenia - teraz loguje się, gdy połączenie jest przywrócone po offline \n* *ENHANCED* *: Standaryzowane async / czekać na wykorzystanie we wszystkich stanowych opiekunów zmian dla spójności \n* *FIXED* *: Usunięto nieużywaną zmienną błędu w metodzie fetchVersion \n* *FIXED* *: Dodano poprawny typ błędu sprawdzający w fetchConfig, aby zapobiec błędom w runtime \n* *TESTING* *: Dodano kompleksowe testy jednostkowe dla modułu httpHelper obejmujące sukcesy, timeout i scenariusze błędów ",
|
|
16
|
+
"uk": "**ENHANCED**: Виправлено всі помилки типу TypeScript, додаючи правильні визначення типу для властивостей конфігурації\n**ENHANCED**: Перефакторований HTTP-запитування - створений багаторазовий модуль HTTPHelper для усунення дублікатів коду\n**ENHANCED**: Конвертовані запити на основі HTTP-повідомлень на основі async/await для кращої обробки помилок\n**ENHANCED***: Покращується з'єднання держреєстрації - тепер журнали, коли з'єднання відновлюється після офлайн\n**ENHANCED***: стандартизоване використання async/await у всіх ручках зі змінами стану для консистенції\n**FIXED**: Видалено невикористану змінну помилку в методі fetchVersion\n**FIXED***: Додано належну перевірку типу помилки в fetchConfig, щоб запобігти помилки часу\n**TESTING***: Додано комплексні тести для модуля httpHelper, що охоплює успіхи, часовий час та сценарії помилок",
|
|
17
|
+
"zh-cn": "** ENHANCED**:通过添加适当的配置属性类型定义来固定所有类型脚本类型错误\n** ENHANCED **: 重置了 HTTP 请求处理 - 创建了可重复使用的 httpHelper 模块,以消除代码重复\n** ENHANCED**: 将基于 HTTP 回调请求转换为同步/等待模式,以更好地处理错误\n** ENHANCED **: 连接状态记录的改进 -- -- 下线后恢复连接时的日志\n** ENHANCED**:所有州变化处理器的标准化合成/等待使用,以保持一致\n** FIXED**:删除了拾取Version 方法中的未使用错误变量\n** FIXED**:在获取中添加适当的错误类型检查Config以防止运行时间错误\n** TESTING**:为httpHelper模块添加了涵盖成功、超时和错误情景的综合单元测试"
|
|
18
|
+
},
|
|
19
|
+
"0.3.1": {
|
|
20
|
+
"en": "Changed: Object creation now uses extendObjectAsync with proper roles and types instead of setObjectNotExistsAsync.",
|
|
21
|
+
"de": "Geändert: Objekt-Erstellung verwendet jetzt ExtendedObjectAsync mit richtigen Rollen und Typen anstelle von Set ObjectNotExistsAsync.",
|
|
22
|
+
"ru": "Изменилось: Создание объектов теперь использует extendObjectAsync с правильными ролями и типами вместо набора ObjectNotExistsAsync.",
|
|
23
|
+
"pt": "Alterado: Criação de objetos agora usa extendObjectAsync com papéis e tipos apropriados em vez de set ObjectNotExistsAsync.",
|
|
24
|
+
"nl": "Gewijzigd: Objectcreatie maakt nu gebruik van extendObjectAsync met juiste rollen en typen in plaats van set ObjectNietBestaatAsync.",
|
|
25
|
+
"fr": "Changement : La création d'objet utilise désormais extensionObjectAsync avec des rôles et types appropriés au lieu de set ObjetNotExistsAsync.",
|
|
26
|
+
"it": "Cambiato: Creazione oggetti ora utilizza extendObjectAsync con ruoli e tipi appropriati invece di set ObjectNotExistsAsync.",
|
|
27
|
+
"es": "Cambio: La creación de objetos ahora utiliza ExtendObjectAsync con roles y tipos adecuados en lugar de conjunto ObjectNoExistsAsync.",
|
|
28
|
+
"pl": "Zmieniono: Tworzenie obiektu wykorzystuje teraz extendObjectAsync z odpowiednimi rolami i typami zamiast zestawu ObjectNotExistsAsync.",
|
|
29
|
+
"uk": "Змінено: Створення об'єктів тепер використовує розширенняObjectAsync з відповідними ролями та типами замість набору Об'єктNotExistsAsync.",
|
|
30
|
+
"zh-cn": "已更改 : 对象创建现在使用扩展对象Async , 并配有合适的角色和类型而不是设定 Object NotExists Async. (原始内容存档于2018-09-31)."
|
|
31
|
+
},
|
|
6
32
|
"0.3.0": {
|
|
7
33
|
"en": "Added traffic light datapoints (`status.trafficLightColor`, `status.trafficLightState`) mapped from Board Manager status (`Throw` / `Takeout` / connection errors).\nRefactored code: visit handling, throw handling (triple / bull) and traffic light logic moved to separate modules.",
|
|
8
34
|
"de": "Es wurden Verkehrslichtdatenpunkte (`status.trafficLightColor`, `status.trafficLightState`) aus dem Status Board Manager (`Throw` / `Takeout` / Verbindungsfehler) abgebildet.\nRefactored Code: Besuchen Sie Handling, Wurf Handling (Triple / Bull) und Ampellogik in separate Module bewegt.",
|
|
@@ -67,32 +93,6 @@
|
|
|
67
93
|
"pl": "Dodano punkty datapointowe dla wyniku odwiedzin, aktualny wynik dart, flagę trójuderzeniową z konfigurowalnym minimalnym wynikiem oraz konfigurację kamery (cam0- cam2).\nOczyszczona logika adaptera i wewnętrzny sondaż / czas.\nAktualizacja tłumaczeń.",
|
|
68
94
|
"uk": "Додано точки даних для облікового запису, поточний запис dart, потрійний прапор з налаштуванням мінімального балу та конфігурації камери (cam0–cam2).\nЗнімання логіки адаптера та внутрішнього опитування / термінів.\nОновлені переклади.",
|
|
69
95
|
"zh-cn": "添加了访问分数的数据点,当前飞镖分数,三重击旗可配置最小分数,以及相机配置(cam0–cam2).\n清理适配器逻辑和内部投票/计时.\n最新译名."
|
|
70
|
-
},
|
|
71
|
-
"0.0.14": {
|
|
72
|
-
"en": "fix",
|
|
73
|
-
"de": "fixieren",
|
|
74
|
-
"ru": "исправлять",
|
|
75
|
-
"pt": "corrigir",
|
|
76
|
-
"nl": "fix",
|
|
77
|
-
"fr": "correction",
|
|
78
|
-
"it": "correzione",
|
|
79
|
-
"es": "arregle",
|
|
80
|
-
"pl": "fix",
|
|
81
|
-
"uk": "фіксація",
|
|
82
|
-
"zh-cn": "固定"
|
|
83
|
-
},
|
|
84
|
-
"0.0.12": {
|
|
85
|
-
"en": "fix",
|
|
86
|
-
"de": "fixieren",
|
|
87
|
-
"ru": "исправлять",
|
|
88
|
-
"pt": "corrigir",
|
|
89
|
-
"nl": "fix",
|
|
90
|
-
"fr": "correction",
|
|
91
|
-
"it": "correzione",
|
|
92
|
-
"es": "arregle",
|
|
93
|
-
"pl": "fix",
|
|
94
|
-
"uk": "фіксація",
|
|
95
|
-
"zh-cn": "固定"
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"titleLang": {
|
package/lib/adapter-config.d.ts
CHANGED
|
@@ -10,7 +10,10 @@ type _AdapterConfig = typeof native;
|
|
|
10
10
|
declare global {
|
|
11
11
|
namespace ioBroker {
|
|
12
12
|
interface AdapterConfig extends _AdapterConfig {
|
|
13
|
-
//
|
|
13
|
+
// Additional properties defined in jsonConfig but not in io-package.json native
|
|
14
|
+
tripleMinScore?: number;
|
|
15
|
+
tripleMaxScore?: number;
|
|
16
|
+
triggerResetMs?: number;
|
|
14
17
|
}
|
|
15
18
|
}
|
|
16
19
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// lib/httpHelper.js
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const http = require("http");
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Makes an HTTP request to the Autodarts Board Manager.
|
|
8
|
+
*
|
|
9
|
+
* @param {import("@iobroker/adapter-core").AdapterInstance} adapter Adapter instance
|
|
10
|
+
* @param {string} path API path (e.g., "/api/state")
|
|
11
|
+
* @param {number} timeout Timeout in milliseconds
|
|
12
|
+
* @returns {Promise<string>} Response data as string
|
|
13
|
+
*/
|
|
14
|
+
function makeRequest(adapter, path, timeout = 1500) {
|
|
15
|
+
return new Promise((resolve, reject) => {
|
|
16
|
+
const options = {
|
|
17
|
+
host: adapter.config.host,
|
|
18
|
+
port: adapter.config.port,
|
|
19
|
+
path: path,
|
|
20
|
+
method: "GET",
|
|
21
|
+
timeout: timeout,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const req = http.request(options, res => {
|
|
25
|
+
let data = "";
|
|
26
|
+
|
|
27
|
+
res.on("data", chunk => (data += chunk));
|
|
28
|
+
res.on("end", () => resolve(data));
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
req.on("error", error => reject(error));
|
|
32
|
+
req.on("timeout", () => {
|
|
33
|
+
req.destroy();
|
|
34
|
+
reject(new Error("Request timeout"));
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
req.end();
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports = {
|
|
42
|
+
makeRequest,
|
|
43
|
+
};
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/* global describe, it, before, after */
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const { expect } = require("chai");
|
|
5
|
+
const http = require("http");
|
|
6
|
+
const httpHelper = require("./httpHelper");
|
|
7
|
+
|
|
8
|
+
describe("httpHelper", () => {
|
|
9
|
+
describe("makeRequest", () => {
|
|
10
|
+
let server;
|
|
11
|
+
let port;
|
|
12
|
+
|
|
13
|
+
before(done => {
|
|
14
|
+
// Create a test HTTP server
|
|
15
|
+
server = http.createServer((req, res) => {
|
|
16
|
+
if (req.url === "/api/test") {
|
|
17
|
+
res.writeHead(200, { "Content-Type": "text/plain" });
|
|
18
|
+
res.end("test response");
|
|
19
|
+
} else if (req.url === "/api/json") {
|
|
20
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
21
|
+
res.end(JSON.stringify({ status: "ok" }));
|
|
22
|
+
} else if (req.url === "/api/timeout") {
|
|
23
|
+
// Don't respond - let it timeout
|
|
24
|
+
return;
|
|
25
|
+
} else if (req.url === "/api/error") {
|
|
26
|
+
req.socket.destroy();
|
|
27
|
+
} else {
|
|
28
|
+
res.writeHead(404);
|
|
29
|
+
res.end("Not found");
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
server.listen(0, "127.0.0.1", () => {
|
|
34
|
+
port = server.address().port;
|
|
35
|
+
done();
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
after(done => {
|
|
40
|
+
if (server) {
|
|
41
|
+
server.close(done);
|
|
42
|
+
} else {
|
|
43
|
+
done();
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("should successfully fetch data from a valid endpoint", async () => {
|
|
48
|
+
const mockAdapter = {
|
|
49
|
+
config: {
|
|
50
|
+
host: "127.0.0.1",
|
|
51
|
+
port: port,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// @ts-expect-error - mockAdapter is a partial mock for testing
|
|
56
|
+
const result = await httpHelper.makeRequest(mockAdapter, "/api/test");
|
|
57
|
+
expect(result).to.equal("test response");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("should successfully fetch JSON data", async () => {
|
|
61
|
+
const mockAdapter = {
|
|
62
|
+
config: {
|
|
63
|
+
host: "127.0.0.1",
|
|
64
|
+
port: port,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// @ts-expect-error - mockAdapter is a partial mock for testing
|
|
69
|
+
const result = await httpHelper.makeRequest(mockAdapter, "/api/json");
|
|
70
|
+
const parsed = JSON.parse(result);
|
|
71
|
+
expect(parsed).to.deep.equal({ status: "ok" });
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("should reject with timeout error when request times out", async () => {
|
|
75
|
+
const mockAdapter = {
|
|
76
|
+
config: {
|
|
77
|
+
host: "127.0.0.1",
|
|
78
|
+
port: port,
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
// @ts-expect-error - mockAdapter is a partial mock for testing
|
|
84
|
+
await httpHelper.makeRequest(mockAdapter, "/api/timeout", 100);
|
|
85
|
+
expect.fail("Should have thrown timeout error");
|
|
86
|
+
} catch (error) {
|
|
87
|
+
expect(error).to.be.an("error");
|
|
88
|
+
expect(error.message).to.equal("Request timeout");
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("should reject with error when connection fails", async () => {
|
|
93
|
+
const mockAdapter = {
|
|
94
|
+
config: {
|
|
95
|
+
host: "127.0.0.1",
|
|
96
|
+
port: 99999, // Invalid port
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
// @ts-expect-error - mockAdapter is a partial mock for testing
|
|
102
|
+
await httpHelper.makeRequest(mockAdapter, "/api/test", 100);
|
|
103
|
+
expect.fail("Should have thrown connection error");
|
|
104
|
+
} catch (error) {
|
|
105
|
+
expect(error).to.be.an("error");
|
|
106
|
+
expect(error.code).to.match(/ECONNREFUSED|EADDRNOTAVAIL|ERR_SOCKET_BAD_PORT/);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("should handle socket destruction gracefully", async () => {
|
|
111
|
+
const mockAdapter = {
|
|
112
|
+
config: {
|
|
113
|
+
host: "127.0.0.1",
|
|
114
|
+
port: port,
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
// @ts-expect-error - mockAdapter is a partial mock for testing
|
|
120
|
+
await httpHelper.makeRequest(mockAdapter, "/api/error", 100);
|
|
121
|
+
expect.fail("Should have thrown error");
|
|
122
|
+
} catch (error) {
|
|
123
|
+
expect(error).to.be.an("error");
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("should use custom timeout value", async () => {
|
|
128
|
+
const mockAdapter = {
|
|
129
|
+
config: {
|
|
130
|
+
host: "127.0.0.1",
|
|
131
|
+
port: port,
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const startTime = Date.now();
|
|
136
|
+
try {
|
|
137
|
+
// @ts-expect-error - mockAdapter is a partial mock for testing
|
|
138
|
+
await httpHelper.makeRequest(mockAdapter, "/api/timeout", 200);
|
|
139
|
+
expect.fail("Should have thrown timeout error");
|
|
140
|
+
} catch (error) {
|
|
141
|
+
const elapsed = Date.now() - startTime;
|
|
142
|
+
expect(error.message).to.equal("Request timeout");
|
|
143
|
+
// Check that timeout happened roughly at the right time (with some tolerance)
|
|
144
|
+
expect(elapsed).to.be.at.least(150);
|
|
145
|
+
expect(elapsed).to.be.at.most(500);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("should use default timeout of 1500ms", async () => {
|
|
150
|
+
const mockAdapter = {
|
|
151
|
+
config: {
|
|
152
|
+
host: "127.0.0.1",
|
|
153
|
+
port: port,
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const startTime = Date.now();
|
|
158
|
+
try {
|
|
159
|
+
// @ts-expect-error - mockAdapter is a partial mock for testing
|
|
160
|
+
await httpHelper.makeRequest(mockAdapter, "/api/timeout");
|
|
161
|
+
expect.fail("Should have thrown timeout error");
|
|
162
|
+
} catch (error) {
|
|
163
|
+
const elapsed = Date.now() - startTime;
|
|
164
|
+
expect(error.message).to.equal("Request timeout");
|
|
165
|
+
// Check that default timeout of 1500ms was used (with tolerance)
|
|
166
|
+
expect(elapsed).to.be.at.least(1400);
|
|
167
|
+
expect(elapsed).to.be.at.most(2000);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
});
|
package/lib/throw.js
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
/**
|
|
5
5
|
* Legt Throw-Channel und States an.
|
|
6
6
|
*
|
|
7
|
-
* @param {import("@iobroker/adapter-core").
|
|
7
|
+
* @param {import("@iobroker/adapter-core").AdapterInstance} adapter Adapter-Instanz dieses Autodarts-Adapters
|
|
8
8
|
*/
|
|
9
9
|
async function init(adapter) {
|
|
10
|
-
await adapter.
|
|
10
|
+
await adapter.extendObjectAsync("throw", {
|
|
11
11
|
type: "channel",
|
|
12
12
|
common: {
|
|
13
13
|
name: {
|
|
@@ -18,7 +18,7 @@ async function init(adapter) {
|
|
|
18
18
|
native: {},
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
await adapter.
|
|
21
|
+
await adapter.extendObjectAsync("throw.current", {
|
|
22
22
|
type: "state",
|
|
23
23
|
common: {
|
|
24
24
|
name: {
|
|
@@ -37,7 +37,7 @@ async function init(adapter) {
|
|
|
37
37
|
native: {},
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
-
await adapter.
|
|
40
|
+
await adapter.extendObjectAsync("throw.isTriple", {
|
|
41
41
|
type: "state",
|
|
42
42
|
common: {
|
|
43
43
|
name: {
|
|
@@ -56,7 +56,7 @@ async function init(adapter) {
|
|
|
56
56
|
native: {},
|
|
57
57
|
});
|
|
58
58
|
|
|
59
|
-
await adapter.
|
|
59
|
+
await adapter.extendObjectAsync("throw.isBullseye", {
|
|
60
60
|
type: "state",
|
|
61
61
|
common: {
|
|
62
62
|
name: {
|
|
@@ -79,23 +79,24 @@ async function init(adapter) {
|
|
|
79
79
|
/**
|
|
80
80
|
* Aktualisiert die Throw-States für den letzten Dart inkl. Triple/Bull-Flags.
|
|
81
81
|
*
|
|
82
|
-
* @param {import("@iobroker/adapter-core").
|
|
82
|
+
* @param {import("@iobroker/adapter-core").AdapterInstance} adapter Adapter-Instanz dieses Autodarts-Adapters
|
|
83
83
|
* @param {any} lastDart Letzter Dart aus state.throws
|
|
84
84
|
*/
|
|
85
85
|
async function updateThrow(adapter, lastDart) {
|
|
86
|
+
// @ts-expect-error - calcScore is a custom method in the Autodarts adapter class
|
|
86
87
|
const score = adapter.calcScore(lastDart);
|
|
87
88
|
const segment = lastDart?.segment?.number || 0;
|
|
88
89
|
|
|
89
90
|
// Score-Range aus Adapter übernehmen
|
|
91
|
+
// @ts-expect-error - tripleMinScoreRuntime is a custom property in the Autodarts adapter class
|
|
90
92
|
let minScore = adapter.tripleMinScoreRuntime;
|
|
93
|
+
// @ts-expect-error - tripleMaxScoreRuntime is a custom property in the Autodarts adapter class
|
|
91
94
|
let maxScore = adapter.tripleMaxScoreRuntime;
|
|
92
95
|
|
|
93
96
|
if (!Number.isFinite(minScore)) {
|
|
94
|
-
// @ts-expect-error tripleMinScore is defined in io-package.json but not in AdapterConfig
|
|
95
97
|
minScore = Number(adapter.config.tripleMinScore) || 1;
|
|
96
98
|
}
|
|
97
99
|
if (!Number.isFinite(maxScore)) {
|
|
98
|
-
// @ts-expect-error tripleMaxScore is defined in io-package.json but not in AdapterConfig
|
|
99
100
|
maxScore = Number(adapter.config.tripleMaxScore) || 20;
|
|
100
101
|
}
|
|
101
102
|
|
|
@@ -114,29 +115,40 @@ async function updateThrow(adapter, lastDart) {
|
|
|
114
115
|
await adapter.setStateAsync("throw.current", { val: score, ack: true });
|
|
115
116
|
|
|
116
117
|
// Timer für Auto-Reset abbrechen
|
|
118
|
+
// @ts-expect-error - tripleResetTimer is a custom property in the Autodarts adapter class
|
|
117
119
|
if (adapter.tripleResetTimer) {
|
|
120
|
+
// @ts-expect-error - tripleResetTimer is a custom property in the Autodarts adapter class
|
|
118
121
|
clearTimeout(adapter.tripleResetTimer);
|
|
122
|
+
// @ts-expect-error - tripleResetTimer is a custom property in the Autodarts adapter class
|
|
119
123
|
adapter.tripleResetTimer = null;
|
|
120
124
|
}
|
|
125
|
+
// @ts-expect-error - bullResetTimer is a custom property in the Autodarts adapter class
|
|
121
126
|
if (adapter.bullResetTimer) {
|
|
127
|
+
// @ts-expect-error - bullResetTimer is a custom property in the Autodarts adapter class
|
|
122
128
|
clearTimeout(adapter.bullResetTimer);
|
|
129
|
+
// @ts-expect-error - bullResetTimer is a custom property in the Autodarts adapter class
|
|
123
130
|
adapter.bullResetTimer = null;
|
|
124
131
|
}
|
|
125
132
|
|
|
126
133
|
await adapter.setStateAsync("throw.isTriple", { val: isTriple, ack: true });
|
|
127
134
|
await adapter.setStateAsync("throw.isBullseye", { val: isBullseye, ack: true });
|
|
128
135
|
|
|
136
|
+
// @ts-expect-error - triggerResetMsRuntime is a custom property in the Autodarts adapter class
|
|
129
137
|
const timeoutMs = Number(adapter.triggerResetMsRuntime) || 0;
|
|
130
138
|
if (timeoutMs > 0) {
|
|
131
139
|
if (isTriple) {
|
|
140
|
+
// @ts-expect-error - tripleResetTimer is a custom property in the Autodarts adapter class
|
|
132
141
|
adapter.tripleResetTimer = setTimeout(() => {
|
|
133
142
|
adapter.setState("throw.isTriple", { val: false, ack: true });
|
|
143
|
+
// @ts-expect-error - tripleResetTimer is a custom property in the Autodarts adapter class
|
|
134
144
|
adapter.tripleResetTimer = null;
|
|
135
145
|
}, timeoutMs);
|
|
136
146
|
}
|
|
137
147
|
if (isBullseye) {
|
|
148
|
+
// @ts-expect-error - bullResetTimer is a custom property in the Autodarts adapter class
|
|
138
149
|
adapter.bullResetTimer = setTimeout(() => {
|
|
139
150
|
adapter.setState("throw.isBullseye", { val: false, ack: true });
|
|
151
|
+
// @ts-expect-error - bullResetTimer is a custom property in the Autodarts adapter class
|
|
140
152
|
adapter.bullResetTimer = null;
|
|
141
153
|
}, timeoutMs);
|
|
142
154
|
}
|
package/lib/trafficLight.js
CHANGED
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
* - trafficLightColor (HEX)
|
|
8
8
|
* - trafficLightState (String)
|
|
9
9
|
*
|
|
10
|
-
* @param {import("@iobroker/adapter-core").
|
|
10
|
+
* @param {import("@iobroker/adapter-core").AdapterInstance} adapter Adapter-Instanz dieses Autodarts-Adapters
|
|
11
11
|
*/
|
|
12
12
|
async function init(adapter) {
|
|
13
13
|
const baseId = "status";
|
|
14
14
|
|
|
15
15
|
// Channel anlegen
|
|
16
|
-
await adapter.
|
|
16
|
+
await adapter.extendObjectAsync(baseId, {
|
|
17
17
|
type: "channel",
|
|
18
18
|
common: {
|
|
19
19
|
name: "Status",
|
|
@@ -22,7 +22,7 @@ async function init(adapter) {
|
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
// HEX-Farbe
|
|
25
|
-
await adapter.
|
|
25
|
+
await adapter.extendObjectAsync(`${baseId}.trafficLightColor`, {
|
|
26
26
|
type: "state",
|
|
27
27
|
common: {
|
|
28
28
|
name: {
|
|
@@ -30,7 +30,7 @@ async function init(adapter) {
|
|
|
30
30
|
de: "Ampelfarbe (HEX)",
|
|
31
31
|
},
|
|
32
32
|
type: "string",
|
|
33
|
-
role: "
|
|
33
|
+
role: "level.color.rgb",
|
|
34
34
|
read: true,
|
|
35
35
|
write: false,
|
|
36
36
|
desc: {
|
|
@@ -42,7 +42,7 @@ async function init(adapter) {
|
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
// Text-Status
|
|
45
|
-
await adapter.
|
|
45
|
+
await adapter.extendObjectAsync(`${baseId}.trafficLightState`, {
|
|
46
46
|
type: "state",
|
|
47
47
|
common: {
|
|
48
48
|
name: {
|
|
@@ -50,7 +50,7 @@ async function init(adapter) {
|
|
|
50
50
|
de: "Ampelstatus",
|
|
51
51
|
},
|
|
52
52
|
type: "string",
|
|
53
|
-
role: "
|
|
53
|
+
role: "text",
|
|
54
54
|
read: true,
|
|
55
55
|
write: false,
|
|
56
56
|
desc: {
|
|
@@ -73,7 +73,7 @@ async function init(adapter) {
|
|
|
73
73
|
/**
|
|
74
74
|
* Setzt Ampel-Status.
|
|
75
75
|
*
|
|
76
|
-
* @param {import("@iobroker/adapter-core").
|
|
76
|
+
* @param {import("@iobroker/adapter-core").AdapterInstance} adapter Adapter-Instanz dieses Autodarts-Adapters
|
|
77
77
|
* @param {"green"|"yellow"|"red"} status Gewünschter Ampelstatus (green/yellow/red)
|
|
78
78
|
*/
|
|
79
79
|
async function setStatus(adapter, status) {
|
package/lib/visit.js
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
/**
|
|
5
5
|
* Legt Visit-Channel und States an.
|
|
6
6
|
*
|
|
7
|
-
* @param {import("@iobroker/adapter-core").
|
|
7
|
+
* @param {import("@iobroker/adapter-core").AdapterInstance} adapter Adapter-Instanz dieses Autodarts-Adapters
|
|
8
8
|
*/
|
|
9
9
|
async function init(adapter) {
|
|
10
|
-
await adapter.
|
|
10
|
+
await adapter.extendObjectAsync("visit", {
|
|
11
11
|
type: "channel",
|
|
12
12
|
common: {
|
|
13
13
|
name: {
|
|
@@ -18,7 +18,7 @@ async function init(adapter) {
|
|
|
18
18
|
native: {},
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
await adapter.
|
|
21
|
+
await adapter.extendObjectAsync("visit.score", {
|
|
22
22
|
type: "state",
|
|
23
23
|
common: {
|
|
24
24
|
name: {
|
|
@@ -41,7 +41,7 @@ async function init(adapter) {
|
|
|
41
41
|
/**
|
|
42
42
|
* Berechnet und schreibt die Visit-Summe, wenn ein Visit abgeschlossen ist.
|
|
43
43
|
*
|
|
44
|
-
* @param {import("@iobroker/adapter-core").
|
|
44
|
+
* @param {import("@iobroker/adapter-core").AdapterInstance} adapter Adapter-Instanz dieses Autodarts-Adapters
|
|
45
45
|
* @param {any[]} currentThrows Array der aktuellen Würfe aus /api/state
|
|
46
46
|
* @param {number} lastThrowsCount Anzahl Würfe beim letzten Poll (adapter.lastThrowsCount)
|
|
47
47
|
* @returns {Promise<number>} Neue lastThrowsCount, damit du ihn im Adapter speichern kannst
|
|
@@ -54,6 +54,7 @@ async function updateVisit(adapter, currentThrows, lastThrowsCount) {
|
|
|
54
54
|
// - vorher weniger als 3 waren (Visit gerade abgeschlossen)
|
|
55
55
|
if (currentCount === 3 && lastThrowsCount < 3) {
|
|
56
56
|
const lastThree = currentThrows.slice(-3);
|
|
57
|
+
// @ts-expect-error - calcScore is a custom method in the Autodarts adapter class
|
|
57
58
|
const visitSum = lastThree.reduce((sum, dart) => sum + adapter.calcScore(dart), 0);
|
|
58
59
|
|
|
59
60
|
await adapter.setStateAsync("visit.score", { val: visitSum, ack: true });
|
package/main.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
const utils = require("@iobroker/adapter-core");
|
|
4
|
-
const http = require("http");
|
|
5
4
|
const throwLogic = require("./lib/throw");
|
|
6
5
|
const visit = require("./lib/visit");
|
|
7
6
|
const trafficLight = require("./lib/trafficLight");
|
|
7
|
+
const httpHelper = require("./lib/httpHelper");
|
|
8
8
|
|
|
9
9
|
class Autodarts extends utils.Adapter {
|
|
10
10
|
constructor(options) {
|
|
@@ -39,14 +39,8 @@ class Autodarts extends utils.Adapter {
|
|
|
39
39
|
this.config.host ??= "127.0.0.1";
|
|
40
40
|
this.config.port ??= 3180;
|
|
41
41
|
this.config.interval ??= 1000;
|
|
42
|
-
// eslint-disable-next-line jsdoc/check-tag-names
|
|
43
|
-
/** @ts-expect-error tripleMinScore is defined in io-package.json but not in AdapterConfig */
|
|
44
42
|
this.config.tripleMinScore ??= 1; // Mindestpunktzahl für Triple-Flag
|
|
45
|
-
// eslint-disable-next-line jsdoc/check-tag-names
|
|
46
|
-
/** @ts-expect-error tripleMaxScore is defined in io-package.json but not in AdapterConfig */
|
|
47
43
|
this.config.tripleMaxScore ??= 20; // Maximalpunktzahl für Triple-Flag
|
|
48
|
-
// eslint-disable-next-line jsdoc/check-tag-names
|
|
49
|
-
/** @ts-expect-error triggerResetMs is defined in io-package.json/jsonConfig but not in AdapterConfig */
|
|
50
44
|
this.config.triggerResetMs ??= 0; // 0 = kein Auto-Reset
|
|
51
45
|
|
|
52
46
|
// Visit-Struktur anlegen (ausgelagert)
|
|
@@ -56,7 +50,7 @@ class Autodarts extends utils.Adapter {
|
|
|
56
50
|
await throwLogic.init(this);
|
|
57
51
|
|
|
58
52
|
// Online-Datenpunkt
|
|
59
|
-
await this.
|
|
53
|
+
await this.extendObjectAsync("online", {
|
|
60
54
|
type: "state",
|
|
61
55
|
common: {
|
|
62
56
|
name: {
|
|
@@ -76,7 +70,7 @@ class Autodarts extends utils.Adapter {
|
|
|
76
70
|
});
|
|
77
71
|
|
|
78
72
|
// System-Channel und BoardVersion-Datenpunkt anlegen
|
|
79
|
-
await this.
|
|
73
|
+
await this.extendObjectAsync("system", {
|
|
80
74
|
type: "channel",
|
|
81
75
|
common: {
|
|
82
76
|
name: {
|
|
@@ -87,7 +81,7 @@ class Autodarts extends utils.Adapter {
|
|
|
87
81
|
native: {},
|
|
88
82
|
});
|
|
89
83
|
|
|
90
|
-
await this.
|
|
84
|
+
await this.extendObjectAsync("system.boardVersion", {
|
|
91
85
|
type: "state",
|
|
92
86
|
common: {
|
|
93
87
|
name: {
|
|
@@ -107,7 +101,7 @@ class Autodarts extends utils.Adapter {
|
|
|
107
101
|
});
|
|
108
102
|
|
|
109
103
|
// Kamera-Infos als JSON-States
|
|
110
|
-
await this.
|
|
104
|
+
await this.extendObjectAsync("system.cam0", {
|
|
111
105
|
type: "state",
|
|
112
106
|
common: {
|
|
113
107
|
name: {
|
|
@@ -126,7 +120,7 @@ class Autodarts extends utils.Adapter {
|
|
|
126
120
|
native: {},
|
|
127
121
|
});
|
|
128
122
|
|
|
129
|
-
await this.
|
|
123
|
+
await this.extendObjectAsync("system.cam1", {
|
|
130
124
|
type: "state",
|
|
131
125
|
common: {
|
|
132
126
|
name: {
|
|
@@ -145,7 +139,7 @@ class Autodarts extends utils.Adapter {
|
|
|
145
139
|
native: {},
|
|
146
140
|
});
|
|
147
141
|
|
|
148
|
-
await this.
|
|
142
|
+
await this.extendObjectAsync("system.cam2", {
|
|
149
143
|
type: "state",
|
|
150
144
|
common: {
|
|
151
145
|
name: {
|
|
@@ -165,7 +159,7 @@ class Autodarts extends utils.Adapter {
|
|
|
165
159
|
});
|
|
166
160
|
|
|
167
161
|
// Config-Channel und States für tripleMinScore / tripleMaxScore / triggerResetMs (zur Laufzeit änderbar)
|
|
168
|
-
await this.
|
|
162
|
+
await this.extendObjectAsync("config", {
|
|
169
163
|
type: "channel",
|
|
170
164
|
common: {
|
|
171
165
|
name: {
|
|
@@ -176,7 +170,7 @@ class Autodarts extends utils.Adapter {
|
|
|
176
170
|
native: {},
|
|
177
171
|
});
|
|
178
172
|
|
|
179
|
-
await this.
|
|
173
|
+
await this.extendObjectAsync("config.tripleMinScore", {
|
|
180
174
|
type: "state",
|
|
181
175
|
common: {
|
|
182
176
|
name: {
|
|
@@ -195,7 +189,7 @@ class Autodarts extends utils.Adapter {
|
|
|
195
189
|
native: {},
|
|
196
190
|
});
|
|
197
191
|
|
|
198
|
-
await this.
|
|
192
|
+
await this.extendObjectAsync("config.tripleMaxScore", {
|
|
199
193
|
type: "state",
|
|
200
194
|
common: {
|
|
201
195
|
name: {
|
|
@@ -214,7 +208,7 @@ class Autodarts extends utils.Adapter {
|
|
|
214
208
|
native: {},
|
|
215
209
|
});
|
|
216
210
|
|
|
217
|
-
await this.
|
|
211
|
+
await this.extendObjectAsync("config.triggerResetMs", {
|
|
218
212
|
type: "state",
|
|
219
213
|
common: {
|
|
220
214
|
name: {
|
|
@@ -234,14 +228,8 @@ class Autodarts extends utils.Adapter {
|
|
|
234
228
|
});
|
|
235
229
|
|
|
236
230
|
// Laufzeitwerte initial aus Adapter-Config setzen
|
|
237
|
-
// eslint-disable-next-line jsdoc/check-tag-names
|
|
238
|
-
/** @ts-expect-error tripleMinScore is defined in io-package.json but not in AdapterConfig */
|
|
239
231
|
this.tripleMinScoreRuntime = Number(this.config.tripleMinScore) || 1;
|
|
240
|
-
// eslint-disable-next-line jsdoc/check-tag-names
|
|
241
|
-
/** @ts-expect-error tripleMaxScore is defined in io-package.json but not in AdapterConfig */
|
|
242
232
|
this.tripleMaxScoreRuntime = Number(this.config.tripleMaxScore) || 20;
|
|
243
|
-
// eslint-disable-next-line jsdoc/check-tag-names
|
|
244
|
-
/** @ts-expect-error triggerResetMs is defined in io-package.json/jsonConfig but not in AdapterConfig */
|
|
245
233
|
this.triggerResetMsRuntime = Number(this.config.triggerResetMs) || 0; // 0 = kein Auto-Reset
|
|
246
234
|
|
|
247
235
|
await this.setStateAsync("config.tripleMinScore", {
|
|
@@ -305,7 +293,7 @@ class Autodarts extends utils.Adapter {
|
|
|
305
293
|
* @param {string} id Full state id
|
|
306
294
|
* @param {ioBroker.State | null | undefined} state New state value (ack=false on user write)
|
|
307
295
|
*/
|
|
308
|
-
onStateChange(id, state) {
|
|
296
|
+
async onStateChange(id, state) {
|
|
309
297
|
if (!state) {
|
|
310
298
|
return;
|
|
311
299
|
}
|
|
@@ -328,7 +316,7 @@ class Autodarts extends utils.Adapter {
|
|
|
328
316
|
this.log.info(`Runtime tripleMinScore updated to ${val}`);
|
|
329
317
|
|
|
330
318
|
// Wert mit ack bestätigen
|
|
331
|
-
this.
|
|
319
|
+
await this.setStateAsync("config.tripleMinScore", { val, ack: true });
|
|
332
320
|
} else if (idShort === "config.tripleMaxScore") {
|
|
333
321
|
const val = Number(state.val);
|
|
334
322
|
if (!Number.isFinite(val) || val <= 0) {
|
|
@@ -340,7 +328,7 @@ class Autodarts extends utils.Adapter {
|
|
|
340
328
|
this.log.info(`Runtime tripleMaxScore updated to ${val}`);
|
|
341
329
|
|
|
342
330
|
// Wert mit ack bestätigen
|
|
343
|
-
this.
|
|
331
|
+
await this.setStateAsync("config.tripleMaxScore", { val, ack: true });
|
|
344
332
|
} else if (idShort === "config.triggerResetMs") {
|
|
345
333
|
const val = Number(state.val);
|
|
346
334
|
if (!Number.isFinite(val) || val < 0) {
|
|
@@ -352,182 +340,120 @@ class Autodarts extends utils.Adapter {
|
|
|
352
340
|
this.log.info(`Runtime triggerResetMs updated to ${val} ms`);
|
|
353
341
|
|
|
354
342
|
// Wert mit ack bestätigen
|
|
355
|
-
this.
|
|
343
|
+
await this.setStateAsync("config.triggerResetMs", { val, ack: true });
|
|
356
344
|
}
|
|
357
345
|
}
|
|
358
346
|
|
|
359
347
|
/**
|
|
360
348
|
* Autodarts API abfragen und Visit-Summe schreiben
|
|
361
349
|
*/
|
|
362
|
-
fetchState() {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
port: this.config.port,
|
|
366
|
-
path: "/api/state",
|
|
367
|
-
method: "GET",
|
|
368
|
-
timeout: 1500,
|
|
369
|
-
};
|
|
370
|
-
|
|
371
|
-
const req = http.request(options, res => {
|
|
372
|
-
let data = "";
|
|
373
|
-
|
|
374
|
-
res.on("data", chunk => (data += chunk));
|
|
375
|
-
res.on("end", async () => {
|
|
376
|
-
this.offline = false;
|
|
377
|
-
this.setState("online", true, true); // Server erreichbar
|
|
378
|
-
|
|
379
|
-
try {
|
|
380
|
-
const state = JSON.parse(data);
|
|
381
|
-
const boardStatus = state.status || ""; // z.B. "Throw" oder "Takeout"
|
|
382
|
-
|
|
383
|
-
if (boardStatus === "Throw") {
|
|
384
|
-
await trafficLight.setStatus(this, "green");
|
|
385
|
-
} else if (boardStatus === "Takeout") {
|
|
386
|
-
await trafficLight.setStatus(this, "yellow");
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
// Nur weiter, wenn throws existieren, Array ist und nicht leer
|
|
390
|
-
if (!state.throws || !Array.isArray(state.throws) || state.throws.length === 0) {
|
|
391
|
-
return;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
const currentThrows = state.throws;
|
|
395
|
-
|
|
396
|
-
// Prüfen, ob sich die Würfe geändert haben
|
|
397
|
-
const signature = JSON.stringify(
|
|
398
|
-
currentThrows.map(d => ({
|
|
399
|
-
name: d.segment?.name || "",
|
|
400
|
-
mult: d.segment?.multiplier || 0,
|
|
401
|
-
})),
|
|
402
|
-
);
|
|
403
|
-
|
|
404
|
-
if (signature === this.lastSignature) {
|
|
405
|
-
return;
|
|
406
|
-
}
|
|
407
|
-
this.lastSignature = signature;
|
|
408
|
-
|
|
409
|
-
// letzten Dart in States schreiben (ausgelagert)
|
|
410
|
-
const lastDart = currentThrows[currentThrows.length - 1];
|
|
411
|
-
await throwLogic.updateThrow(this, lastDart);
|
|
412
|
-
|
|
413
|
-
// Visit-Summe aktualisieren (ausgelagert)
|
|
414
|
-
this.lastThrowsCount = await visit.updateVisit(this, currentThrows, this.lastThrowsCount);
|
|
415
|
-
} catch (e) {
|
|
416
|
-
this.log.warn(`Autodarts API Fehler: ${e.message} | Daten: ${data.substring(0, 200)}...`);
|
|
417
|
-
// Bei JSON-Fehler: Board war erreichbar, aber Antwort kaputt
|
|
418
|
-
this.setState("online", true, true);
|
|
419
|
-
}
|
|
420
|
-
});
|
|
421
|
-
});
|
|
350
|
+
async fetchState() {
|
|
351
|
+
try {
|
|
352
|
+
const data = await httpHelper.makeRequest(this, "/api/state");
|
|
422
353
|
|
|
423
|
-
|
|
424
|
-
if (
|
|
425
|
-
this.log.
|
|
426
|
-
this.offline = true;
|
|
354
|
+
// Log wenn Verbindung wiederhergestellt wurde
|
|
355
|
+
if (this.offline) {
|
|
356
|
+
this.log.info("Autodarts connection restored");
|
|
427
357
|
}
|
|
428
|
-
|
|
429
|
-
this.
|
|
430
|
-
|
|
358
|
+
this.offline = false;
|
|
359
|
+
await this.setStateAsync("online", true, true); // Server erreichbar
|
|
360
|
+
|
|
361
|
+
try {
|
|
362
|
+
const state = JSON.parse(data);
|
|
363
|
+
const boardStatus = state.status || ""; // z.B. "Throw" oder "Takeout"
|
|
364
|
+
|
|
365
|
+
if (boardStatus === "Throw") {
|
|
366
|
+
await trafficLight.setStatus(this, "green");
|
|
367
|
+
} else if (boardStatus === "Takeout") {
|
|
368
|
+
await trafficLight.setStatus(this, "yellow");
|
|
369
|
+
}
|
|
431
370
|
|
|
432
|
-
|
|
433
|
-
|
|
371
|
+
// Nur weiter, wenn throws existieren, Array ist und nicht leer
|
|
372
|
+
if (!state.throws || !Array.isArray(state.throws) || state.throws.length === 0) {
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const currentThrows = state.throws;
|
|
377
|
+
|
|
378
|
+
// Prüfen, ob sich die Würfe geändert haben
|
|
379
|
+
const signature = JSON.stringify(
|
|
380
|
+
currentThrows.map(d => ({
|
|
381
|
+
name: d.segment?.name || "",
|
|
382
|
+
mult: d.segment?.multiplier || 0,
|
|
383
|
+
})),
|
|
384
|
+
);
|
|
385
|
+
|
|
386
|
+
if (signature === this.lastSignature) {
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
this.lastSignature = signature;
|
|
390
|
+
|
|
391
|
+
// letzten Dart in States schreiben (ausgelagert)
|
|
392
|
+
const lastDart = currentThrows[currentThrows.length - 1];
|
|
393
|
+
await throwLogic.updateThrow(this, lastDart);
|
|
394
|
+
|
|
395
|
+
// Visit-Summe aktualisieren (ausgelagert)
|
|
396
|
+
this.lastThrowsCount = await visit.updateVisit(this, currentThrows, this.lastThrowsCount);
|
|
397
|
+
} catch (e) {
|
|
398
|
+
this.log.warn(`Autodarts API Fehler: ${e.message} | Daten: ${data.substring(0, 200)}...`);
|
|
399
|
+
// Bei JSON-Fehler: Board war erreichbar, aber Antwort kaputt
|
|
400
|
+
await this.setStateAsync("online", true, true);
|
|
401
|
+
}
|
|
402
|
+
} catch (error) {
|
|
434
403
|
if (!this.offline) {
|
|
435
|
-
this.log.warn(
|
|
404
|
+
this.log.warn(`Autodarts not reachable: ${error.message}`);
|
|
436
405
|
this.offline = true;
|
|
437
406
|
}
|
|
438
407
|
await trafficLight.setStatus(this, "red"); // Ampel = rot
|
|
439
|
-
this.
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
req.end();
|
|
408
|
+
await this.setStateAsync("online", false, true); // Server offline
|
|
409
|
+
}
|
|
443
410
|
}
|
|
444
411
|
|
|
445
412
|
/**
|
|
446
413
|
* Boardmanager Version abfragen
|
|
447
414
|
*/
|
|
448
|
-
fetchVersion() {
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
const req = http.request(options, res => {
|
|
458
|
-
let data = "";
|
|
459
|
-
res.on("data", chunk => (data += chunk));
|
|
460
|
-
res.on("end", () => {
|
|
461
|
-
try {
|
|
462
|
-
const version = data.trim();
|
|
463
|
-
this.setState("system.boardVersion", { val: version, ack: true });
|
|
464
|
-
} catch (e) {
|
|
465
|
-
this.log.warn(`Fehler beim Lesen der Version: ${e.message}`);
|
|
466
|
-
}
|
|
467
|
-
});
|
|
468
|
-
});
|
|
469
|
-
|
|
470
|
-
req.on("error", () => {
|
|
471
|
-
// Keine Log-Warnung, nur State leeren
|
|
472
|
-
this.setState("system.boardVersion", { val: "", ack: true });
|
|
473
|
-
});
|
|
474
|
-
|
|
475
|
-
req.on("timeout", () => {
|
|
476
|
-
req.destroy();
|
|
477
|
-
// Keine Log-Warnung, nur State leeren
|
|
478
|
-
this.setState("system.boardVersion", { val: "", ack: true });
|
|
479
|
-
});
|
|
480
|
-
|
|
481
|
-
req.end();
|
|
415
|
+
async fetchVersion() {
|
|
416
|
+
try {
|
|
417
|
+
const data = await httpHelper.makeRequest(this, "/api/version");
|
|
418
|
+
const version = data.trim();
|
|
419
|
+
await this.setStateAsync("system.boardVersion", { val: version, ack: true });
|
|
420
|
+
} catch {
|
|
421
|
+
// Bei Fehler State leeren (keine Log-Warnung)
|
|
422
|
+
await this.setStateAsync("system.boardVersion", { val: "", ack: true });
|
|
423
|
+
}
|
|
482
424
|
}
|
|
483
425
|
|
|
484
426
|
/**
|
|
485
427
|
* Board-Konfiguration abfragen (Kameras)
|
|
486
428
|
*/
|
|
487
|
-
fetchConfig() {
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
} catch (e) {
|
|
516
|
-
this.log.warn(`Fehler beim Lesen der Config: ${e.message} | Daten: ${data.substring(0, 200)}...`);
|
|
517
|
-
}
|
|
518
|
-
});
|
|
519
|
-
});
|
|
520
|
-
|
|
521
|
-
req.on("error", () => {
|
|
522
|
-
// Keine Log-Warnung mehr
|
|
523
|
-
});
|
|
524
|
-
|
|
525
|
-
req.on("timeout", () => {
|
|
526
|
-
req.destroy();
|
|
527
|
-
// Keine Log-Warnung mehr
|
|
528
|
-
});
|
|
529
|
-
|
|
530
|
-
req.end();
|
|
429
|
+
async fetchConfig() {
|
|
430
|
+
try {
|
|
431
|
+
const data = await httpHelper.makeRequest(this, "/api/config");
|
|
432
|
+
const cfg = JSON.parse(data);
|
|
433
|
+
|
|
434
|
+
const cam = cfg.cam || {};
|
|
435
|
+
const camInfo = {
|
|
436
|
+
width: cam.width ?? 1280,
|
|
437
|
+
height: cam.height ?? 720,
|
|
438
|
+
fps: cam.fps ?? 20,
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
const json = JSON.stringify(camInfo);
|
|
442
|
+
|
|
443
|
+
await this.setStateAsync("system.cam0", { val: json, ack: true });
|
|
444
|
+
await this.setStateAsync("system.cam1", { val: json, ack: true });
|
|
445
|
+
await this.setStateAsync("system.cam2", { val: json, ack: true });
|
|
446
|
+
} catch (error) {
|
|
447
|
+
// Bei Fehler keine Log-Warnung
|
|
448
|
+
if (
|
|
449
|
+
error &&
|
|
450
|
+
typeof error === "object" &&
|
|
451
|
+
typeof error.message === "string" &&
|
|
452
|
+
error.message.includes("JSON")
|
|
453
|
+
) {
|
|
454
|
+
this.log.debug(`Could not parse camera config: ${error.message}`);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
531
457
|
}
|
|
532
458
|
|
|
533
459
|
onUnload(callback) {
|