iobroker.govee-local 0.2.4 → 0.2.6
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 +12 -0
- package/admin/i18n/de/translations.json +2 -1
- package/admin/i18n/en/translations.json +2 -1
- package/admin/i18n/es/translations.json +2 -1
- package/admin/i18n/fr/translations.json +2 -1
- package/admin/i18n/it/translations.json +2 -1
- package/admin/i18n/nl/translations.json +2 -1
- package/admin/i18n/pl/translations.json +2 -1
- package/admin/i18n/pt/translations.json +2 -1
- package/admin/i18n/ru/translations.json +2 -1
- package/admin/i18n/uk/translations.json +2 -1
- package/admin/i18n/zh-cn/translations.json +2 -1
- package/admin/jsonConfig.json +14 -4
- package/build/main.js +30 -56
- package/build/main.js.map +2 -2
- package/build/tools/hexTool.js +44 -0
- package/build/tools/hexTool.js.map +7 -0
- package/io-package.json +29 -28
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -16,12 +16,24 @@ Control Govee devices via local access (no cloud)
|
|
|
16
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)>)
|
|
17
17
|
As I currently only have the H6051 lamp, this is the only device I can test with.
|
|
18
18
|
|
|
19
|
+
For **Windows** Users: Please go to the settings and make sure you choose the correct network interface, otherwise the adapter will not receive any response from Govee Devices.
|
|
20
|
+
|
|
19
21
|
## Changelog
|
|
20
22
|
|
|
21
23
|
<!--
|
|
22
24
|
Placeholder for the next version (at the beginning of the line):
|
|
23
25
|
### **WORK IN PROGRESS**
|
|
24
26
|
-->
|
|
27
|
+
### 0.2.6 (2024-02-06)
|
|
28
|
+
|
|
29
|
+
- fix brightness change also changing white tmperature
|
|
30
|
+
|
|
31
|
+
### 0.2.5 (2024-01-13)
|
|
32
|
+
|
|
33
|
+
- create only one socket, as the second seems not to be necessary
|
|
34
|
+
- refactoring the code for better structure
|
|
35
|
+
- possibility to choose listen interface in settings
|
|
36
|
+
|
|
25
37
|
### 0.2.4 (2024-01-05)
|
|
26
38
|
|
|
27
39
|
- fix access
|
|
@@ -4,5 +4,6 @@
|
|
|
4
4
|
"_deviceStatusRefreshInterval": "Aktualisierungsintervall für den Gerätestatus",
|
|
5
5
|
"_configDescription": "Hier muss nichts konfiguriert werden. Bitte die Intervalle nur ändern, wenn dies explizit gewollt ist.",
|
|
6
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"
|
|
7
|
+
"_extendedLogging": "Erweiterte Protokollierung aktiviert",
|
|
8
|
+
"_networkInterface": "Netzwerkschnittstelle"
|
|
8
9
|
}
|
|
@@ -4,5 +4,6 @@
|
|
|
4
4
|
"_deviceStatusRefreshInterval": "device status refresh interval",
|
|
5
5
|
"_configDescription": "There is nothing mandatory to configure. Please change the intervals only when you are sure that this is what you need",
|
|
6
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"
|
|
7
|
+
"_extendedLogging": "Extended Logging enabled",
|
|
8
|
+
"_networkInterface": "Network Interface"
|
|
8
9
|
}
|
|
@@ -4,5 +4,6 @@
|
|
|
4
4
|
"_deviceStatusRefreshInterval": "intervalo de actualización del estado del dispositivo",
|
|
5
5
|
"_configDescription": "No hay nada obligatorio para configurar. Cambie los intervalos solo cuando esté seguro de que esto es lo que necesita",
|
|
6
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"
|
|
7
|
+
"_extendedLogging": "Registro extendido habilitado",
|
|
8
|
+
"_networkInterface": "Interfaz de red"
|
|
8
9
|
}
|
|
@@ -4,5 +4,6 @@
|
|
|
4
4
|
"_deviceStatusRefreshInterval": "intervalle d'actualisation de l'état de l'appareil",
|
|
5
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
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"
|
|
7
|
+
"_extendedLogging": "Journalisation étendue activée",
|
|
8
|
+
"_networkInterface": "Interface réseau"
|
|
8
9
|
}
|
|
@@ -4,5 +4,6 @@
|
|
|
4
4
|
"_deviceStatusRefreshInterval": "intervallo di aggiornamento dello stato del dispositivo",
|
|
5
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
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"
|
|
7
|
+
"_extendedLogging": "Registrazione estesa abilitata",
|
|
8
|
+
"_networkInterface": "Interfaccia di rete"
|
|
8
9
|
}
|
|
@@ -4,5 +4,6 @@
|
|
|
4
4
|
"_deviceStatusRefreshInterval": "vernieuwingsinterval apparaatstatus",
|
|
5
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
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"
|
|
7
|
+
"_extendedLogging": "Uitgebreide logboekregistratie ingeschakeld",
|
|
8
|
+
"_networkInterface": "Netwerkinterface"
|
|
8
9
|
}
|
|
@@ -4,5 +4,6 @@
|
|
|
4
4
|
"_deviceStatusRefreshInterval": "interwał odświeżania stanu urządzenia",
|
|
5
5
|
"_configDescription": "Nie ma nic obowiązkowego do skonfigurowania. Zmień interwały tylko wtedy, gdy jesteś pewien, że tego właśnie potrzebujesz",
|
|
6
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"
|
|
7
|
+
"_extendedLogging": "Włączono rozszerzone rejestrowanie",
|
|
8
|
+
"_networkInterface": "Interfejs sieciowy"
|
|
8
9
|
}
|
|
@@ -4,5 +4,6 @@
|
|
|
4
4
|
"_deviceStatusRefreshInterval": "intervalo de atualização do status do dispositivo",
|
|
5
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
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"
|
|
7
|
+
"_extendedLogging": "Registro estendido ativado",
|
|
8
|
+
"_networkInterface": "Interface de rede"
|
|
8
9
|
}
|
|
@@ -4,5 +4,6 @@
|
|
|
4
4
|
"_deviceStatusRefreshInterval": "интервал обновления статуса устройства",
|
|
5
5
|
"_configDescription": "Нет ничего обязательного для настройки. Пожалуйста, меняйте интервалы только тогда, когда вы уверены, что это то, что вам нужно.",
|
|
6
6
|
"_extendedLoggingDescription": "Расширенная регистрация записывает все данные, полученные устройством, в журнал с информацией об уровне. Поскольку это приводит к большому количеству спама в журналах, рекомендуется включать эту функцию только при необходимости, а затем снова выключать.",
|
|
7
|
-
"_extendedLogging": "Расширенное ведение журнала включено"
|
|
7
|
+
"_extendedLogging": "Расширенное ведение журнала включено",
|
|
8
|
+
"_networkInterface": "Сетевой интерфейс"
|
|
8
9
|
}
|
|
@@ -4,5 +4,6 @@
|
|
|
4
4
|
"_deviceStatusRefreshInterval": "інтервал оновлення стану пристрою",
|
|
5
5
|
"_configDescription": "Немає нічого обов’язкового для налаштування. Будь ласка, змінюйте інтервали лише тоді, коли ви впевнені, що це те, що вам потрібно",
|
|
6
6
|
"_extendedLoggingDescription": "Extended Logging друкує всі дані, отримані пристроєм, у журналі з інформацією про рівень. Оскільки це створює величезну кількість спаму в журналі, рекомендується вмикати це лише за потреби, а потім знову вимикати.",
|
|
7
|
-
"_extendedLogging": "Розширене журналювання ввімкнено"
|
|
7
|
+
"_extendedLogging": "Розширене журналювання ввімкнено",
|
|
8
|
+
"_networkInterface": "Мережевий інтерфейс"
|
|
8
9
|
}
|
|
@@ -4,5 +4,6 @@
|
|
|
4
4
|
"_deviceStatusRefreshInterval": "设备状态刷新间隔",
|
|
5
5
|
"_configDescription": "没有什么必须配置的。仅当您确定这是您需要的时才更改间隔",
|
|
6
6
|
"_extendedLoggingDescription": "扩展日志记录将设备接收到的所有数据打印到带有级别信息的日志中。由于这会产生大量日志垃圾邮件,因此建议仅在需要时打开此功能,然后再次关闭。",
|
|
7
|
-
"_extendedLogging": "启用扩展日志记录"
|
|
7
|
+
"_extendedLogging": "启用扩展日志记录",
|
|
8
|
+
"_networkInterface": "网络接口"
|
|
8
9
|
}
|
package/admin/jsonConfig.json
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
"type": "number",
|
|
14
14
|
"min": 1,
|
|
15
15
|
"max": 1000,
|
|
16
|
-
"sm":
|
|
17
|
-
"md":
|
|
16
|
+
"sm": 6,
|
|
17
|
+
"md": 3,
|
|
18
18
|
"lg": 2,
|
|
19
19
|
"label": "_searchInterval"
|
|
20
20
|
},
|
|
@@ -22,11 +22,21 @@
|
|
|
22
22
|
"type": "number",
|
|
23
23
|
"min": 1,
|
|
24
24
|
"max": 1000,
|
|
25
|
-
"sm":
|
|
26
|
-
"md":
|
|
25
|
+
"sm": 6,
|
|
26
|
+
"md": 3,
|
|
27
27
|
"lg": 2,
|
|
28
28
|
"label": "_deviceStatusRefreshInterval"
|
|
29
29
|
},
|
|
30
|
+
"interface": {
|
|
31
|
+
"type": "ip",
|
|
32
|
+
"listenOnAllPorts": true,
|
|
33
|
+
"onlyIp4": true,
|
|
34
|
+
"label": "_networkInterface",
|
|
35
|
+
"newLine": true,
|
|
36
|
+
"sm": 12,
|
|
37
|
+
"md": 6,
|
|
38
|
+
"lg": 4
|
|
39
|
+
},
|
|
30
40
|
"_descriptionExtendedLogging": {
|
|
31
41
|
"type": "staticText",
|
|
32
42
|
"sm": 12,
|
package/build/main.js
CHANGED
|
@@ -5,10 +5,6 @@ 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
|
-
};
|
|
12
8
|
var __copyProps = (to, from, except, desc) => {
|
|
13
9
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
10
|
for (let key of __getOwnPropNames(from))
|
|
@@ -21,21 +17,14 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
21
17
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
18
|
mod
|
|
23
19
|
));
|
|
24
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
25
|
-
var main_exports = {};
|
|
26
|
-
__export(main_exports, {
|
|
27
|
-
componentToHex: () => componentToHex,
|
|
28
|
-
hexToRgb: () => hexToRgb
|
|
29
|
-
});
|
|
30
|
-
module.exports = __toCommonJS(main_exports);
|
|
31
20
|
var utils = __toESM(require("@iobroker/adapter-core"));
|
|
32
21
|
var dgram = __toESM(require("node:dgram"));
|
|
22
|
+
var import_hexTool = require("./tools/hexTool");
|
|
33
23
|
const LOCAL_PORT = 4002;
|
|
34
24
|
const SEND_SCAN_PORT = 4001;
|
|
35
25
|
const CONTROL_PORT = 4003;
|
|
36
26
|
const M_CAST = "239.255.255.250";
|
|
37
|
-
const
|
|
38
|
-
const client = dgram.createSocket("udp4");
|
|
27
|
+
const socket = dgram.createSocket({ type: "udp4" });
|
|
39
28
|
const scanMessage = { msg: { cmd: "scan", data: { account_topic: "reserved" } } };
|
|
40
29
|
const requestStatusMessage = { msg: { cmd: "devStatus", data: {} } };
|
|
41
30
|
let searchInterval;
|
|
@@ -64,20 +53,24 @@ class GoveeLocal extends utils.Adapter {
|
|
|
64
53
|
},
|
|
65
54
|
native: {}
|
|
66
55
|
});
|
|
67
|
-
|
|
68
|
-
|
|
56
|
+
socket.on("message", this.onUdpMessage.bind(this));
|
|
57
|
+
socket.on("error", (error) => {
|
|
69
58
|
this.log.error("server bind error : " + error.message);
|
|
70
59
|
this.setStateChanged("info.connection", { val: false, ack: true });
|
|
71
60
|
});
|
|
72
|
-
|
|
61
|
+
if (this.config.extendedLogging) {
|
|
62
|
+
this.log.debug("running with extended logging");
|
|
63
|
+
}
|
|
64
|
+
socket.bind({ address: this.config.interface, port: LOCAL_PORT }, this.serverBound.bind(this));
|
|
73
65
|
this.subscribeStates("*.devStatus.*");
|
|
74
66
|
}
|
|
75
67
|
async serverBound() {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
68
|
+
socket.setBroadcast(true);
|
|
69
|
+
socket.setMulticastTTL(128);
|
|
70
|
+
socket.setMulticastInterface(this.config.interface);
|
|
71
|
+
socket.addMembership(M_CAST);
|
|
79
72
|
this.setStateChanged("info.connection", { val: true, ack: true });
|
|
80
|
-
this.log.debug("UDP listening on " +
|
|
73
|
+
this.log.debug("UDP listening on " + socket.address().address + ":" + socket.address().port);
|
|
81
74
|
const deviceSearchInterval = this.setInterval(this.sendScan.bind(this), this.config.searchInterval * 1e3);
|
|
82
75
|
if (deviceSearchInterval) {
|
|
83
76
|
searchInterval = deviceSearchInterval;
|
|
@@ -174,7 +167,7 @@ class GoveeLocal extends utils.Adapter {
|
|
|
174
167
|
native: {}
|
|
175
168
|
});
|
|
176
169
|
this.setState(`${sendingDevice}.devStatus.color`, {
|
|
177
|
-
val: "#" + componentToHex(devStatusMessageObject.msg.data.color.r) + componentToHex(devStatusMessageObject.msg.data.color.g) + componentToHex(devStatusMessageObject.msg.data.color.b),
|
|
170
|
+
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),
|
|
178
171
|
ack: true
|
|
179
172
|
});
|
|
180
173
|
this.setObjectNotExists(`${sendingDevice}.devStatus.colorTemInKelvin`, {
|
|
@@ -205,18 +198,17 @@ class GoveeLocal extends utils.Adapter {
|
|
|
205
198
|
}
|
|
206
199
|
requestDeviceStatus(receiver) {
|
|
207
200
|
const requestDeviceStatusBuffer = Buffer.from(JSON.stringify(requestStatusMessage));
|
|
208
|
-
|
|
201
|
+
socket.send(requestDeviceStatusBuffer, 0, requestDeviceStatusBuffer.length, CONTROL_PORT, receiver);
|
|
209
202
|
}
|
|
210
203
|
async sendScan() {
|
|
211
204
|
const scanMessageBuffer = Buffer.from(JSON.stringify(scanMessage));
|
|
212
|
-
|
|
205
|
+
socket.send(scanMessageBuffer, 0, scanMessageBuffer.length, SEND_SCAN_PORT, M_CAST);
|
|
213
206
|
}
|
|
214
207
|
onUnload(callback) {
|
|
215
208
|
try {
|
|
216
209
|
this.clearInterval(searchInterval);
|
|
217
210
|
this.clearInterval(refreshInterval);
|
|
218
|
-
|
|
219
|
-
server.close();
|
|
211
|
+
socket.close();
|
|
220
212
|
this.setState("info.connection", { val: false, ack: true });
|
|
221
213
|
callback();
|
|
222
214
|
} catch (e) {
|
|
@@ -233,30 +225,31 @@ class GoveeLocal extends utils.Adapter {
|
|
|
233
225
|
case "onOff":
|
|
234
226
|
const turnMessage = { msg: { cmd: "turn", data: { value: state.val ? 1 : 0 } } };
|
|
235
227
|
const turnMessageBuffer = Buffer.from(JSON.stringify(turnMessage));
|
|
236
|
-
|
|
228
|
+
socket.send(turnMessageBuffer, 0, turnMessageBuffer.length, CONTROL_PORT, receiver);
|
|
237
229
|
break;
|
|
238
230
|
case "brightness":
|
|
239
231
|
const brightnessMessage = { msg: { cmd: "brightness", data: { value: state.val } } };
|
|
240
232
|
const brightnessMessageBuffer = Buffer.from(JSON.stringify(brightnessMessage));
|
|
241
|
-
|
|
233
|
+
socket.send(brightnessMessageBuffer, 0, brightnessMessageBuffer.length, CONTROL_PORT, receiver);
|
|
242
234
|
break;
|
|
243
235
|
case "colorTemInKelvin":
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
236
|
+
const colorTempMessageBuffer = Buffer.from(
|
|
237
|
+
JSON.stringify({
|
|
238
|
+
msg: {
|
|
239
|
+
cmd: "colorwc",
|
|
240
|
+
data: { color: { r: "0", g: "0", b: "0" }, colorTemInKelvin: state.val }
|
|
241
|
+
}
|
|
242
|
+
})
|
|
243
|
+
);
|
|
244
|
+
socket.send(colorTempMessageBuffer, 0, colorTempMessageBuffer.length, CONTROL_PORT, receiver);
|
|
252
245
|
break;
|
|
253
246
|
case "color":
|
|
254
247
|
const colorValue = (_b = state.val) == null ? void 0 : _b.toString();
|
|
255
248
|
if (colorValue) {
|
|
256
|
-
const rgb = hexToRgb(colorValue);
|
|
249
|
+
const rgb = (0, import_hexTool.hexToRgb)(colorValue);
|
|
257
250
|
const colorMessage = { msg: { cmd: "colorwc", data: { color: rgb } } };
|
|
258
251
|
const colorMessageBuffer = Buffer.from(JSON.stringify(colorMessage));
|
|
259
|
-
|
|
252
|
+
socket.send(colorMessageBuffer, 0, colorMessageBuffer.length, CONTROL_PORT, receiver);
|
|
260
253
|
}
|
|
261
254
|
break;
|
|
262
255
|
}
|
|
@@ -289,23 +282,4 @@ function getDatapointDescription(name) {
|
|
|
289
282
|
return "";
|
|
290
283
|
}
|
|
291
284
|
}
|
|
292
|
-
function componentToHex(c) {
|
|
293
|
-
const hex = c.toString(16);
|
|
294
|
-
return hex.length == 1 ? "0" + hex : hex;
|
|
295
|
-
}
|
|
296
|
-
function hexToRgb(hexString) {
|
|
297
|
-
if (!/^#[0-9a-fA-F]{6}$/i.test(hexString)) {
|
|
298
|
-
throw new Error("Invalid hex string");
|
|
299
|
-
}
|
|
300
|
-
return {
|
|
301
|
-
r: parseInt(hexString.slice(1, 3), 16),
|
|
302
|
-
g: parseInt(hexString.slice(3, 5), 16),
|
|
303
|
-
b: parseInt(hexString.slice(5, 7), 16)
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
307
|
-
0 && (module.exports = {
|
|
308
|
-
componentToHex,
|
|
309
|
-
hexToRgb
|
|
310
|
-
});
|
|
311
285
|
//# 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';\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;\nlet refreshInterval: NodeJS.Timeout;\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\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.setStateChanged('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.setStateChanged('info.connection', { val: true, ack: true });\n\t\tthis.log.debug('UDP listening on ' + server.address().address + ':' + server.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\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\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\tthis.setState(`${sendingDevice}.devStatus.onOff`, {\n\t\t\t\t\t\tval: devStatusMessageObject.msg.data.onOff == 1,\n\t\t\t\t\t\tack: true,\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\tthis.setState(`${sendingDevice}.devStatus.brightness`, {\n\t\t\t\t\t\tval: devStatusMessageObject.msg.data.brightness,\n\t\t\t\t\t\tack: true,\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\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\tthis.setState(`${sendingDevice}.devStatus.colorTemInKelvin`, {\n\t\t\t\t\t\tval: devStatusMessageObject.msg.data.colorTemInKelvin,\n\t\t\t\t\t\tack: true,\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\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\tthis.clearInterval(refreshInterval);\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 = {\n\t\t\t\t\t\t\tmsg: {\n\t\t\t\t\t\t\t\tcmd: 'colorwc',\n\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},\n\t\t\t\t\t\t};\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 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\tclient.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\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-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}\n\ntype Color = {\n\tr: number;\n\tg: number;\n\tb: number;\n};\n\nexport { componentToHex, hexToRgb };\n"],
|
|
5
|
-
"mappings": "
|
|
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: NodeJS.Timeout;\nlet refreshInterval: NodeJS.Timeout;\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\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\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\tthis.setState(`${sendingDevice}.devStatus.onOff`, {\n\t\t\t\t\t\tval: devStatusMessageObject.msg.data.onOff == 1,\n\t\t\t\t\t\tack: true,\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\tthis.setState(`${sendingDevice}.devStatus.brightness`, {\n\t\t\t\t\t\tval: devStatusMessageObject.msg.data.brightness,\n\t\t\t\t\t\tack: true,\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\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\tthis.setState(`${sendingDevice}.devStatus.colorTemInKelvin`, {\n\t\t\t\t\t\tval: devStatusMessageObject.msg.data.colorTemInKelvin,\n\t\t\t\t\t\tack: true,\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.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\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\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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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var hexTool_exports = {};
|
|
20
|
+
__export(hexTool_exports, {
|
|
21
|
+
componentToHex: () => componentToHex,
|
|
22
|
+
hexToRgb: () => hexToRgb
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(hexTool_exports);
|
|
25
|
+
function componentToHex(c) {
|
|
26
|
+
const hex = c.toString(16);
|
|
27
|
+
return hex.length == 1 ? "0" + hex : hex;
|
|
28
|
+
}
|
|
29
|
+
function hexToRgb(hexString) {
|
|
30
|
+
if (!/^#[0-9a-fA-F]{6}$/i.test(hexString)) {
|
|
31
|
+
throw new Error("Invalid hex string");
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
r: parseInt(hexString.slice(1, 3), 16),
|
|
35
|
+
g: parseInt(hexString.slice(3, 5), 16),
|
|
36
|
+
b: parseInt(hexString.slice(5, 7), 16)
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
40
|
+
0 && (module.exports = {
|
|
41
|
+
componentToHex,
|
|
42
|
+
hexToRgb
|
|
43
|
+
});
|
|
44
|
+
//# sourceMappingURL=hexTool.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 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;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "govee-local",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.6",
|
|
5
5
|
"news": {
|
|
6
|
+
"0.2.6": {
|
|
7
|
+
"en": "fix brightness change also changing white tmperature",
|
|
8
|
+
"de": "helligkeitsänderung auch ändern weiße tmperatur",
|
|
9
|
+
"ru": "исправить яркость изменения также изменение белое tmperature",
|
|
10
|
+
"pt": "corrigir a mudança de brilho também mudando a tintura branca",
|
|
11
|
+
"nl": "fix helderheid verandering ook het veranderen van witte tmperatuur",
|
|
12
|
+
"fr": "fixer le changement de luminosité aussi changer la morphologie blanche",
|
|
13
|
+
"it": "correzione cambiamento di luminosità anche cambiando la serratura bianca",
|
|
14
|
+
"es": "arreglar el cambio de brillo también cambiar la tmperatura blanca",
|
|
15
|
+
"pl": "naprawić zmianę jasności również zmieniając biały tmperature",
|
|
16
|
+
"uk": "зафіксувати яскравість зміни також змінюють білу мпературу",
|
|
17
|
+
"zh-cn": "固定亮度改变, 也改变白色温度"
|
|
18
|
+
},
|
|
19
|
+
"0.2.5": {
|
|
20
|
+
"en": "create only one socket, as the second seems not to be necessary\nrefactoring the code for better structure\npossibility to choose listen interface in settings",
|
|
21
|
+
"de": "nur eine steckdose erstellen, da die zweite scheinbar nicht notwendig ist\nrefactoring des codes für bessere struktur\nmöglichkeit, die hörschnittstelle in einstellungen zu wählen",
|
|
22
|
+
"ru": "создать только один розеток, так как второй кажется не нужным\nрефакторинг кода для лучшей структуры\nвозможность выбора интерфейса прослушивания в настройках",
|
|
23
|
+
"pt": "criar apenas um soquete, como o segundo parece não ser necessário\nrefatorando o código para melhor estrutura\npossibilidade de escolher a interface de escuta em configurações",
|
|
24
|
+
"nl": "maken slechts een socket, omdat de tweede lijkt niet nodig\nrefactoring van de code voor betere structuur\nmogelijkheid om luisterinterface in instellingen te kiezen",
|
|
25
|
+
"fr": "créer une seule prise, car la seconde ne semble pas nécessaire\nrefactorer le code pour une meilleure structure\npossibilité de choisir l'interface d'écoute dans les paramètres",
|
|
26
|
+
"it": "creare solo una presa, come il secondo sembra non essere necessario\nrefactoring il codice per una migliore struttura\npossibilità di scegliere l'interfaccia di ascolto nelle impostazioni",
|
|
27
|
+
"es": "crear sólo una toma, ya que el segundo parece no ser necesario\nrefactorización del código para una mejor estructura\nposibilidad de elegir la interfaz de escucha en los ajustes",
|
|
28
|
+
"pl": "utworzyć tylko jedno gniazdo, ponieważ drugie wydaje się nie być konieczne\nrefaktoring kodu dla lepszej struktury\nmożliwość wyboru interfejsu słuchania w ustawieniach",
|
|
29
|
+
"uk": "створити тільки одну розетку, так як другий здається не потрібно\nрефакторинг коду для кращої структури\nможливість вибору інтерфейсу прослуховування в налаштуваннях",
|
|
30
|
+
"zh-cn": "只创建一个套接字, 因为第二个似乎没有必要\n为更好的结构重构代码\n在设置中选择监听界面的可能性"
|
|
31
|
+
},
|
|
6
32
|
"0.2.4": {
|
|
7
33
|
"en": "fix access",
|
|
8
34
|
"de": "zugriff",
|
|
@@ -67,32 +93,6 @@
|
|
|
67
93
|
"pl": "kontrolować kolor\nrozszerzony tryb logowania",
|
|
68
94
|
"uk": "супровід управління кольором\nрозширений режим входу",
|
|
69
95
|
"zh-cn": "控制颜色的支助\n扩大的伐木模式"
|
|
70
|
-
},
|
|
71
|
-
"0.1.2": {
|
|
72
|
-
"en": "change icon path and resolution",
|
|
73
|
-
"de": "icon pfad und auflösung ändern",
|
|
74
|
-
"ru": "изменить путь иконки и разрешение",
|
|
75
|
-
"pt": "mudar o caminho do ícone e resolução",
|
|
76
|
-
"nl": "verander icoon en resolutie",
|
|
77
|
-
"fr": "changer le chemin d'icône et la résolution",
|
|
78
|
-
"it": "cambiare percorso icona e risoluzione",
|
|
79
|
-
"es": "cambiar la ruta del icono y la resolución",
|
|
80
|
-
"pl": "ikonywana droga i rozdzielczość",
|
|
81
|
-
"uk": "зміна ікони шлях і роздільна здатність",
|
|
82
|
-
"zh-cn": "b. 改变道路和决议"
|
|
83
|
-
},
|
|
84
|
-
"0.1.1": {
|
|
85
|
-
"en": "fix image",
|
|
86
|
-
"de": "das bild",
|
|
87
|
-
"ru": "исправить изображение",
|
|
88
|
-
"pt": "corrigir imagem",
|
|
89
|
-
"nl": "vertaling:",
|
|
90
|
-
"fr": "correction",
|
|
91
|
-
"it": "immagine di correzione",
|
|
92
|
-
"es": "imagen",
|
|
93
|
-
"pl": "zdjęcie",
|
|
94
|
-
"uk": "фіксувати зображення",
|
|
95
|
-
"zh-cn": "fix图像"
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"titleLang": {
|
|
@@ -159,7 +159,8 @@
|
|
|
159
159
|
"native": {
|
|
160
160
|
"searchInterval": 10,
|
|
161
161
|
"deviceStatusRefreshInterval": 1,
|
|
162
|
-
"extendedLogging": false
|
|
162
|
+
"extendedLogging": false,
|
|
163
|
+
"interface": "0.0.0.0"
|
|
163
164
|
},
|
|
164
165
|
"objects": [],
|
|
165
166
|
"instanceObjects": []
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.govee-local",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"description": "Control Govee devices via local access (no cloud)",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Børge Grunicke",
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
"@tsconfig/node18": "^18.2.2",
|
|
35
35
|
"@tsconfig/node20": "^20.1.2",
|
|
36
36
|
"@types/chai": "^4.3.11",
|
|
37
|
-
"@types/chai-as-promised": "^7.1.
|
|
37
|
+
"@types/chai-as-promised": "^7.1.8",
|
|
38
38
|
"@types/mocha": "^10.0.1",
|
|
39
|
-
"@types/node": "^20.
|
|
40
|
-
"@types/proxyquire": "^1.3.
|
|
39
|
+
"@types/node": "^20.11.14",
|
|
40
|
+
"@types/proxyquire": "^1.3.31",
|
|
41
41
|
"@types/sinon": "^10.0.13",
|
|
42
42
|
"@types/sinon-chai": "^3.2.12",
|
|
43
43
|
"@typescript-eslint/eslint-plugin": "^6.2.1",
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
"chai": "^4.3.10",
|
|
46
46
|
"chai-as-promised": "^7.1.1",
|
|
47
47
|
"eslint": "^8.56.0",
|
|
48
|
-
"eslint-config-prettier": "^9.
|
|
49
|
-
"eslint-plugin-prettier": "^5.1.
|
|
48
|
+
"eslint-config-prettier": "^9.1.0",
|
|
49
|
+
"eslint-plugin-prettier": "^5.1.3",
|
|
50
50
|
"mocha": "^10.2.0",
|
|
51
51
|
"prettier": "^3.1.0",
|
|
52
52
|
"proxyquire": "^2.1.3",
|