iobroker.autodarts 0.0.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.
@@ -0,0 +1,132 @@
1
+ {
2
+ "i18n": true,
3
+ "type": "panel",
4
+ "items": {
5
+ "intro": {
6
+ "type": "staticText",
7
+ "text": {
8
+ "en": "Autodarts adapter configuration.<br>Please enter host and port from Boardmanager as well as the polling interval.",
9
+ "de": "Autodarts-Adapterkonfiguration.<br> Bitte gebe die IP und den Port von Boardmanager sowie den Abfrageintervall ein.",
10
+ "ru": "Настройка адаптера Autodarts.<br> Пожалуйста, введите хост и порт из Boardmanager, а также интервал опроса.",
11
+ "pt": "Configuração do adaptador Autodarts.<br> Por favor, insira o host e a porta do Boardmanager, bem como o intervalo de polling.",
12
+ "nl": "Configuratie van de Autodarts-adapter.<br> Voer de host en poort van Boardmanager in, evenals het pollinginterval.",
13
+ "fr": "Configuration de l&#39;adaptateur Autodarts.<br> Veuillez saisir l&#39;hôte et le port depuis Boardmanager ainsi que l&#39;intervalle d&#39;interrogation.",
14
+ "it": "Configurazione dell&#39;adattatore Autodarts.<br> Inserisci l&#39;host e la porta da Boardmanager, nonché l&#39;intervallo di polling.",
15
+ "es": "Configuración del adaptador Autodarts.<br> Ingrese el host y el puerto de Boardmanager, así como el intervalo de sondeo.",
16
+ "pl": "Konfiguracja adaptera Autodarts.<br> Proszę wprowadzić hosta i port z Boardmanager&#39;a, a także interwał odpytywania.",
17
+ "uk": "Конфігурація адаптера Autodarts.<br> Будь ласка, введіть хост і порт з Boardmanager, а також інтервал опитування.",
18
+ "zh-cn": "Autodarts适配器配置。<br>请从 Boardmanager 输入主机和端口以及轮询间隔。"
19
+ },
20
+ "newLine": true,
21
+ "sm": 12,
22
+ "xs": 12,
23
+ "md": 8,
24
+ "lg": 6,
25
+ "xl": 4,
26
+ "style": {
27
+ "border": "1px solid #ccc",
28
+ "borderRadius": "0px",
29
+ "padding": "8px",
30
+ "marginBottom": "10px",
31
+ "textAlign": "center",
32
+ "font-size": "larger"
33
+ }
34
+ },
35
+ "host": {
36
+ "type": "text",
37
+ "label": {
38
+ "en": "Autodarts (Boardmanager) Host / IP",
39
+ "de": "Autodarts (Boardmanager) Host / IP",
40
+ "ru": "Autodarts (Boardmanager) Хост / IP",
41
+ "pt": "Host/IP do Autodarts (Boardmanager)",
42
+ "nl": "Autodarts (Boardmanager) Host / IP",
43
+ "fr": "Hôte/IP d'Autodarts (Boardmanager)",
44
+ "it": "Autodarts (Boardmanager) Host / IP",
45
+ "es": "Host / IP de Autodarts (Boardmanager)",
46
+ "pl": "Autodarts (Boardmanager) Host / IP",
47
+ "uk": "Хост / IP-адреса Autodarts (Boardmanager)",
48
+ "zh-cn": "自动飞镖(棋盘管理器)主机/IP"
49
+ },
50
+ "newLine": true,
51
+ "sm": 12,
52
+ "xs": 12,
53
+ "md": 8,
54
+ "lg": 6,
55
+ "xl": 4
56
+ },
57
+ "port": {
58
+ "type": "number",
59
+ "label": {
60
+ "en": "Autodarts (Boardmanager) Port",
61
+ "de": "Autodarts (Boardmanager) Port",
62
+ "ru": "Порт Autodarts (Boardmanager)",
63
+ "pt": "Autodarts (Boardmanager) Port",
64
+ "nl": "Autodarts (Boardmanager) Port",
65
+ "fr": "Port Autodarts (Boardmanager)",
66
+ "it": "Autodarts (Boardmanager) Port",
67
+ "es": "Puerto de Autodarts (Boardmanager)",
68
+ "pl": "Autodarts (Boardmanager) Port",
69
+ "uk": "Порт Autodarts (менеджер дощок)",
70
+ "zh-cn": "自动飞镖(Boardmanager)端口"
71
+ },
72
+ "newLine": true,
73
+ "sm": 12,
74
+ "xs": 12,
75
+ "md": 8,
76
+ "lg": 6,
77
+ "xl": 4
78
+ },
79
+ "interval": {
80
+ "type": "number",
81
+ "label": {
82
+ "en": "Polling interval (ms)",
83
+ "de": "Abfrageintervall (ms)",
84
+ "ru": "Интервал опроса (мс)",
85
+ "pt": "Intervalo de pesquisa (ms)",
86
+ "nl": "Polling-interval (ms)",
87
+ "fr": "Intervalle d'interrogation (ms)",
88
+ "it": "Intervallo di polling (ms)",
89
+ "es": "Intervalo de sondeo (ms)",
90
+ "pl": "Interwał odpytywania (ms)",
91
+ "uk": "Інтервал опитування (мс)",
92
+ "zh-cn": "轮询间隔(毫秒)"
93
+ },
94
+ "newLine": true,
95
+ "sm": 12,
96
+ "xs": 12,
97
+ "md": 8,
98
+ "lg": 6,
99
+ "xl": 4
100
+ },
101
+ "outro": {
102
+ "type": "staticText",
103
+ "text": {
104
+ "en": "Team inventwo • <a href=\"https://github.com/inventwo\">https://github.com/inventwo</a>",
105
+ "de": "Team inventwo • <a href=\"https://github.com/inventwo\">https://github.com/inventwo</a>",
106
+ "ru": "Команда inventwo • <a href=\"https://github.com/inventwo\">https://github.com/inventwo</a>",
107
+ "pt": "Equipe Inventwo • <a href=\"https://github.com/inventwo\">https://github.com/inventwo</a>",
108
+ "nl": "Team inventwo • <a href=\"https://github.com/inventwo\">https://github.com/inventwo</a>",
109
+ "fr": "Équipe inventwo • <a href=\"https://github.com/inventwo\">https://github.com/inventwo</a>",
110
+ "it": "Team inventwo • <a href=\"https://github.com/inventwo\">https://github.com/inventwo</a>",
111
+ "es": "Equipo invento • <a href=\"https://github.com/inventwo\">https://github.com/inventwo</a>",
112
+ "pl": "Zespół inventwo • <a href=\"https://github.com/inventwo\">https://github.com/inventwo</a>",
113
+ "uk": "Команда inventwo • <a href=\"https://github.com/inventwo\">https://github.com/inventwo</a>",
114
+ "zh-cn": "inventwo 团队 • <a href=\"https://github.com/inventwo\">https://github.com/inventwo</a>"
115
+ },
116
+ "newLine": true,
117
+ "sm": 12,
118
+ "xs": 12,
119
+ "md": 8,
120
+ "lg": 6,
121
+ "xl": 4,
122
+ "style": {
123
+ "border": "1px solid #ccc",
124
+ "borderRadius": "0px",
125
+ "padding": "8px",
126
+ "marginBottom": "10px",
127
+ "textAlign": "center",
128
+ "font-size": "larger"
129
+ }
130
+ }
131
+ }
132
+ }
@@ -0,0 +1,32 @@
1
+ /* You can delete those if you want. I just found them very helpful */
2
+ * {
3
+ box-sizing: border-box
4
+ }
5
+ .m {
6
+ /* Don't cut off dropdowns! */
7
+ overflow: initial;
8
+ }
9
+ .m.adapter-container,
10
+ .m.adapter-container > div.App {
11
+ /* Fix layout/scrolling issues with tabs */
12
+ height: 100%;
13
+ width: 100%;
14
+ position: relative;
15
+ }
16
+ .m .select-wrapper + label {
17
+ /* The positioning for dropdown labels is messed up */
18
+ transform: none !important;
19
+ }
20
+
21
+ label > i[title] {
22
+ /* Display the help cursor for the tooltip icons and fix their positioning */
23
+ cursor: help;
24
+ margin-left: 0.25em;
25
+ }
26
+
27
+ .dropdown-content {
28
+ /* Don't wrap text in dropdowns */
29
+ white-space: nowrap;
30
+ }
31
+
32
+ /* Add your styles here */
@@ -0,0 +1,104 @@
1
+ {
2
+ "common": {
3
+ "name": "autodarts",
4
+ "version": "0.0.2",
5
+ "news": {
6
+ "0.0.2": {
7
+ "en": "initial release",
8
+ "de": "erstausstrahlung",
9
+ "ru": "первоначальное освобождение",
10
+ "pt": "libertação inicial",
11
+ "nl": "eerste release",
12
+ "fr": "libération initiale",
13
+ "it": "rilascio iniziale",
14
+ "es": "liberación inicial",
15
+ "pl": "początkowe zwolnienie",
16
+ "uk": "початковий реліз",
17
+ "zh-cn": "初步释放"
18
+ },
19
+ "0.0.1": {
20
+ "en": "Initial release",
21
+ "de": "Erstveröffentlichung",
22
+ "ru": "Первый релиз",
23
+ "pt": "Lançamento inicial",
24
+ "nl": "Eerste release",
25
+ "fr": "Version initiale",
26
+ "it": "Versione iniziale",
27
+ "es": "Lanzamiento inicial",
28
+ "pl": "Pierwsze wydanie",
29
+ "uk": "Початковий випуск",
30
+ "zh-cn": "初始版本"
31
+ }
32
+ },
33
+ "titleLang": {
34
+ "en": "Autodarts Integration",
35
+ "de": "Autodarts-Integration",
36
+ "ru": "Интеграция Autodarts",
37
+ "pt": "Integração com Autodarts",
38
+ "nl": "AutoDART-integratie",
39
+ "fr": "Intégration d'Autodarts",
40
+ "it": "Integrazione Autodarts",
41
+ "es": "Integración de Autodarts",
42
+ "pl": "Integracja Autodarts",
43
+ "uk": "Інтеграція з AutoDarts",
44
+ "zh-cn": "Autodarts 集成"
45
+ },
46
+ "desc": {
47
+ "en": "Autodarts Autoscoring via API",
48
+ "de": "Autodarts-Autoscoring über API",
49
+ "ru": "Автоматическая подсчет очков в Autodarts через API",
50
+ "pt": "Autodarts Autoscoring via API",
51
+ "nl": "AutoDarts automatische scoreberekening via API",
52
+ "fr": "Autodarts : système de notation automatique via API",
53
+ "it": "Punteggio automatico di Autodarts tramite API",
54
+ "es": "Puntuación automática de Autodarts mediante API",
55
+ "pl": "Autoscore w Autodarts za pośrednictwem API",
56
+ "uk": "Автопідрахунок очок Autodarts через API",
57
+ "zh-cn": "通过 API 实现自动计分"
58
+ },
59
+ "authors": [
60
+ "skvarel <skvarel@inventwo.com>"
61
+ ],
62
+ "keywords": [
63
+ "dart",
64
+ "scoring",
65
+ "autodarts"
66
+ ],
67
+ "licenseInformation": {
68
+ "type": "free",
69
+ "license": "MIT"
70
+ },
71
+ "platform": "Javascript/Node.js",
72
+ "icon": "autodarts.svg",
73
+ "extIcon": "https://raw.githubusercontent.com/inventwo/ioBroker.autodarts/main/admin/autodarts.svg",
74
+ "enabled": true,
75
+ "loglevel": "info",
76
+ "mode": "daemon",
77
+ "tier": 3,
78
+ "type": "protocols",
79
+ "compact": true,
80
+ "connectionType": "local",
81
+ "dataSource": "poll",
82
+ "adminUI": {
83
+ "config": "json"
84
+ },
85
+ "eraseOnUpload": true,
86
+ "dependencies": [
87
+ {
88
+ "js-controller": ">=6.0.11"
89
+ }
90
+ ],
91
+ "globalDependencies": [
92
+ {
93
+ "admin": ">=7.0.23"
94
+ }
95
+ ]
96
+ },
97
+ "native": {
98
+ "host": "127.0.0.1",
99
+ "port": 3180,
100
+ "interval": 2000
101
+ },
102
+ "objects": [],
103
+ "instanceObjects": []
104
+ }
@@ -0,0 +1,19 @@
1
+ // This file extends the AdapterConfig type from "@iobroker/types"
2
+ // using the actual properties present in io-package.json
3
+ // in order to provide typings for adapter.config properties
4
+
5
+ import { native } from "../io-package.json";
6
+
7
+ type _AdapterConfig = typeof native;
8
+
9
+ // Augment the globally declared type ioBroker.AdapterConfig
10
+ declare global {
11
+ namespace ioBroker {
12
+ interface AdapterConfig extends _AdapterConfig {
13
+ // Do not enter anything here!
14
+ }
15
+ }
16
+ }
17
+
18
+ // this is required so the above AdapterConfig is found by TypeScript / type checking
19
+ export {};
package/main.js ADDED
@@ -0,0 +1,196 @@
1
+ "use strict";
2
+
3
+ const utils = require("@iobroker/adapter-core");
4
+ const http = require("http");
5
+
6
+ class Autodarts extends utils.Adapter {
7
+ constructor(options) {
8
+ super({
9
+ ...options,
10
+ name: "autodarts",
11
+ });
12
+
13
+ this.on("ready", this.onReady.bind(this));
14
+ this.on("unload", this.onUnload.bind(this));
15
+
16
+ this.pollTimer = null;
17
+ this.lastThrowsCount = 0; // Anzahl Darts im aktuellen Visit
18
+ this.lastSignature = ""; // Verhindert doppelte Verarbeitung gleicher Würfe
19
+ this.offline = false;
20
+ }
21
+
22
+ async onReady() {
23
+ this.log.info("Autodarts adapter started");
24
+
25
+ // Defaults aus io-package.json absichern
26
+ this.config.host ??= "127.0.0.1";
27
+ this.config.port ??= 3180;
28
+ this.config.interval ??= 2000;
29
+
30
+ // Visit-Struktur anlegen
31
+ await this.setObjectNotExistsAsync("visit", {
32
+ type: "channel",
33
+ common: { name: "Current visit" },
34
+ native: {},
35
+ });
36
+
37
+ await this.setObjectNotExistsAsync("visit.score", {
38
+ type: "state",
39
+ common: {
40
+ name: {
41
+ en: "Visit score (Total of 3 darts)",
42
+ de: "Visit-Punkte (Summe der 3 Darts)",
43
+ },
44
+ type: "number",
45
+ role: "value",
46
+ read: true,
47
+ write: false,
48
+ desc: {
49
+ en: "Total of the last complete visit",
50
+ de: "Summe des letzten vollständigen Visit",
51
+ },
52
+ },
53
+ native: {},
54
+ });
55
+
56
+ // Online-Datenpunkt
57
+ await this.setObjectNotExistsAsync("online", {
58
+ type: "state",
59
+ common: {
60
+ name: {
61
+ en: "Autodarts Board online",
62
+ de: "Autodarts Board online",
63
+ },
64
+ type: "boolean",
65
+ role: "indicator.reachable",
66
+ read: true,
67
+ write: false,
68
+ desc: {
69
+ en: "true = Board reachable, false = not reachable",
70
+ de: "true = Board erreichbar, false = nicht erreichbar",
71
+ },
72
+ },
73
+ native: {},
74
+ });
75
+
76
+ // Zustand zurücksetzen
77
+ this.lastThrowsCount = 0;
78
+ this.lastSignature = "";
79
+
80
+ // Polling starten
81
+ this.pollTimer = setInterval(() => this.fetchState(), this.config.interval);
82
+ this.fetchState();
83
+ }
84
+
85
+ /**
86
+ * Punkte eines Dart berechnen
87
+ *
88
+ * @param {object} dart - Ein Dart-Objekt aus Autodarts throws
89
+ * @returns {number} Punkte
90
+ */
91
+ calcScore(dart) {
92
+ if (!dart?.segment) {
93
+ return 0;
94
+ }
95
+ return (dart.segment.number || 0) * (dart.segment.multiplier || 0);
96
+ }
97
+
98
+ /**
99
+ * Autodarts API abfragen und Visit-Summe schreiben
100
+ */
101
+ fetchState() {
102
+ const options = {
103
+ host: this.config.host,
104
+ port: this.config.port,
105
+ path: "/api/state",
106
+ method: "GET",
107
+ timeout: 1500,
108
+ };
109
+
110
+ const req = http.request(options, res => {
111
+ let data = "";
112
+
113
+ res.on("data", chunk => (data += chunk));
114
+ res.on("end", () => {
115
+ this.offline = false;
116
+ this.setState("online", true, true); // Server erreichbar
117
+
118
+ try {
119
+ const state = JSON.parse(data);
120
+
121
+ // Nur weiter, wenn throws existieren, Array ist und nicht leer
122
+ if (!state.throws || !Array.isArray(state.throws) || state.throws.length === 0) {
123
+ return;
124
+ }
125
+
126
+ const currentThrows = state.throws;
127
+ const currentCount = currentThrows.length;
128
+
129
+ // Prüfen, ob sich die Würfe geändert haben
130
+ const signature = JSON.stringify(
131
+ currentThrows.map(d => ({
132
+ name: d.segment?.name || "",
133
+ mult: d.segment?.multiplier || 0,
134
+ })),
135
+ );
136
+
137
+ if (signature === this.lastSignature) {
138
+ return;
139
+ }
140
+ this.lastSignature = signature;
141
+
142
+ // Nur schreiben, wenn:
143
+ // - genau 3 Darts geworfen wurden
144
+ // - vorher weniger als 3 waren (Visit gerade abgeschlossen)
145
+ if (currentCount === 3 && this.lastThrowsCount < 3) {
146
+ const lastThrows = currentThrows.slice(-3);
147
+ const visitSum = lastThrows.reduce((sum, dart) => sum + this.calcScore(dart), 0);
148
+
149
+ // WICHTIG: Immer schreiben, auch wenn Wert gleich bleibt
150
+ this.setState("visit.score", { val: visitSum, ack: true });
151
+ }
152
+
153
+ // Zustand speichern
154
+ this.lastThrowsCount = currentCount;
155
+ } catch (e) {
156
+ this.log.warn(`Autodarts API Fehler: ${e.message} | Daten: ${data.substring(0, 200)}...`);
157
+ // Bei JSON-Fehler: Board war erreichbar, aber Antwort kaputt
158
+ this.setState("online", true, true);
159
+ }
160
+ });
161
+ });
162
+
163
+ req.on("error", () => {
164
+ if (!this.offline) {
165
+ this.log.warn("Autodarts not reachable");
166
+ this.offline = true;
167
+ }
168
+ this.setState("online", false, true); // Server offline
169
+ });
170
+
171
+ req.on("timeout", () => {
172
+ req.destroy();
173
+ this.setState("online", false, true); // Server offline bei Timeout
174
+ });
175
+
176
+ req.end();
177
+ }
178
+
179
+ onUnload(callback) {
180
+ try {
181
+ if (this.pollTimer) {
182
+ clearInterval(this.pollTimer);
183
+ }
184
+ callback();
185
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
186
+ } catch (e) {
187
+ callback();
188
+ }
189
+ }
190
+ }
191
+
192
+ if (require.main !== module) {
193
+ module.exports = options => new Autodarts(options);
194
+ } else {
195
+ new Autodarts();
196
+ }
package/package.json ADDED
@@ -0,0 +1,89 @@
1
+ {
2
+ "name": "iobroker.autodarts",
3
+ "version": "0.0.2",
4
+ "description": "Autodarts Autoscoring",
5
+ "author": "skvarel <skvarel@inventwo.com>",
6
+ "contributors": [
7
+ {
8
+ "name": "jkvarel",
9
+ "email": "jkvarel@inventwo.com"
10
+ },
11
+ {
12
+ "name": "skvarel",
13
+ "email": "skvarel@inventwo.com"
14
+ }
15
+ ],
16
+ "homepage": "https://github.com/inventwo/ioBroker.autodarts",
17
+ "license": "MIT",
18
+ "keywords": [
19
+ "dart",
20
+ "scoring"
21
+ ],
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/inventwo/ioBroker.autodarts.git"
25
+ },
26
+ "engines": {
27
+ "node": ">= 20"
28
+ },
29
+ "dependencies": {
30
+ "@iobroker/adapter-core": "^3.3.2"
31
+ },
32
+ "devDependencies": {
33
+ "@alcalzone/release-script": "^5.0.0",
34
+ "@alcalzone/release-script-plugin-iobroker": "^4.0.0",
35
+ "@alcalzone/release-script-plugin-license": "^4.0.0",
36
+ "@alcalzone/release-script-plugin-manual-review": "^4.0.0",
37
+ "@iobroker/adapter-dev": "^1.5.0",
38
+ "@iobroker/adapter-react": "2.0.22",
39
+ "@iobroker/dev-server": "^0.8.0",
40
+ "@iobroker/eslint-config": "^2.2.0",
41
+ "@iobroker/testing": "^5.2.2",
42
+ "@material-ui/core": "^4.12.4",
43
+ "@tsconfig/node20": "^20.1.8",
44
+ "@types/iobroker": "npm:@iobroker/types@^7.1.0",
45
+ "@types/node": "^20.19.27",
46
+ "@types/react": "^17.0.90",
47
+ "@types/react-dom": "^17.0.26",
48
+ "react": "^17.0.2",
49
+ "react-dom": "^17.0.2",
50
+ "typescript": "~5.9.3"
51
+ },
52
+ "main": "main.js",
53
+ "files": [
54
+ "admin{,/!(src)/**}/!(tsconfig|tsconfig.*|.eslintrc).{json,json5}",
55
+ "admin{,/!(src)/**}/*.{html,css,png,svg,jpg,js}",
56
+ "admin/build/",
57
+ "lib/",
58
+ "www/",
59
+ "io-package.json",
60
+ "LICENSE",
61
+ "main.js"
62
+ ],
63
+ "scripts": {
64
+ "release-patch": "release-script patch --yes",
65
+ "release-minor": "release-script minor --yes",
66
+ "release-major": "release-script major --yes",
67
+ "prebuild": "rimraf admin/build",
68
+ "build": "build-adapter react",
69
+ "watch": "build-adapter react --watch",
70
+ "prebuild:react": "rimraf admin/build",
71
+ "build:react": "build-adapter react",
72
+ "watch:react": "build-adapter react --watch",
73
+ "test:js": "mocha --config test/mocharc.custom.json \"{!(node_modules|test)/**/*.test.js,*.test.js,test/**/test!(PackageFiles|Startup).js}\"",
74
+ "test:package": "mocha test/package --exit",
75
+ "test:integration": "mocha test/integration --exit",
76
+ "test": "npm run test:js && npm run test:package",
77
+ "check": "tsc --noEmit -p tsconfig.check.json",
78
+ "lint": "eslint -c eslint.config.mjs .",
79
+ "translate": "translate-adapter",
80
+ "dev-server": "dev-server"
81
+ },
82
+ "bugs": {
83
+ "url": "https://github.com/skvarel/ioBroker.autodarts/issues"
84
+ },
85
+ "directories": {
86
+ "lib": "lib",
87
+ "test": "test"
88
+ }
89
+ }