iobroker.fakeroku 0.3.0 → 0.5.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.
@@ -1,18 +1,29 @@
1
+ # Dependabot configuration
2
+ # Cooldown delays updating normal npm dependencies by 7 days but allows security updates to be processed immediately.
3
+ # Note: Cooldown is not supported for the github-actions ecosystem.
4
+ # Reference: https://docs.github.com/en/code-security/reference/supply-chain-security/dependabot-options-reference
1
5
  version: 2
2
6
  updates:
3
- - package-ecosystem: npm
4
- directory: "/"
7
+
8
+ - package-ecosystem: 'npm'
9
+ directory: '/'
5
10
  schedule:
6
- interval: monthly
7
- time: "04:00"
8
- timezone: Europe/Berlin
11
+ interval: 'cron'
12
+ timezone: 'Europe/Berlin'
13
+ cronjob: '55 3 20 * *'
9
14
  open-pull-requests-limit: 15
10
- versioning-strategy: increase
15
+ versioning-strategy: 'increase'
16
+ cooldown:
17
+ default-days: 7
18
+ ignore:
19
+ - dependency-name: '@types/node'
20
+ update-types:
21
+ - 'version-update:semver-major'
11
22
 
12
- - package-ecosystem: github-actions
13
- directory: "/"
23
+ - package-ecosystem: 'github-actions'
24
+ directory: '/'
14
25
  schedule:
15
- interval: monthly
16
- time: "04:00"
17
- timezone: Europe/Berlin
26
+ interval: 'cron'
27
+ timezone: 'Europe/Berlin'
28
+ cronjob: '55 3 20 * *'
18
29
  open-pull-requests-limit: 15
@@ -0,0 +1,35 @@
1
+ # Workflow for auto-merging Dependabot PRs
2
+ # This workflow uses the action-automerge-dependabot action to automatically merge
3
+ # Dependabot PRs based on the rules defined in .github/auto-merge.yml
4
+
5
+ name: Auto-Merge Dependabot PRs
6
+
7
+ on:
8
+ # Trigger when a PR is opened or updated
9
+ # WARNING: This needs to be run in the PR base, DO NOT build untrusted code in this action
10
+ pull_request_target:
11
+ types: [opened, synchronize, reopened]
12
+
13
+ jobs:
14
+ auto-merge:
15
+ runs-on: ubuntu-latest
16
+ # Only run if actor is dependabot
17
+ if: github.actor == 'dependabot[bot]'
18
+
19
+ permissions:
20
+ contents: write
21
+ pull-requests: write
22
+
23
+ steps:
24
+ - name: Auto-merge Dependabot PRs
25
+ uses: iobroker-bot-orga/action-automerge-dependabot@v1
26
+ with:
27
+ github-token: ${{ secrets.GITHUB_TOKEN }}
28
+ # Optional: Path to your auto-merge configuration file
29
+ # config-file-path: '.github/auto-merge.yml'
30
+ # Optional: Merge method (merge, squash, or rebase)
31
+ # merge-method: 'squash'
32
+ # Optional: Wait for other checks to complete
33
+ # wait-for-checks: 'true'
34
+ # Optional: Maximum time to wait for checks in seconds (default: 3600)
35
+ # max-wait-time: '3600'
@@ -0,0 +1,25 @@
1
+ # Workflow for auto-merging ioBroker-Bot PRs
2
+ # This workflow uses the action-automerge-iobroker-bot action to automatically merge
3
+ # PRs created by ioBroker-Bot if all required checks pass successfully.
4
+
5
+ name: Auto-Merge ioBroker-Bot PRs
6
+
7
+ on:
8
+ pull_request_target:
9
+ types: [opened, synchronize, reopened, edited]
10
+
11
+ jobs:
12
+ auto-merge:
13
+ runs-on: ubuntu-latest
14
+ if: github.actor == 'ioBroker-Bot'
15
+
16
+ permissions:
17
+ contents: write
18
+ pull-requests: write
19
+
20
+ steps:
21
+ - name: Auto-merge ioBroker-Bot PRs
22
+ uses: iobroker-bot-orga/action-automerge-iobroker-bot@v1
23
+ with:
24
+ github-token: ${{ secrets.AUTO_MERGE_TOKEN_IOBROKER_BOT }}
25
+ pull-request-ref: ${{ github.event.pull_request.number }}
@@ -26,9 +26,9 @@ jobs:
26
26
  runs-on: ubuntu-latest
27
27
 
28
28
  steps:
29
- - uses: ioBroker/testing-action-check@v1
29
+ - uses: ioBroker/testing-action-check@v2
30
30
  with:
31
- node-version: '20.x'
31
+ node-version: '24.x'
32
32
  # Uncomment the following line if your adapter cannot be installed using 'npm ci'
33
33
  # install-command: 'npm install'
34
34
  lint: false
@@ -36,12 +36,13 @@ jobs:
36
36
 
37
37
  # Runs adapter tests on all supported node versions and OSes
38
38
  adapter-tests:
39
+ needs: [check-and-lint]
39
40
  if: contains(github.event.head_commit.message, '[skip ci]') == false
40
41
 
41
42
  runs-on: ${{ matrix.os }}
42
43
  strategy:
43
44
  matrix:
44
- node-version: [18.x, 20.x]
45
+ node-version: [22.x, 24.x]
45
46
  os: [ubuntu-latest, windows-latest, macos-latest]
46
47
 
47
48
  steps:
@@ -71,14 +72,15 @@ jobs:
71
72
  # Write permissions are required to create Github releases
72
73
  permissions:
73
74
  contents: write
75
+ id-token: write
74
76
 
75
77
  steps:
76
78
  - uses: ioBroker/testing-action-deploy@v1
77
79
  with:
78
- node-version: '20.x'
80
+ node-version: '24.x'
79
81
  # Uncomment the following line if your adapter cannot be installed using 'npm ci'
80
82
  # install-command: 'npm install'
81
- npm-token: ${{ secrets.NPM_TOKEN }}
83
+ # npm-token: ${{ secrets.NPM_TOKEN }} # Commented out for migration to Trusted Publishing
82
84
  github-token: ${{ secrets.GITHUB_TOKEN }}
83
85
 
84
86
  # When using Sentry for error reporting, Sentry can be informed about new releases
@@ -0,0 +1,9 @@
1
+ # Older changes
2
+ ## 0.2.0
3
+ (Pmant) run multiple fakeroku's in one instance
4
+
5
+ ## 0.1.1
6
+ (Pmant) fix package.json
7
+
8
+ ## 0.1.0
9
+ (Pmant) initial release
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2024 iobroker-community-adapters <iobroker-community-adapters@gmx.de>
3
+ Copyright (c) 2024-2026 iobroker-community-adapters <iobroker-community-adapters@gmx.de>
4
4
  Copyright (c) 2017 Pmant
5
5
 
6
6
  Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -19,4 +19,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
19
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
20
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
21
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
- THE SOFTWARE.
22
+ THE SOFTWARE.
package/README.md CHANGED
@@ -30,6 +30,16 @@ States are automatically created when fakeRoku receives a key for the first time
30
30
  Placeholder for the next version (at the beginning of the line):
31
31
  ### __WORK IN PROGRESS__
32
32
  -->
33
+ ### 0.5.1 (2026-08-05)
34
+ - (copilot) Adapter requires node.js >= 22 now
35
+ * (mcm1957) Dependencies have been updated
36
+
37
+ ### 0.4.0 (2026-03-07)
38
+ - (iobroker-bot) Adapter requires node.js >= 20 now.
39
+ - (copilot) Adapter requires admin >= 7.7.22 now
40
+ - (copilot) Adapter requires js-controller >= 6.0.11 now
41
+ - (mcm1957) Dependencies have been updated
42
+
33
43
  ### 0.3.0 (2024-06-11)
34
44
  * (mcm1957) Adapter requires node.js >= 18 and js-controller >= 5 now
35
45
  * (mcm1957) Dependencies have been updated
@@ -41,19 +51,13 @@ States are automatically created when fakeRoku receives a key for the first time
41
51
  (Pmant) fix jQuery error in admin
42
52
  (ykuendig) add translations
43
53
 
44
- ### 0.2.0
45
- (Pmant) run multiple fakeroku's in one instance
46
-
47
- ### 0.1.1
48
- (Pmant) fix package.json
49
54
 
50
- ### 0.1.0
51
- (Pmant) initial release
55
+ [Older changelogs can be found there](CHANGELOG_OLD.md)
52
56
 
53
57
  ## License
54
58
  The MIT License (MIT)
55
59
 
56
- Copyright (c) 2024 iobroker-community-adapters <iobroker-community-adapters@gmx.de>
60
+ Copyright (c) 2024-2026 iobroker-community-adapters <iobroker-community-adapters@gmx.de>
57
61
  Copyright (c) 2017 Pmant
58
62
 
59
63
  Permission is hereby granted, free of charge, to any person obtaining a copy
package/io-package.json CHANGED
@@ -1,8 +1,47 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "fakeroku",
4
- "version": "0.3.0",
4
+ "version": "0.5.1",
5
5
  "news": {
6
+ "0.5.1": {
7
+ "en": "Adapter requires node.js >= 22 now\nDependencies have been updated",
8
+ "de": "Der Adapter benötigt jetzt Node.js >= 22.\nDie Abhängigkeiten wurden aktualisiert.",
9
+ "ru": "Для работы адаптера требуется Node.js версии >= 22.\nЗависимости обновлены.",
10
+ "pt": "O adaptador agora requer Node.js >= 22.\nAs dependências foram atualizadas.",
11
+ "nl": "De adapter vereist nu Node.js versie 22 of hoger.\nAfhankelijkheden zijn bijgewerkt.",
12
+ "fr": "L'adaptateur nécessite désormais Node.js >= 22.\nLes dépendances ont été mises à jour",
13
+ "it": "L'adattatore ora richiede Node.js >= 22\nLe dipendenze sono state aggiornate",
14
+ "es": "El adaptador ahora requiere node.js >= 22.\nSe han actualizado las dependencias.",
15
+ "pl": "Adapter wymaga teraz node.js >= 22\nZaktualizowano zależności",
16
+ "uk": "Адаптер тепер вимагає node.js >= 22\nЗалежності оновлено",
17
+ "zh-cn": "适配器现在需要 node.js 版本 >= 22。\n依赖项已更新"
18
+ },
19
+ "0.5.0": {
20
+ "en": "Adapter requires node.js >= 22 now\nDependencies have been updated",
21
+ "de": "Der Adapter benötigt jetzt Node.js >= 22.\nDie Abhängigkeiten wurden aktualisiert.",
22
+ "ru": "Для работы адаптера требуется Node.js версии >= 22.\nЗависимости обновлены.",
23
+ "pt": "O adaptador agora requer Node.js >= 22.\nAs dependências foram atualizadas.",
24
+ "nl": "De adapter vereist nu Node.js versie 22 of hoger.\nAfhankelijkheden zijn bijgewerkt.",
25
+ "fr": "L'adaptateur nécessite désormais Node.js >= 22.\nLes dépendances ont été mises à jour",
26
+ "it": "L'adattatore ora richiede Node.js >= 22\nLe dipendenze sono state aggiornate",
27
+ "es": "El adaptador ahora requiere node.js >= 22.\nSe han actualizado las dependencias.",
28
+ "pl": "Adapter wymaga teraz node.js >= 22\nZaktualizowano zależności",
29
+ "uk": "Адаптер тепер вимагає node.js >= 22\nЗалежності оновлено",
30
+ "zh-cn": "适配器现在需要 node.js 版本 >= 22。\n依赖项已更新"
31
+ },
32
+ "0.4.0": {
33
+ "en": "Adapter requires node.js >= 20 now.\nAdapter requires admin >= 7.7.22 now\nAdapter requires js-controller >= 6.0.11 now\nDependencies have been updated",
34
+ "de": "Adapter benötigt jetzt node.js >= 20.\nAdapter benötigt admin >= 7.7.22 jetzt\nAdapter benötigt jetzt js-controller >= 6.0.11\nAbhängigkeiten wurden aktualisiert",
35
+ "ru": "Адаптер требует node.js >= 20 сейчас.\nАдаптер требует администратора >= 7.7.22\nАдаптер требует js-контроллер >= 6.0.11\nЗависимости были обновлены",
36
+ "pt": "O adaptador requer gnod.js >= 20 agora.\nAdaptador requer admin >= 7.7.22 agora\nAdaptador requer js-controlador >= 6.0.11 agora\nAs dependências foram atualizadas",
37
+ "nl": "Voor de adapter zijn node.js < 20 nu nodig.\nAdapter vereist admin < 7.7.22 nu\nAdapter vereist js-controller > 6,0.11 nu\nAfhankelijkheden zijn bijgewerkt",
38
+ "fr": "Adaptateur nécessite node.js >= 20 maintenant.\nAdaptateur nécessite admin >= 7.7.22 maintenant\nAdaptateur nécessite js-controller >= 6.0.11 maintenant\nLes dépendances ont été actualisées",
39
+ "it": "Adattatore richiede node.js >= 20 ora.\nAdattatore richiede admin >= 7.7.22 ora\nAdattatore richiede js-controller >= 6.0.11 ora\nLe dipendenze sono state aggiornate",
40
+ "es": "Adaptador requiere node.js >= 20 ahora.\nEl adaptador requiere admin= 7.7.22 ahora\nAdaptador requiere js-controller >= 6.0.11\nSe han actualizado las dependencias",
41
+ "pl": "Adapter wymaga node.js > = 20 teraz.\nAdapter wymaga admin > = 7.7.22\nAdapter wymaga sterownika js- > = 6.0.11\nZaktualizowano zależności",
42
+ "uk": "Адаптер вимагає node.js >= 20 тепер.\nАдаптер вимагає адмін >= 7.7.22 тепер\nАдаптер вимагає js-controller >=6.0.11 тепер\nЗалежність було оновлено",
43
+ "zh-cn": "适配器需要节点.js >= 20 现在.\n适任者需要管理员 \\ 7.7.22 现在\n适配器需要js控制器 现在6.0.11\n依赖关系已更新"
44
+ },
6
45
  "0.3.0": {
7
46
  "en": "Adapter requires node.js >= 18 and js-controller >= 5 now\nDependencies have been updated",
8
47
  "de": "Adapter benötigt node.js >= 18 und js-controller >= 5 jetzt\nAbhängigkeiten wurden aktualisiert",
@@ -45,17 +84,15 @@
45
84
  "0.2.0": {
46
85
  "en": "emulate multiple rokus",
47
86
  "de": "emuliere mehrere rokus",
48
- "ru": "emulate multiple rokus"
49
- },
50
- "0.1.1": {
51
- "en": "fix package.json",
52
- "de": "fix package.json",
53
- "ru": "fix package.json"
54
- },
55
- "0.1.0": {
56
- "en": "first version",
57
- "de": "erste Version",
58
- "ru": "first version"
87
+ "ru": "emulate multiple rokus",
88
+ "pt": "emular vários rokus",
89
+ "nl": "meerdere roku's emuleren",
90
+ "fr": "émuler plusieurs rokus",
91
+ "it": "emulare più roku",
92
+ "es": "emular múltiples rokus",
93
+ "pl": "emulować wiele roku",
94
+ "uk": "емулювати кілька rokus",
95
+ "zh-cn": "模拟多个 roku"
59
96
  }
60
97
  },
61
98
  "titleLang": {
@@ -74,7 +111,15 @@
74
111
  "desc": {
75
112
  "en": "Adapter emulates Roku-Devices to Harmony Hub",
76
113
  "de": "Adapter simuliert Roku-Geräte für den Harmony Hub",
77
- "ru": "ioBroker fakeroku драйвер как образец"
114
+ "ru": "ioBroker fakeroku драйвер как образец",
115
+ "pt": "Adaptador emula dispositivos Roku para Harmony Hub",
116
+ "nl": "Adapter emuleert Roku-apparaten naar Harmony Hub",
117
+ "fr": "L'adaptateur émule les appareils Roku vers Harmony Hub",
118
+ "it": "L'adattatore emula i dispositivi Roku su Harmony Hub",
119
+ "es": "El adaptador emula dispositivos Roku a Harmony Hub",
120
+ "pl": "Adapter emuluje urządzenia Roku do Harmony Hub",
121
+ "uk": "Адаптер емулює Roku-Devices до Harmony Hub",
122
+ "zh-cn": "适配器模拟 Roku-Devices 到 Harmony Hub"
78
123
  },
79
124
  "keywords": [
80
125
  "fakeroku",
@@ -91,23 +136,30 @@
91
136
  "readme": "https://github.com/iobroker-community-adapters/ioBroker.fakeroku/blob/master/README.md",
92
137
  "loglevel": "info",
93
138
  "tier": 2,
139
+ "compact": false,
140
+ "connectionType": "local",
141
+ "dataSource": "poll",
94
142
  "type": "multimedia",
95
143
  "enabled": true,
96
144
  "authors": [
97
- "Pmant <patrickmo@gmx.de>"
145
+ "Pmant <patrickmo@gmx.de>",
146
+ "iobroker-community-adapters <iobroker-community-adapters@gmx.de>"
98
147
  ],
99
148
  "restartAdapters": [],
100
149
  "singletonHost": true,
101
150
  "dependencies": [
102
151
  {
103
- "js-controller": ">=5.0.19"
152
+ "js-controller": ">=6.0.11"
104
153
  }
105
154
  ],
106
155
  "globalDependencies": [
107
156
  {
108
- "admin": ">=6.13.16"
157
+ "admin": ">=7.7.22"
109
158
  }
110
- ]
159
+ ],
160
+ "adminUI": {
161
+ "config": "html"
162
+ }
111
163
  },
112
164
  "native": {
113
165
  "MULTICAST_IP": "239.255.255.250",
package/main.js CHANGED
@@ -1,9 +1,9 @@
1
- /* jshint -W097 */// jshint strict:false
1
+ /* jshint -W097 */ // jshint strict:false
2
2
  /*jslint node: true */
3
- "use strict";
3
+ 'use strict';
4
4
 
5
- var dgram = require('dgram');
6
- var http = require('http');
5
+ var dgram = require('node:dgram');
6
+ var http = require('node:http');
7
7
  var httpHeaders = require('http-headers');
8
8
 
9
9
  var utils = require('@iobroker/adapter-core'); // Get common adapter utils
@@ -25,7 +25,7 @@ adapter.on('unload', function (callback) {
25
25
  stopServer(devArray[j]);
26
26
  }
27
27
  callback();
28
- } catch (e) {
28
+ } catch {
29
29
  callback();
30
30
  }
31
31
  });
@@ -35,17 +35,17 @@ adapter.on('ready', function () {
35
35
  });
36
36
 
37
37
  function init() {
38
- MULTICAST_IP = adapter.config.MULTICAST_IP || "239.255.255.250";
39
- BIND = adapter.config.BIND || "0.0.0.0";
38
+ MULTICAST_IP = adapter.config.MULTICAST_IP || '239.255.255.250';
39
+ BIND = adapter.config.BIND || '0.0.0.0';
40
40
 
41
41
  for (var i = 0; i < adapter.config.devices.length; i++) {
42
42
  var dev = adapter.config.devices[i];
43
43
  var UUID = dev.uuid || genUUID(dev.name);
44
44
  var HTTP_PORT = Math.min(65535, Math.max(0, parseInt(dev.port, 10) || 9093));
45
45
  var SSDP_RESPONSE = new Buffer(
46
- "HTTP/1.1 200 OK\r\nCache-Control: max-age=300\r\nST: roku:ecp\r\nUSN: uuid:roku:ecp:" +
47
- UUID + "\r\nExt: \r\nServer: Roku UPnP/1.0 MiniUPnPd/1.4\r\nLOCATION: http://" +
48
- BIND + ":" + HTTP_PORT + "/\r\n\r\n"
46
+ `HTTP/1.1 200 OK\r\nCache-Control: max-age=300\r\nST: roku:ecp\r\nUSN: uuid:roku:ecp:${
47
+ UUID
48
+ }\r\nExt: \r\nServer: Roku UPnP/1.0 MiniUPnPd/1.4\r\nLOCATION: http://${BIND}:${HTTP_PORT}/\r\n\r\n`,
49
49
  );
50
50
  var DESCXML = `<?xml version="1.0" encoding="UTF-8" ?>
51
51
  <root xmlns="urn:schemas-upnp-org:device-1-0">
@@ -96,7 +96,7 @@ function init() {
96
96
  APPSXML: APPSXML,
97
97
  server: null,
98
98
  objects: [],
99
- sync: false
99
+ sync: false,
100
100
  };
101
101
  devArray.push(dev.name.replace(/[.\s]+/g, '_'));
102
102
  }
@@ -105,11 +105,16 @@ function init() {
105
105
  for (let d = 0; d < devs.length; d++) {
106
106
  //delete old device
107
107
  if (!devices[devs[d].common.name]) {
108
- adapter.deleteDevice(devs[d].common.name);
109
- adapter.log.debug('deleting old device ' + devs[d]._id);
108
+ adapter.delObject(devs[d]._id, { recursive: true }, function (err) {
109
+ if (err) {
110
+ adapter.log.warn(`Error deleting device ${devs[d]._id}: ${err}`);
111
+ } else {
112
+ adapter.log.debug(`deleting old device ${devs[d]._id}`);
113
+ }
114
+ });
110
115
  } else {
111
116
  devices[devs[d].common.name].sync = true;
112
- adapter.log.debug('found device ' + devs[d]._id);
117
+ adapter.log.debug(`found device ${devs[d]._id}`);
113
118
  }
114
119
  }
115
120
 
@@ -139,15 +144,37 @@ function init() {
139
144
  }
140
145
 
141
146
  function createDevice(device, last) {
142
- adapter.log.debug("creating device: " + device);
143
- adapter.createDevice(device, {name: device}, function () {
144
- adapter.log.debug("creating channels for " + device);
145
- adapter.createChannel(device, 'keys', {name: 'keys'}, function () {
146
- adapter.createChannel(device, 'apps', {name: 'apps'}, function () {
147
- devices[device].sync = true;
148
- if (last) main();
149
- });
150
- });
147
+ adapter.log.debug(`creating device: ${device}`);
148
+ adapter.setObjectNotExists(device, { type: 'device', common: { name: device }, native: {} }, function (err) {
149
+ if (err) {
150
+ adapter.log.warn(`Error creating device ${device}: ${err}`);
151
+ return;
152
+ }
153
+ adapter.log.debug(`creating channels for ${device}`);
154
+ adapter.setObjectNotExists(
155
+ `${device}.keys`,
156
+ { type: 'channel', common: { name: 'keys' }, native: {} },
157
+ function (err) {
158
+ if (err) {
159
+ adapter.log.warn(`Error creating channel ${device}.keys: ${err}`);
160
+ return;
161
+ }
162
+ adapter.setObjectNotExists(
163
+ `${device}.apps`,
164
+ { type: 'channel', common: { name: 'apps' }, native: {} },
165
+ function (err) {
166
+ if (err) {
167
+ adapter.log.warn(`Error creating channel ${device}.apps: ${err}`);
168
+ return;
169
+ }
170
+ devices[device].sync = true;
171
+ if (last) {
172
+ main();
173
+ }
174
+ },
175
+ );
176
+ },
177
+ );
151
178
  });
152
179
  }
153
180
 
@@ -164,141 +191,160 @@ function startServer(device, callback) {
164
191
  var method = request.method;
165
192
  var url = request.url;
166
193
  var body = [];
167
- request.on('error', function (err) {
168
- adapter.log.warn(err);
169
- }).on('data', function (chunk) {
170
- body.push(chunk);
171
- }).on('end', function () {
172
- response.on('error', function (err) {
194
+ request
195
+ .on('error', function (err) {
173
196
  adapter.log.warn(err);
174
- });
175
- adapter.log.debug(method + "-request to " + url + " from " + request.connection.remoteAddress);
176
- if (method === 'GET' && url == '/') {
177
- response.statusCode = 200;
178
- response.setHeader('Content-Type', 'text/xml; charset=utf-8');
179
- response.setHeader('Connection', 'close');
180
- adapter.log.debug("sending service description");
181
- response.end(devices[device].DESCXML, function () {
182
- request.connection.unref();
197
+ })
198
+ .on('data', function (chunk) {
199
+ body.push(chunk);
200
+ })
201
+ .on('end', function () {
202
+ response.on('error', function (err) {
203
+ adapter.log.warn(err);
183
204
  });
184
- } else {
185
- if (method === "GET") {
186
- var message = parseQuery(device, url);
205
+ adapter.log.debug(`${method}-request to ${url} from ${request.connection.remoteAddress}`);
206
+ if (method === 'GET' && url == '/') {
187
207
  response.statusCode = 200;
188
208
  response.setHeader('Content-Type', 'text/xml; charset=utf-8');
189
209
  response.setHeader('Connection', 'close');
190
- adapter.log.debug("responding to get request");
191
- response.end(message, function () {
210
+ adapter.log.debug('sending service description');
211
+ response.end(devices[device].DESCXML, function () {
192
212
  request.connection.unref();
193
213
  });
194
214
  } else {
195
- parseCommand(device, url);
196
- response.end(function () {
197
- request.connection.unref();
198
- });
215
+ if (method === 'GET') {
216
+ var message = parseQuery(device, url);
217
+ response.statusCode = 200;
218
+ response.setHeader('Content-Type', 'text/xml; charset=utf-8');
219
+ response.setHeader('Connection', 'close');
220
+ adapter.log.debug('responding to get request');
221
+ response.end(message, function () {
222
+ request.connection.unref();
223
+ });
224
+ } else {
225
+ parseCommand(device, url);
226
+ response.end(function () {
227
+ request.connection.unref();
228
+ });
229
+ }
199
230
  }
200
- }
201
- });
231
+ });
202
232
  });
203
233
  devices[device].server.on('connection', function (socket) {
204
234
  socket.unref();
205
235
  });
206
- devices[device].server.on("error", function (err) {
236
+ devices[device].server.on('error', function (err) {
207
237
  adapter.log.error(err);
208
238
  stopServer(device);
209
239
  });
210
240
  devices[device].server.listen(devices[device].HTTP_PORT, BIND, function () {
211
- adapter.log.debug("HTTP-Server started on " + BIND + ":" + devices[device].HTTP_PORT);
241
+ adapter.log.debug(`HTTP-Server started on ${BIND}:${devices[device].HTTP_PORT}`);
212
242
  });
213
- if (typeof callback === 'function') callback();
243
+ if (typeof callback === 'function') {
244
+ callback();
245
+ }
214
246
  }
215
247
 
216
248
  function stopServer(device) {
217
- if (devices[device].server) devices[device].server.close();
249
+ if (devices[device].server) {
250
+ devices[device].server.close();
251
+ }
218
252
  }
219
253
 
220
254
  function startDiscovery() {
221
- socket = dgram.createSocket({type: 'udp4', reuseAddr: true});
222
- socket.on("error", function (error) {
223
- adapter.log.error(error);
224
- stopDiscovery();
225
- }
226
- );
227
- socket.on("message", function (msg, rinfo) {
228
- if (msg.toString().match(/^(M-SEARCH) \* HTTP\/1.\d/)) {
229
- var headers = httpHeaders(msg);
230
- if (headers.man === '"ssdp:discover"') {
231
- adapter.log.debug("responding to " + rinfo.address + ":" + rinfo.port);
232
- for (let j = 0; j < devArray.length; j++) {
233
- socket.send(devices[devArray[j]].SSDP_RESPONSE, 0, devices[devArray[j]].SSDP_RESPONSE.length, rinfo.port, rinfo.address);
234
- }
255
+ socket = dgram.createSocket({ type: 'udp4', reuseAddr: true });
256
+ socket.on('error', function (error) {
257
+ adapter.log.error(error);
258
+ stopDiscovery();
259
+ });
260
+ socket.on('message', function (msg, rinfo) {
261
+ if (msg.toString().match(/^(M-SEARCH) \* HTTP\/1.\d/)) {
262
+ var headers = httpHeaders(msg);
263
+ if (headers.man === '"ssdp:discover"') {
264
+ adapter.log.debug(`responding to ${rinfo.address}:${rinfo.port}`);
265
+ for (let j = 0; j < devArray.length; j++) {
266
+ socket.send(
267
+ devices[devArray[j]].SSDP_RESPONSE,
268
+ 0,
269
+ devices[devArray[j]].SSDP_RESPONSE.length,
270
+ rinfo.port,
271
+ rinfo.address,
272
+ );
235
273
  }
236
- } else if (msg.toString().match(/^(NOTIFY) \* HTTP\/1.\d/)) {
237
- //@todo
238
274
  }
275
+ } else if (msg.toString().match(/^(NOTIFY) \* HTTP\/1.\d/)) {
276
+ //@todo
239
277
  }
240
- );
241
- socket.bind(1900, "0.0.0.0", function () {
278
+ });
279
+ socket.bind(1900, '0.0.0.0', function () {
242
280
  socket.addMembership(MULTICAST_IP);
243
- adapter.log.debug("listening on 0.0.0.0:1900");
281
+ adapter.log.debug('listening on 0.0.0.0:1900');
244
282
  });
245
283
  }
246
284
 
247
285
  function stopDiscovery() {
248
- if (socket && socket._bindState) socket.close();
286
+ if (socket && socket._bindState) {
287
+ socket.close();
288
+ }
249
289
  }
250
290
 
251
291
  function parseCommand(device, command) {
252
292
  var m;
253
- if (m = command.match(/^\/([^\/]+)\/(\S+)$/)) {
293
+ if ((m = command.match(/^\/([^/]+)\/(\S+)$/))) {
254
294
  switch (m[1]) {
255
- case "keypress":
295
+ case 'keypress':
256
296
  //key is pressed once => set state to true for 50ms
257
- setState(device, "keys", m[2].replace(".", "_"), true, function (err) {
258
- if (err) return;
297
+ setState(device, 'keys', m[2].replace('.', '_'), true, function (err) {
298
+ if (err) {
299
+ return;
300
+ }
259
301
  setTimeout(function () {
260
- setState(device, "keys", m[2].replace(".", "_"), false);
302
+ setState(device, 'keys', m[2].replace('.', '_'), false);
261
303
  }, 50);
262
304
  });
263
305
  break;
264
- case "keydown":
306
+ case 'keydown':
265
307
  //key is pressed => set state to true
266
- setState(device, "keys", m[2].replace(".", "_"), true);
308
+ setState(device, 'keys', m[2].replace('.', '_'), true);
267
309
  break;
268
- case "keyup":
310
+ case 'keyup':
269
311
  //key is released => set state to false
270
- setState(device, "keys", m[2].replace(".", "_"), false);
312
+ setState(device, 'keys', m[2].replace('.', '_'), false);
271
313
  break;
272
- case "launch":
314
+ case 'launch':
273
315
  //launch app => set state to true for 50ms
274
- setState(device, "apps", m[2].replace(".", "_"), true, function (err) {
275
- if (err) return;
316
+ setState(device, 'apps', m[2].replace('.', '_'), true, function (err) {
317
+ if (err) {
318
+ return;
319
+ }
276
320
  setTimeout(function () {
277
- setState(device, "apps", m[2].replace(".", "_"), false);
321
+ setState(device, 'apps', m[2].replace('.', '_'), false);
278
322
  }, 50);
279
323
  });
280
324
  break;
281
- case "install":
325
+ case 'install':
282
326
  //install app => set state to true for 50ms
283
- setState(device, "apps", m[2].replace(".", "_"), true, function (err) {
284
- if (err) return;
327
+ setState(device, 'apps', m[2].replace('.', '_'), true, function (err) {
328
+ if (err) {
329
+ return;
330
+ }
285
331
  setTimeout(function () {
286
- setState(device, "apps", m[2].replace(".", "_"), false);
332
+ setState(device, 'apps', m[2].replace('.', '_'), false);
287
333
  }, 50);
288
334
  });
289
335
  break;
290
336
  default:
291
- adapter.log.debug("unknown command: " + command);
337
+ adapter.log.debug(`unknown command: ${command}`);
292
338
  }
293
339
  } else {
294
- adapter.log.debug("unknown command: " + command);
340
+ adapter.log.debug(`unknown command: ${command}`);
295
341
  }
296
342
  }
297
343
 
298
344
  function parseQuery(device, query) {
299
- var message = "";
345
+ var message = '';
300
346
  switch (query) {
301
- case "/query/apps":
347
+ case '/query/apps':
302
348
  message = devices[device].APPSXML;
303
349
  break;
304
350
  default:
@@ -308,49 +354,72 @@ function parseQuery(device, query) {
308
354
  }
309
355
 
310
356
  function setState(device, channel, state, val, callback) {
311
- var id = device + "." + channel + "." + state;
357
+ var id = `${device}.${channel}.${state}`;
312
358
  if (devices[device].objects[id]) {
313
359
  adapter.log.debug('state cached -> writing value');
314
- adapter.setState(id, {val: val, ack: true});
315
- if (typeof callback === 'function') callback();
360
+ adapter.setState(id, { val: val, ack: true });
361
+ if (typeof callback === 'function') {
362
+ callback();
363
+ }
316
364
  } else {
317
365
  adapter.getObject(id, function (err, obj) {
318
366
  if (err) {
319
367
  adapter.log.debug(err);
320
- if (typeof callback === 'function') callback(err);
368
+ if (typeof callback === 'function') {
369
+ callback(err);
370
+ }
321
371
  return;
322
372
  }
323
373
  if (!obj) {
324
374
  adapter.log.debug('creating new state');
325
375
  //create object first
326
- adapter.createState(device, channel, state, {
327
- name: state,
328
- def: false,
329
- type: 'boolean',
330
- read: 'true',
331
- write: 'false',
332
- role: 'indicator.state',
333
- }, {
334
- url: channel + "/" + state,
335
- }, function () {
336
- adapter.log.debug('created new state -> writing value');
337
- adapter.setState(id, {val: val, ack: true});
338
- devices[device].objects[id] = true;
339
- if (typeof callback === 'function') callback();
340
- });
376
+ adapter.setObjectNotExists(
377
+ id,
378
+ {
379
+ type: 'state',
380
+ common: {
381
+ name: state,
382
+ def: false,
383
+ type: 'boolean',
384
+ read: true,
385
+ write: false,
386
+ role: 'indicator.state',
387
+ },
388
+ native: {
389
+ url: `${channel}/${state}`,
390
+ },
391
+ },
392
+ function (err) {
393
+ if (err) {
394
+ adapter.log.warn(`Error creating state ${id}: ${err}`);
395
+ if (typeof callback === 'function') {
396
+ callback(err);
397
+ }
398
+ return;
399
+ }
400
+ adapter.log.debug('created new state -> writing value');
401
+ adapter.setState(id, { val: val, ack: true });
402
+ devices[device].objects[id] = true;
403
+ if (typeof callback === 'function') {
404
+ callback();
405
+ }
406
+ },
407
+ );
341
408
  return;
342
409
  }
343
410
  adapter.log.debug('state found -> writing value');
344
- adapter.setState(id, {val: val, ack: true});
411
+ adapter.setState(id, { val: val, ack: true });
345
412
  devices[device].objects[id] = true;
346
- if (typeof callback === 'function') callback();
413
+ if (typeof callback === 'function') {
414
+ callback();
415
+ }
347
416
  });
348
417
  }
349
418
  }
350
419
 
351
420
  function genUUID(device) {
352
- var crypto = require('crypto');
353
- var uuid = crypto.createHash('md5').update(crypto.randomBytes(256)).digest("hex");
421
+ var crypto = require('node:crypto');
422
+ var uuid = crypto.createHash('md5').update(crypto.randomBytes(256)).digest('hex');
354
423
  for (var i = 0; i < adapter.config.devices.length; i++) {
355
424
  if (adapter.config.devices[i].name === device) {
356
425
  adapter.config.devices[i].uuid = uuid;
@@ -361,16 +430,13 @@ function genUUID(device) {
361
430
  }
362
431
 
363
432
  function updateConfig() {
364
- adapter.getForeignObject('system.adapter.fakeroku.' + adapter.instance, function (err, obj) {
433
+ adapter.getForeignObject(`system.adapter.fakeroku.${adapter.instance}`, function (err, obj) {
365
434
  if (err || !obj) {
366
- adapter.log.warn("adapter config object not found!");
435
+ adapter.log.warn('adapter config object not found!');
367
436
  return;
368
437
  }
369
438
  obj.native = adapter.config;
370
- adapter.log.debug("updating config with new uuid");
371
- adapter.setForeignObject('system.adapter.fakeroku.' + adapter.instance, obj, function () {
372
-
373
- });
439
+ adapter.log.debug('updating config with new uuid');
440
+ adapter.setForeignObject(`system.adapter.fakeroku.${adapter.instance}`, obj, function () {});
374
441
  });
375
442
  }
376
-
package/package.json CHANGED
@@ -1,16 +1,11 @@
1
1
  {
2
2
  "name": "iobroker.fakeroku",
3
- "version": "0.3.0",
3
+ "version": "0.5.1",
4
4
  "description": "ioBroker fakeroku Adapter",
5
- "author": {
6
- "name": "Pmant",
7
- "email": "patrickmo@gmx.de"
8
- },
5
+ "author": "Pmant <patrickmo@gmx.de>",
9
6
  "contributors": [
10
- {
11
- "name": "Pmant",
12
- "email": "patrickmo@gmx.de"
13
- }
7
+ "Pmant <patrickmo@gmx.de>",
8
+ "iobroker-community-adapters <iobroker-community-adapters@gmx.de>"
14
9
  ],
15
10
  "homepage": "https://github.com/iobroker-community-adapters/ioBroker.fakeroku",
16
11
  "license": "MIT",
@@ -25,38 +20,23 @@
25
20
  "url": "https://github.com/iobroker-community-adapters/ioBroker.fakeroku"
26
21
  },
27
22
  "engines": {
28
- "node": ">=18"
23
+ "node": ">=22"
29
24
  },
30
25
  "dependencies": {
31
- "http-headers": "^3.0.1",
32
- "@iobroker/adapter-core": "^3.1.6"
26
+ "@iobroker/adapter-core": "^3.4.3",
27
+ "http-headers": "^3.0.1"
33
28
  },
34
29
  "devDependencies": {
35
- "@alcalzone/release-script": "^3.7.0",
36
- "@alcalzone/release-script-plugin-iobroker": "^3.7.0",
37
- "@alcalzone/release-script-plugin-license": "^3.7.0",
38
- "@alcalzone/release-script-plugin-manual-review": "^3.7.0",
39
- "@iobroker/adapter-dev": "^1.3.0",
40
- "@iobroker/testing": "^4.1.3",
41
- "@tsconfig/node14": "^14.1.0",
42
- "@types/chai": "^4.3.11",
43
- "@types/chai-as-promised": "^7.1.8",
44
- "@types/mocha": "^10.0.6",
45
- "@types/node": "^20.14.2",
46
- "@types/proxyquire": "^1.3.31",
47
- "@types/sinon": "^17.0.3",
48
- "@types/sinon-chai": "^3.2.12",
49
- "chai": "^4.4.1",
50
- "chai-as-promised": "^7.1.1",
51
- "eslint": "^8.57.0",
52
- "eslint-config-prettier": "^9.1.0",
53
- "eslint-plugin-prettier": "^5.1.3",
54
- "mocha": "^10.3.0",
55
- "prettier": "^3.2.5",
56
- "proxyquire": "^2.1.3",
57
- "sinon": "^17.0.1",
58
- "sinon-chai": "^3.7.0",
59
- "typescript": "~5.4.2"
30
+ "@alcalzone/release-script": "^5.2.1",
31
+ "@alcalzone/release-script-plugin-iobroker": "^5.2.0",
32
+ "@alcalzone/release-script-plugin-license": "^5.2.0",
33
+ "@alcalzone/release-script-plugin-manual-review": "^5.2.0",
34
+ "@iobroker/adapter-dev": "^1.5.0",
35
+ "@iobroker/eslint-config": "^2.3.4",
36
+ "@iobroker/testing": "^5.3.0",
37
+ "@tsconfig/node22": "^22.0.5",
38
+ "@types/node": "^22.20.1",
39
+ "typescript": "~5.9.3"
60
40
  },
61
41
  "main": "main.js",
62
42
  "scripts": {
@@ -65,7 +45,7 @@
65
45
  "test:integration": "mocha test/integration --exit",
66
46
  "test": "npm run test:js && npm run test:package",
67
47
  "check": "tsc --noEmit -p tsconfig.check.json",
68
- "lint": "eslint .",
48
+ "lint": "eslint -c eslint.config.mjs .",
69
49
  "translate": "translate-adapter",
70
50
  "release": "release-script"
71
51
  },
package/.eslintignore DELETED
@@ -1,2 +0,0 @@
1
- **/.eslintrc.js
2
- admin/words.js
package/.eslintrc.json DELETED
@@ -1,42 +0,0 @@
1
- {
2
- "root": true,
3
- "env": {
4
- "es6": true,
5
- "node": true,
6
- "mocha": true
7
- },
8
- "extends": ["eslint:recommended"],
9
- "plugins": [],
10
- "rules": {
11
- "indent": [
12
- "error",
13
- 4,
14
- {
15
- "SwitchCase": 1
16
- }
17
- ],
18
- "no-console": "off",
19
- "no-unused-vars": [
20
- "error",
21
- {
22
- "ignoreRestSiblings": true,
23
- "argsIgnorePattern": "^_"
24
- }
25
- ],
26
- "no-var": "error",
27
- "no-trailing-spaces": "error",
28
- "prefer-const": "error",
29
- "quotes": [
30
- "error",
31
- "single",
32
- {
33
- "avoidEscape": true,
34
- "allowTemplateLiterals": true
35
- }
36
- ],
37
- "semi": ["error", "always"]
38
- },
39
- "parserOptions": {
40
- "ecmaVersion": 2020
41
- }
42
- }
package/.prettierignore DELETED
@@ -1,2 +0,0 @@
1
- package.json
2
- package-lock.json
package/.prettierrc.js DELETED
@@ -1,9 +0,0 @@
1
- module.exports = {
2
- semi: true,
3
- trailingComma: 'all',
4
- singleQuote: true,
5
- printWidth: 120,
6
- useTabs: false,
7
- tabWidth: 4,
8
- endOfLine: 'lf',
9
- };