iobroker.govee-local 0.2.0 → 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 +14 -1
- package/build/main.js +106 -96
- package/build/main.js.map +2 -2
- package/io-package.json +53 -53
- package/package.json +7 -7
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,6 +22,19 @@ 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
|
+
|
|
33
|
+
### 0.2.1 (2023-12-24)
|
|
34
|
+
|
|
35
|
+
- repair onOff / all other actions Fixes: [#65](https://github.com/boergegrunicke/ioBroker.govee-local/issues/65)
|
|
36
|
+
- fix log spamming because of wildcard
|
|
37
|
+
|
|
25
38
|
### 0.2.0 (2023-12-17)
|
|
26
39
|
|
|
27
40
|
- support controlling the color
|
|
@@ -68,7 +81,7 @@ As I currently only have the H6051 lamp, this is the only device I can test with
|
|
|
68
81
|
|
|
69
82
|
MIT License
|
|
70
83
|
|
|
71
|
-
Copyright (c)
|
|
84
|
+
Copyright (c) 2024 Børge Grunicke
|
|
72
85
|
|
|
73
86
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
74
87
|
of this software and associated documentation files (the "Software"), to deal
|
package/build/main.js
CHANGED
|
@@ -24,7 +24,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
25
25
|
var main_exports = {};
|
|
26
26
|
__export(main_exports, {
|
|
27
|
-
componentToHex: () => componentToHex
|
|
27
|
+
componentToHex: () => componentToHex,
|
|
28
|
+
hexToRgb: () => hexToRgb
|
|
28
29
|
});
|
|
29
30
|
module.exports = __toCommonJS(main_exports);
|
|
30
31
|
var utils = __toESM(require("@iobroker/adapter-core"));
|
|
@@ -38,7 +39,8 @@ const client = dgram.createSocket("udp4");
|
|
|
38
39
|
const scanMessage = { msg: { cmd: "scan", data: { account_topic: "reserved" } } };
|
|
39
40
|
const requestStatusMessage = { msg: { cmd: "devStatus", data: {} } };
|
|
40
41
|
let searchInterval;
|
|
41
|
-
|
|
42
|
+
let refreshInterval;
|
|
43
|
+
const devices = {};
|
|
42
44
|
const loggedDevices = [];
|
|
43
45
|
class GoveeLocal extends utils.Adapter {
|
|
44
46
|
constructor(options = {}) {
|
|
@@ -65,7 +67,7 @@ class GoveeLocal extends utils.Adapter {
|
|
|
65
67
|
server.on("message", this.onUdpMessage.bind(this));
|
|
66
68
|
server.on("error", (error) => {
|
|
67
69
|
this.log.error("server bind error : " + error.message);
|
|
68
|
-
this.
|
|
70
|
+
this.setStateChanged("info.connection", { val: false, ack: true });
|
|
69
71
|
});
|
|
70
72
|
server.bind(LOCAL_PORT, this.serverBound.bind(this));
|
|
71
73
|
this.subscribeStates("*.devStatus.*");
|
|
@@ -74,11 +76,18 @@ class GoveeLocal extends utils.Adapter {
|
|
|
74
76
|
server.setBroadcast(true);
|
|
75
77
|
server.setMulticastTTL(128);
|
|
76
78
|
server.addMembership(M_CAST);
|
|
77
|
-
this.
|
|
79
|
+
this.setStateChanged("info.connection", { val: true, ack: true });
|
|
78
80
|
this.log.debug("UDP listening on " + server.address().address + ":" + server.address().port);
|
|
79
|
-
const
|
|
80
|
-
if (
|
|
81
|
-
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;
|
|
82
91
|
}
|
|
83
92
|
}
|
|
84
93
|
async onUdpMessage(message, remote) {
|
|
@@ -88,6 +97,7 @@ class GoveeLocal extends utils.Adapter {
|
|
|
88
97
|
for (const key of Object.keys(messageObject.msg.data)) {
|
|
89
98
|
if (key != "device") {
|
|
90
99
|
const deviceName = messageObject.msg.data.device.replace(this.FORBIDDEN_CHARS, "_");
|
|
100
|
+
devices[remote.address] = deviceName;
|
|
91
101
|
this.setObjectNotExists(deviceName, {
|
|
92
102
|
type: "device",
|
|
93
103
|
common: {
|
|
@@ -113,107 +123,98 @@ class GoveeLocal extends utils.Adapter {
|
|
|
113
123
|
});
|
|
114
124
|
}
|
|
115
125
|
}
|
|
116
|
-
if (!(messageObject.msg.data.device in intervals)) {
|
|
117
|
-
const result = this.setInterval(
|
|
118
|
-
() => this.requestDeviceStatus(messageObject.msg.data.ip),
|
|
119
|
-
this.config.deviceStatusRefreshInterval * 1e3
|
|
120
|
-
);
|
|
121
|
-
if (result !== void 0) {
|
|
122
|
-
intervals[messageObject.msg.data.device] = result;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
126
|
break;
|
|
126
127
|
case "devStatus":
|
|
127
|
-
const
|
|
128
|
-
if (
|
|
129
|
-
this.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
for (const key in devices) {
|
|
133
|
-
if (devices[key].val == remote.address) {
|
|
134
|
-
const sendingDevice = key.split(".")[2].replace(this.FORBIDDEN_CHARS, "_");
|
|
135
|
-
const devStatusMessageObject = JSON.parse(message.toString());
|
|
136
|
-
this.setObjectNotExists(`${sendingDevice}.devStatus.onOff`, {
|
|
137
|
-
type: "state",
|
|
138
|
-
common: {
|
|
139
|
-
name: "On / Off state of the lamp",
|
|
140
|
-
type: "boolean",
|
|
141
|
-
role: "switch",
|
|
142
|
-
read: true,
|
|
143
|
-
write: true
|
|
144
|
-
},
|
|
145
|
-
native: {}
|
|
146
|
-
});
|
|
147
|
-
this.setState(`${sendingDevice}.devStatus.onOff`, {
|
|
148
|
-
val: devStatusMessageObject.msg.data.onOff == 1,
|
|
149
|
-
ack: true
|
|
150
|
-
});
|
|
151
|
-
this.setObjectNotExists(`${sendingDevice}.devStatus.brightness`, {
|
|
152
|
-
type: "state",
|
|
153
|
-
common: {
|
|
154
|
-
name: "Brightness of the light",
|
|
155
|
-
type: "number",
|
|
156
|
-
role: "level.dimmer",
|
|
157
|
-
read: true,
|
|
158
|
-
write: true
|
|
159
|
-
},
|
|
160
|
-
native: {}
|
|
161
|
-
});
|
|
162
|
-
this.setState(`${sendingDevice}.devStatus.brightness`, {
|
|
163
|
-
val: devStatusMessageObject.msg.data.brightness,
|
|
164
|
-
ack: true
|
|
165
|
-
});
|
|
166
|
-
this.setObjectNotExists(`${sendingDevice}.devStatus.color`, {
|
|
167
|
-
type: "state",
|
|
168
|
-
common: {
|
|
169
|
-
name: "Current showing color of the lamp",
|
|
170
|
-
type: "string",
|
|
171
|
-
role: "level.color.rgb",
|
|
172
|
-
read: true,
|
|
173
|
-
write: true
|
|
174
|
-
},
|
|
175
|
-
native: {}
|
|
176
|
-
});
|
|
177
|
-
this.setState(`${sendingDevice}.devStatus.color`, {
|
|
178
|
-
val: "#" + componentToHex(devStatusMessageObject.msg.data.color.r) + componentToHex(devStatusMessageObject.msg.data.color.g) + componentToHex(devStatusMessageObject.msg.data.color.b),
|
|
179
|
-
ack: true
|
|
180
|
-
});
|
|
181
|
-
this.setObjectNotExists(`${sendingDevice}.devStatus.colorTemInKelvin`, {
|
|
182
|
-
type: "state",
|
|
183
|
-
common: {
|
|
184
|
-
name: "If staying in white light, the color temperature",
|
|
185
|
-
type: "number",
|
|
186
|
-
role: "level.color.temperature",
|
|
187
|
-
read: true,
|
|
188
|
-
write: true
|
|
189
|
-
},
|
|
190
|
-
native: {}
|
|
191
|
-
});
|
|
192
|
-
this.setState(`${sendingDevice}.devStatus.colorTemInKelvin`, {
|
|
193
|
-
val: devStatusMessageObject.msg.data.colorTemInKelvin,
|
|
194
|
-
ack: true
|
|
195
|
-
});
|
|
128
|
+
const sendingDevice = devices[remote.address];
|
|
129
|
+
if (sendingDevice) {
|
|
130
|
+
if (this.config.extendedLogging && !loggedDevices.includes(remote.address.toString())) {
|
|
131
|
+
this.log.info(`deivce status message data: ${JSON.stringify(messageObject)}`);
|
|
132
|
+
loggedDevices.push(remote.address.toString());
|
|
196
133
|
}
|
|
134
|
+
const devStatusMessageObject = JSON.parse(message.toString());
|
|
135
|
+
this.setObjectNotExists(`${sendingDevice}.devStatus.onOff`, {
|
|
136
|
+
type: "state",
|
|
137
|
+
common: {
|
|
138
|
+
name: "On / Off state of the lamp",
|
|
139
|
+
type: "boolean",
|
|
140
|
+
role: "switch",
|
|
141
|
+
read: true,
|
|
142
|
+
write: true
|
|
143
|
+
},
|
|
144
|
+
native: {}
|
|
145
|
+
});
|
|
146
|
+
this.setState(`${sendingDevice}.devStatus.onOff`, {
|
|
147
|
+
val: devStatusMessageObject.msg.data.onOff == 1,
|
|
148
|
+
ack: true
|
|
149
|
+
});
|
|
150
|
+
this.setObjectNotExists(`${sendingDevice}.devStatus.brightness`, {
|
|
151
|
+
type: "state",
|
|
152
|
+
common: {
|
|
153
|
+
name: "Brightness of the light",
|
|
154
|
+
type: "number",
|
|
155
|
+
role: "level.dimmer",
|
|
156
|
+
read: true,
|
|
157
|
+
write: true
|
|
158
|
+
},
|
|
159
|
+
native: {}
|
|
160
|
+
});
|
|
161
|
+
this.setState(`${sendingDevice}.devStatus.brightness`, {
|
|
162
|
+
val: devStatusMessageObject.msg.data.brightness,
|
|
163
|
+
ack: true
|
|
164
|
+
});
|
|
165
|
+
this.setObjectNotExists(`${sendingDevice}.devStatus.color`, {
|
|
166
|
+
type: "state",
|
|
167
|
+
common: {
|
|
168
|
+
name: "Current showing color of the lamp",
|
|
169
|
+
type: "string",
|
|
170
|
+
role: "level.color.rgb",
|
|
171
|
+
read: true,
|
|
172
|
+
write: true
|
|
173
|
+
},
|
|
174
|
+
native: {}
|
|
175
|
+
});
|
|
176
|
+
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),
|
|
178
|
+
ack: true
|
|
179
|
+
});
|
|
180
|
+
this.setObjectNotExists(`${sendingDevice}.devStatus.colorTemInKelvin`, {
|
|
181
|
+
type: "state",
|
|
182
|
+
common: {
|
|
183
|
+
name: "If staying in white light, the color temperature",
|
|
184
|
+
type: "number",
|
|
185
|
+
role: "level.color.temperature",
|
|
186
|
+
read: true,
|
|
187
|
+
write: true
|
|
188
|
+
},
|
|
189
|
+
native: {}
|
|
190
|
+
});
|
|
191
|
+
this.setState(`${sendingDevice}.devStatus.colorTemInKelvin`, {
|
|
192
|
+
val: devStatusMessageObject.msg.data.colorTemInKelvin,
|
|
193
|
+
ack: true
|
|
194
|
+
});
|
|
197
195
|
}
|
|
198
196
|
break;
|
|
199
197
|
default:
|
|
200
198
|
this.log.error("message from: " + remote.address + ":" + remote.port + " - " + message);
|
|
201
199
|
}
|
|
202
200
|
}
|
|
201
|
+
async refreshAllDevices() {
|
|
202
|
+
for (const ip in devices) {
|
|
203
|
+
this.requestDeviceStatus(ip);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
203
206
|
requestDeviceStatus(receiver) {
|
|
204
|
-
console.log("request device status " + receiver);
|
|
205
207
|
const requestDeviceStatusBuffer = Buffer.from(JSON.stringify(requestStatusMessage));
|
|
206
208
|
client.send(requestDeviceStatusBuffer, 0, requestDeviceStatusBuffer.length, CONTROL_PORT, receiver);
|
|
207
209
|
}
|
|
208
210
|
async sendScan() {
|
|
209
|
-
this.log.info("send scan");
|
|
210
211
|
const scanMessageBuffer = Buffer.from(JSON.stringify(scanMessage));
|
|
211
212
|
client.send(scanMessageBuffer, 0, scanMessageBuffer.length, SEND_SCAN_PORT, M_CAST);
|
|
212
213
|
}
|
|
213
214
|
onUnload(callback) {
|
|
214
215
|
try {
|
|
215
216
|
this.clearInterval(searchInterval);
|
|
216
|
-
|
|
217
|
+
this.clearInterval(refreshInterval);
|
|
217
218
|
client.close();
|
|
218
219
|
server.close();
|
|
219
220
|
this.setState("info.connection", { val: false, ack: true });
|
|
@@ -224,7 +225,7 @@ class GoveeLocal extends utils.Adapter {
|
|
|
224
225
|
}
|
|
225
226
|
async onStateChange(id, state) {
|
|
226
227
|
var _a, _b;
|
|
227
|
-
if (state && !state.ack
|
|
228
|
+
if (state && !state.ack) {
|
|
228
229
|
const ipOfDevice = await this.getStateAsync(id.split(".")[2] + ".deviceInfo.ip");
|
|
229
230
|
if (ipOfDevice) {
|
|
230
231
|
const receiver = (_a = ipOfDevice.val) == null ? void 0 : _a.toString();
|
|
@@ -240,15 +241,23 @@ class GoveeLocal extends utils.Adapter {
|
|
|
240
241
|
client.send(brightnessMessageBuffer, 0, brightnessMessageBuffer.length, CONTROL_PORT, receiver);
|
|
241
242
|
break;
|
|
242
243
|
case "colorTemInKelvin":
|
|
243
|
-
const colorTempMessage = {
|
|
244
|
+
const colorTempMessage = {
|
|
245
|
+
msg: {
|
|
246
|
+
cmd: "colorwc",
|
|
247
|
+
data: { color: { r: "0", g: "0", b: "0" }, colorTemInKelvin: state.val }
|
|
248
|
+
}
|
|
249
|
+
};
|
|
244
250
|
const colorTempMessageBuffer = Buffer.from(JSON.stringify(colorTempMessage));
|
|
245
251
|
client.send(colorTempMessageBuffer, 0, colorTempMessageBuffer.length, CONTROL_PORT, receiver);
|
|
246
252
|
break;
|
|
247
253
|
case "color":
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
254
|
+
const colorValue = (_b = state.val) == null ? void 0 : _b.toString();
|
|
255
|
+
if (colorValue) {
|
|
256
|
+
const rgb = hexToRgb(colorValue);
|
|
257
|
+
const colorMessage = { msg: { cmd: "colorwc", data: { color: rgb } } };
|
|
258
|
+
const colorMessageBuffer = Buffer.from(JSON.stringify(colorMessage));
|
|
259
|
+
client.send(colorMessageBuffer, 0, colorMessageBuffer.length, CONTROL_PORT, receiver);
|
|
260
|
+
}
|
|
252
261
|
break;
|
|
253
262
|
}
|
|
254
263
|
} else {
|
|
@@ -285,7 +294,7 @@ function componentToHex(c) {
|
|
|
285
294
|
return hex.length == 1 ? "0" + hex : hex;
|
|
286
295
|
}
|
|
287
296
|
function hexToRgb(hexString) {
|
|
288
|
-
if (!/^#[0-9a-
|
|
297
|
+
if (!/^#[0-9a-fA-F]{6}$/i.test(hexString)) {
|
|
289
298
|
throw new Error("Invalid hex string");
|
|
290
299
|
}
|
|
291
300
|
return {
|
|
@@ -296,6 +305,7 @@ function hexToRgb(hexString) {
|
|
|
296
305
|
}
|
|
297
306
|
// Annotate the CommonJS export names for ESM import in node:
|
|
298
307
|
0 && (module.exports = {
|
|
299
|
-
componentToHex
|
|
308
|
+
componentToHex,
|
|
309
|
+
hexToRgb
|
|
300
310
|
});
|
|
301
311
|
//# 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;\n\nconst intervals: { [device: string]: NodeJS.Timeout } = {};\n\nconst loggedDevices = [] as string[];\n\nclass GoveeLocal extends utils.Adapter {\n\tpublic constructor(options: Partial<utils.AdapterOptions> = {}) {\n\t\tsuper({\n\t\t\t...options,\n\t\t\tname: 'govee-local',\n\t\t});\n\t\tthis.on('ready', this.onReady.bind(this));\n\t\tthis.on('stateChange', this.onStateChange.bind(this));\n\t\t// this.on('objectChange', this.onObjectChange.bind(this));\n\t\t// this.on('message', this.onMessage.bind(this));\n\t\tthis.on('unload', this.onUnload.bind(this));\n\t}\n\n\t/**\n\t * Is called when databases are connected and adapter received configuration.\n\t */\n\tprivate async onReady(): Promise<void> {\n\t\tthis.setObjectNotExists('info.connection', {\n\t\t\ttype: 'state',\n\t\t\tcommon: {\n\t\t\t\tname: 'Device discovery running',\n\t\t\t\ttype: 'boolean',\n\t\t\t\trole: 'indicator.connected',\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\t\tserver.on('message', this.onUdpMessage.bind(this));\n\t\tserver.on('error', (error) => {\n\t\t\tthis.log.error('server bind error : ' + error.message);\n\t\t\tthis.setState('info.connection', { val: false, ack: true });\n\t\t});\n\n\t\tserver.bind(LOCAL_PORT, this.serverBound.bind(this));\n\n\t\tthis.subscribeStates('*.devStatus.*');\n\t}\n\n\t/**\n\t * handles when udp socket is up\n\t * configure multicast membership\n\t * start periodic scan for devices\n\t */\n\tprivate async serverBound(): Promise<void> {\n\t\tserver.setBroadcast(true);\n\t\tserver.setMulticastTTL(128);\n\t\tserver.addMembership(M_CAST);\n\t\tthis.setState('info.connection', { val: true, ack: true });\n\t\tthis.log.debug('UDP listening on ' + server.address().address + ':' + server.address().port);\n\n\t\tconst result = this.setInterval(this.sendScan.bind(this), this.config.searchInterval * 1000);\n\t\tif (result !== void 0) {\n\t\t\tsearchInterval = result;\n\t\t}\n\t}\n\n\t/**\n\t * handle icoming messages on the udp socket\n\t * @param message the message itself\n\t * @param remote the sender of the message\n\t */\n\tprivate async onUdpMessage(message: Buffer, remote: dgram.RemoteInfo): Promise<void> {\n\t\tconst messageObject = JSON.parse(message.toString());\n\t\tswitch (messageObject.msg.cmd) {\n\t\t\tcase 'scan':\n\t\t\t\tfor (const key of Object.keys(messageObject.msg.data)) {\n\t\t\t\t\tif (key != 'device') {\n\t\t\t\t\t\tconst deviceName = messageObject.msg.data.device.replace(this.FORBIDDEN_CHARS, '_');\n\t\t\t\t\t\tthis.setObjectNotExists(deviceName, {\n\t\t\t\t\t\t\ttype: 'device',\n\t\t\t\t\t\t\tcommon: {\n\t\t\t\t\t\t\t\tname: messageObject.msg.data.sku,\n\t\t\t\t\t\t\t\trole: 'group',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tnative: {},\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.setObjectNotExists(`${deviceName}.deviceInfo.${key}`, {\n\t\t\t\t\t\t\ttype: 'state',\n\t\t\t\t\t\t\tcommon: {\n\t\t\t\t\t\t\t\tname: getDatapointDescription(key),\n\t\t\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\t\t\trole: 'state',\n\t\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\t\twrite: false,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tnative: {},\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.setState(`${deviceName}.deviceInfo.${key}`, {\n\t\t\t\t\t\t\tval: messageObject.msg.data[key],\n\t\t\t\t\t\t\tack: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!(messageObject.msg.data.device in intervals)) {\n\t\t\t\t\tconst result = this.setInterval(\n\t\t\t\t\t\t() => this.requestDeviceStatus(messageObject.msg.data.ip),\n\t\t\t\t\t\tthis.config.deviceStatusRefreshInterval * 1000,\n\t\t\t\t\t);\n\t\t\t\t\tif (result !== void 0) {\n\t\t\t\t\t\tintervals[messageObject.msg.data.device] = result;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'devStatus':\n\t\t\t\tconst devices = await this.getStatesAsync(`${this.name}.${this.instance}.*.deviceInfo.ip`);\n\t\t\t\tif (this.config.extendedLogging && !loggedDevices.includes(remote.address.toString())) {\n\t\t\t\t\tthis.log.info(`deivce status message data: ${JSON.stringify(messageObject.msg.data)}`);\n\t\t\t\t\tloggedDevices.push(remote.address.toString());\n\t\t\t\t}\n\t\t\t\tfor (const key in devices) {\n\t\t\t\t\tif (devices[key as keyof typeof devices].val == remote.address) {\n\t\t\t\t\t\tconst sendingDevice = key.split('.')[2].replace(this.FORBIDDEN_CHARS, '_');\n\t\t\t\t\t\tconst devStatusMessageObject = JSON.parse(message.toString());\n\t\t\t\t\t\tthis.setObjectNotExists(`${sendingDevice}.devStatus.onOff`, {\n\t\t\t\t\t\t\ttype: 'state',\n\t\t\t\t\t\t\tcommon: {\n\t\t\t\t\t\t\t\tname: 'On / Off state of the lamp',\n\t\t\t\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\t\t\t\trole: 'switch',\n\t\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\t\twrite: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tnative: {},\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.setState(`${sendingDevice}.devStatus.onOff`, {\n\t\t\t\t\t\t\tval: devStatusMessageObject.msg.data.onOff == 1,\n\t\t\t\t\t\t\tack: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.setObjectNotExists(`${sendingDevice}.devStatus.brightness`, {\n\t\t\t\t\t\t\ttype: 'state',\n\t\t\t\t\t\t\tcommon: {\n\t\t\t\t\t\t\t\tname: 'Brightness of the light',\n\t\t\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t\t\t\trole: 'level.dimmer',\n\t\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\t\twrite: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tnative: {},\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.setState(`${sendingDevice}.devStatus.brightness`, {\n\t\t\t\t\t\t\tval: devStatusMessageObject.msg.data.brightness,\n\t\t\t\t\t\t\tack: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.setObjectNotExists(`${sendingDevice}.devStatus.color`, {\n\t\t\t\t\t\t\ttype: 'state',\n\t\t\t\t\t\t\tcommon: {\n\t\t\t\t\t\t\t\tname: 'Current showing color of the lamp',\n\t\t\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\t\t\trole: 'level.color.rgb',\n\t\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\t\twrite: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tnative: {},\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.setState(`${sendingDevice}.devStatus.color`, {\n\t\t\t\t\t\t\tval:\n\t\t\t\t\t\t\t\t'#' +\n\t\t\t\t\t\t\t\tcomponentToHex(devStatusMessageObject.msg.data.color.r) +\n\t\t\t\t\t\t\t\tcomponentToHex(devStatusMessageObject.msg.data.color.g) +\n\t\t\t\t\t\t\t\tcomponentToHex(devStatusMessageObject.msg.data.color.b),\n\t\t\t\t\t\t\tack: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.setObjectNotExists(`${sendingDevice}.devStatus.colorTemInKelvin`, {\n\t\t\t\t\t\t\ttype: 'state',\n\t\t\t\t\t\t\tcommon: {\n\t\t\t\t\t\t\t\tname: 'If staying in white light, the color temperature',\n\t\t\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t\t\t\trole: 'level.color.temperature',\n\t\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\t\twrite: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tnative: {},\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.setState(`${sendingDevice}.devStatus.colorTemInKelvin`, {\n\t\t\t\t\t\t\tval: devStatusMessageObject.msg.data.colorTemInKelvin,\n\t\t\t\t\t\t\tack: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tthis.log.error('message from: ' + remote.address + ':' + remote.port + ' - ' + message);\n\t\t}\n\t}\n\n\t/**\n\t * sends the device status request to one specific device\n\t * @param receiver the ip ( / hsotname ) of the device that should be queried\n\t */\n\tprivate requestDeviceStatus(receiver: string): void {\n\t\tconsole.log('request device status ' + receiver);\n\t\tconst requestDeviceStatusBuffer = Buffer.from(JSON.stringify(requestStatusMessage));\n\t\tclient.send(requestDeviceStatusBuffer, 0, requestDeviceStatusBuffer.length, CONTROL_PORT, receiver);\n\t}\n\n\t/**\n\t * send the scan message to the udp multicast address\n\t */\n\tprivate async sendScan(): Promise<void> {\n\t\tthis.log.info('send scan');\n\t\tconst scanMessageBuffer = Buffer.from(JSON.stringify(scanMessage));\n\t\tclient.send(scanMessageBuffer, 0, scanMessageBuffer.length, SEND_SCAN_PORT, M_CAST);\n\t}\n\n\t/**\n\t * Is called when adapter shuts down - callback has to be called under any circumstances!\n\t */\n\tprivate onUnload(callback: () => void): void {\n\t\ttry {\n\t\t\tthis.clearInterval(searchInterval);\n\t\t\tObject.entries(intervals).forEach(([_, interval]) => this.clearInterval(interval));\n\t\t\tclient.close();\n\t\t\tserver.close();\n\t\t\tthis.setState('info.connection', { val: false, ack: true });\n\t\t\tcallback();\n\t\t} catch (e) {\n\t\t\tcallback();\n\t\t}\n\t}\n\n\t/**\n\t * Is called if a subscribed state changes\n\t */\n\tprivate async onStateChange(id: string, state: ioBroker.State | null | undefined): Promise<void> {\n\t\tif (state && !state.ack && state.val) {\n\t\t\tconst ipOfDevice = await this.getStateAsync(id.split('.')[2] + '.deviceInfo.ip');\n\t\t\tif (ipOfDevice) {\n\t\t\t\tconst receiver = ipOfDevice.val?.toString();\n\t\t\t\tswitch (id.split('.')[4]) {\n\t\t\t\t\tcase 'onOff':\n\t\t\t\t\t\tconst turnMessage = { msg: { cmd: 'turn', data: { value: state.val ? 1 : 0 } } };\n\t\t\t\t\t\tconst turnMessageBuffer = Buffer.from(JSON.stringify(turnMessage));\n\t\t\t\t\t\tclient.send(turnMessageBuffer, 0, turnMessageBuffer.length, CONTROL_PORT, receiver);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'brightness':\n\t\t\t\t\t\tconst brightnessMessage = { msg: { cmd: 'brightness', data: { value: state.val } } };\n\t\t\t\t\t\tconst brightnessMessageBuffer = Buffer.from(JSON.stringify(brightnessMessage));\n\t\t\t\t\t\tclient.send(brightnessMessageBuffer, 0, brightnessMessageBuffer.length, CONTROL_PORT, receiver);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'colorTemInKelvin':\n\t\t\t\t\t\tconst colorTempMessage = { msg: { cmd: 'colorTemInKelvin', data: { value: state.val } } };\n\t\t\t\t\t\tconst colorTempMessageBuffer = Buffer.from(JSON.stringify(colorTempMessage));\n\t\t\t\t\t\tclient.send(colorTempMessageBuffer, 0, colorTempMessageBuffer.length, CONTROL_PORT, receiver);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'color':\n\t\t\t\t\t\tconst rgb = hexToRgb(state.val?.toString());\n\t\t\t\t\t\tconst colorMessage = { msg: { cmd: 'colorwc', data: { color: rgb } } };\n\t\t\t\t\t\tconst colorMessageBuffer = Buffer.from(JSON.stringify(colorMessage));\n\t\t\t\t\t\tclient.send(colorMessageBuffer, 0, colorMessageBuffer.length, CONTROL_PORT, receiver);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.log.error('device not found');\n\t\t\t}\n\t\t}\n\t}\n}\n\nif (require.main !== module) {\n\t// Export the constructor in compact mode\n\tmodule.exports = (options: Partial<utils.AdapterOptions> | undefined) => new GoveeLocal(options);\n} else {\n\t// otherwise start the instance directly\n\t(() => new GoveeLocal())();\n}\n\n/**\n * This method returns the description for device information datapoints\n * to unbloat the upper methods.\n * tanslations would be great here\n * @param name the name of the parameter retrieved from the device\n * @returns the description, that should be set to the datapoint\n */\nfunction getDatapointDescription(name: string): string {\n\tswitch (name) {\n\t\tcase 'model':\n\t\t\treturn 'Specific model of the Lamp';\n\t\tcase 'ip':\n\t\t\treturn 'IP address of the Lamp';\n\t\tcase 'bleVersionHard':\n\t\t\treturn 'Bluetooth Low Energy Hardware Version';\n\t\tcase 'bleVersionSoft':\n\t\t\treturn 'Bluetooth Low Energy Software Version';\n\t\tcase 'wifiVersionHard':\n\t\t\treturn 'WiFi Hardware Version';\n\t\tcase 'wifiVersionSoft':\n\t\t\treturn 'WiFi Software Version';\n\t\tdefault:\n\t\t\treturn '';\n\t}\n}\n\n/**\n * Convert number (<255) to two digit hex for colorcode\n * @param the int value, should me < 255\n * @returns the hex value as string\n */\nfunction componentToHex(c: number): string {\n\tconst hex = c.toString(16);\n\treturn hex.length == 1 ? '0' + hex : hex;\n}\n\nfunction hexToRgb(hexString: string): Color {\n\t// Check if the hex string is valid\n\tif (!/^#[0-9a-f]{6}$/i.test(hexString)) {\n\t\tthrow new Error('Invalid hex string');\n\t}\n\n\treturn {\n\t\tr: parseInt(hexString.slice(1, 3), 16),\n\t\tg: parseInt(hexString.slice(3, 5), 16),\n\t\tb: parseInt(hexString.slice(5, 7), 16),\n\t};\n}\n\ntype Color = {\n\tr: number;\n\tg: number;\n\tb: number;\n};\n\nexport { componentToHex };\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;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;AAEJ,MAAM,
|
|
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,60 @@
|
|
|
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
|
+
},
|
|
45
|
+
"0.2.1": {
|
|
46
|
+
"en": "repair onOff / all other actions Fixes: #65\nfix log spamming because of wildcard",
|
|
47
|
+
"de": "reparatur onOff / alle anderen Aktionen Behebungen: #65\nprotokoll spamming wegen wildcard",
|
|
48
|
+
"ru": "ремонт onOff / все другие действия Исправления: #65\nисправить спамирование лога из-за дикой карты",
|
|
49
|
+
"pt": "reparação emOff / todas as outras ações Correções: #65 #\ncorrigir spam de log por causa do wildcard",
|
|
50
|
+
"nl": "vertaling: Vertaling: 65\nvertaling:",
|
|
51
|
+
"fr": "réparation onOff / toutes les autres actions Fixes: #65\ncorriger l'éblouissement du journal à cause de wildcard",
|
|
52
|
+
"it": "riparazione onOff / tutte le altre azioni Fissi: #65\nsistemare il log spamming a causa di jolly",
|
|
53
|
+
"es": "reparación onOff / todas las demás acciones Arreglos: #65\nfijar registro de spam debido a wildcard",
|
|
54
|
+
"pl": "remontowanie Off / wszystkie inne działania Fiksy #65\nusunąć z powodu dzikiej karty",
|
|
55
|
+
"uk": "ремонт наОфф / всі інші дії Виправлення: #65\nфіксація спамерування колод через дикийкарт",
|
|
56
|
+
"zh-cn": "b. 修理效率/所有其他行动 固定: #65\nfix 由于野生素卡的投机"
|
|
57
|
+
},
|
|
6
58
|
"0.2.0": {
|
|
7
59
|
"en": "support controlling the color\nextended logging mode",
|
|
8
60
|
"de": "unterstützung controlling der farbe\nerweiterter logging-modus",
|
|
@@ -41,58 +93,6 @@
|
|
|
41
93
|
"pl": "zdjęcie",
|
|
42
94
|
"uk": "фіксувати зображення",
|
|
43
95
|
"zh-cn": "fix图像"
|
|
44
|
-
},
|
|
45
|
-
"0.1.0": {
|
|
46
|
-
"en": "make search intervals configurable\nclear all timeouts, when adapter is stopped\nreplace forbidden characters in names\nupdate translations\nupdate dependecies",
|
|
47
|
-
"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",
|
|
48
|
-
"ru": "сделать поисковые интервалы конфигурируемыми\nочистить все тайм-аут, когда адаптер остановлен\nзаменить запрещенные символы в именах\nобновление переводов\nобновление зависимостей",
|
|
49
|
-
"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",
|
|
50
|
-
"nl": "doorzoekingsbesprekingen beperkt\nmaak alle time-outs vrij wanneer de adapter stopt\nverboden personages in naam\nvertaling:\nvertaling:",
|
|
51
|
-
"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",
|
|
52
|
-
"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",
|
|
53
|
-
"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",
|
|
54
|
-
"pl": "przeszukiwań konfigurowalnych\noczywiście cały czas, gdy adapter zostaje zatrzymany\nzastępowanie bohaterów nazw\ntłumaczenia aktualizacyjne\naktualizacja",
|
|
55
|
-
"uk": "зробіть інтервали пошуку налаштувати\nочистити всі маршрути, коли адаптер припиняється\nзамінити заборонені символи в іменах\nоновлення перекладів\nоновлення залежності",
|
|
56
|
-
"zh-cn": "定期探查\n所有时间都很清楚,当适应人员被停止时\n用名称取代禁止的特性\n更新翻译\na. 最新依赖情况"
|
|
57
|
-
},
|
|
58
|
-
"0.0.6": {
|
|
59
|
-
"en": "update dependencies",
|
|
60
|
-
"de": "aktualisierung der abhängigkeiten",
|
|
61
|
-
"ru": "обновление зависимостей",
|
|
62
|
-
"pt": "dependências",
|
|
63
|
-
"nl": "vertaling:",
|
|
64
|
-
"fr": "mettre à jour les dépendances",
|
|
65
|
-
"it": "aggiornamento dipendenze",
|
|
66
|
-
"es": "dependencias de actualización",
|
|
67
|
-
"pl": "zależności",
|
|
68
|
-
"uk": "оновлення залежності",
|
|
69
|
-
"zh-cn": "a. 最新受扶养人"
|
|
70
|
-
},
|
|
71
|
-
"0.0.5": {
|
|
72
|
-
"en": "make pipeline run",
|
|
73
|
-
"de": "pipeline laufen lassen",
|
|
74
|
-
"ru": "сделать пробег трубопровода",
|
|
75
|
-
"pt": "fazer a execução do pipeline",
|
|
76
|
-
"nl": "maak pijplijnen",
|
|
77
|
-
"fr": "faire fonctionner le pipeline",
|
|
78
|
-
"it": "rendere il processo di tubazione",
|
|
79
|
-
"es": "funcionamiento del gasoducto",
|
|
80
|
-
"pl": "rurociąg",
|
|
81
|
-
"uk": "зведення трубопроводів",
|
|
82
|
-
"zh-cn": "管道"
|
|
83
|
-
},
|
|
84
|
-
"0.0.4": {
|
|
85
|
-
"en": "make device status refresh invertal indepentent from device search interval",
|
|
86
|
-
"de": "die gerätestatus erfrischen invertal indepentent von der gerätesuche intervall",
|
|
87
|
-
"ru": "сделать статус устройства обновленный инвертальный непонятный с интервала поиска устройства",
|
|
88
|
-
"pt": "fazer o status do dispositivo atualizar indepente invertal do intervalo de pesquisa do dispositivo",
|
|
89
|
-
"nl": "maak de status verfrissend onafhankelijk van het apparaat",
|
|
90
|
-
"fr": "faire rafraîchir l'état de l'appareil indépentant de l'intervalle de recherche de l'appareil",
|
|
91
|
-
"it": "rendere lo stato del dispositivo aggiornare invertal indipendente dall'intervallo di ricerca del dispositivo",
|
|
92
|
-
"es": "hacer actualización del estado del dispositivo indepentente invertal del intervalo de búsqueda del dispositivo",
|
|
93
|
-
"pl": "status odświeżający",
|
|
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",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"@iobroker/adapter-core": "^3.0.4"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@alcalzone/release-script": "^3.
|
|
27
|
+
"@alcalzone/release-script": "^3.7.0",
|
|
28
28
|
"@alcalzone/release-script-plugin-iobroker": "^3.6.0",
|
|
29
29
|
"@alcalzone/release-script-plugin-license": "^3.5.9",
|
|
30
30
|
"@alcalzone/release-script-plugin-manual-review": "^3.5.9",
|
|
@@ -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": [
|