iobroker.govee-local 0.1.2 → 0.2.0

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
@@ -2,6 +2,15 @@
2
2
 
3
3
  ## govee-local adapter for ioBroker
4
4
 
5
+ [![NPM version](https://img.shields.io/npm/v/iobroker.govee-local.svg)](https://www.npmjs.com/package/iobroker.govee-local)
6
+ [![Downloads](https://img.shields.io/npm/dm/iobroker.govee-local.svg)](https://www.npmjs.com/package/iobroker.govee-local)
7
+ ![Number of Installations](https://iobroker.live/badges/govee-local-installed.svg)
8
+ ![Current version in stable repository](https://iobroker.live/badges/govee-local-stable.svg)
9
+
10
+ [![NPM](https://nodei.co/npm/iobroker.govee-local.png?downloads=true)](https://nodei.co/npm/iobroker.govee-local/)
11
+
12
+ **Tests:** ![Test and Release](https://github.com/boergegrunicke/ioBroker.govee-local/workflows/Test%20and%20Release/badge.svg)
13
+
5
14
  Control Govee devices via local access (no cloud)
6
15
 
7
16
  To be able to control govee deivce locally, the feature needs to be explicitely turned on in the settings of the govve application settings as described in their [documentation](<https://app-h5.govee.com/user-manual/wlan-guide#:~:text=Supported%20Product%20Models%20(continually%20updated)>)
@@ -13,8 +22,14 @@ As I currently only have the H6051 lamp, this is the only device I can test with
13
22
  Placeholder for the next version (at the beginning of the line):
14
23
  ### **WORK IN PROGRESS**
15
24
  -->
25
+ ### 0.2.0 (2023-12-17)
26
+
27
+ - support controlling the color
28
+ - extended logging mode
29
+
16
30
  ### 0.1.2 (2023-09-06)
17
- - change icon path and resolution
31
+
32
+ - change icon path and resolution
18
33
 
19
34
  ### 0.1.1 (2023-08-21)
20
35
 
@@ -1,6 +1,8 @@
1
1
  {
2
- "govee-local adapter settings": "Adaptereinstellungen für govee-local",
3
- "_searchInterval": "Suchintervall",
4
- "_deviceStatusRefreshInterval": "Aktualisierungsintervall für den Gerätestatus",
5
- "_configDescription": "Hier muss nichts konfiguriert werden. Bitte die Intervalle nur ändern, wenn dies explizit gewollt ist."
2
+ "govee-local adapter settings": "Adaptereinstellungen für govee-local",
3
+ "_searchInterval": "Suchintervall",
4
+ "_deviceStatusRefreshInterval": "Aktualisierungsintervall für den Gerätestatus",
5
+ "_configDescription": "Hier muss nichts konfiguriert werden. Bitte die Intervalle nur ändern, wenn dies explizit gewollt ist.",
6
+ "_extendedLoggingDescription": "Die erweiterte Protokollierung druckt alle vom Gerät empfangenen Daten mit Ebeneninformationen in das Protokoll. Da dies zu einem großen Log-Spam führt, wird empfohlen, die Funktion nur bei Bedarf einzuschalten und anschließend wieder auszuschalten.",
7
+ "_extendedLogging": "Erweiterte Protokollierung aktiviert"
6
8
  }
@@ -2,5 +2,7 @@
2
2
  "govee-local adapter settings": "Adapter settings for govee-local",
3
3
  "_searchInterval": "Search interval",
4
4
  "_deviceStatusRefreshInterval": "device status refresh interval",
5
- "_configDescription": "There is nothing mandatory to configure. Please change the intervals only when you are sure that this is what you need"
5
+ "_configDescription": "There is nothing mandatory to configure. Please change the intervals only when you are sure that this is what you need",
6
+ "_extendedLoggingDescription": "Extended Logging prints all the data received by the device to the log with level info. As this produces a huge log spamming it is recommended to turn this on, only when needed and turnoff again afterwards.",
7
+ "_extendedLogging": "Extended Logging enabled"
6
8
  }
@@ -2,5 +2,7 @@
2
2
  "govee-local adapter settings": "Ajustes del adaptador para govee-local",
3
3
  "_searchInterval": "Intervalo de búsqueda",
4
4
  "_deviceStatusRefreshInterval": "intervalo de actualización del estado del dispositivo",
5
- "_configDescription": "No hay nada obligatorio para configurar. Cambie los intervalos solo cuando esté seguro de que esto es lo que necesita"
5
+ "_configDescription": "No hay nada obligatorio para configurar. Cambie los intervalos solo cuando esté seguro de que esto es lo que necesita",
6
+ "_extendedLoggingDescription": "El registro extendido imprime todos los datos recibidos por el dispositivo en el registro con información de nivel. Como esto produce un enorme spam de registros, se recomienda activarlo sólo cuando sea necesario y desactivarlo nuevamente después.",
7
+ "_extendedLogging": "Registro extendido habilitado"
6
8
  }
@@ -2,5 +2,7 @@
2
2
  "govee-local adapter settings": "Paramètres d'adaptateur pour govee-local",
3
3
  "_searchInterval": "Intervalle de recherche",
4
4
  "_deviceStatusRefreshInterval": "intervalle d'actualisation de l'état de l'appareil",
5
- "_configDescription": "Il n'y a rien d'obligatoire à configurer. Veuillez modifier les intervalles uniquement lorsque vous êtes sûr que c'est ce dont vous avez besoin"
5
+ "_configDescription": "Il n'y a rien d'obligatoire à configurer. Veuillez modifier les intervalles uniquement lorsque vous êtes sûr que c'est ce dont vous avez besoin",
6
+ "_extendedLoggingDescription": "La journalisation étendue imprime toutes les données reçues par l'appareil dans le journal avec les informations de niveau. Comme cela produit un énorme spam de journaux, il est recommandé de l'activer uniquement lorsque cela est nécessaire et de le désactiver à nouveau par la suite.",
7
+ "_extendedLogging": "Journalisation étendue activée"
6
8
  }
@@ -2,5 +2,7 @@
2
2
  "govee-local adapter settings": "Impostazioni dell'adattatore per govee-local",
3
3
  "_searchInterval": "Intervallo di ricerca",
4
4
  "_deviceStatusRefreshInterval": "intervallo di aggiornamento dello stato del dispositivo",
5
- "_configDescription": "Non c'è nulla di obbligatorio da configurare. Si prega di modificare gli intervalli solo quando si è sicuri che questo è ciò di cui si ha bisogno"
5
+ "_configDescription": "Non c'è nulla di obbligatorio da configurare. Si prega di modificare gli intervalli solo quando si è sicuri che questo è ciò di cui si ha bisogno",
6
+ "_extendedLoggingDescription": "La registrazione estesa stampa tutti i dati ricevuti dal dispositivo nel registro con le informazioni sul livello. Poiché ciò produce un enorme spam nei registri, si consiglia di attivarlo solo quando necessario e di disattivarlo nuovamente in seguito.",
7
+ "_extendedLogging": "Registrazione estesa abilitata"
6
8
  }
@@ -2,5 +2,7 @@
2
2
  "govee-local adapter settings": "Adapterinstellingen voor govee-local",
3
3
  "_searchInterval": "Zoek interval",
4
4
  "_deviceStatusRefreshInterval": "vernieuwingsinterval apparaatstatus",
5
- "_configDescription": "Er is niets verplicht om te configureren. Wijzig de intervallen alleen als u zeker weet dat dit is wat u nodig heeft"
5
+ "_configDescription": "Er is niets verplicht om te configureren. Wijzig de intervallen alleen als u zeker weet dat dit is wat u nodig heeft",
6
+ "_extendedLoggingDescription": "Uitgebreide logboekregistratie drukt alle door het apparaat ontvangen gegevens af naar het logboek met niveau-informatie. Omdat dit een enorme log-spam veroorzaakt, is het aan te raden dit alleen in te schakelen als dat nodig is en daarna weer uit te schakelen.",
7
+ "_extendedLogging": "Uitgebreide logboekregistratie ingeschakeld"
6
8
  }
@@ -2,5 +2,7 @@
2
2
  "govee-local adapter settings": "Ustawienia adaptera dla govee-local",
3
3
  "_searchInterval": "Interwał wyszukiwania",
4
4
  "_deviceStatusRefreshInterval": "interwał odświeżania stanu urządzenia",
5
- "_configDescription": "Nie ma nic obowiązkowego do skonfigurowania. Zmień interwały tylko wtedy, gdy jesteś pewien, że tego właśnie potrzebujesz"
5
+ "_configDescription": "Nie ma nic obowiązkowego do skonfigurowania. Zmień interwały tylko wtedy, gdy jesteś pewien, że tego właśnie potrzebujesz",
6
+ "_extendedLoggingDescription": "Rozszerzone rejestrowanie drukuje wszystkie dane otrzymane przez urządzenie w dzienniku z informacjami o poziomie. Ponieważ powoduje to powstawanie ogromnego spamu w dziennikach, zaleca się włączenie tej opcji tylko w razie potrzeby, a następnie wyłączenie jej ponownie.",
7
+ "_extendedLogging": "Włączono rozszerzone rejestrowanie"
6
8
  }
@@ -2,5 +2,7 @@
2
2
  "govee-local adapter settings": "Configurações do adaptador para govee-local",
3
3
  "_searchInterval": "Intervalo de pesquisa",
4
4
  "_deviceStatusRefreshInterval": "intervalo de atualização do status do dispositivo",
5
- "_configDescription": "Não há nada obrigatório para configurar. Por favor, altere os intervalos somente quando tiver certeza de que é isso que você precisa"
5
+ "_configDescription": "Não há nada obrigatório para configurar. Por favor, altere os intervalos somente quando tiver certeza de que é isso que você precisa",
6
+ "_extendedLoggingDescription": "O Extended Logging imprime todos os dados recebidos pelo dispositivo no log com informações de nível. Como isso produz um grande spam de log, é recomendável ativá-lo somente quando necessário e desligá-lo novamente depois.",
7
+ "_extendedLogging": "Registro estendido ativado"
6
8
  }
@@ -2,5 +2,7 @@
2
2
  "govee-local adapter settings": "Настройки адаптера для govee-local",
3
3
  "_searchInterval": "Интервал поиска",
4
4
  "_deviceStatusRefreshInterval": "интервал обновления статуса устройства",
5
- "_configDescription": "Нет ничего обязательного для настройки. Пожалуйста, меняйте интервалы только тогда, когда вы уверены, что это то, что вам нужно."
5
+ "_configDescription": "Нет ничего обязательного для настройки. Пожалуйста, меняйте интервалы только тогда, когда вы уверены, что это то, что вам нужно.",
6
+ "_extendedLoggingDescription": "Расширенная регистрация записывает все данные, полученные устройством, в журнал с информацией об уровне. Поскольку это приводит к большому количеству спама в журналах, рекомендуется включать эту функцию только при необходимости, а затем снова выключать.",
7
+ "_extendedLogging": "Расширенное ведение журнала включено"
6
8
  }
@@ -2,5 +2,7 @@
2
2
  "govee-local adapter settings": "Adapter settings for govee-local",
3
3
  "_searchInterval": "Інтервал пошуку",
4
4
  "_deviceStatusRefreshInterval": "інтервал оновлення стану пристрою",
5
- "_configDescription": "Немає нічого обов’язкового для налаштування. Будь ласка, змінюйте інтервали лише тоді, коли ви впевнені, що це те, що вам потрібно"
5
+ "_configDescription": "Немає нічого обов’язкового для налаштування. Будь ласка, змінюйте інтервали лише тоді, коли ви впевнені, що це те, що вам потрібно",
6
+ "_extendedLoggingDescription": "Extended Logging друкує всі дані, отримані пристроєм, у журналі з інформацією про рівень. Оскільки це створює величезну кількість спаму в журналі, рекомендується вмикати це лише за потреби, а потім знову вимикати.",
7
+ "_extendedLogging": "Розширене журналювання ввімкнено"
6
8
  }
@@ -2,5 +2,7 @@
2
2
  "govee-local adapter settings": "govee-local的适配器设置",
3
3
  "_searchInterval": "搜索间隔",
4
4
  "_deviceStatusRefreshInterval": "设备状态刷新间隔",
5
- "_configDescription": "没有什么必须配置的。仅当您确定这是您需要的时才更改间隔"
5
+ "_configDescription": "没有什么必须配置的。仅当您确定这是您需要的时才更改间隔",
6
+ "_extendedLoggingDescription": "扩展日志记录将设备接收到的所有数据打印到带有级别信息的日志中。由于这会产生大量日志垃圾邮件,因此建议仅在需要时打开此功能,然后再次关闭。",
7
+ "_extendedLogging": "启用扩展日志记录"
6
8
  }
@@ -26,6 +26,20 @@
26
26
  "md": 2,
27
27
  "lg": 2,
28
28
  "label": "_deviceStatusRefreshInterval"
29
+ },
30
+ "_descriptionExtendedLogging": {
31
+ "type": "staticText",
32
+ "sm": 12,
33
+ "md": 12,
34
+ "lg": 12,
35
+ "text": "_extendedLoggingDescription"
36
+ },
37
+ "extendedLogging": {
38
+ "type": "checkbox",
39
+ "sm": 12,
40
+ "md": 6,
41
+ "lg": 3,
42
+ "label": "_extendedLogging"
29
43
  }
30
44
  }
31
45
  }
package/build/main.js CHANGED
@@ -39,6 +39,7 @@ const scanMessage = { msg: { cmd: "scan", data: { account_topic: "reserved" } }
39
39
  const requestStatusMessage = { msg: { cmd: "devStatus", data: {} } };
40
40
  let searchInterval;
41
41
  const intervals = {};
42
+ const loggedDevices = [];
42
43
  class GoveeLocal extends utils.Adapter {
43
44
  constructor(options = {}) {
44
45
  super({
@@ -123,7 +124,11 @@ class GoveeLocal extends utils.Adapter {
123
124
  }
124
125
  break;
125
126
  case "devStatus":
126
- const devices = await this.getStatesAsync(this.name + "." + this.instance + ".*.deviceInfo.ip");
127
+ const devices = await this.getStatesAsync(`${this.name}.${this.instance}.*.deviceInfo.ip`);
128
+ if (this.config.extendedLogging && !loggedDevices.includes(remote.address.toString())) {
129
+ this.log.info(`deivce status message data: ${JSON.stringify(messageObject.msg.data)}`);
130
+ loggedDevices.push(remote.address.toString());
131
+ }
127
132
  for (const key in devices) {
128
133
  if (devices[key].val == remote.address) {
129
134
  const sendingDevice = key.split(".")[2].replace(this.FORBIDDEN_CHARS, "_");
@@ -201,6 +206,7 @@ class GoveeLocal extends utils.Adapter {
201
206
  client.send(requestDeviceStatusBuffer, 0, requestDeviceStatusBuffer.length, CONTROL_PORT, receiver);
202
207
  }
203
208
  async sendScan() {
209
+ this.log.info("send scan");
204
210
  const scanMessageBuffer = Buffer.from(JSON.stringify(scanMessage));
205
211
  client.send(scanMessageBuffer, 0, scanMessageBuffer.length, SEND_SCAN_PORT, M_CAST);
206
212
  }
@@ -217,8 +223,8 @@ class GoveeLocal extends utils.Adapter {
217
223
  }
218
224
  }
219
225
  async onStateChange(id, state) {
220
- var _a;
221
- if (state && !state.ack) {
226
+ var _a, _b;
227
+ if (state && !state.ack && state.val) {
222
228
  const ipOfDevice = await this.getStateAsync(id.split(".")[2] + ".deviceInfo.ip");
223
229
  if (ipOfDevice) {
224
230
  const receiver = (_a = ipOfDevice.val) == null ? void 0 : _a.toString();
@@ -237,6 +243,13 @@ class GoveeLocal extends utils.Adapter {
237
243
  const colorTempMessage = { msg: { cmd: "colorTemInKelvin", data: { value: state.val } } };
238
244
  const colorTempMessageBuffer = Buffer.from(JSON.stringify(colorTempMessage));
239
245
  client.send(colorTempMessageBuffer, 0, colorTempMessageBuffer.length, CONTROL_PORT, receiver);
246
+ break;
247
+ case "color":
248
+ const rgb = hexToRgb((_b = state.val) == null ? void 0 : _b.toString());
249
+ const colorMessage = { msg: { cmd: "colorwc", data: { color: rgb } } };
250
+ const colorMessageBuffer = Buffer.from(JSON.stringify(colorMessage));
251
+ client.send(colorMessageBuffer, 0, colorMessageBuffer.length, CONTROL_PORT, receiver);
252
+ break;
240
253
  }
241
254
  } else {
242
255
  this.log.error("device not found");
@@ -271,6 +284,16 @@ function componentToHex(c) {
271
284
  const hex = c.toString(16);
272
285
  return hex.length == 1 ? "0" + hex : hex;
273
286
  }
287
+ function hexToRgb(hexString) {
288
+ if (!/^#[0-9a-f]{6}$/i.test(hexString)) {
289
+ throw new Error("Invalid hex string");
290
+ }
291
+ return {
292
+ r: parseInt(hexString.slice(1, 3), 16),
293
+ g: parseInt(hexString.slice(3, 5), 16),
294
+ b: parseInt(hexString.slice(5, 7), 16)
295
+ };
296
+ }
274
297
  // Annotate the CommonJS export names for ESM import in node:
275
298
  0 && (module.exports = {
276
299
  componentToHex
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';\n\n// Load your modules here, e.g.:\n// import * as fs from \"fs\";\n\nconst LOCAL_PORT = 4002;\nconst SEND_SCAN_PORT = 4001;\nconst CONTROL_PORT = 4003;\nconst M_CAST = '239.255.255.250';\n\nconst server = dgram.createSocket('udp4');\nconst client = dgram.createSocket('udp4');\n\nconst scanMessage = { msg: { cmd: 'scan', data: { account_topic: 'reserved' } } };\nconst requestStatusMessage = { msg: { cmd: 'devStatus', data: {} } };\n\nlet searchInterval: NodeJS.Timeout;\n\nconst intervals: { [device: string]: NodeJS.Timeout } = {};\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\tserver.on('message', this.onUdpMessage.bind(this));\n\t\tserver.on('error', (error) => {\n\t\t\tthis.log.error('server bind error : ' + error.message);\n\t\t\tthis.setState('info.connection', { val: false, ack: true });\n\t\t});\n\n\t\tserver.bind(LOCAL_PORT, this.serverBound.bind(this));\n\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\tserver.setBroadcast(true);\n\t\tserver.setMulticastTTL(128);\n\t\tserver.addMembership(M_CAST);\n\t\tthis.setState('info.connection', { val: true, ack: true });\n\t\tthis.log.debug('UDP listening on ' + server.address().address + ':' + server.address().port);\n\n\t\tconst result = this.setInterval(this.sendScan.bind(this), this.config.searchInterval * 1000);\n\t\tif (result !== void 0) {\n\t\t\tsearchInterval = result;\n\t\t}\n\t\t// this.sendScan();\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\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\tthis.setState(`${deviceName}.deviceInfo.${key}`, {\n\t\t\t\t\t\t\tval: messageObject.msg.data[key],\n\t\t\t\t\t\t\tack: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!(messageObject.msg.data.device in intervals)) {\n\t\t\t\t\tconst result = this.setInterval(\n\t\t\t\t\t\t() => this.requestDeviceStatus(messageObject.msg.data.ip),\n\t\t\t\t\t\tthis.config.deviceStatusRefreshInterval * 1000,\n\t\t\t\t\t);\n\t\t\t\t\tif (result !== void 0) {\n\t\t\t\t\t\tintervals[messageObject.msg.data.device] = result;\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 devices = await this.getStatesAsync(this.name + '.' + this.instance + '.*.deviceInfo.ip');\n\t\t\t\tfor (const key in devices) {\n\t\t\t\t\tif (devices[key as keyof typeof devices].val == remote.address) {\n\t\t\t\t\t\tconst sendingDevice = key.split('.')[2].replace(this.FORBIDDEN_CHARS, '_');\n\t\t\t\t\t\tconst devStatusMessageObject = JSON.parse(message.toString());\n\t\t\t\t\t\tthis.setObjectNotExists(`${sendingDevice}.devStatus.onOff`, {\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: 'On / Off state of the lamp',\n\t\t\t\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\t\t\t\trole: 'switch',\n\t\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\t\twrite: true,\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.setState(`${sendingDevice}.devStatus.onOff`, {\n\t\t\t\t\t\t\tval: devStatusMessageObject.msg.data.onOff == 1,\n\t\t\t\t\t\t\tack: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.setObjectNotExists(`${sendingDevice}.devStatus.brightness`, {\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: 'Brightness of the light',\n\t\t\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t\t\t\trole: 'level.dimmer',\n\t\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\t\twrite: true,\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.setState(`${sendingDevice}.devStatus.brightness`, {\n\t\t\t\t\t\t\tval: devStatusMessageObject.msg.data.brightness,\n\t\t\t\t\t\t\tack: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.setObjectNotExists(`${sendingDevice}.devStatus.color`, {\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: 'Current showing color of the lamp',\n\t\t\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\t\t\trole: 'level.color.rgb',\n\t\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\t\twrite: true,\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.setState(`${sendingDevice}.devStatus.color`, {\n\t\t\t\t\t\t\tval:\n\t\t\t\t\t\t\t\t'#' +\n\t\t\t\t\t\t\t\tcomponentToHex(devStatusMessageObject.msg.data.color.r) +\n\t\t\t\t\t\t\t\tcomponentToHex(devStatusMessageObject.msg.data.color.g) +\n\t\t\t\t\t\t\t\tcomponentToHex(devStatusMessageObject.msg.data.color.b),\n\t\t\t\t\t\t\tack: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.setObjectNotExists(`${sendingDevice}.devStatus.colorTemInKelvin`, {\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: 'If staying in white light, the color temperature',\n\t\t\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t\t\t\trole: 'level.color.temperature',\n\t\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\t\twrite: true,\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.setState(`${sendingDevice}.devStatus.colorTemInKelvin`, {\n\t\t\t\t\t\t\tval: devStatusMessageObject.msg.data.colorTemInKelvin,\n\t\t\t\t\t\t\tack: true,\n\t\t\t\t\t\t});\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\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\tconsole.log('request device status ' + receiver);\n\t\tconst requestDeviceStatusBuffer = Buffer.from(JSON.stringify(requestStatusMessage));\n\t\tclient.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\tclient.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\tObject.entries(intervals).forEach(([_, interval]) => this.clearInterval(interval));\n\t\t\tclient.close();\n\t\t\tserver.close();\n\t\t\tthis.setState('info.connection', { val: false, ack: true });\n\t\t\tcallback();\n\t\t} catch (e) {\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\tclient.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\tclient.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 colorTempMessage = { msg: { cmd: 'colorTemInKelvin', data: { value: state.val } } };\n\t\t\t\t\t\tconst colorTempMessageBuffer = Buffer.from(JSON.stringify(colorTempMessage));\n\t\t\t\t\t\tclient.send(colorTempMessageBuffer, 0, colorTempMessageBuffer.length, CONTROL_PORT, receiver);\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\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\n/**\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 */\nfunction componentToHex(c: number): string {\n\tconst hex = c.toString(16);\n\treturn hex.length == 1 ? '0' + hex : hex;\n}\n\nexport { componentToHex };\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';\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 server = dgram.createSocket('udp4');\nconst client = dgram.createSocket('udp4');\n\nconst scanMessage = { msg: { cmd: 'scan', data: { account_topic: 'reserved' } } };\nconst requestStatusMessage = { msg: { cmd: 'devStatus', data: {} } };\n\nlet searchInterval: NodeJS.Timeout;\n\nconst intervals: { [device: string]: NodeJS.Timeout } = {};\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\tserver.on('message', this.onUdpMessage.bind(this));\n\t\tserver.on('error', (error) => {\n\t\t\tthis.log.error('server bind error : ' + error.message);\n\t\t\tthis.setState('info.connection', { val: false, ack: true });\n\t\t});\n\n\t\tserver.bind(LOCAL_PORT, this.serverBound.bind(this));\n\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\tserver.setBroadcast(true);\n\t\tserver.setMulticastTTL(128);\n\t\tserver.addMembership(M_CAST);\n\t\tthis.setState('info.connection', { val: true, ack: true });\n\t\tthis.log.debug('UDP listening on ' + server.address().address + ':' + server.address().port);\n\n\t\tconst result = this.setInterval(this.sendScan.bind(this), this.config.searchInterval * 1000);\n\t\tif (result !== void 0) {\n\t\t\tsearchInterval = result;\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\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\tthis.setState(`${deviceName}.deviceInfo.${key}`, {\n\t\t\t\t\t\t\tval: messageObject.msg.data[key],\n\t\t\t\t\t\t\tack: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!(messageObject.msg.data.device in intervals)) {\n\t\t\t\t\tconst result = this.setInterval(\n\t\t\t\t\t\t() => this.requestDeviceStatus(messageObject.msg.data.ip),\n\t\t\t\t\t\tthis.config.deviceStatusRefreshInterval * 1000,\n\t\t\t\t\t);\n\t\t\t\t\tif (result !== void 0) {\n\t\t\t\t\t\tintervals[messageObject.msg.data.device] = result;\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 devices = await this.getStatesAsync(`${this.name}.${this.instance}.*.deviceInfo.ip`);\n\t\t\t\tif (this.config.extendedLogging && !loggedDevices.includes(remote.address.toString())) {\n\t\t\t\t\tthis.log.info(`deivce status message data: ${JSON.stringify(messageObject.msg.data)}`);\n\t\t\t\t\tloggedDevices.push(remote.address.toString());\n\t\t\t\t}\n\t\t\t\tfor (const key in devices) {\n\t\t\t\t\tif (devices[key as keyof typeof devices].val == remote.address) {\n\t\t\t\t\t\tconst sendingDevice = key.split('.')[2].replace(this.FORBIDDEN_CHARS, '_');\n\t\t\t\t\t\tconst devStatusMessageObject = JSON.parse(message.toString());\n\t\t\t\t\t\tthis.setObjectNotExists(`${sendingDevice}.devStatus.onOff`, {\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: 'On / Off state of the lamp',\n\t\t\t\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\t\t\t\trole: 'switch',\n\t\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\t\twrite: true,\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.setState(`${sendingDevice}.devStatus.onOff`, {\n\t\t\t\t\t\t\tval: devStatusMessageObject.msg.data.onOff == 1,\n\t\t\t\t\t\t\tack: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.setObjectNotExists(`${sendingDevice}.devStatus.brightness`, {\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: 'Brightness of the light',\n\t\t\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t\t\t\trole: 'level.dimmer',\n\t\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\t\twrite: true,\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.setState(`${sendingDevice}.devStatus.brightness`, {\n\t\t\t\t\t\t\tval: devStatusMessageObject.msg.data.brightness,\n\t\t\t\t\t\t\tack: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.setObjectNotExists(`${sendingDevice}.devStatus.color`, {\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: 'Current showing color of the lamp',\n\t\t\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\t\t\trole: 'level.color.rgb',\n\t\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\t\twrite: true,\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.setState(`${sendingDevice}.devStatus.color`, {\n\t\t\t\t\t\t\tval:\n\t\t\t\t\t\t\t\t'#' +\n\t\t\t\t\t\t\t\tcomponentToHex(devStatusMessageObject.msg.data.color.r) +\n\t\t\t\t\t\t\t\tcomponentToHex(devStatusMessageObject.msg.data.color.g) +\n\t\t\t\t\t\t\t\tcomponentToHex(devStatusMessageObject.msg.data.color.b),\n\t\t\t\t\t\t\tack: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.setObjectNotExists(`${sendingDevice}.devStatus.colorTemInKelvin`, {\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: 'If staying in white light, the color temperature',\n\t\t\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t\t\t\trole: 'level.color.temperature',\n\t\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\t\twrite: true,\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.setState(`${sendingDevice}.devStatus.colorTemInKelvin`, {\n\t\t\t\t\t\t\tval: devStatusMessageObject.msg.data.colorTemInKelvin,\n\t\t\t\t\t\t\tack: true,\n\t\t\t\t\t\t});\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\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\tconsole.log('request device status ' + receiver);\n\t\tconst requestDeviceStatusBuffer = Buffer.from(JSON.stringify(requestStatusMessage));\n\t\tclient.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\tthis.log.info('send scan');\n\t\tconst scanMessageBuffer = Buffer.from(JSON.stringify(scanMessage));\n\t\tclient.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\tObject.entries(intervals).forEach(([_, interval]) => this.clearInterval(interval));\n\t\t\tclient.close();\n\t\t\tserver.close();\n\t\t\tthis.setState('info.connection', { val: false, ack: true });\n\t\t\tcallback();\n\t\t} catch (e) {\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 && state.val) {\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\tclient.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\tclient.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 colorTempMessage = { msg: { cmd: 'colorTemInKelvin', data: { value: state.val } } };\n\t\t\t\t\t\tconst colorTempMessageBuffer = Buffer.from(JSON.stringify(colorTempMessage));\n\t\t\t\t\t\tclient.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 rgb = hexToRgb(state.val?.toString());\n\t\t\t\t\t\tconst colorMessage = { msg: { cmd: 'colorwc', data: { color: rgb } } };\n\t\t\t\t\t\tconst colorMessageBuffer = Buffer.from(JSON.stringify(colorMessage));\n\t\t\t\t\t\tclient.send(colorMessageBuffer, 0, colorMessageBuffer.length, CONTROL_PORT, receiver);\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\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\n/**\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 */\nfunction componentToHex(c: number): string {\n\tconst hex = c.toString(16);\n\treturn hex.length == 1 ? '0' + hex : hex;\n}\n\nfunction hexToRgb(hexString: string): Color {\n\t// Check if the hex string is valid\n\tif (!/^#[0-9a-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}\n\ntype Color = {\n\tr: number;\n\tg: number;\n\tb: number;\n};\n\nexport { componentToHex };\n"],
5
+ "mappings": "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",
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.1.2",
4
+ "version": "0.2.0",
5
5
  "news": {
6
+ "0.2.0": {
7
+ "en": "support controlling the color\nextended logging mode",
8
+ "de": "unterstützung controlling der farbe\nerweiterter logging-modus",
9
+ "ru": "поддержка контролируя цвет\nрасширенный режим входа",
10
+ "pt": "suporte controlando a cor\nmodo de registro estendido",
11
+ "nl": "de kleur controleren\nverlengde logging mode",
12
+ "fr": "support de contrôle de la couleur\nmode d ' enregistrement élargi",
13
+ "it": "supporto che controlla il colore\nmodalità di registrazione estesa",
14
+ "es": "soporte controlando el color\nmodo de registro ampliado",
15
+ "pl": "kontrolować kolor\nrozszerzony tryb logowania",
16
+ "uk": "супровід управління кольором\nрозширений режим входу",
17
+ "zh-cn": "控制颜色的支助\n扩大的伐木模式"
18
+ },
6
19
  "0.1.2": {
7
20
  "en": "change icon path and resolution",
8
21
  "de": "icon pfad und auflösung ändern",
@@ -80,19 +93,6 @@
80
93
  "pl": "status odświeżający",
81
94
  "uk": "зробити стан пристрою, освіжаючи інверторний індикент з інтервалу пошуку пристрою",
82
95
  "zh-cn": "利用装置搜寻装置进行喷雾装置的装置"
83
- },
84
- "0.0.3": {
85
- "en": "update dependecies",
86
- "de": "aktualisierung der abhängigkeiten",
87
- "ru": "обновление зависимостей",
88
- "pt": "atualizações",
89
- "nl": "vertaling:",
90
- "fr": "mettre à jour les dépendances",
91
- "it": "dipendenze di aggiornamento",
92
- "es": "dependencias de actualización",
93
- "pl": "aktualizacja",
94
- "uk": "оновлення залежності",
95
- "zh-cn": "a. 最新依赖情况"
96
96
  }
97
97
  },
98
98
  "titleLang": {
@@ -158,7 +158,8 @@
158
158
  },
159
159
  "native": {
160
160
  "searchInterval": 10,
161
- "deviceStatusRefreshInterval": 1
161
+ "deviceStatusRefreshInterval": 1,
162
+ "extendedLogging": false
162
163
  },
163
164
  "objects": [],
164
165
  "instanceObjects": []
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.govee-local",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "Control Govee devices via local access (no cloud)",
5
5
  "author": {
6
6
  "name": "Børge Grunicke",
@@ -21,36 +21,37 @@
21
21
  "node": ">= 16.0"
22
22
  },
23
23
  "dependencies": {
24
- "@iobroker/adapter-core": "^3.0.3"
24
+ "@iobroker/adapter-core": "^3.0.4"
25
25
  },
26
26
  "devDependencies": {
27
- "@alcalzone/release-script": "^3.5.9",
27
+ "@alcalzone/release-script": "^3.6.0",
28
28
  "@alcalzone/release-script-plugin-iobroker": "^3.6.0",
29
29
  "@alcalzone/release-script-plugin-license": "^3.5.9",
30
30
  "@alcalzone/release-script-plugin-manual-review": "^3.5.9",
31
31
  "@iobroker/adapter-dev": "^1.2.0",
32
32
  "@iobroker/testing": "^4.1.0",
33
33
  "@tsconfig/node14": "^14.1.0",
34
- "@tsconfig/node18": "^18.2.1",
35
- "@types/chai": "^4.3.5",
36
- "@types/chai-as-promised": "^7.1.5",
34
+ "@tsconfig/node18": "^18.2.2",
35
+ "@tsconfig/node20": "^20.1.2",
36
+ "@types/chai": "^4.3.11",
37
+ "@types/chai-as-promised": "^7.1.7",
37
38
  "@types/mocha": "^10.0.1",
38
- "@types/node": "^20.5.7",
39
+ "@types/node": "^20.10.1",
39
40
  "@types/proxyquire": "^1.3.28",
40
41
  "@types/sinon": "^10.0.13",
41
- "@types/sinon-chai": "^3.2.9",
42
+ "@types/sinon-chai": "^3.2.12",
42
43
  "@typescript-eslint/eslint-plugin": "^6.2.1",
43
- "@typescript-eslint/parser": "^6.3.0",
44
- "chai": "^4.3.7",
44
+ "@typescript-eslint/parser": "^6.13.1",
45
+ "chai": "^4.3.10",
45
46
  "chai-as-promised": "^7.1.1",
46
- "eslint": "^8.48.0",
47
+ "eslint": "^8.50.0",
47
48
  "eslint-config-prettier": "^9.0.0",
48
49
  "eslint-plugin-prettier": "^5.0.0",
49
50
  "mocha": "^10.2.0",
50
- "prettier": "^3.0.3",
51
+ "prettier": "^3.1.0",
51
52
  "proxyquire": "^2.1.3",
52
- "rimraf": "^4.4.1",
53
- "sinon": "^15.2.0",
53
+ "rimraf": "^5.0.5",
54
+ "sinon": "^17.0.0",
54
55
  "sinon-chai": "^3.7.0",
55
56
  "source-map-support": "^0.5.21",
56
57
  "ts-node": "^10.9.1",