iobroker.govee-local 0.2.8 → 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,9 +24,16 @@ For **Windows** Users: Please go to the settings and make sure you choose the co
24
24
  Placeholder for the next version (at the beginning of the line):
25
25
  ### **WORK IN PROGRESS**
26
26
  -->
27
+ ### 0.2.9 (2025-08-22)
28
+
29
+ - update dependencies
30
+ - add support for node 24
31
+ - update to ESlint 9
32
+
27
33
  ### 0.2.8 (2025-03-28)
28
34
 
29
35
  - update dependencies
36
+ - avoid repeated overriding of states
30
37
 
31
38
  ### 0.2.7 (2024-08-18)
32
39
 
package/build/main.js CHANGED
@@ -5,6 +5,10 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
8
12
  var __copyProps = (to, from, except, desc) => {
9
13
  if (from && typeof from === "object" || typeof from === "function") {
10
14
  for (let key of __getOwnPropNames(from))
@@ -21,6 +25,13 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
21
25
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
26
  mod
23
27
  ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var main_exports = {};
30
+ __export(main_exports, {
31
+ GoveeLocal: () => GoveeLocal,
32
+ getDatapointDescription: () => getDatapointDescription
33
+ });
34
+ module.exports = __toCommonJS(main_exports);
24
35
  var utils = __toESM(require("@iobroker/adapter-core"));
25
36
  var dgram = __toESM(require("node:dgram"));
26
37
  var import_hexTool = require("./tools/hexTool");
@@ -49,7 +60,7 @@ class GoveeLocal extends utils.Adapter {
49
60
  * Is called when databases are connected and adapter received configuration.
50
61
  */
51
62
  async onReady() {
52
- this.setObjectNotExists("info.connection", {
63
+ void this.setObjectNotExists("info.connection", {
53
64
  type: "state",
54
65
  common: {
55
66
  name: "Device discovery running",
@@ -62,14 +73,15 @@ class GoveeLocal extends utils.Adapter {
62
73
  });
63
74
  socket.on("message", this.onUdpMessage.bind(this));
64
75
  socket.on("error", (error) => {
65
- this.log.error("server bind error : " + error.message);
66
- this.setStateChanged("info.connection", { val: false, ack: true });
76
+ this.log.error(`server bind error : ${error.message}`);
77
+ void this.setStateChanged("info.connection", { val: false, ack: true });
67
78
  });
68
79
  if (this.config.extendedLogging) {
69
80
  this.log.debug("running with extended logging");
70
81
  }
71
- socket.bind({ address: this.config.interface, port: LOCAL_PORT }, this.serverBound.bind(this));
72
- this.subscribeStates("*.devStatus.*");
82
+ void socket.bind({ address: this.config.interface, port: LOCAL_PORT }, this.serverBound.bind(this));
83
+ void this.subscribeStates("*.devStatus.*");
84
+ return Promise.resolve();
73
85
  }
74
86
  /**
75
87
  * handles when udp socket is up
@@ -81,8 +93,8 @@ class GoveeLocal extends utils.Adapter {
81
93
  socket.setMulticastTTL(128);
82
94
  socket.setMulticastInterface(this.config.interface);
83
95
  socket.addMembership(M_CAST);
84
- this.setStateChanged("info.connection", { val: true, ack: true });
85
- this.log.debug("UDP listening on " + socket.address().address + ":" + socket.address().port);
96
+ void this.setStateChanged("info.connection", { val: true, ack: true });
97
+ this.log.debug(`UDP listening on ${socket.address().address}:${socket.address().port}`);
86
98
  const deviceSearchInterval = this.setInterval(this.sendScan.bind(this), this.config.searchInterval * 1e3);
87
99
  if (deviceSearchInterval) {
88
100
  searchInterval = deviceSearchInterval;
@@ -94,21 +106,23 @@ class GoveeLocal extends utils.Adapter {
94
106
  if (deviceRefreshInterval) {
95
107
  refreshInterval = deviceRefreshInterval;
96
108
  }
109
+ return Promise.resolve();
97
110
  }
98
111
  /**
99
112
  * handle icoming messages on the udp socket
113
+ *
100
114
  * @param message the message itself
101
115
  * @param remote the sender of the message
102
116
  */
103
117
  async onUdpMessage(message, remote) {
104
118
  const messageObject = JSON.parse(message.toString());
105
119
  switch (messageObject.msg.cmd) {
106
- case "scan":
120
+ case "scan": {
107
121
  for (const key of Object.keys(messageObject.msg.data)) {
108
122
  if (key != "device") {
109
123
  const deviceName = messageObject.msg.data.device.replace(this.FORBIDDEN_CHARS, "_");
110
124
  devices[remote.address] = deviceName;
111
- this.setObjectNotExists(deviceName, {
125
+ void this.setObjectNotExists(deviceName, {
112
126
  type: "device",
113
127
  common: {
114
128
  name: messageObject.msg.data.sku,
@@ -116,7 +130,7 @@ class GoveeLocal extends utils.Adapter {
116
130
  },
117
131
  native: {}
118
132
  });
119
- this.setObjectNotExists(`${deviceName}.deviceInfo.${key}`, {
133
+ void this.setObjectNotExists(`${deviceName}.deviceInfo.${key}`, {
120
134
  type: "state",
121
135
  common: {
122
136
  name: getDatapointDescription(key),
@@ -127,11 +141,12 @@ class GoveeLocal extends utils.Adapter {
127
141
  },
128
142
  native: {}
129
143
  });
130
- await this.updateStateAsync(`${deviceName}.deviceInfo.${key}`, messageObject.msg.data[key]);
144
+ void this.updateStateAsync(`${deviceName}.deviceInfo.${key}`, messageObject.msg.data[key]);
131
145
  }
132
146
  }
133
147
  break;
134
- case "devStatus":
148
+ }
149
+ case "devStatus": {
135
150
  const sendingDevice = devices[remote.address];
136
151
  if (sendingDevice) {
137
152
  if (this.config.extendedLogging && !loggedDevices.includes(remote.address.toString())) {
@@ -139,7 +154,7 @@ class GoveeLocal extends utils.Adapter {
139
154
  loggedDevices.push(remote.address.toString());
140
155
  }
141
156
  const devStatusMessageObject = JSON.parse(message.toString());
142
- this.setObjectNotExists(`${sendingDevice}.devStatus.onOff`, {
157
+ void this.setObjectNotExists(`${sendingDevice}.devStatus.onOff`, {
143
158
  type: "state",
144
159
  common: {
145
160
  name: "On / Off state of the lamp",
@@ -150,11 +165,11 @@ class GoveeLocal extends utils.Adapter {
150
165
  },
151
166
  native: {}
152
167
  });
153
- await this.updateStateAsync(
168
+ void this.updateStateAsync(
154
169
  `${sendingDevice}.devStatus.onOff`,
155
170
  devStatusMessageObject.msg.data.onOff == 1
156
171
  );
157
- this.setObjectNotExists(`${sendingDevice}.devStatus.brightness`, {
172
+ void this.setObjectNotExists(`${sendingDevice}.devStatus.brightness`, {
158
173
  type: "state",
159
174
  common: {
160
175
  name: "Brightness of the light",
@@ -165,11 +180,11 @@ class GoveeLocal extends utils.Adapter {
165
180
  },
166
181
  native: {}
167
182
  });
168
- await this.updateStateAsync(
183
+ void this.updateStateAsync(
169
184
  `${sendingDevice}.devStatus.brightness`,
170
185
  devStatusMessageObject.msg.data.brightness
171
186
  );
172
- this.setObjectNotExists(`${sendingDevice}.devStatus.color`, {
187
+ void this.setObjectNotExists(`${sendingDevice}.devStatus.color`, {
173
188
  type: "state",
174
189
  common: {
175
190
  name: "Current showing color of the lamp",
@@ -180,15 +195,13 @@ class GoveeLocal extends utils.Adapter {
180
195
  },
181
196
  native: {}
182
197
  });
183
- this.setState(`${sendingDevice}.devStatus.color`, {
184
- val: "#" + (0, import_hexTool.componentToHex)(devStatusMessageObject.msg.data.color.r) + (0, import_hexTool.componentToHex)(devStatusMessageObject.msg.data.color.g) + (0, import_hexTool.componentToHex)(devStatusMessageObject.msg.data.color.b),
198
+ const colorString = `#${(0, import_hexTool.componentToHex)(devStatusMessageObject.msg.data.color.r)}${(0, import_hexTool.componentToHex)(devStatusMessageObject.msg.data.color.g)}${(0, import_hexTool.componentToHex)(devStatusMessageObject.msg.data.color.b)}`;
199
+ void this.setState(`${sendingDevice}.devStatus.color`, {
200
+ val: colorString,
185
201
  ack: true
186
202
  });
187
- await this.updateStateAsync(
188
- `${sendingDevice}.devStatus.color`,
189
- `#${(0, import_hexTool.componentToHex)(devStatusMessageObject.msg.data.color.r)}${(0, import_hexTool.componentToHex)(devStatusMessageObject.msg.data.color.g)}${(0, import_hexTool.componentToHex)(devStatusMessageObject.msg.data.color.b)}`
190
- );
191
- this.setObjectNotExists(`${sendingDevice}.devStatus.colorTemInKelvin`, {
203
+ void this.updateStateAsync(`${sendingDevice}.devStatus.color`, colorString);
204
+ void this.setObjectNotExists(`${sendingDevice}.devStatus.colorTemInKelvin`, {
192
205
  type: "state",
193
206
  common: {
194
207
  name: "If staying in white light, the color temperature",
@@ -199,45 +212,53 @@ class GoveeLocal extends utils.Adapter {
199
212
  },
200
213
  native: {}
201
214
  });
202
- await this.updateStateAsync(
215
+ void this.updateStateAsync(
203
216
  `${sendingDevice}.devStatus.colorTemInKelvin`,
204
217
  devStatusMessageObject.msg.data.colorTemInKelvin
205
218
  );
206
219
  }
207
220
  break;
208
- default:
209
- this.log.error("message from: " + remote.address + ":" + remote.port + " - " + message);
221
+ }
222
+ default: {
223
+ this.log.error(`message from: ${remote.address}:${remote.port} - ${message.toString()}`);
224
+ }
210
225
  }
226
+ return Promise.resolve();
211
227
  }
212
228
  async refreshAllDevices() {
213
229
  for (const ip in devices) {
214
230
  this.requestDeviceStatus(ip);
215
231
  }
232
+ return Promise.resolve();
216
233
  }
217
234
  /**
218
235
  * sends the device status request to one specific device
236
+ *
219
237
  * @param receiver the ip ( / hsotname ) of the device that should be queried
220
238
  */
221
239
  requestDeviceStatus(receiver) {
222
240
  const requestDeviceStatusBuffer = Buffer.from(JSON.stringify(requestStatusMessage));
223
- socket.send(requestDeviceStatusBuffer, 0, requestDeviceStatusBuffer.length, CONTROL_PORT, receiver);
241
+ void socket.send(requestDeviceStatusBuffer, 0, requestDeviceStatusBuffer.length, CONTROL_PORT, receiver);
224
242
  }
225
243
  /**
226
244
  * send the scan message to the udp multicast address
227
245
  */
228
246
  async sendScan() {
229
247
  const scanMessageBuffer = Buffer.from(JSON.stringify(scanMessage));
230
- socket.send(scanMessageBuffer, 0, scanMessageBuffer.length, SEND_SCAN_PORT, M_CAST);
248
+ void socket.send(scanMessageBuffer, 0, scanMessageBuffer.length, SEND_SCAN_PORT, M_CAST);
249
+ return Promise.resolve();
231
250
  }
232
251
  /**
233
252
  * Is called when adapter shuts down - callback has to be called under any circumstances!
253
+ *
254
+ * @param callback Callback-Funktion, die nach Abschluss des Unload-Prozesses aufgerufen wird.
234
255
  */
235
256
  onUnload(callback) {
236
257
  try {
237
258
  this.clearInterval(searchInterval);
238
259
  this.clearInterval(refreshInterval);
239
260
  socket.close();
240
- this.updateStateAsync("info.connection", false);
261
+ void this.updateStateAsync("info.connection", false);
241
262
  callback();
242
263
  } catch (e) {
243
264
  this.log.error(e.message);
@@ -246,25 +267,36 @@ class GoveeLocal extends utils.Adapter {
246
267
  }
247
268
  /**
248
269
  * Is called if a subscribed state changes
270
+ *
271
+ * @param id Die ID des geänderten States.
272
+ * @param state Das neue State-Objekt oder null/undefined.
249
273
  */
250
274
  async onStateChange(id, state) {
251
275
  var _a, _b;
252
276
  if (state && !state.ack) {
253
- const ipOfDevice = await this.getStateAsync(id.split(".")[2] + ".deviceInfo.ip");
277
+ const ipOfDevice = await this.getStateAsync(`${id.split(".")[2]}.deviceInfo.ip`);
254
278
  if (ipOfDevice) {
255
279
  const receiver = (_a = ipOfDevice.val) == null ? void 0 : _a.toString();
256
280
  switch (id.split(".")[4]) {
257
- case "onOff":
281
+ case "onOff": {
258
282
  const turnMessage = { msg: { cmd: "turn", data: { value: state.val ? 1 : 0 } } };
259
283
  const turnMessageBuffer = Buffer.from(JSON.stringify(turnMessage));
260
- socket.send(turnMessageBuffer, 0, turnMessageBuffer.length, CONTROL_PORT, receiver);
284
+ void socket.send(turnMessageBuffer, 0, turnMessageBuffer.length, CONTROL_PORT, receiver);
261
285
  break;
262
- case "brightness":
286
+ }
287
+ case "brightness": {
263
288
  const brightnessMessage = { msg: { cmd: "brightness", data: { value: state.val } } };
264
289
  const brightnessMessageBuffer = Buffer.from(JSON.stringify(brightnessMessage));
265
- socket.send(brightnessMessageBuffer, 0, brightnessMessageBuffer.length, CONTROL_PORT, receiver);
290
+ void socket.send(
291
+ brightnessMessageBuffer,
292
+ 0,
293
+ brightnessMessageBuffer.length,
294
+ CONTROL_PORT,
295
+ receiver
296
+ );
266
297
  break;
267
- case "colorTemInKelvin":
298
+ }
299
+ case "colorTemInKelvin": {
268
300
  const colorTempMessageBuffer = Buffer.from(
269
301
  JSON.stringify({
270
302
  msg: {
@@ -273,27 +305,36 @@ class GoveeLocal extends utils.Adapter {
273
305
  }
274
306
  })
275
307
  );
276
- socket.send(colorTempMessageBuffer, 0, colorTempMessageBuffer.length, CONTROL_PORT, receiver);
308
+ void socket.send(
309
+ colorTempMessageBuffer,
310
+ 0,
311
+ colorTempMessageBuffer.length,
312
+ CONTROL_PORT,
313
+ receiver
314
+ );
277
315
  break;
278
- case "color":
316
+ }
317
+ case "color": {
279
318
  const colorValue = (_b = state.val) == null ? void 0 : _b.toString();
280
319
  if (colorValue) {
281
320
  const rgb = (0, import_hexTool.hexToRgb)(colorValue);
282
321
  const colorMessage = { msg: { cmd: "colorwc", data: { color: rgb } } };
283
322
  const colorMessageBuffer = Buffer.from(JSON.stringify(colorMessage));
284
- socket.send(colorMessageBuffer, 0, colorMessageBuffer.length, CONTROL_PORT, receiver);
323
+ void socket.send(colorMessageBuffer, 0, colorMessageBuffer.length, CONTROL_PORT, receiver);
285
324
  }
286
325
  break;
326
+ }
287
327
  }
288
328
  } else {
289
329
  this.log.error("device not found");
290
330
  }
291
331
  }
332
+ return Promise.resolve();
292
333
  }
293
334
  async updateStateAsync(fullName, state, acknowledged = true) {
294
335
  const currentState = await this.getStateAsync(fullName);
295
336
  if (currentState != state) {
296
- this.setState(fullName, {
337
+ void this.setState(fullName, {
297
338
  val: state,
298
339
  ack: acknowledged
299
340
  });
@@ -323,4 +364,9 @@ function getDatapointDescription(name) {
323
364
  return "";
324
365
  }
325
366
  }
367
+ // Annotate the CommonJS export names for ESM import in node:
368
+ 0 && (module.exports = {
369
+ GoveeLocal,
370
+ getDatapointDescription
371
+ });
326
372
  //# sourceMappingURL=main.js.map
package/build/main.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/main.ts"],
4
- "sourcesContent": ["/*\n * Created with @iobroker/create-adapter v2.3.0\n */\n\n// The adapter-core module gives you access to the core ioBroker functions\n// you need to create an adapter\nimport * as utils from '@iobroker/adapter-core';\nimport * as dgram from 'node:dgram';\nimport { componentToHex, hexToRgb } from './tools/hexTool';\n\n// Load your modules here, e.g.:\n\nconst LOCAL_PORT = 4002;\nconst SEND_SCAN_PORT = 4001;\nconst CONTROL_PORT = 4003;\nconst M_CAST = '239.255.255.250';\n\nconst socket = dgram.createSocket({ type: 'udp4' });\n\nconst scanMessage = { msg: { cmd: 'scan', data: { account_topic: 'reserved' } } };\nconst requestStatusMessage = { msg: { cmd: 'devStatus', data: {} } };\n\nlet searchInterval: ioBroker.Interval;\nlet refreshInterval: ioBroker.Interval;\n\nconst devices: { [ip: string]: string } = {};\n\nconst loggedDevices = [] as string[];\n\nclass GoveeLocal extends utils.Adapter {\n\tpublic constructor(options: Partial<utils.AdapterOptions> = {}) {\n\t\tsuper({\n\t\t\t...options,\n\t\t\tname: 'govee-local',\n\t\t});\n\t\tthis.on('ready', this.onReady.bind(this));\n\t\tthis.on('stateChange', this.onStateChange.bind(this));\n\t\t// this.on('objectChange', this.onObjectChange.bind(this));\n\t\t// this.on('message', this.onMessage.bind(this));\n\t\tthis.on('unload', this.onUnload.bind(this));\n\t}\n\n\t/**\n\t * Is called when databases are connected and adapter received configuration.\n\t */\n\tprivate async onReady(): Promise<void> {\n\t\tthis.setObjectNotExists('info.connection', {\n\t\t\ttype: 'state',\n\t\t\tcommon: {\n\t\t\t\tname: 'Device discovery running',\n\t\t\t\ttype: 'boolean',\n\t\t\t\trole: 'indicator.connected',\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\t\tsocket.on('message', this.onUdpMessage.bind(this));\n\t\tsocket.on('error', (error) => {\n\t\t\tthis.log.error('server bind error : ' + error.message);\n\t\t\tthis.setStateChanged('info.connection', { val: false, ack: true });\n\t\t});\n\n\t\tif (this.config.extendedLogging) {\n\t\t\tthis.log.debug('running with extended logging');\n\t\t}\n\n\t\tsocket.bind({ address: this.config.interface, port: LOCAL_PORT }, this.serverBound.bind(this));\n\t\tthis.subscribeStates('*.devStatus.*');\n\t}\n\n\t/**\n\t * handles when udp socket is up\n\t * configure multicast membership\n\t * start periodic scan for devices\n\t */\n\tprivate async serverBound(): Promise<void> {\n\t\tsocket.setBroadcast(true);\n\t\tsocket.setMulticastTTL(128);\n\t\tsocket.setMulticastInterface(this.config.interface);\n\t\tsocket.addMembership(M_CAST);\n\t\tthis.setStateChanged('info.connection', { val: true, ack: true });\n\t\tthis.log.debug('UDP listening on ' + socket.address().address + ':' + socket.address().port);\n\n\t\tconst deviceSearchInterval = this.setInterval(this.sendScan.bind(this), this.config.searchInterval * 1000);\n\t\tif (deviceSearchInterval) {\n\t\t\tsearchInterval = deviceSearchInterval;\n\t\t}\n\n\t\tconst deviceRefreshInterval = this.setInterval(\n\t\t\tthis.refreshAllDevices.bind(this),\n\t\t\tthis.config.deviceStatusRefreshInterval * 1000,\n\t\t);\n\t\tif (deviceRefreshInterval) {\n\t\t\trefreshInterval = deviceRefreshInterval;\n\t\t}\n\t}\n\n\t/**\n\t * handle icoming messages on the udp socket\n\t * @param message the message itself\n\t * @param remote the sender of the message\n\t */\n\tprivate async onUdpMessage(message: Buffer, remote: dgram.RemoteInfo): Promise<void> {\n\t\tconst messageObject = JSON.parse(message.toString());\n\t\tswitch (messageObject.msg.cmd) {\n\t\t\tcase 'scan':\n\t\t\t\tfor (const key of Object.keys(messageObject.msg.data)) {\n\t\t\t\t\tif (key != 'device') {\n\t\t\t\t\t\tconst deviceName = messageObject.msg.data.device.replace(this.FORBIDDEN_CHARS, '_');\n\t\t\t\t\t\tdevices[remote.address] = deviceName;\n\t\t\t\t\t\tthis.setObjectNotExists(deviceName, {\n\t\t\t\t\t\t\ttype: 'device',\n\t\t\t\t\t\t\tcommon: {\n\t\t\t\t\t\t\t\tname: messageObject.msg.data.sku,\n\t\t\t\t\t\t\t\trole: 'group',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tnative: {},\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.setObjectNotExists(`${deviceName}.deviceInfo.${key}`, {\n\t\t\t\t\t\t\ttype: 'state',\n\t\t\t\t\t\t\tcommon: {\n\t\t\t\t\t\t\t\tname: getDatapointDescription(key),\n\t\t\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\t\t\trole: 'state',\n\t\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\t\twrite: false,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tnative: {},\n\t\t\t\t\t\t});\n\t\t\t\t\t\tawait this.updateStateAsync(`${deviceName}.deviceInfo.${key}`, messageObject.msg.data[key]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'devStatus':\n\t\t\t\tconst sendingDevice = devices[remote.address];\n\t\t\t\tif (sendingDevice) {\n\t\t\t\t\t// const devices = await this.getStatesAsync(`${this.name}.${this.instance}.*.deviceInfo.ip`);\n\t\t\t\t\tif (this.config.extendedLogging && !loggedDevices.includes(remote.address.toString())) {\n\t\t\t\t\t\tthis.log.info(`deivce status message data: ${JSON.stringify(messageObject)}`);\n\t\t\t\t\t\tloggedDevices.push(remote.address.toString());\n\t\t\t\t\t}\n\t\t\t\t\tconst devStatusMessageObject = JSON.parse(message.toString());\n\t\t\t\t\tthis.setObjectNotExists(`${sendingDevice}.devStatus.onOff`, {\n\t\t\t\t\t\ttype: 'state',\n\t\t\t\t\t\tcommon: {\n\t\t\t\t\t\t\tname: 'On / Off state of the lamp',\n\t\t\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\t\t\trole: 'switch',\n\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\twrite: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tnative: {},\n\t\t\t\t\t});\n\t\t\t\t\tawait this.updateStateAsync(\n\t\t\t\t\t\t`${sendingDevice}.devStatus.onOff`,\n\t\t\t\t\t\tdevStatusMessageObject.msg.data.onOff == 1,\n\t\t\t\t\t);\n\t\t\t\t\tthis.setObjectNotExists(`${sendingDevice}.devStatus.brightness`, {\n\t\t\t\t\t\ttype: 'state',\n\t\t\t\t\t\tcommon: {\n\t\t\t\t\t\t\tname: 'Brightness of the light',\n\t\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t\t\trole: 'level.dimmer',\n\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\twrite: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tnative: {},\n\t\t\t\t\t});\n\t\t\t\t\tawait this.updateStateAsync(\n\t\t\t\t\t\t`${sendingDevice}.devStatus.brightness`,\n\t\t\t\t\t\tdevStatusMessageObject.msg.data.brightness,\n\t\t\t\t\t);\n\t\t\t\t\tthis.setObjectNotExists(`${sendingDevice}.devStatus.color`, {\n\t\t\t\t\t\ttype: 'state',\n\t\t\t\t\t\tcommon: {\n\t\t\t\t\t\t\tname: 'Current showing color of the lamp',\n\t\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\t\trole: 'level.color.rgb',\n\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\twrite: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tnative: {},\n\t\t\t\t\t});\n\t\t\t\t\tthis.setState(`${sendingDevice}.devStatus.color`, {\n\t\t\t\t\t\tval:\n\t\t\t\t\t\t\t'#' +\n\t\t\t\t\t\t\tcomponentToHex(devStatusMessageObject.msg.data.color.r) +\n\t\t\t\t\t\t\tcomponentToHex(devStatusMessageObject.msg.data.color.g) +\n\t\t\t\t\t\t\tcomponentToHex(devStatusMessageObject.msg.data.color.b),\n\t\t\t\t\t\tack: true,\n\t\t\t\t\t});\n\t\t\t\t\tawait this.updateStateAsync(\n\t\t\t\t\t\t`${sendingDevice}.devStatus.color`,\n\t\t\t\t\t\t`#${componentToHex(devStatusMessageObject.msg.data.color.r)}${componentToHex(devStatusMessageObject.msg.data.color.g)}${componentToHex(devStatusMessageObject.msg.data.color.b)}`,\n\t\t\t\t\t);\n\t\t\t\t\tthis.setObjectNotExists(`${sendingDevice}.devStatus.colorTemInKelvin`, {\n\t\t\t\t\t\ttype: 'state',\n\t\t\t\t\t\tcommon: {\n\t\t\t\t\t\t\tname: 'If staying in white light, the color temperature',\n\t\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t\t\trole: 'level.color.temperature',\n\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\twrite: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tnative: {},\n\t\t\t\t\t});\n\t\t\t\t\tawait this.updateStateAsync(\n\t\t\t\t\t\t`${sendingDevice}.devStatus.colorTemInKelvin`,\n\t\t\t\t\t\tdevStatusMessageObject.msg.data.colorTemInKelvin,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tthis.log.error('message from: ' + remote.address + ':' + remote.port + ' - ' + message);\n\t\t}\n\t}\n\n\tprivate async refreshAllDevices(): Promise<void> {\n\t\tfor (const ip in devices) {\n\t\t\tthis.requestDeviceStatus(ip);\n\t\t}\n\t}\n\n\t/**\n\t * sends the device status request to one specific device\n\t * @param receiver the ip ( / hsotname ) of the device that should be queried\n\t */\n\tprivate requestDeviceStatus(receiver: string): void {\n\t\tconst requestDeviceStatusBuffer = Buffer.from(JSON.stringify(requestStatusMessage));\n\t\tsocket.send(requestDeviceStatusBuffer, 0, requestDeviceStatusBuffer.length, CONTROL_PORT, receiver);\n\t}\n\n\t/**\n\t * send the scan message to the udp multicast address\n\t */\n\tprivate async sendScan(): Promise<void> {\n\t\tconst scanMessageBuffer = Buffer.from(JSON.stringify(scanMessage));\n\t\tsocket.send(scanMessageBuffer, 0, scanMessageBuffer.length, SEND_SCAN_PORT, M_CAST);\n\t}\n\n\t/**\n\t * Is called when adapter shuts down - callback has to be called under any circumstances!\n\t */\n\tprivate onUnload(callback: () => void): void {\n\t\ttry {\n\t\t\tthis.clearInterval(searchInterval);\n\t\t\tthis.clearInterval(refreshInterval);\n\t\t\tsocket.close();\n\t\t\tthis.updateStateAsync('info.connection', false);\n\t\t\tcallback();\n\t\t} catch (e: any) {\n\t\t\tthis.log.error(e.message);\n\t\t\tcallback();\n\t\t}\n\t}\n\n\t/**\n\t * Is called if a subscribed state changes\n\t */\n\tprivate async onStateChange(id: string, state: ioBroker.State | null | undefined): Promise<void> {\n\t\tif (state && !state.ack) {\n\t\t\tconst ipOfDevice = await this.getStateAsync(id.split('.')[2] + '.deviceInfo.ip');\n\t\t\tif (ipOfDevice) {\n\t\t\t\tconst receiver = ipOfDevice.val?.toString();\n\t\t\t\tswitch (id.split('.')[4]) {\n\t\t\t\t\tcase 'onOff':\n\t\t\t\t\t\tconst turnMessage = { msg: { cmd: 'turn', data: { value: state.val ? 1 : 0 } } };\n\t\t\t\t\t\tconst turnMessageBuffer = Buffer.from(JSON.stringify(turnMessage));\n\t\t\t\t\t\tsocket.send(turnMessageBuffer, 0, turnMessageBuffer.length, CONTROL_PORT, receiver);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'brightness':\n\t\t\t\t\t\tconst brightnessMessage = { msg: { cmd: 'brightness', data: { value: state.val } } };\n\t\t\t\t\t\tconst brightnessMessageBuffer = Buffer.from(JSON.stringify(brightnessMessage));\n\t\t\t\t\t\tsocket.send(brightnessMessageBuffer, 0, brightnessMessageBuffer.length, CONTROL_PORT, receiver);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'colorTemInKelvin':\n\t\t\t\t\t\tconst colorTempMessageBuffer = Buffer.from(\n\t\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\t\tmsg: {\n\t\t\t\t\t\t\t\t\tcmd: 'colorwc',\n\t\t\t\t\t\t\t\t\tdata: { color: { r: '0', g: '0', b: '0' }, colorTemInKelvin: state.val },\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tsocket.send(colorTempMessageBuffer, 0, colorTempMessageBuffer.length, CONTROL_PORT, receiver);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'color':\n\t\t\t\t\t\tconst colorValue = state.val?.toString();\n\t\t\t\t\t\tif (colorValue) {\n\t\t\t\t\t\t\tconst rgb = hexToRgb(colorValue);\n\t\t\t\t\t\t\tconst colorMessage = { msg: { cmd: 'colorwc', data: { color: rgb } } };\n\t\t\t\t\t\t\tconst colorMessageBuffer = Buffer.from(JSON.stringify(colorMessage));\n\t\t\t\t\t\t\tsocket.send(colorMessageBuffer, 0, colorMessageBuffer.length, CONTROL_PORT, receiver);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.log.error('device not found');\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async updateStateAsync(fullName: string, state: any, acknowledged = true): Promise<void> {\n\t\tconst currentState = await this.getStateAsync(fullName);\n\t\tif (currentState != state) {\n\t\t\tthis.setState(fullName, {\n\t\t\t\tval: state,\n\t\t\t\tack: acknowledged,\n\t\t\t});\n\t\t}\n\t}\n}\n\nif (require.main !== module) {\n\t// Export the constructor in compact mode\n\tmodule.exports = (options: Partial<utils.AdapterOptions> | undefined) => new GoveeLocal(options);\n} else {\n\t// otherwise start the instance directly\n\t(() => new GoveeLocal())();\n}\n\n/**\n * This method returns the description for device information datapoints\n * to unbloat the upper methods.\n * tanslations would be great here\n * @param name the name of the parameter retrieved from the device\n * @returns the description, that should be set to the datapoint\n */\nfunction getDatapointDescription(name: string): string {\n\tswitch (name) {\n\t\tcase 'model':\n\t\t\treturn 'Specific model of the Lamp';\n\t\tcase 'ip':\n\t\t\treturn 'IP address of the Lamp';\n\t\tcase 'bleVersionHard':\n\t\t\treturn 'Bluetooth Low Energy Hardware Version';\n\t\tcase 'bleVersionSoft':\n\t\t\treturn 'Bluetooth Low Energy Software Version';\n\t\tcase 'wifiVersionHard':\n\t\t\treturn 'WiFi Hardware Version';\n\t\tcase 'wifiVersionSoft':\n\t\t\treturn 'WiFi Software Version';\n\t\tdefault:\n\t\t\treturn '';\n\t}\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/*\n * Created with @iobroker/create-adapter v2.3.0\n */\n\n// The adapter-core module gives you access to the core ioBroker functions\n// you need to create an adapter\nimport * as utils from '@iobroker/adapter-core';\nimport * as dgram from 'node:dgram';\nimport { componentToHex, hexToRgb } from './tools/hexTool';\n\n// Load your modules here, e.g.:\n\nconst LOCAL_PORT = 4002;\nconst SEND_SCAN_PORT = 4001;\nconst CONTROL_PORT = 4003;\nconst M_CAST = '239.255.255.250';\n\nconst socket = dgram.createSocket({ type: 'udp4' });\n\nconst scanMessage = { msg: { cmd: 'scan', data: { account_topic: 'reserved' } } };\nconst requestStatusMessage = { msg: { cmd: 'devStatus', data: {} } };\n\nlet searchInterval: ioBroker.Interval;\nlet refreshInterval: ioBroker.Interval;\n\nconst devices: { [ip: string]: string } = {};\n\nconst loggedDevices = [] as string[];\n\nexport class GoveeLocal extends utils.Adapter {\n\tpublic constructor(options: Partial<utils.AdapterOptions> = {}) {\n\t\tsuper({\n\t\t\t...options,\n\t\t\tname: 'govee-local',\n\t\t});\n\t\tthis.on('ready', this.onReady.bind(this));\n\t\tthis.on('stateChange', this.onStateChange.bind(this));\n\t\t// this.on('objectChange', this.onObjectChange.bind(this));\n\t\t// this.on('message', this.onMessage.bind(this));\n\t\tthis.on('unload', this.onUnload.bind(this));\n\t}\n\n\t/**\n\t * Is called when databases are connected and adapter received configuration.\n\t */\n\tprivate async onReady(): Promise<void> {\n\t\tvoid this.setObjectNotExists('info.connection', {\n\t\t\ttype: 'state',\n\t\t\tcommon: {\n\t\t\t\tname: 'Device discovery running',\n\t\t\t\ttype: 'boolean',\n\t\t\t\trole: 'indicator.connected',\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\t\tsocket.on('message', this.onUdpMessage.bind(this));\n\t\tsocket.on('error', (error) => {\n\t\t\tthis.log.error(`server bind error : ${error.message}`);\n\t\t\tvoid this.setStateChanged('info.connection', { val: false, ack: true });\n\t\t});\n\n\t\tif (this.config.extendedLogging) {\n\t\t\tthis.log.debug('running with extended logging');\n\t\t}\n\n\t\tvoid socket.bind({ address: this.config.interface, port: LOCAL_PORT }, this.serverBound.bind(this));\n\t\tvoid this.subscribeStates('*.devStatus.*');\n\t\treturn Promise.resolve();\n\t}\n\n\t/**\n\t * handles when udp socket is up\n\t * configure multicast membership\n\t * start periodic scan for devices\n\t */\n\tprivate async serverBound(): Promise<void> {\n\t\tsocket.setBroadcast(true);\n\t\tsocket.setMulticastTTL(128);\n\t\tsocket.setMulticastInterface(this.config.interface);\n\t\tsocket.addMembership(M_CAST);\n\t\tvoid this.setStateChanged('info.connection', { val: true, ack: true });\n\t\tthis.log.debug(`UDP listening on ${(socket.address() as any).address}:${(socket.address() as any).port}`);\n\n\t\tconst deviceSearchInterval = this.setInterval(this.sendScan.bind(this), this.config.searchInterval * 1000);\n\t\tif (deviceSearchInterval) {\n\t\t\tsearchInterval = deviceSearchInterval;\n\t\t}\n\n\t\tconst deviceRefreshInterval = this.setInterval(\n\t\t\tthis.refreshAllDevices.bind(this),\n\t\t\tthis.config.deviceStatusRefreshInterval * 1000,\n\t\t);\n\t\tif (deviceRefreshInterval) {\n\t\t\trefreshInterval = deviceRefreshInterval;\n\t\t}\n\t\treturn Promise.resolve();\n\t}\n\n\t/**\n\t * handle icoming messages on the udp socket\n\t *\n\t * @param message the message itself\n\t * @param remote the sender of the message\n\t */\n\tprivate async onUdpMessage(message: Buffer, remote: dgram.RemoteInfo): Promise<void> {\n\t\tconst messageObject = JSON.parse(message.toString());\n\t\tswitch (messageObject.msg.cmd) {\n\t\t\tcase 'scan': {\n\t\t\t\tfor (const key of Object.keys(messageObject.msg.data)) {\n\t\t\t\t\tif (key != 'device') {\n\t\t\t\t\t\tconst deviceName = messageObject.msg.data.device.replace(this.FORBIDDEN_CHARS, '_');\n\t\t\t\t\t\tdevices[remote.address] = deviceName;\n\t\t\t\t\t\tvoid this.setObjectNotExists(deviceName, {\n\t\t\t\t\t\t\ttype: 'device',\n\t\t\t\t\t\t\tcommon: {\n\t\t\t\t\t\t\t\tname: messageObject.msg.data.sku,\n\t\t\t\t\t\t\t\trole: 'group',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tnative: {},\n\t\t\t\t\t\t});\n\t\t\t\t\t\tvoid this.setObjectNotExists(`${deviceName}.deviceInfo.${key}`, {\n\t\t\t\t\t\t\ttype: 'state',\n\t\t\t\t\t\t\tcommon: {\n\t\t\t\t\t\t\t\tname: getDatapointDescription(key),\n\t\t\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\t\t\trole: 'state',\n\t\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\t\twrite: false,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tnative: {},\n\t\t\t\t\t\t});\n\t\t\t\t\t\tvoid this.updateStateAsync(`${deviceName}.deviceInfo.${key}`, messageObject.msg.data[key]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'devStatus': {\n\t\t\t\tconst sendingDevice = devices[remote.address];\n\t\t\t\tif (sendingDevice) {\n\t\t\t\t\tif (this.config.extendedLogging && !loggedDevices.includes(remote.address.toString())) {\n\t\t\t\t\t\tthis.log.info(`deivce status message data: ${JSON.stringify(messageObject)}`);\n\t\t\t\t\t\tloggedDevices.push(remote.address.toString());\n\t\t\t\t\t}\n\t\t\t\t\tconst devStatusMessageObject = JSON.parse(message.toString());\n\t\t\t\t\tvoid this.setObjectNotExists(`${sendingDevice}.devStatus.onOff`, {\n\t\t\t\t\t\ttype: 'state',\n\t\t\t\t\t\tcommon: {\n\t\t\t\t\t\t\tname: 'On / Off state of the lamp',\n\t\t\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\t\t\trole: 'switch',\n\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\twrite: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tnative: {},\n\t\t\t\t\t});\n\t\t\t\t\tvoid this.updateStateAsync(\n\t\t\t\t\t\t`${sendingDevice}.devStatus.onOff`,\n\t\t\t\t\t\tdevStatusMessageObject.msg.data.onOff == 1,\n\t\t\t\t\t);\n\t\t\t\t\tvoid this.setObjectNotExists(`${sendingDevice}.devStatus.brightness`, {\n\t\t\t\t\t\ttype: 'state',\n\t\t\t\t\t\tcommon: {\n\t\t\t\t\t\t\tname: 'Brightness of the light',\n\t\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t\t\trole: 'level.dimmer',\n\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\twrite: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tnative: {},\n\t\t\t\t\t});\n\t\t\t\t\tvoid this.updateStateAsync(\n\t\t\t\t\t\t`${sendingDevice}.devStatus.brightness`,\n\t\t\t\t\t\tdevStatusMessageObject.msg.data.brightness,\n\t\t\t\t\t);\n\t\t\t\t\tvoid this.setObjectNotExists(`${sendingDevice}.devStatus.color`, {\n\t\t\t\t\t\ttype: 'state',\n\t\t\t\t\t\tcommon: {\n\t\t\t\t\t\t\tname: 'Current showing color of the lamp',\n\t\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\t\trole: 'level.color.rgb',\n\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\twrite: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tnative: {},\n\t\t\t\t\t});\n\t\t\t\t\tconst colorString = `#${componentToHex(devStatusMessageObject.msg.data.color.r)}${componentToHex(devStatusMessageObject.msg.data.color.g)}${componentToHex(devStatusMessageObject.msg.data.color.b)}`;\n\t\t\t\t\tvoid this.setState(`${sendingDevice}.devStatus.color`, {\n\t\t\t\t\t\tval: colorString,\n\t\t\t\t\t\tack: true,\n\t\t\t\t\t});\n\t\t\t\t\tvoid this.updateStateAsync(`${sendingDevice}.devStatus.color`, colorString);\n\t\t\t\t\tvoid this.setObjectNotExists(`${sendingDevice}.devStatus.colorTemInKelvin`, {\n\t\t\t\t\t\ttype: 'state',\n\t\t\t\t\t\tcommon: {\n\t\t\t\t\t\t\tname: 'If staying in white light, the color temperature',\n\t\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t\t\trole: 'level.color.temperature',\n\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\twrite: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tnative: {},\n\t\t\t\t\t});\n\t\t\t\t\tvoid this.updateStateAsync(\n\t\t\t\t\t\t`${sendingDevice}.devStatus.colorTemInKelvin`,\n\t\t\t\t\t\tdevStatusMessageObject.msg.data.colorTemInKelvin,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tthis.log.error(`message from: ${remote.address}:${remote.port} - ${message.toString()}`);\n\t\t\t}\n\t\t}\n\t\treturn Promise.resolve();\n\t}\n\n\tprivate async refreshAllDevices(): Promise<void> {\n\t\tfor (const ip in devices) {\n\t\t\tthis.requestDeviceStatus(ip);\n\t\t}\n\t\treturn Promise.resolve();\n\t}\n\n\t/**\n\t * sends the device status request to one specific device\n\t *\n\t * @param receiver the ip ( / hsotname ) of the device that should be queried\n\t */\n\tprivate requestDeviceStatus(receiver: string): void {\n\t\tconst requestDeviceStatusBuffer = Buffer.from(JSON.stringify(requestStatusMessage));\n\t\tvoid socket.send(requestDeviceStatusBuffer, 0, requestDeviceStatusBuffer.length, CONTROL_PORT, receiver);\n\t}\n\n\t/**\n\t * send the scan message to the udp multicast address\n\t */\n\tprivate async sendScan(): Promise<void> {\n\t\tconst scanMessageBuffer = Buffer.from(JSON.stringify(scanMessage));\n\t\tvoid socket.send(scanMessageBuffer, 0, scanMessageBuffer.length, SEND_SCAN_PORT, M_CAST);\n\t\treturn Promise.resolve();\n\t}\n\n\t/**\n\t * Is called when adapter shuts down - callback has to be called under any circumstances!\n\t *\n\t * @param callback Callback-Funktion, die nach Abschluss des Unload-Prozesses aufgerufen wird.\n\t */\n\tprivate onUnload(callback: () => void): void {\n\t\ttry {\n\t\t\tthis.clearInterval(searchInterval);\n\t\t\tthis.clearInterval(refreshInterval);\n\t\t\tsocket.close();\n\t\t\tvoid this.updateStateAsync('info.connection', false);\n\t\t\tcallback();\n\t\t} catch (e: any) {\n\t\t\tthis.log.error(e.message);\n\t\t\tcallback();\n\t\t}\n\t}\n\n\t/**\n\t * Is called if a subscribed state changes\n\t *\n\t * @param id Die ID des ge\u00E4nderten States.\n\t * @param state Das neue State-Objekt oder null/undefined.\n\t */\n\tprivate async onStateChange(id: string, state: ioBroker.State | null | undefined): Promise<void> {\n\t\tif (state && !state.ack) {\n\t\t\tconst ipOfDevice = await this.getStateAsync(`${id.split('.')[2]}.deviceInfo.ip`);\n\t\t\tif (ipOfDevice) {\n\t\t\t\tconst receiver = ipOfDevice.val?.toString();\n\t\t\t\tswitch (id.split('.')[4]) {\n\t\t\t\t\tcase 'onOff': {\n\t\t\t\t\t\tconst turnMessage = { msg: { cmd: 'turn', data: { value: state.val ? 1 : 0 } } };\n\t\t\t\t\t\tconst turnMessageBuffer = Buffer.from(JSON.stringify(turnMessage));\n\t\t\t\t\t\tvoid socket.send(turnMessageBuffer, 0, turnMessageBuffer.length, CONTROL_PORT, receiver);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase 'brightness': {\n\t\t\t\t\t\tconst brightnessMessage = { msg: { cmd: 'brightness', data: { value: state.val } } };\n\t\t\t\t\t\tconst brightnessMessageBuffer = Buffer.from(JSON.stringify(brightnessMessage));\n\t\t\t\t\t\tvoid socket.send(\n\t\t\t\t\t\t\tbrightnessMessageBuffer,\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\tbrightnessMessageBuffer.length,\n\t\t\t\t\t\t\tCONTROL_PORT,\n\t\t\t\t\t\t\treceiver,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase 'colorTemInKelvin': {\n\t\t\t\t\t\tconst colorTempMessageBuffer = Buffer.from(\n\t\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\t\tmsg: {\n\t\t\t\t\t\t\t\t\tcmd: 'colorwc',\n\t\t\t\t\t\t\t\t\tdata: { color: { r: '0', g: '0', b: '0' }, colorTemInKelvin: state.val },\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tvoid socket.send(\n\t\t\t\t\t\t\tcolorTempMessageBuffer,\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\tcolorTempMessageBuffer.length,\n\t\t\t\t\t\t\tCONTROL_PORT,\n\t\t\t\t\t\t\treceiver,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase 'color': {\n\t\t\t\t\t\tconst colorValue = state.val?.toString();\n\t\t\t\t\t\tif (colorValue) {\n\t\t\t\t\t\t\tconst rgb = hexToRgb(colorValue);\n\t\t\t\t\t\t\tconst colorMessage = { msg: { cmd: 'colorwc', data: { color: rgb } } };\n\t\t\t\t\t\t\tconst colorMessageBuffer = Buffer.from(JSON.stringify(colorMessage));\n\t\t\t\t\t\t\tvoid socket.send(colorMessageBuffer, 0, colorMessageBuffer.length, CONTROL_PORT, receiver);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.log.error('device not found');\n\t\t\t}\n\t\t}\n\t\treturn Promise.resolve();\n\t}\n\n\tprivate async updateStateAsync(fullName: string, state: any, acknowledged = true): Promise<void> {\n\t\tconst currentState = await this.getStateAsync(fullName);\n\t\tif (currentState != state) {\n\t\t\tvoid this.setState(fullName, {\n\t\t\t\tval: state,\n\t\t\t\tack: acknowledged,\n\t\t\t});\n\t\t}\n\t}\n}\n\nif (require.main !== module) {\n\t// Exportiere eine Factory-Funktion f\u00FCr ioBroker, aber die Klasse ist jetzt auch als ES6-Export verf\u00FCgbar\n\tmodule.exports = (options: Partial<utils.AdapterOptions> | undefined) => new GoveeLocal(options);\n} else {\n\t// otherwise start the instance directly\n\t(() => new GoveeLocal())();\n}\n\n/**\n * This method returns the description for device information datapoints\n * to unbloat the upper methods.\n * tanslations would be great here\n *\n * @param name the name of the parameter retrieved from the device\n * @returns the description, that should be set to the datapoint\n */\nexport function getDatapointDescription(name: string): string {\n\tswitch (name) {\n\t\tcase 'model':\n\t\t\treturn 'Specific model of the Lamp';\n\t\tcase 'ip':\n\t\t\treturn 'IP address of the Lamp';\n\t\tcase 'bleVersionHard':\n\t\t\treturn 'Bluetooth Low Energy Hardware Version';\n\t\tcase 'bleVersionSoft':\n\t\t\treturn 'Bluetooth Low Energy Software Version';\n\t\tcase 'wifiVersionHard':\n\t\t\treturn 'WiFi Hardware Version';\n\t\tcase 'wifiVersionSoft':\n\t\t\treturn 'WiFi Software Version';\n\t\tdefault:\n\t\t\treturn '';\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -24,7 +24,7 @@ __export(hexTool_exports, {
24
24
  module.exports = __toCommonJS(hexTool_exports);
25
25
  function componentToHex(c) {
26
26
  const hex = c.toString(16);
27
- return hex.length == 1 ? "0" + hex : hex;
27
+ return hex.length == 1 ? `0${hex}` : hex;
28
28
  }
29
29
  function hexToRgb(hexString) {
30
30
  if (!/^#[0-9a-fA-F]{6}$/i.test(hexString)) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/tools/hexTool.ts"],
4
- "sourcesContent": ["/**\n * Convert number (<255) to two digit hex for colorcode\n * @param the int value, should me < 255\n * @returns the hex value as string\n */\nexport function componentToHex(c: number): string {\n\tconst hex = c.toString(16);\n\treturn hex.length == 1 ? '0' + hex : hex;\n}\n\nexport function hexToRgb(hexString: string): Color {\n\t// Check if the hex string is valid\n\tif (!/^#[0-9a-fA-F]{6}$/i.test(hexString)) {\n\t\tthrow new Error('Invalid hex string');\n\t}\n\n\treturn {\n\t\tr: parseInt(hexString.slice(1, 3), 16),\n\t\tg: parseInt(hexString.slice(3, 5), 16),\n\t\tb: parseInt(hexString.slice(5, 7), 16),\n\t};\n}\ntype Color = {\n\tr: number;\n\tg: number;\n\tb: number;\n};\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKO,SAAS,eAAe,GAAmB;AACjD,QAAM,MAAM,EAAE,SAAS,EAAE;AACzB,SAAO,IAAI,UAAU,IAAI,MAAM,MAAM;AACtC;AAEO,SAAS,SAAS,WAA0B;AAElD,MAAI,CAAC,qBAAqB,KAAK,SAAS,GAAG;AAC1C,UAAM,IAAI,MAAM,oBAAoB;AAAA,EACrC;AAEA,SAAO;AAAA,IACN,GAAG,SAAS,UAAU,MAAM,GAAG,CAAC,GAAG,EAAE;AAAA,IACrC,GAAG,SAAS,UAAU,MAAM,GAAG,CAAC,GAAG,EAAE;AAAA,IACrC,GAAG,SAAS,UAAU,MAAM,GAAG,CAAC,GAAG,EAAE;AAAA,EACtC;AACD;",
4
+ "sourcesContent": ["/**\n * Konvertiert eine Zahl (<255) in einen zweistelligen Hex-String f\u00FCr Farbwerte.\n *\n * @param c Die Zahl, die konvertiert werden soll (0-255)\n * @returns Der Hex-Wert als String\n */\nexport function componentToHex(c: number): string {\n\tconst hex = c.toString(16);\n\treturn hex.length == 1 ? `0${hex}` : hex;\n}\n\n/**\n * Wandelt einen Hex-Farbstring (#RRGGBB) in ein Color-Objekt um.\n *\n * @param hexString Hex-Farbwert als String (Format: #RRGGBB)\n * @returns Ein Objekt mit den Farbwerten r, g und b\n */\nexport function hexToRgb(hexString: string): Color {\n\tif (!/^#[0-9a-fA-F]{6}$/i.test(hexString)) {\n\t\tthrow new Error('Invalid hex string');\n\t}\n\treturn {\n\t\tr: parseInt(hexString.slice(1, 3), 16),\n\t\tg: parseInt(hexString.slice(3, 5), 16),\n\t\tb: parseInt(hexString.slice(5, 7), 16),\n\t};\n}\n\n/**\n * Farbobjekt mit Werten f\u00FCr Rot, Gr\u00FCn und Blau\n */\ntype Color = {\n\tr: number;\n\tg: number;\n\tb: number;\n};\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMO,SAAS,eAAe,GAAmB;AACjD,QAAM,MAAM,EAAE,SAAS,EAAE;AACzB,SAAO,IAAI,UAAU,IAAI,IAAI,GAAG,KAAK;AACtC;AAQO,SAAS,SAAS,WAA0B;AAClD,MAAI,CAAC,qBAAqB,KAAK,SAAS,GAAG;AAC1C,UAAM,IAAI,MAAM,oBAAoB;AAAA,EACrC;AACA,SAAO;AAAA,IACN,GAAG,SAAS,UAAU,MAAM,GAAG,CAAC,GAAG,EAAE;AAAA,IACrC,GAAG,SAAS,UAAU,MAAM,GAAG,CAAC,GAAG,EAAE;AAAA,IACrC,GAAG,SAAS,UAAU,MAAM,GAAG,CAAC,GAAG,EAAE;AAAA,EACtC;AACD;",
6
6
  "names": []
7
7
  }
package/io-package.json CHANGED
@@ -1,8 +1,21 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "govee-local",
4
- "version": "0.2.8",
4
+ "version": "0.2.9",
5
5
  "news": {
6
+ "0.2.9": {
7
+ "en": "update dependencies\nadd support for node 24\nupdate to ESlint 9",
8
+ "de": "aktualisierung der abhängigkeiten\nunterstützung für knoten 24 hinzufügen\nupdate auf ESlint 9",
9
+ "ru": "обновление зависимостей\nдобавить поддержку node 24\nобновление для ESlint 9",
10
+ "pt": "atualizar dependências\nadicionar suporte para o nó 24\natualização para ESlint 9",
11
+ "nl": "afhankelijkheden bijwerken\nondersteuning voor node 24 toevoegen\nupdate naar ESlint 9",
12
+ "fr": "mettre à jour les dépendances\najouter un support pour le nœud 24\nmise à jour de ESlint 9",
13
+ "it": "aggiornamento dipendenze\naggiungere supporto per nodo 24\naggiornamento a ESlint 9",
14
+ "es": "dependencias de actualización\nañadir soporte para nodo 24\nactualización a ESlint 9",
15
+ "pl": "aktualizacji zależności\ndodaj obsługę węzła 24\naktualizacja do ESlint 9",
16
+ "uk": "оновлення залежності\nдодати підтримку для вузла 24\nоновлення до ESlint 9",
17
+ "zh-cn": "更新依赖关系\n添加节点24的支持\n更新到 Eslint 9"
18
+ },
6
19
  "0.2.8": {
7
20
  "en": "update dependencies",
8
21
  "de": "aktualisierung der abhängigkeiten",
@@ -80,19 +93,6 @@
80
93
  "pl": "remontowanie Off / wszystkie inne działania Fiksy #65\nusunąć z powodu dzikiej karty",
81
94
  "uk": "ремонт наОфф / всі інші дії Виправлення: #65\nфіксація спамерування колод через дикийкарт",
82
95
  "zh-cn": "b. 修理效率/所有其他行动 固定: #65\nfix 由于野生素卡的投机"
83
- },
84
- "0.2.0": {
85
- "en": "support controlling the color\nextended logging mode",
86
- "de": "unterstützung controlling der farbe\nerweiterter logging-modus",
87
- "ru": "поддержка контролируя цвет\nрасширенный режим входа",
88
- "pt": "suporte controlando a cor\nmodo de registro estendido",
89
- "nl": "de kleur controleren\nverlengde logging mode",
90
- "fr": "support de contrôle de la couleur\nmode d ' enregistrement élargi",
91
- "it": "supporto che controlla il colore\nmodalità di registrazione estesa",
92
- "es": "soporte controlando el color\nmodo de registro ampliado",
93
- "pl": "kontrolować kolor\nrozszerzony tryb logowania",
94
- "uk": "супровід управління кольором\nрозширений режим входу",
95
- "zh-cn": "控制颜色的支助\n扩大的伐木模式"
96
96
  }
97
97
  },
98
98
  "titleLang": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.govee-local",
3
- "version": "0.2.8",
3
+ "version": "0.2.9",
4
4
  "description": "Control Govee devices via local access (no cloud)",
5
5
  "author": {
6
6
  "name": "Børge Grunicke",
@@ -29,30 +29,27 @@
29
29
  "@alcalzone/release-script-plugin-iobroker": "^3.7.2",
30
30
  "@alcalzone/release-script-plugin-license": "^3.7.0",
31
31
  "@alcalzone/release-script-plugin-manual-review": "^3.7.0",
32
- "@iobroker/adapter-dev": "^1.3.0",
33
- "@iobroker/testing": "^5.0.0",
34
- "@tsconfig/node14": "^14.1.2",
32
+ "@iobroker/adapter-dev": "^1.4.0",
33
+ "@iobroker/eslint-config": "^2.0.2",
34
+ "@iobroker/testing": "^5.0.4",
35
+ "@tsconfig/node14": "^14.1.3",
35
36
  "@tsconfig/node18": "^18.2.4",
36
- "@tsconfig/node20": "^20.1.4",
37
+ "@tsconfig/node20": "^20.1.6",
37
38
  "@types/chai": "^4.1.1",
38
- "@types/chai-as-promised": "^8.0.0",
39
- "@types/mocha": "^10.0.9",
40
- "@types/node": "^22.8.7",
39
+ "@types/chai-as-promised": "^8.0.2",
40
+ "@types/mocha": "^10.0.10",
41
+ "@types/node": "^24.0.8",
41
42
  "@types/proxyquire": "^1.3.31",
42
- "@types/sinon": "^17.0.3",
43
+ "@types/sinon": "^17.0.4",
43
44
  "@types/sinon-chai": "^3.2.12",
44
- "@typescript-eslint/eslint-plugin": "^8.12.2",
45
- "@typescript-eslint/parser": "^8.12.2",
46
45
  "chai": "^4.5.0",
47
- "chai-as-promised": "^8.0.0",
48
- "eslint": "^8.57.1",
49
- "eslint-config-prettier": "^9.1.0",
50
- "eslint-plugin-prettier": "^5.2.1",
51
- "mocha": "^10.8.2",
46
+ "chai-as-promised": "^8.0.1",
47
+ "eslint": "^9.32.0",
48
+ "mocha": "^11.7.1",
52
49
  "prettier": "^3.3.3",
53
50
  "proxyquire": "^2.1.3",
54
51
  "rimraf": "^6.0.1",
55
- "sinon": "^19.0.2",
52
+ "sinon": "^21.0.0",
56
53
  "sinon-chai": "^3.7.0",
57
54
  "source-map-support": "^0.5.21",
58
55
  "ts-node": "^10.9.2",