iobroker.govee-local 0.2.1 → 0.2.4
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/LICENSE +1 -1
- package/README.md +10 -2
- package/build/main.js +34 -16
- package/build/main.js.map +2 -2
- package/io-package.json +40 -40
- package/package.json +6 -6
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) 2024 Børge Grunicke <boerge@grunicke.de>
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -22,9 +22,17 @@ As I currently only have the H6051 lamp, this is the only device I can test with
|
|
|
22
22
|
Placeholder for the next version (at the beginning of the line):
|
|
23
23
|
### **WORK IN PROGRESS**
|
|
24
24
|
-->
|
|
25
|
+
### 0.2.4 (2024-01-05)
|
|
26
|
+
|
|
27
|
+
- fix access
|
|
28
|
+
|
|
29
|
+
### 0.2.2 (2024-01-05)
|
|
30
|
+
|
|
31
|
+
- fix color temperature messsage
|
|
32
|
+
|
|
25
33
|
### 0.2.1 (2023-12-24)
|
|
26
34
|
|
|
27
|
-
- repair onOff / all other actions Fixes: #65
|
|
35
|
+
- repair onOff / all other actions Fixes: [#65](https://github.com/boergegrunicke/ioBroker.govee-local/issues/65)
|
|
28
36
|
- fix log spamming because of wildcard
|
|
29
37
|
|
|
30
38
|
### 0.2.0 (2023-12-17)
|
|
@@ -73,7 +81,7 @@ As I currently only have the H6051 lamp, this is the only device I can test with
|
|
|
73
81
|
|
|
74
82
|
MIT License
|
|
75
83
|
|
|
76
|
-
Copyright (c)
|
|
84
|
+
Copyright (c) 2024 Børge Grunicke
|
|
77
85
|
|
|
78
86
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
79
87
|
of this software and associated documentation files (the "Software"), to deal
|
package/build/main.js
CHANGED
|
@@ -39,7 +39,7 @@ const client = dgram.createSocket("udp4");
|
|
|
39
39
|
const scanMessage = { msg: { cmd: "scan", data: { account_topic: "reserved" } } };
|
|
40
40
|
const requestStatusMessage = { msg: { cmd: "devStatus", data: {} } };
|
|
41
41
|
let searchInterval;
|
|
42
|
-
|
|
42
|
+
let refreshInterval;
|
|
43
43
|
const devices = {};
|
|
44
44
|
const loggedDevices = [];
|
|
45
45
|
class GoveeLocal extends utils.Adapter {
|
|
@@ -53,6 +53,17 @@ class GoveeLocal extends utils.Adapter {
|
|
|
53
53
|
this.on("unload", this.onUnload.bind(this));
|
|
54
54
|
}
|
|
55
55
|
async onReady() {
|
|
56
|
+
this.setObjectNotExists("info.connection", {
|
|
57
|
+
type: "state",
|
|
58
|
+
common: {
|
|
59
|
+
name: "Device discovery running",
|
|
60
|
+
type: "boolean",
|
|
61
|
+
role: "indicator.connected",
|
|
62
|
+
read: true,
|
|
63
|
+
write: false
|
|
64
|
+
},
|
|
65
|
+
native: {}
|
|
66
|
+
});
|
|
56
67
|
server.on("message", this.onUdpMessage.bind(this));
|
|
57
68
|
server.on("error", (error) => {
|
|
58
69
|
this.log.error("server bind error : " + error.message);
|
|
@@ -67,9 +78,16 @@ class GoveeLocal extends utils.Adapter {
|
|
|
67
78
|
server.addMembership(M_CAST);
|
|
68
79
|
this.setStateChanged("info.connection", { val: true, ack: true });
|
|
69
80
|
this.log.debug("UDP listening on " + server.address().address + ":" + server.address().port);
|
|
70
|
-
const
|
|
71
|
-
if (
|
|
72
|
-
searchInterval =
|
|
81
|
+
const deviceSearchInterval = this.setInterval(this.sendScan.bind(this), this.config.searchInterval * 1e3);
|
|
82
|
+
if (deviceSearchInterval) {
|
|
83
|
+
searchInterval = deviceSearchInterval;
|
|
84
|
+
}
|
|
85
|
+
const deviceRefreshInterval = this.setInterval(
|
|
86
|
+
this.refreshAllDevices.bind(this),
|
|
87
|
+
this.config.deviceStatusRefreshInterval * 1e3
|
|
88
|
+
);
|
|
89
|
+
if (deviceRefreshInterval) {
|
|
90
|
+
refreshInterval = deviceRefreshInterval;
|
|
73
91
|
}
|
|
74
92
|
}
|
|
75
93
|
async onUdpMessage(message, remote) {
|
|
@@ -105,15 +123,6 @@ class GoveeLocal extends utils.Adapter {
|
|
|
105
123
|
});
|
|
106
124
|
}
|
|
107
125
|
}
|
|
108
|
-
if (!(messageObject.msg.data.device in intervals)) {
|
|
109
|
-
const result = this.setInterval(
|
|
110
|
-
() => this.requestDeviceStatus(messageObject.msg.data.ip),
|
|
111
|
-
this.config.deviceStatusRefreshInterval * 1e3
|
|
112
|
-
);
|
|
113
|
-
if (result !== void 0) {
|
|
114
|
-
intervals[messageObject.msg.data.device] = result;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
126
|
break;
|
|
118
127
|
case "devStatus":
|
|
119
128
|
const sendingDevice = devices[remote.address];
|
|
@@ -189,6 +198,11 @@ class GoveeLocal extends utils.Adapter {
|
|
|
189
198
|
this.log.error("message from: " + remote.address + ":" + remote.port + " - " + message);
|
|
190
199
|
}
|
|
191
200
|
}
|
|
201
|
+
async refreshAllDevices() {
|
|
202
|
+
for (const ip in devices) {
|
|
203
|
+
this.requestDeviceStatus(ip);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
192
206
|
requestDeviceStatus(receiver) {
|
|
193
207
|
const requestDeviceStatusBuffer = Buffer.from(JSON.stringify(requestStatusMessage));
|
|
194
208
|
client.send(requestDeviceStatusBuffer, 0, requestDeviceStatusBuffer.length, CONTROL_PORT, receiver);
|
|
@@ -200,7 +214,7 @@ class GoveeLocal extends utils.Adapter {
|
|
|
200
214
|
onUnload(callback) {
|
|
201
215
|
try {
|
|
202
216
|
this.clearInterval(searchInterval);
|
|
203
|
-
|
|
217
|
+
this.clearInterval(refreshInterval);
|
|
204
218
|
client.close();
|
|
205
219
|
server.close();
|
|
206
220
|
this.setState("info.connection", { val: false, ack: true });
|
|
@@ -218,7 +232,6 @@ class GoveeLocal extends utils.Adapter {
|
|
|
218
232
|
switch (id.split(".")[4]) {
|
|
219
233
|
case "onOff":
|
|
220
234
|
const turnMessage = { msg: { cmd: "turn", data: { value: state.val ? 1 : 0 } } };
|
|
221
|
-
this.log.info("turn message : " + JSON.stringify(turnMessage));
|
|
222
235
|
const turnMessageBuffer = Buffer.from(JSON.stringify(turnMessage));
|
|
223
236
|
client.send(turnMessageBuffer, 0, turnMessageBuffer.length, CONTROL_PORT, receiver);
|
|
224
237
|
break;
|
|
@@ -228,7 +241,12 @@ class GoveeLocal extends utils.Adapter {
|
|
|
228
241
|
client.send(brightnessMessageBuffer, 0, brightnessMessageBuffer.length, CONTROL_PORT, receiver);
|
|
229
242
|
break;
|
|
230
243
|
case "colorTemInKelvin":
|
|
231
|
-
const colorTempMessage = {
|
|
244
|
+
const colorTempMessage = {
|
|
245
|
+
msg: {
|
|
246
|
+
cmd: "colorwc",
|
|
247
|
+
data: { color: { r: "0", g: "0", b: "0" }, colorTemInKelvin: state.val }
|
|
248
|
+
}
|
|
249
|
+
};
|
|
232
250
|
const colorTempMessageBuffer = Buffer.from(JSON.stringify(colorTempMessage));
|
|
233
251
|
client.send(colorTempMessageBuffer, 0, colorTempMessageBuffer.length, CONTROL_PORT, receiver);
|
|
234
252
|
break;
|
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;\n\nconst intervals: { [device: string]: 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\t// this.setObjectNotExists('info.connection', {\n\t\t// \ttype: 'state',\n\t\t// \tcommon: {\n\t\t// \t\tname: 'Device discovery running',\n\t\t// \t\ttype: 'boolean',\n\t\t// \t\trole: 'indicator.connected',\n\t\t// \t\tread: true,\n\t\t// \t\twrite: false,\n\t\t// \t},\n\t\t// \tnative: {},\n\t\t// });\n\t\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 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\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\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 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\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\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\tthis.log.info('turn message : ' + JSON.stringify(turnMessage));\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 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": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,YAAuB;AACvB,YAAuB;AAIvB,MAAM,aAAa;AACnB,MAAM,iBAAiB;AACvB,MAAM,eAAe;AACrB,MAAM,SAAS;AAEf,MAAM,SAAS,MAAM,aAAa,MAAM;AACxC,MAAM,SAAS,MAAM,aAAa,MAAM;AAExC,MAAM,cAAc,EAAE,KAAK,EAAE,KAAK,QAAQ,MAAM,EAAE,eAAe,WAAW,EAAE,EAAE;AAChF,MAAM,uBAAuB,EAAE,KAAK,EAAE,KAAK,aAAa,MAAM,CAAC,EAAE,EAAE;AAEnE,IAAI;
|
|
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": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,47 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "govee-local",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.4",
|
|
5
5
|
"news": {
|
|
6
|
+
"0.2.4": {
|
|
7
|
+
"en": "fix access",
|
|
8
|
+
"de": "zugriff",
|
|
9
|
+
"ru": "исправить доступ",
|
|
10
|
+
"pt": "corrigir o acesso",
|
|
11
|
+
"nl": "fix toegang",
|
|
12
|
+
"fr": "fixer l'accès",
|
|
13
|
+
"it": "fissare l'accesso",
|
|
14
|
+
"es": "acceso fijo",
|
|
15
|
+
"pl": "naprawić dostęp",
|
|
16
|
+
"uk": "фіксувати доступ",
|
|
17
|
+
"zh-cn": "固定访问"
|
|
18
|
+
},
|
|
19
|
+
"0.2.3": {
|
|
20
|
+
"en": "fix access",
|
|
21
|
+
"de": "zugriff",
|
|
22
|
+
"ru": "исправить доступ",
|
|
23
|
+
"pt": "corrigir o acesso",
|
|
24
|
+
"nl": "fix toegang",
|
|
25
|
+
"fr": "fixer l'accès",
|
|
26
|
+
"it": "fissare l'accesso",
|
|
27
|
+
"es": "acceso fijo",
|
|
28
|
+
"pl": "naprawić dostęp",
|
|
29
|
+
"uk": "фіксувати доступ",
|
|
30
|
+
"zh-cn": "固定访问"
|
|
31
|
+
},
|
|
32
|
+
"0.2.2": {
|
|
33
|
+
"en": "fix color temperature messsage",
|
|
34
|
+
"de": "fixe farbtemperatur message",
|
|
35
|
+
"ru": "фиксация цветовой температуры",
|
|
36
|
+
"pt": "corrigir a confusão de temperatura de cor",
|
|
37
|
+
"nl": "fix kleur temperatuur message",
|
|
38
|
+
"fr": "fixer la température de couleur message",
|
|
39
|
+
"it": "correzione di di disordine della temperatura del colore",
|
|
40
|
+
"es": "arreglar el desorden de temperatura de color",
|
|
41
|
+
"pl": "naprawić mieszankę temperatury kolorów",
|
|
42
|
+
"uk": "фіксувати колір температури messsage",
|
|
43
|
+
"zh-cn": "校正颜色温度组合"
|
|
44
|
+
},
|
|
6
45
|
"0.2.1": {
|
|
7
46
|
"en": "repair onOff / all other actions Fixes: #65\nfix log spamming because of wildcard",
|
|
8
47
|
"de": "reparatur onOff / alle anderen Aktionen Behebungen: #65\nprotokoll spamming wegen wildcard",
|
|
@@ -54,45 +93,6 @@
|
|
|
54
93
|
"pl": "zdjęcie",
|
|
55
94
|
"uk": "фіксувати зображення",
|
|
56
95
|
"zh-cn": "fix图像"
|
|
57
|
-
},
|
|
58
|
-
"0.1.0": {
|
|
59
|
-
"en": "make search intervals configurable\nclear all timeouts, when adapter is stopped\nreplace forbidden characters in names\nupdate translations\nupdate dependecies",
|
|
60
|
-
"de": "die suchintervalle konfigurierbar machen\nalle timeouts löschen, wenn der adapter gestoppt wird\nverbotene zeichen in namen ersetzen\nübersetzungen aktualisieren\naktualisierung der abhängigkeiten",
|
|
61
|
-
"ru": "сделать поисковые интервалы конфигурируемыми\nочистить все тайм-аут, когда адаптер остановлен\nзаменить запрещенные символы в именах\nобновление переводов\nобновление зависимостей",
|
|
62
|
-
"pt": "fazer intervalos de pesquisa configuráveis\nlimpar todos os prazos, quando o adaptador é parado\nsubstituir caracteres proibidos em nomes\ntraduções de atualização\natualizações",
|
|
63
|
-
"nl": "doorzoekingsbesprekingen beperkt\nmaak alle time-outs vrij wanneer de adapter stopt\nverboden personages in naam\nvertaling:\nvertaling:",
|
|
64
|
-
"fr": "faire des intervalles de recherche configurables\neffacer tous les timeouts, quand l'adaptateur est arrêté\nremplacer les caractères interdits dans les noms\nmise à jour des traductions\nmettre à jour les dépendances",
|
|
65
|
-
"it": "rendere configurabili gli intervalli di ricerca\nchiaro tutti i timeout, quando l'adattatore viene fermato\nsostituire i caratteri vietati in nomi\naggiornare le traduzioni\ndipendenze di aggiornamento",
|
|
66
|
-
"es": "hacer intervalos de búsqueda configurable\ndespejado todo el tiempo, cuando el adaptador es detenido\nreemplazar caracteres prohibidos en nombres\ntraducción actualizada\ndependencias de actualización",
|
|
67
|
-
"pl": "przeszukiwań konfigurowalnych\noczywiście cały czas, gdy adapter zostaje zatrzymany\nzastępowanie bohaterów nazw\ntłumaczenia aktualizacyjne\naktualizacja",
|
|
68
|
-
"uk": "зробіть інтервали пошуку налаштувати\nочистити всі маршрути, коли адаптер припиняється\nзамінити заборонені символи в іменах\nоновлення перекладів\nоновлення залежності",
|
|
69
|
-
"zh-cn": "定期探查\n所有时间都很清楚,当适应人员被停止时\n用名称取代禁止的特性\n更新翻译\na. 最新依赖情况"
|
|
70
|
-
},
|
|
71
|
-
"0.0.6": {
|
|
72
|
-
"en": "update dependencies",
|
|
73
|
-
"de": "aktualisierung der abhängigkeiten",
|
|
74
|
-
"ru": "обновление зависимостей",
|
|
75
|
-
"pt": "dependências",
|
|
76
|
-
"nl": "vertaling:",
|
|
77
|
-
"fr": "mettre à jour les dépendances",
|
|
78
|
-
"it": "aggiornamento dipendenze",
|
|
79
|
-
"es": "dependencias de actualización",
|
|
80
|
-
"pl": "zależności",
|
|
81
|
-
"uk": "оновлення залежності",
|
|
82
|
-
"zh-cn": "a. 最新受扶养人"
|
|
83
|
-
},
|
|
84
|
-
"0.0.5": {
|
|
85
|
-
"en": "make pipeline run",
|
|
86
|
-
"de": "pipeline laufen lassen",
|
|
87
|
-
"ru": "сделать пробег трубопровода",
|
|
88
|
-
"pt": "fazer a execução do pipeline",
|
|
89
|
-
"nl": "maak pijplijnen",
|
|
90
|
-
"fr": "faire fonctionner le pipeline",
|
|
91
|
-
"it": "rendere il processo di tubazione",
|
|
92
|
-
"es": "funcionamiento del gasoducto",
|
|
93
|
-
"pl": "rurociąg",
|
|
94
|
-
"uk": "зведення трубопроводів",
|
|
95
|
-
"zh-cn": "管道"
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"titleLang": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.govee-local",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Control Govee devices via local access (no cloud)",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Børge Grunicke",
|
|
@@ -36,17 +36,17 @@
|
|
|
36
36
|
"@types/chai": "^4.3.11",
|
|
37
37
|
"@types/chai-as-promised": "^7.1.7",
|
|
38
38
|
"@types/mocha": "^10.0.1",
|
|
39
|
-
"@types/node": "^20.10.
|
|
39
|
+
"@types/node": "^20.10.6",
|
|
40
40
|
"@types/proxyquire": "^1.3.28",
|
|
41
41
|
"@types/sinon": "^10.0.13",
|
|
42
42
|
"@types/sinon-chai": "^3.2.12",
|
|
43
43
|
"@typescript-eslint/eslint-plugin": "^6.2.1",
|
|
44
|
-
"@typescript-eslint/parser": "^6.
|
|
44
|
+
"@typescript-eslint/parser": "^6.16.0",
|
|
45
45
|
"chai": "^4.3.10",
|
|
46
46
|
"chai-as-promised": "^7.1.1",
|
|
47
|
-
"eslint": "^8.
|
|
47
|
+
"eslint": "^8.56.0",
|
|
48
48
|
"eslint-config-prettier": "^9.0.0",
|
|
49
|
-
"eslint-plugin-prettier": "^5.
|
|
49
|
+
"eslint-plugin-prettier": "^5.1.2",
|
|
50
50
|
"mocha": "^10.2.0",
|
|
51
51
|
"prettier": "^3.1.0",
|
|
52
52
|
"proxyquire": "^2.1.3",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"sinon-chai": "^3.7.0",
|
|
56
56
|
"source-map-support": "^0.5.21",
|
|
57
57
|
"ts-node": "^10.9.1",
|
|
58
|
-
"typescript": "^5.
|
|
58
|
+
"typescript": "^5.3.3"
|
|
59
59
|
},
|
|
60
60
|
"main": "build/main.js",
|
|
61
61
|
"files": [
|