iobroker.govee-local 0.2.8 → 0.3.1
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 +42 -25
- package/build/lib/goveeService.js +297 -0
- package/build/lib/goveeService.js.map +7 -0
- package/build/lib/goveeServiceOptions.js +17 -0
- package/build/lib/goveeServiceOptions.js.map +7 -0
- package/build/lib/tools/datapointTools.js +46 -0
- package/build/lib/tools/datapointTools.js.map +7 -0
- package/build/{tools → lib/tools}/hexTool.js +10 -8
- package/build/lib/tools/hexTool.js.map +7 -0
- package/build/main.js +164 -244
- package/build/main.js.map +2 -2
- package/io-package.json +42 -42
- package/package.json +17 -20
- package/build/tools/hexTool.js.map +0 -7
package/README.md
CHANGED
|
@@ -24,78 +24,95 @@ For **Windows** Users: Please go to the settings and make sure you choose the co
|
|
|
24
24
|
Placeholder for the next version (at the beginning of the line):
|
|
25
25
|
### **WORK IN PROGRESS**
|
|
26
26
|
-->
|
|
27
|
+
### 0.3.1 (2025-10-19)
|
|
28
|
+
|
|
29
|
+
- updated release script run configuration
|
|
30
|
+
|
|
31
|
+
### 0.3.0 (2025-10-19)
|
|
32
|
+
|
|
33
|
+
- Refactored: Moved all device logic to a dedicated GoveeService class, modularized utilities
|
|
34
|
+
- Improved test coverage
|
|
35
|
+
- Dependencies updated
|
|
36
|
+
|
|
37
|
+
### 0.2.9 (2025-08-22)
|
|
38
|
+
|
|
39
|
+
- update dependencies
|
|
40
|
+
- add support for node 24
|
|
41
|
+
- update to ESlint 9
|
|
42
|
+
|
|
27
43
|
### 0.2.8 (2025-03-28)
|
|
28
44
|
|
|
29
|
-
-
|
|
45
|
+
- update dependencies
|
|
46
|
+
- avoid repeated overriding of states
|
|
30
47
|
|
|
31
48
|
### 0.2.7 (2024-08-18)
|
|
32
49
|
|
|
33
|
-
-
|
|
50
|
+
- update core dependencies and min required node version to 18
|
|
34
51
|
|
|
35
52
|
### 0.2.6 (2024-02-06)
|
|
36
53
|
|
|
37
|
-
-
|
|
54
|
+
- fix brightness change also changing white temperature
|
|
38
55
|
|
|
39
56
|
### 0.2.5 (2024-01-13)
|
|
40
57
|
|
|
41
|
-
-
|
|
42
|
-
-
|
|
43
|
-
-
|
|
58
|
+
- create only one socket, as the second seems not to be necessary
|
|
59
|
+
- refactoring the code for better structure
|
|
60
|
+
- possibility to choose listen interface in settings
|
|
44
61
|
|
|
45
62
|
### 0.2.4 (2024-01-05)
|
|
46
63
|
|
|
47
|
-
-
|
|
64
|
+
- fix access
|
|
48
65
|
|
|
49
66
|
### 0.2.2 (2024-01-05)
|
|
50
67
|
|
|
51
|
-
-
|
|
68
|
+
- fix color temperature message
|
|
52
69
|
|
|
53
70
|
### 0.2.1 (2023-12-24)
|
|
54
71
|
|
|
55
|
-
-
|
|
56
|
-
-
|
|
72
|
+
- repair onOff / all other actions Fixes: [#65](https://github.com/boergegrunicke/ioBroker.govee-local/issues/65)
|
|
73
|
+
- fix log spamming because of wildcard
|
|
57
74
|
|
|
58
75
|
### 0.2.0 (2023-12-17)
|
|
59
76
|
|
|
60
|
-
-
|
|
61
|
-
-
|
|
77
|
+
- support controlling the color
|
|
78
|
+
- extended logging mode
|
|
62
79
|
|
|
63
80
|
### 0.1.2 (2023-09-06)
|
|
64
81
|
|
|
65
|
-
-
|
|
82
|
+
- change icon path and resolution
|
|
66
83
|
|
|
67
84
|
### 0.1.1 (2023-08-21)
|
|
68
85
|
|
|
69
|
-
-
|
|
86
|
+
- fix image
|
|
70
87
|
|
|
71
88
|
### 0.1.0 (2023-08-09)
|
|
72
89
|
|
|
73
|
-
-
|
|
74
|
-
-
|
|
75
|
-
-
|
|
76
|
-
-
|
|
77
|
-
-
|
|
90
|
+
- make search intervals configurable
|
|
91
|
+
- clear all timeouts, when adapter is stopped
|
|
92
|
+
- replace forbidden characters in names
|
|
93
|
+
- update translations
|
|
94
|
+
- update dependencies
|
|
78
95
|
|
|
79
96
|
### 0.0.6 (2023-05-18)
|
|
80
97
|
|
|
81
|
-
-
|
|
98
|
+
- update dependencies
|
|
82
99
|
|
|
83
100
|
### 0.0.5 (2023-04-02)
|
|
84
101
|
|
|
85
|
-
-
|
|
102
|
+
- make pipeline run
|
|
86
103
|
|
|
87
104
|
### 0.0.4 (2023-04-02)
|
|
88
105
|
|
|
89
|
-
-
|
|
106
|
+
- make device status refresh independent from device search interval
|
|
90
107
|
|
|
91
108
|
### 0.0.3 (2023-04-01)
|
|
92
109
|
|
|
93
|
-
-
|
|
110
|
+
- update dependencies
|
|
94
111
|
|
|
95
112
|
### 0.0.2
|
|
96
113
|
|
|
97
|
-
-
|
|
98
|
-
-
|
|
114
|
+
- frequently searching for devices and requesting their specific state
|
|
115
|
+
- on / off state, brightness and and color temperature can be controlled
|
|
99
116
|
|
|
100
117
|
## License
|
|
101
118
|
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
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
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var goveeService_exports = {};
|
|
30
|
+
__export(goveeService_exports, {
|
|
31
|
+
GoveeService: () => GoveeService
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(goveeService_exports);
|
|
34
|
+
var dgram = __toESM(require("node:dgram"));
|
|
35
|
+
var import_node_events = require("node:events");
|
|
36
|
+
var import_hexTool = require("./tools/hexTool");
|
|
37
|
+
class GoveeService extends import_node_events.EventEmitter {
|
|
38
|
+
socket;
|
|
39
|
+
options;
|
|
40
|
+
devices = {};
|
|
41
|
+
loggedDevices = [];
|
|
42
|
+
searchInterval;
|
|
43
|
+
refreshInterval;
|
|
44
|
+
static LOCAL_PORT = 4002;
|
|
45
|
+
static SEND_SCAN_PORT = 4001;
|
|
46
|
+
static CONTROL_PORT = 4003;
|
|
47
|
+
static M_CAST = "239.255.255.250";
|
|
48
|
+
static scanMessage = { msg: { cmd: "scan", data: { account_topic: "reserved" } } };
|
|
49
|
+
static requestStatusMessage = { msg: { cmd: "devStatus", data: {} } };
|
|
50
|
+
/**
|
|
51
|
+
* Create a new GoveeService instance.
|
|
52
|
+
*
|
|
53
|
+
* @param options Configuration options for the service.
|
|
54
|
+
*/
|
|
55
|
+
constructor(options) {
|
|
56
|
+
super();
|
|
57
|
+
this.options = options;
|
|
58
|
+
this.socket = dgram.createSocket({ type: "udp4" });
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Bind UDP socket and start device search/refresh intervals.
|
|
62
|
+
*/
|
|
63
|
+
start() {
|
|
64
|
+
this.socket.on("message", this.onUdpMessage.bind(this));
|
|
65
|
+
this.socket.on("error", (error) => {
|
|
66
|
+
var _a;
|
|
67
|
+
(_a = this.options.logger) == null ? void 0 : _a.error(`server bind error : ${error.message}`);
|
|
68
|
+
});
|
|
69
|
+
this.socket.bind(
|
|
70
|
+
{ address: this.options.interface, port: GoveeService.LOCAL_PORT },
|
|
71
|
+
this.serverBound.bind(this)
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
serverBound() {
|
|
75
|
+
var _a;
|
|
76
|
+
this.socket.setBroadcast(true);
|
|
77
|
+
this.socket.setMulticastTTL(128);
|
|
78
|
+
this.socket.setMulticastInterface(this.options.interface);
|
|
79
|
+
this.socket.addMembership(GoveeService.M_CAST);
|
|
80
|
+
(_a = this.options.logger) == null ? void 0 : _a.debug(
|
|
81
|
+
`UDP listening on ${this.socket.address().address}:${this.socket.address().port}`
|
|
82
|
+
);
|
|
83
|
+
this.searchInterval = setInterval(() => this.sendScan(), this.options.searchInterval * 1e3);
|
|
84
|
+
this.refreshInterval = setInterval(
|
|
85
|
+
() => this.refreshAllDevices(),
|
|
86
|
+
this.options.deviceStatusRefreshInterval * 1e3
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Handle incoming UDP messages.
|
|
91
|
+
*
|
|
92
|
+
* @param message The message buffer.
|
|
93
|
+
* @param remote The sender info.
|
|
94
|
+
*/
|
|
95
|
+
onUdpMessage(message, remote) {
|
|
96
|
+
var _a, _b, _c;
|
|
97
|
+
const messageObject = JSON.parse(message.toString());
|
|
98
|
+
switch (messageObject.msg.cmd) {
|
|
99
|
+
case "scan": {
|
|
100
|
+
if (messageObject.msg.data.device) {
|
|
101
|
+
const deviceName = messageObject.msg.data.device.replace(
|
|
102
|
+
(_a = this.options.forbiddenChars) != null ? _a : /[^a-zA-Z0-9_-]/g,
|
|
103
|
+
"_"
|
|
104
|
+
);
|
|
105
|
+
this.devices[remote.address] = deviceName;
|
|
106
|
+
this.emit("deviceDiscovered", {
|
|
107
|
+
ip: remote.address,
|
|
108
|
+
deviceName
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
case "devStatus": {
|
|
114
|
+
const sendingDevice = this.devices[remote.address];
|
|
115
|
+
if (sendingDevice) {
|
|
116
|
+
if (this.options.extendedLogging && !this.loggedDevices.includes(remote.address.toString())) {
|
|
117
|
+
(_b = this.options.logger) == null ? void 0 : _b.info(`device status message data: ${JSON.stringify(messageObject)}`);
|
|
118
|
+
this.loggedDevices.push(remote.address.toString());
|
|
119
|
+
}
|
|
120
|
+
this.emitDeviceStatusUpdate(sendingDevice, remote.address, messageObject);
|
|
121
|
+
}
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
default: {
|
|
125
|
+
(_c = this.options.logger) == null ? void 0 : _c.debug(`message from: ${remote.address}:${remote.port} - ${message.toString()}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Send device status request to all known devices.
|
|
131
|
+
*/
|
|
132
|
+
refreshAllDevices() {
|
|
133
|
+
for (const ip in this.devices) {
|
|
134
|
+
this.requestDeviceStatus(ip);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Send device status request to a specific device.
|
|
139
|
+
*
|
|
140
|
+
* @param receiver The IP address or hostname of the device.
|
|
141
|
+
*/
|
|
142
|
+
requestDeviceStatus(receiver) {
|
|
143
|
+
const requestDeviceStatusBuffer = Buffer.from(JSON.stringify(GoveeService.requestStatusMessage));
|
|
144
|
+
this.socket.send(
|
|
145
|
+
requestDeviceStatusBuffer,
|
|
146
|
+
0,
|
|
147
|
+
requestDeviceStatusBuffer.length,
|
|
148
|
+
GoveeService.CONTROL_PORT,
|
|
149
|
+
receiver
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Send scan message to the UDP multicast address.
|
|
154
|
+
*/
|
|
155
|
+
sendScan() {
|
|
156
|
+
var _a;
|
|
157
|
+
(_a = this.options.logger) == null ? void 0 : _a.debug("sending scan message");
|
|
158
|
+
const scanMessageBuffer = Buffer.from(JSON.stringify(GoveeService.scanMessage));
|
|
159
|
+
this.socket.send(
|
|
160
|
+
scanMessageBuffer,
|
|
161
|
+
0,
|
|
162
|
+
scanMessageBuffer.length,
|
|
163
|
+
GoveeService.SEND_SCAN_PORT,
|
|
164
|
+
GoveeService.M_CAST
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Stop all intervals and close the socket.
|
|
169
|
+
*/
|
|
170
|
+
stop() {
|
|
171
|
+
if (this.searchInterval) {
|
|
172
|
+
clearInterval(this.searchInterval);
|
|
173
|
+
}
|
|
174
|
+
if (this.refreshInterval) {
|
|
175
|
+
clearInterval(this.refreshInterval);
|
|
176
|
+
}
|
|
177
|
+
this.socket.close();
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Get all known devices.
|
|
181
|
+
*/
|
|
182
|
+
getDevices() {
|
|
183
|
+
return this.devices;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Handles a state change and sends the appropriate command to the device.
|
|
187
|
+
*
|
|
188
|
+
* @param id The state ID
|
|
189
|
+
* @param state The new state object
|
|
190
|
+
* @param receiver The device IP as string
|
|
191
|
+
*/
|
|
192
|
+
handleStateChange(id, state, receiver) {
|
|
193
|
+
var _a;
|
|
194
|
+
const stateKey = id.split(".")[4];
|
|
195
|
+
switch (stateKey) {
|
|
196
|
+
case "onOff":
|
|
197
|
+
this.sendTurnCommand(receiver, !!state.val);
|
|
198
|
+
break;
|
|
199
|
+
case "brightness":
|
|
200
|
+
this.sendBrightnessCommand(receiver, Number(state.val));
|
|
201
|
+
break;
|
|
202
|
+
case "colorTemInKelvin":
|
|
203
|
+
this.sendColorTempCommand(receiver, Number(state.val));
|
|
204
|
+
break;
|
|
205
|
+
case "color": {
|
|
206
|
+
const colorValue = (_a = state.val) == null ? void 0 : _a.toString();
|
|
207
|
+
if (colorValue) {
|
|
208
|
+
this.sendColorCommand(receiver, colorValue);
|
|
209
|
+
}
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Send a turn on/off command to a device.
|
|
216
|
+
*
|
|
217
|
+
* @param receiver IP address or hostname
|
|
218
|
+
* @param value true for on, false for off
|
|
219
|
+
*/
|
|
220
|
+
sendTurnCommand(receiver, value) {
|
|
221
|
+
const turnMessage = { msg: { cmd: "turn", data: { value: value ? 1 : 0 } } };
|
|
222
|
+
const turnMessageBuffer = Buffer.from(JSON.stringify(turnMessage));
|
|
223
|
+
this.socket.send(turnMessageBuffer, 0, turnMessageBuffer.length, GoveeService.CONTROL_PORT, receiver);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Send a brightness command to a device.
|
|
227
|
+
*
|
|
228
|
+
* @param receiver IP address or hostname
|
|
229
|
+
* @param value Brightness value
|
|
230
|
+
*/
|
|
231
|
+
sendBrightnessCommand(receiver, value) {
|
|
232
|
+
const brightnessMessage = { msg: { cmd: "brightness", data: { value } } };
|
|
233
|
+
const brightnessMessageBuffer = Buffer.from(JSON.stringify(brightnessMessage));
|
|
234
|
+
this.socket.send(
|
|
235
|
+
brightnessMessageBuffer,
|
|
236
|
+
0,
|
|
237
|
+
brightnessMessageBuffer.length,
|
|
238
|
+
GoveeService.CONTROL_PORT,
|
|
239
|
+
receiver
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Send a color temperature command to a device.
|
|
244
|
+
*
|
|
245
|
+
* @param receiver IP address or hostname
|
|
246
|
+
* @param kelvin Color temperature in Kelvin
|
|
247
|
+
*/
|
|
248
|
+
sendColorTempCommand(receiver, kelvin) {
|
|
249
|
+
const colorTempMessageBuffer = Buffer.from(
|
|
250
|
+
JSON.stringify({
|
|
251
|
+
msg: {
|
|
252
|
+
cmd: "colorwc",
|
|
253
|
+
data: { color: { r: 0, g: 0, b: 0 }, colorTemInKelvin: kelvin }
|
|
254
|
+
}
|
|
255
|
+
})
|
|
256
|
+
);
|
|
257
|
+
this.socket.send(colorTempMessageBuffer, 0, colorTempMessageBuffer.length, GoveeService.CONTROL_PORT, receiver);
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Send a color command to a device.
|
|
261
|
+
*
|
|
262
|
+
* @param receiver IP address or hostname
|
|
263
|
+
* @param hexColor Color as hex string (e.g. #FFAABB)
|
|
264
|
+
*/
|
|
265
|
+
sendColorCommand(receiver, hexColor) {
|
|
266
|
+
const rgb = (0, import_hexTool.hexToRgb)(hexColor);
|
|
267
|
+
const colorMessage = { msg: { cmd: "colorwc", data: { color: rgb } } };
|
|
268
|
+
const colorMessageBuffer = Buffer.from(JSON.stringify(colorMessage));
|
|
269
|
+
this.socket.send(colorMessageBuffer, 0, colorMessageBuffer.length, GoveeService.CONTROL_PORT, receiver);
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Emit device status update event with parsed status data.
|
|
273
|
+
*
|
|
274
|
+
* @param deviceName The device name.
|
|
275
|
+
* @param ip The device IP address.
|
|
276
|
+
* @param messageObject The parsed message object containing device status.
|
|
277
|
+
*/
|
|
278
|
+
emitDeviceStatusUpdate(deviceName, ip, messageObject) {
|
|
279
|
+
const deviceData = messageObject.msg.data;
|
|
280
|
+
const colorString = `#${(0, import_hexTool.componentToHex)(deviceData.color.r)}${(0, import_hexTool.componentToHex)(deviceData.color.g)}${(0, import_hexTool.componentToHex)(deviceData.color.b)}`;
|
|
281
|
+
this.emit("deviceStatusUpdate", {
|
|
282
|
+
deviceName,
|
|
283
|
+
ip,
|
|
284
|
+
status: {
|
|
285
|
+
onOff: deviceData.onOff === 1,
|
|
286
|
+
brightness: deviceData.brightness,
|
|
287
|
+
color: colorString,
|
|
288
|
+
colorTemInKelvin: deviceData.colorTemInKelvin
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
294
|
+
0 && (module.exports = {
|
|
295
|
+
GoveeService
|
|
296
|
+
});
|
|
297
|
+
//# sourceMappingURL=goveeService.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/lib/goveeService.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * GoveeService handles all business logic for device discovery, status updates, and UDP communication.\n * This class is independent from ioBroker.Adapter and can be tested separately.\n */\n\nimport * as dgram from 'node:dgram';\nimport { EventEmitter } from 'node:events';\nimport type { GoveeServiceOptions } from './goveeServiceOptions';\nimport { componentToHex, hexToRgb } from './tools/hexTool';\n\n/**\n * Device discovery event data.\n */\nexport interface DeviceDiscoveryEvent {\n\t/** The IP address of the discovered device. */\n\tip: string;\n\t/** The sanitized device name. */\n\tdeviceName: string;\n}\n\n/**\n * Device status update event data.\n */\nexport interface DeviceStatusEvent {\n\t/** The sanitized device name. */\n\tdeviceName: string;\n\t/** The IP address of the device. */\n\tip: string;\n\t/** The current status of the device. */\n\tstatus: {\n\t\t/** Current on/off state. */\n\t\tonOff: boolean;\n\t\t/** Current brightness level. */\n\t\tbrightness: number;\n\t\t/** Current color as hex string. */\n\t\tcolor: string;\n\t\t/** Current color temperature in Kelvin. */\n\t\tcolorTemInKelvin: number;\n\t};\n}\n\n/**\n * GoveeService handles all business logic for device discovery, status updates, and UDP communication.\n * This class is independent from ioBroker.Adapter and can be tested separately.\n *\n * Events:\n * - 'deviceDiscovered': Emitted when a new device is found\n * - 'deviceStatusUpdate': Emitted when device status is updated\n *\n * Usage:\n * const service = new GoveeService(options);\n * service.on('deviceDiscovered', (data) => { ... });\n * service.on('deviceStatusUpdate', (data) => { ... });\n * service.start();\n * // ...\n * service.stop();\n */\nexport class GoveeService extends EventEmitter {\n\tprivate socket: dgram.Socket;\n\tprivate options: GoveeServiceOptions;\n\tprivate devices: { [ip: string]: string } = {};\n\tprivate loggedDevices: string[] = [];\n\tprivate searchInterval?: NodeJS.Timeout;\n\tprivate refreshInterval?: NodeJS.Timeout;\n\n\tstatic readonly LOCAL_PORT = 4002;\n\tstatic readonly SEND_SCAN_PORT = 4001;\n\tstatic readonly CONTROL_PORT = 4003;\n\tstatic readonly M_CAST = '239.255.255.250';\n\tstatic readonly scanMessage = { msg: { cmd: 'scan', data: { account_topic: 'reserved' } } };\n\tstatic readonly requestStatusMessage = { msg: { cmd: 'devStatus', data: {} } };\n\n\t/**\n\t * Create a new GoveeService instance.\n\t *\n\t * @param options Configuration options for the service.\n\t */\n\tconstructor(options: GoveeServiceOptions) {\n\t\tsuper();\n\t\tthis.options = options;\n\t\tthis.socket = dgram.createSocket({ type: 'udp4' });\n\t}\n\n\t/**\n\t * Bind UDP socket and start device search/refresh intervals.\n\t */\n\tpublic start(): void {\n\t\tthis.socket.on('message', this.onUdpMessage.bind(this));\n\t\tthis.socket.on('error', (error) => {\n\t\t\tthis.options.logger?.error(`server bind error : ${error.message}`);\n\t\t});\n\t\tthis.socket.bind(\n\t\t\t{ address: this.options.interface, port: GoveeService.LOCAL_PORT },\n\t\t\tthis.serverBound.bind(this),\n\t\t);\n\t}\n\n\tprivate serverBound(): void {\n\t\tthis.socket.setBroadcast(true);\n\t\tthis.socket.setMulticastTTL(128);\n\t\tthis.socket.setMulticastInterface(this.options.interface);\n\t\tthis.socket.addMembership(GoveeService.M_CAST);\n\t\tthis.options.logger?.debug(\n\t\t\t`UDP listening on ${(this.socket.address() as any).address}:${(this.socket.address() as any).port}`,\n\t\t);\n\t\tthis.searchInterval = setInterval(() => this.sendScan(), this.options.searchInterval * 1000);\n\t\tthis.refreshInterval = setInterval(\n\t\t\t() => this.refreshAllDevices(),\n\t\t\tthis.options.deviceStatusRefreshInterval * 1000,\n\t\t);\n\t}\n\n\t/**\n\t * Handle incoming UDP messages.\n\t *\n\t * @param message The message buffer.\n\t * @param remote The sender info.\n\t */\n\tprivate onUdpMessage(message: Buffer, remote: dgram.RemoteInfo): void {\n\t\tconst messageObject = JSON.parse(message.toString());\n\t\tswitch (messageObject.msg.cmd) {\n\t\t\tcase 'scan': {\n\t\t\t\tif (messageObject.msg.data.device) {\n\t\t\t\t\tconst deviceName = messageObject.msg.data.device.replace(\n\t\t\t\t\t\tthis.options.forbiddenChars ?? /[^a-zA-Z0-9_-]/g,\n\t\t\t\t\t\t'_',\n\t\t\t\t\t);\n\t\t\t\t\tthis.devices[remote.address] = deviceName;\n\t\t\t\t\tthis.emit('deviceDiscovered', {\n\t\t\t\t\t\tip: remote.address,\n\t\t\t\t\t\tdeviceName: deviceName,\n\t\t\t\t\t} as DeviceDiscoveryEvent);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'devStatus': {\n\t\t\t\tconst sendingDevice = this.devices[remote.address];\n\t\t\t\tif (sendingDevice) {\n\t\t\t\t\tif (this.options.extendedLogging && !this.loggedDevices.includes(remote.address.toString())) {\n\t\t\t\t\t\tthis.options.logger?.info(`device status message data: ${JSON.stringify(messageObject)}`);\n\t\t\t\t\t\tthis.loggedDevices.push(remote.address.toString());\n\t\t\t\t\t}\n\t\t\t\t\tthis.emitDeviceStatusUpdate(sendingDevice, remote.address, messageObject);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tthis.options.logger?.debug(`message from: ${remote.address}:${remote.port} - ${message.toString()}`);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Send device status request to all known devices.\n\t */\n\tpublic refreshAllDevices(): void {\n\t\tfor (const ip in this.devices) {\n\t\t\tthis.requestDeviceStatus(ip);\n\t\t}\n\t}\n\n\t/**\n\t * Send device status request to a specific device.\n\t *\n\t * @param receiver The IP address or hostname of the device.\n\t */\n\tpublic requestDeviceStatus(receiver: string): void {\n\t\tconst requestDeviceStatusBuffer = Buffer.from(JSON.stringify(GoveeService.requestStatusMessage));\n\t\tthis.socket.send(\n\t\t\trequestDeviceStatusBuffer,\n\t\t\t0,\n\t\t\trequestDeviceStatusBuffer.length,\n\t\t\tGoveeService.CONTROL_PORT,\n\t\t\treceiver,\n\t\t);\n\t}\n\n\t/**\n\t * Send scan message to the UDP multicast address.\n\t */\n\tpublic sendScan(): void {\n\t\tthis.options.logger?.debug('sending scan message');\n\t\tconst scanMessageBuffer = Buffer.from(JSON.stringify(GoveeService.scanMessage));\n\t\tthis.socket.send(\n\t\t\tscanMessageBuffer,\n\t\t\t0,\n\t\t\tscanMessageBuffer.length,\n\t\t\tGoveeService.SEND_SCAN_PORT,\n\t\t\tGoveeService.M_CAST,\n\t\t);\n\t}\n\n\t/**\n\t * Stop all intervals and close the socket.\n\t */\n\tpublic stop(): void {\n\t\tif (this.searchInterval) {\n\t\t\tclearInterval(this.searchInterval);\n\t\t}\n\t\tif (this.refreshInterval) {\n\t\t\tclearInterval(this.refreshInterval);\n\t\t}\n\t\tthis.socket.close();\n\t}\n\n\t/**\n\t * Get all known devices.\n\t */\n\tpublic getDevices(): { [ip: string]: string } {\n\t\treturn this.devices;\n\t}\n\n\t/**\n\t * Handles a state change and sends the appropriate command to the device.\n\t *\n\t * @param id The state ID\n\t * @param state The new state object\n\t * @param receiver The device IP as string\n\t */\n\tpublic handleStateChange(id: string, state: ioBroker.State, receiver: string): void {\n\t\tconst stateKey = id.split('.')[4];\n\t\tswitch (stateKey) {\n\t\t\tcase 'onOff':\n\t\t\t\tthis.sendTurnCommand(receiver, !!state.val);\n\t\t\t\tbreak;\n\t\t\tcase 'brightness':\n\t\t\t\tthis.sendBrightnessCommand(receiver, Number(state.val));\n\t\t\t\tbreak;\n\t\t\tcase 'colorTemInKelvin':\n\t\t\t\tthis.sendColorTempCommand(receiver, Number(state.val));\n\t\t\t\tbreak;\n\t\t\tcase 'color': {\n\t\t\t\tconst colorValue = state.val?.toString();\n\t\t\t\tif (colorValue) {\n\t\t\t\t\tthis.sendColorCommand(receiver, colorValue);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\t/**\n\t * Send a turn on/off command to a device.\n\t *\n\t * @param receiver IP address or hostname\n\t * @param value true for on, false for off\n\t */\n\tpublic sendTurnCommand(receiver: string, value: boolean): void {\n\t\tconst turnMessage = { msg: { cmd: 'turn', data: { value: value ? 1 : 0 } } };\n\t\tconst turnMessageBuffer = Buffer.from(JSON.stringify(turnMessage));\n\t\tthis.socket.send(turnMessageBuffer, 0, turnMessageBuffer.length, GoveeService.CONTROL_PORT, receiver);\n\t}\n\n\t/**\n\t * Send a brightness command to a device.\n\t *\n\t * @param receiver IP address or hostname\n\t * @param value Brightness value\n\t */\n\tpublic sendBrightnessCommand(receiver: string, value: number): void {\n\t\tconst brightnessMessage = { msg: { cmd: 'brightness', data: { value } } };\n\t\tconst brightnessMessageBuffer = Buffer.from(JSON.stringify(brightnessMessage));\n\t\tthis.socket.send(\n\t\t\tbrightnessMessageBuffer,\n\t\t\t0,\n\t\t\tbrightnessMessageBuffer.length,\n\t\t\tGoveeService.CONTROL_PORT,\n\t\t\treceiver,\n\t\t);\n\t}\n\n\t/**\n\t * Send a color temperature command to a device.\n\t *\n\t * @param receiver IP address or hostname\n\t * @param kelvin Color temperature in Kelvin\n\t */\n\tpublic sendColorTempCommand(receiver: string, kelvin: number): void {\n\t\tconst colorTempMessageBuffer = Buffer.from(\n\t\t\tJSON.stringify({\n\t\t\t\tmsg: {\n\t\t\t\t\tcmd: 'colorwc',\n\t\t\t\t\tdata: { color: { r: 0, g: 0, b: 0 }, colorTemInKelvin: kelvin },\n\t\t\t\t},\n\t\t\t}),\n\t\t);\n\t\tthis.socket.send(colorTempMessageBuffer, 0, colorTempMessageBuffer.length, GoveeService.CONTROL_PORT, receiver);\n\t}\n\n\t/**\n\t * Send a color command to a device.\n\t *\n\t * @param receiver IP address or hostname\n\t * @param hexColor Color as hex string (e.g. #FFAABB)\n\t */\n\tpublic sendColorCommand(receiver: string, hexColor: string): void {\n\t\tconst rgb = hexToRgb(hexColor);\n\t\tconst colorMessage = { msg: { cmd: 'colorwc', data: { color: rgb } } };\n\t\tconst colorMessageBuffer = Buffer.from(JSON.stringify(colorMessage));\n\t\tthis.socket.send(colorMessageBuffer, 0, colorMessageBuffer.length, GoveeService.CONTROL_PORT, receiver);\n\t}\n\n\t/**\n\t * Emit device status update event with parsed status data.\n\t *\n\t * @param deviceName The device name.\n\t * @param ip The device IP address.\n\t * @param messageObject The parsed message object containing device status.\n\t */\n\tprivate emitDeviceStatusUpdate(deviceName: string, ip: string, messageObject: any): void {\n\t\tconst deviceData = messageObject.msg.data;\n\t\tconst colorString = `#${componentToHex(deviceData.color.r)}${componentToHex(deviceData.color.g)}${componentToHex(deviceData.color.b)}`;\n\n\t\tthis.emit('deviceStatusUpdate', {\n\t\t\tdeviceName: deviceName,\n\t\t\tip: ip,\n\t\t\tstatus: {\n\t\t\t\tonOff: deviceData.onOff === 1,\n\t\t\t\tbrightness: deviceData.brightness,\n\t\t\t\tcolor: colorString,\n\t\t\t\tcolorTemInKelvin: deviceData.colorTemInKelvin,\n\t\t\t},\n\t\t} as DeviceStatusEvent);\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
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 __copyProps = (to, from, except, desc) => {
|
|
7
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
8
|
+
for (let key of __getOwnPropNames(from))
|
|
9
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
10
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
11
|
+
}
|
|
12
|
+
return to;
|
|
13
|
+
};
|
|
14
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
15
|
+
var goveeServiceOptions_exports = {};
|
|
16
|
+
module.exports = __toCommonJS(goveeServiceOptions_exports);
|
|
17
|
+
//# sourceMappingURL=goveeServiceOptions.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/lib/goveeServiceOptions.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Configuration options for the GoveeService.\n */\nexport interface GoveeServiceOptions {\n\t/** Network interface to bind UDP socket to. */\n\tinterface: string;\n\t/** Interval in seconds for device search. */\n\tsearchInterval: number;\n\t/** Interval in seconds for device status refresh. */\n\tdeviceStatusRefreshInterval: number;\n\t/** Enable extended debug/info logging. */\n\textendedLogging?: boolean;\n\t/** RegExp for forbidden characters in device names. */\n\tforbiddenChars?: RegExp;\n\t/** Logger object with debug/info/error methods. */\n\tlogger?: { debug: (msg: string) => void; info: (msg: string) => void; error: (msg: string) => void };\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;AAAA;AAAA;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
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 datapointTools_exports = {};
|
|
20
|
+
__export(datapointTools_exports, {
|
|
21
|
+
getDatapointDescription: () => getDatapointDescription
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(datapointTools_exports);
|
|
24
|
+
function getDatapointDescription(name) {
|
|
25
|
+
switch (name) {
|
|
26
|
+
case "model":
|
|
27
|
+
return "Specific model of the Lamp";
|
|
28
|
+
case "ip":
|
|
29
|
+
return "IP address of the Lamp";
|
|
30
|
+
case "bleVersionHard":
|
|
31
|
+
return "Bluetooth Low Energy Hardware Version";
|
|
32
|
+
case "bleVersionSoft":
|
|
33
|
+
return "Bluetooth Low Energy Software Version";
|
|
34
|
+
case "wifiVersionHard":
|
|
35
|
+
return "WiFi Hardware Version";
|
|
36
|
+
case "wifiVersionSoft":
|
|
37
|
+
return "WiFi Software Version";
|
|
38
|
+
default:
|
|
39
|
+
return "";
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
43
|
+
0 && (module.exports = {
|
|
44
|
+
getDatapointDescription
|
|
45
|
+
});
|
|
46
|
+
//# sourceMappingURL=datapointTools.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/lib/tools/datapointTools.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Returns the description for device information datapoints.\n * This helps to keep the main adapter class clean and centralizes datapoint metadata.\n *\n * @param name The name of the parameter retrieved from the device\n * @returns The description to be set to the datapoint\n */\nexport function getDatapointDescription(name: string): string {\n\tswitch (name) {\n\t\tcase 'model':\n\t\t\treturn 'Specific model of the Lamp';\n\t\tcase 'ip':\n\t\t\treturn 'IP address of the Lamp';\n\t\tcase 'bleVersionHard':\n\t\t\treturn 'Bluetooth Low Energy Hardware Version';\n\t\tcase 'bleVersionSoft':\n\t\t\treturn 'Bluetooth Low Energy Software Version';\n\t\tcase 'wifiVersionHard':\n\t\t\treturn 'WiFi Hardware Version';\n\t\tcase 'wifiVersionSoft':\n\t\t\treturn 'WiFi Software Version';\n\t\tdefault:\n\t\t\treturn '';\n\t}\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAOO,SAAS,wBAAwB,MAAsB;AAC7D,UAAQ,MAAM;AAAA,IACb,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR;AACC,aAAO;AAAA,EACT;AACD;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -23,17 +23,19 @@ __export(hexTool_exports, {
|
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(hexTool_exports);
|
|
25
25
|
function componentToHex(c) {
|
|
26
|
-
const hex = c.toString(16);
|
|
27
|
-
return hex.
|
|
26
|
+
const hex = c.toString(16).toUpperCase();
|
|
27
|
+
return hex.padStart(2, "0");
|
|
28
28
|
}
|
|
29
|
-
function hexToRgb(
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
function hexToRgb(hex) {
|
|
30
|
+
hex = hex.replace(/^#/, "");
|
|
31
|
+
if (hex.length === 3) {
|
|
32
|
+
hex = hex.split("").map((x) => x + x).join("");
|
|
32
33
|
}
|
|
34
|
+
const num = parseInt(hex, 16);
|
|
33
35
|
return {
|
|
34
|
-
r:
|
|
35
|
-
g:
|
|
36
|
-
b:
|
|
36
|
+
r: num >> 16 & 255,
|
|
37
|
+
g: num >> 8 & 255,
|
|
38
|
+
b: num & 255
|
|
37
39
|
};
|
|
38
40
|
}
|
|
39
41
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/lib/tools/hexTool.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Converts a number (0-255) to a two-digit hexadecimal string.\n *\n * @param c The number to convert.\n * @returns Hex string (e.g. '0A', 'FF').\n */\nexport function componentToHex(c: number): string {\n\tconst hex = c.toString(16).toUpperCase();\n\treturn hex.padStart(2, '0');\n}\n\n/**\n * Converts a hex color string (e.g. '#FFAABB') to an RGB object.\n *\n * @param hex The hex color string.\n * @returns An object with r, g, b properties.\n */\nexport function hexToRgb(hex: string): { r: number; g: number; b: number } {\n\t// Remove leading # if present\n\thex = hex.replace(/^#/, '');\n\tif (hex.length === 3) {\n\t\thex = hex\n\t\t\t.split('')\n\t\t\t.map((x) => x + x)\n\t\t\t.join('');\n\t}\n\tconst num = parseInt(hex, 16);\n\treturn {\n\t\tr: (num >> 16) & 255,\n\t\tg: (num >> 8) & 255,\n\t\tb: num & 255,\n\t};\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMO,SAAS,eAAe,GAAmB;AACjD,QAAM,MAAM,EAAE,SAAS,EAAE,EAAE,YAAY;AACvC,SAAO,IAAI,SAAS,GAAG,GAAG;AAC3B;AAQO,SAAS,SAAS,KAAkD;AAE1E,QAAM,IAAI,QAAQ,MAAM,EAAE;AAC1B,MAAI,IAAI,WAAW,GAAG;AACrB,UAAM,IACJ,MAAM,EAAE,EACR,IAAI,CAAC,MAAM,IAAI,CAAC,EAChB,KAAK,EAAE;AAAA,EACV;AACA,QAAM,MAAM,SAAS,KAAK,EAAE;AAC5B,SAAO;AAAA,IACN,GAAI,OAAO,KAAM;AAAA,IACjB,GAAI,OAAO,IAAK;AAAA,IAChB,GAAG,MAAM;AAAA,EACV;AACD;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|