iobroker.govee-local 0.1.2 → 0.2.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 +21 -1
- package/admin/i18n/de/translations.json +6 -4
- package/admin/i18n/en/translations.json +3 -1
- package/admin/i18n/es/translations.json +3 -1
- package/admin/i18n/fr/translations.json +3 -1
- package/admin/i18n/it/translations.json +3 -1
- package/admin/i18n/nl/translations.json +3 -1
- package/admin/i18n/pl/translations.json +3 -1
- package/admin/i18n/pt/translations.json +3 -1
- package/admin/i18n/ru/translations.json +3 -1
- package/admin/i18n/uk/translations.json +3 -1
- package/admin/i18n/zh-cn/translations.json +3 -1
- package/admin/jsonConfig.json +14 -0
- package/build/main.js +97 -82
- package/build/main.js.map +2 -2
- package/io-package.json +29 -28
- package/package.json +15 -14
package/README.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## govee-local adapter for ioBroker
|
|
4
4
|
|
|
5
|
+
[](https://www.npmjs.com/package/iobroker.govee-local)
|
|
6
|
+
[](https://www.npmjs.com/package/iobroker.govee-local)
|
|
7
|
+

|
|
8
|
+

|
|
9
|
+
|
|
10
|
+
[](https://nodei.co/npm/iobroker.govee-local/)
|
|
11
|
+
|
|
12
|
+
**Tests:** 
|
|
13
|
+
|
|
5
14
|
Control Govee devices via local access (no cloud)
|
|
6
15
|
|
|
7
16
|
To be able to control govee deivce locally, the feature needs to be explicitely turned on in the settings of the govve application settings as described in their [documentation](<https://app-h5.govee.com/user-manual/wlan-guide#:~:text=Supported%20Product%20Models%20(continually%20updated)>)
|
|
@@ -13,8 +22,19 @@ As I currently only have the H6051 lamp, this is the only device I can test with
|
|
|
13
22
|
Placeholder for the next version (at the beginning of the line):
|
|
14
23
|
### **WORK IN PROGRESS**
|
|
15
24
|
-->
|
|
25
|
+
### 0.2.1 (2023-12-24)
|
|
26
|
+
|
|
27
|
+
- repair onOff / all other actions Fixes: #65
|
|
28
|
+
- fix log spamming because of wildcard
|
|
29
|
+
|
|
30
|
+
### 0.2.0 (2023-12-17)
|
|
31
|
+
|
|
32
|
+
- support controlling the color
|
|
33
|
+
- extended logging mode
|
|
34
|
+
|
|
16
35
|
### 0.1.2 (2023-09-06)
|
|
17
|
-
|
|
36
|
+
|
|
37
|
+
- change icon path and resolution
|
|
18
38
|
|
|
19
39
|
### 0.1.1 (2023-08-21)
|
|
20
40
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
"govee-local adapter settings": "Adaptereinstellungen für govee-local",
|
|
3
|
+
"_searchInterval": "Suchintervall",
|
|
4
|
+
"_deviceStatusRefreshInterval": "Aktualisierungsintervall für den Gerätestatus",
|
|
5
|
+
"_configDescription": "Hier muss nichts konfiguriert werden. Bitte die Intervalle nur ändern, wenn dies explizit gewollt ist.",
|
|
6
|
+
"_extendedLoggingDescription": "Die erweiterte Protokollierung druckt alle vom Gerät empfangenen Daten mit Ebeneninformationen in das Protokoll. Da dies zu einem großen Log-Spam führt, wird empfohlen, die Funktion nur bei Bedarf einzuschalten und anschließend wieder auszuschalten.",
|
|
7
|
+
"_extendedLogging": "Erweiterte Protokollierung aktiviert"
|
|
6
8
|
}
|
|
@@ -2,5 +2,7 @@
|
|
|
2
2
|
"govee-local adapter settings": "Adapter settings for govee-local",
|
|
3
3
|
"_searchInterval": "Search interval",
|
|
4
4
|
"_deviceStatusRefreshInterval": "device status refresh interval",
|
|
5
|
-
"_configDescription": "There is nothing mandatory to configure. Please change the intervals only when you are sure that this is what you need"
|
|
5
|
+
"_configDescription": "There is nothing mandatory to configure. Please change the intervals only when you are sure that this is what you need",
|
|
6
|
+
"_extendedLoggingDescription": "Extended Logging prints all the data received by the device to the log with level info. As this produces a huge log spamming it is recommended to turn this on, only when needed and turnoff again afterwards.",
|
|
7
|
+
"_extendedLogging": "Extended Logging enabled"
|
|
6
8
|
}
|
|
@@ -2,5 +2,7 @@
|
|
|
2
2
|
"govee-local adapter settings": "Ajustes del adaptador para govee-local",
|
|
3
3
|
"_searchInterval": "Intervalo de búsqueda",
|
|
4
4
|
"_deviceStatusRefreshInterval": "intervalo de actualización del estado del dispositivo",
|
|
5
|
-
"_configDescription": "No hay nada obligatorio para configurar. Cambie los intervalos solo cuando esté seguro de que esto es lo que necesita"
|
|
5
|
+
"_configDescription": "No hay nada obligatorio para configurar. Cambie los intervalos solo cuando esté seguro de que esto es lo que necesita",
|
|
6
|
+
"_extendedLoggingDescription": "El registro extendido imprime todos los datos recibidos por el dispositivo en el registro con información de nivel. Como esto produce un enorme spam de registros, se recomienda activarlo sólo cuando sea necesario y desactivarlo nuevamente después.",
|
|
7
|
+
"_extendedLogging": "Registro extendido habilitado"
|
|
6
8
|
}
|
|
@@ -2,5 +2,7 @@
|
|
|
2
2
|
"govee-local adapter settings": "Paramètres d'adaptateur pour govee-local",
|
|
3
3
|
"_searchInterval": "Intervalle de recherche",
|
|
4
4
|
"_deviceStatusRefreshInterval": "intervalle d'actualisation de l'état de l'appareil",
|
|
5
|
-
"_configDescription": "Il n'y a rien d'obligatoire à configurer. Veuillez modifier les intervalles uniquement lorsque vous êtes sûr que c'est ce dont vous avez besoin"
|
|
5
|
+
"_configDescription": "Il n'y a rien d'obligatoire à configurer. Veuillez modifier les intervalles uniquement lorsque vous êtes sûr que c'est ce dont vous avez besoin",
|
|
6
|
+
"_extendedLoggingDescription": "La journalisation étendue imprime toutes les données reçues par l'appareil dans le journal avec les informations de niveau. Comme cela produit un énorme spam de journaux, il est recommandé de l'activer uniquement lorsque cela est nécessaire et de le désactiver à nouveau par la suite.",
|
|
7
|
+
"_extendedLogging": "Journalisation étendue activée"
|
|
6
8
|
}
|
|
@@ -2,5 +2,7 @@
|
|
|
2
2
|
"govee-local adapter settings": "Impostazioni dell'adattatore per govee-local",
|
|
3
3
|
"_searchInterval": "Intervallo di ricerca",
|
|
4
4
|
"_deviceStatusRefreshInterval": "intervallo di aggiornamento dello stato del dispositivo",
|
|
5
|
-
"_configDescription": "Non c'è nulla di obbligatorio da configurare. Si prega di modificare gli intervalli solo quando si è sicuri che questo è ciò di cui si ha bisogno"
|
|
5
|
+
"_configDescription": "Non c'è nulla di obbligatorio da configurare. Si prega di modificare gli intervalli solo quando si è sicuri che questo è ciò di cui si ha bisogno",
|
|
6
|
+
"_extendedLoggingDescription": "La registrazione estesa stampa tutti i dati ricevuti dal dispositivo nel registro con le informazioni sul livello. Poiché ciò produce un enorme spam nei registri, si consiglia di attivarlo solo quando necessario e di disattivarlo nuovamente in seguito.",
|
|
7
|
+
"_extendedLogging": "Registrazione estesa abilitata"
|
|
6
8
|
}
|
|
@@ -2,5 +2,7 @@
|
|
|
2
2
|
"govee-local adapter settings": "Adapterinstellingen voor govee-local",
|
|
3
3
|
"_searchInterval": "Zoek interval",
|
|
4
4
|
"_deviceStatusRefreshInterval": "vernieuwingsinterval apparaatstatus",
|
|
5
|
-
"_configDescription": "Er is niets verplicht om te configureren. Wijzig de intervallen alleen als u zeker weet dat dit is wat u nodig heeft"
|
|
5
|
+
"_configDescription": "Er is niets verplicht om te configureren. Wijzig de intervallen alleen als u zeker weet dat dit is wat u nodig heeft",
|
|
6
|
+
"_extendedLoggingDescription": "Uitgebreide logboekregistratie drukt alle door het apparaat ontvangen gegevens af naar het logboek met niveau-informatie. Omdat dit een enorme log-spam veroorzaakt, is het aan te raden dit alleen in te schakelen als dat nodig is en daarna weer uit te schakelen.",
|
|
7
|
+
"_extendedLogging": "Uitgebreide logboekregistratie ingeschakeld"
|
|
6
8
|
}
|
|
@@ -2,5 +2,7 @@
|
|
|
2
2
|
"govee-local adapter settings": "Ustawienia adaptera dla govee-local",
|
|
3
3
|
"_searchInterval": "Interwał wyszukiwania",
|
|
4
4
|
"_deviceStatusRefreshInterval": "interwał odświeżania stanu urządzenia",
|
|
5
|
-
"_configDescription": "Nie ma nic obowiązkowego do skonfigurowania. Zmień interwały tylko wtedy, gdy jesteś pewien, że tego właśnie potrzebujesz"
|
|
5
|
+
"_configDescription": "Nie ma nic obowiązkowego do skonfigurowania. Zmień interwały tylko wtedy, gdy jesteś pewien, że tego właśnie potrzebujesz",
|
|
6
|
+
"_extendedLoggingDescription": "Rozszerzone rejestrowanie drukuje wszystkie dane otrzymane przez urządzenie w dzienniku z informacjami o poziomie. Ponieważ powoduje to powstawanie ogromnego spamu w dziennikach, zaleca się włączenie tej opcji tylko w razie potrzeby, a następnie wyłączenie jej ponownie.",
|
|
7
|
+
"_extendedLogging": "Włączono rozszerzone rejestrowanie"
|
|
6
8
|
}
|
|
@@ -2,5 +2,7 @@
|
|
|
2
2
|
"govee-local adapter settings": "Configurações do adaptador para govee-local",
|
|
3
3
|
"_searchInterval": "Intervalo de pesquisa",
|
|
4
4
|
"_deviceStatusRefreshInterval": "intervalo de atualização do status do dispositivo",
|
|
5
|
-
"_configDescription": "Não há nada obrigatório para configurar. Por favor, altere os intervalos somente quando tiver certeza de que é isso que você precisa"
|
|
5
|
+
"_configDescription": "Não há nada obrigatório para configurar. Por favor, altere os intervalos somente quando tiver certeza de que é isso que você precisa",
|
|
6
|
+
"_extendedLoggingDescription": "O Extended Logging imprime todos os dados recebidos pelo dispositivo no log com informações de nível. Como isso produz um grande spam de log, é recomendável ativá-lo somente quando necessário e desligá-lo novamente depois.",
|
|
7
|
+
"_extendedLogging": "Registro estendido ativado"
|
|
6
8
|
}
|
|
@@ -2,5 +2,7 @@
|
|
|
2
2
|
"govee-local adapter settings": "Настройки адаптера для govee-local",
|
|
3
3
|
"_searchInterval": "Интервал поиска",
|
|
4
4
|
"_deviceStatusRefreshInterval": "интервал обновления статуса устройства",
|
|
5
|
-
"_configDescription": "Нет ничего обязательного для настройки. Пожалуйста, меняйте интервалы только тогда, когда вы уверены, что это то, что вам нужно."
|
|
5
|
+
"_configDescription": "Нет ничего обязательного для настройки. Пожалуйста, меняйте интервалы только тогда, когда вы уверены, что это то, что вам нужно.",
|
|
6
|
+
"_extendedLoggingDescription": "Расширенная регистрация записывает все данные, полученные устройством, в журнал с информацией об уровне. Поскольку это приводит к большому количеству спама в журналах, рекомендуется включать эту функцию только при необходимости, а затем снова выключать.",
|
|
7
|
+
"_extendedLogging": "Расширенное ведение журнала включено"
|
|
6
8
|
}
|
|
@@ -2,5 +2,7 @@
|
|
|
2
2
|
"govee-local adapter settings": "Adapter settings for govee-local",
|
|
3
3
|
"_searchInterval": "Інтервал пошуку",
|
|
4
4
|
"_deviceStatusRefreshInterval": "інтервал оновлення стану пристрою",
|
|
5
|
-
"_configDescription": "Немає нічого обов’язкового для налаштування. Будь ласка, змінюйте інтервали лише тоді, коли ви впевнені, що це те, що вам потрібно"
|
|
5
|
+
"_configDescription": "Немає нічого обов’язкового для налаштування. Будь ласка, змінюйте інтервали лише тоді, коли ви впевнені, що це те, що вам потрібно",
|
|
6
|
+
"_extendedLoggingDescription": "Extended Logging друкує всі дані, отримані пристроєм, у журналі з інформацією про рівень. Оскільки це створює величезну кількість спаму в журналі, рекомендується вмикати це лише за потреби, а потім знову вимикати.",
|
|
7
|
+
"_extendedLogging": "Розширене журналювання ввімкнено"
|
|
6
8
|
}
|
|
@@ -2,5 +2,7 @@
|
|
|
2
2
|
"govee-local adapter settings": "govee-local的适配器设置",
|
|
3
3
|
"_searchInterval": "搜索间隔",
|
|
4
4
|
"_deviceStatusRefreshInterval": "设备状态刷新间隔",
|
|
5
|
-
"_configDescription": "没有什么必须配置的。仅当您确定这是您需要的时才更改间隔"
|
|
5
|
+
"_configDescription": "没有什么必须配置的。仅当您确定这是您需要的时才更改间隔",
|
|
6
|
+
"_extendedLoggingDescription": "扩展日志记录将设备接收到的所有数据打印到带有级别信息的日志中。由于这会产生大量日志垃圾邮件,因此建议仅在需要时打开此功能,然后再次关闭。",
|
|
7
|
+
"_extendedLogging": "启用扩展日志记录"
|
|
6
8
|
}
|
package/admin/jsonConfig.json
CHANGED
|
@@ -26,6 +26,20 @@
|
|
|
26
26
|
"md": 2,
|
|
27
27
|
"lg": 2,
|
|
28
28
|
"label": "_deviceStatusRefreshInterval"
|
|
29
|
+
},
|
|
30
|
+
"_descriptionExtendedLogging": {
|
|
31
|
+
"type": "staticText",
|
|
32
|
+
"sm": 12,
|
|
33
|
+
"md": 12,
|
|
34
|
+
"lg": 12,
|
|
35
|
+
"text": "_extendedLoggingDescription"
|
|
36
|
+
},
|
|
37
|
+
"extendedLogging": {
|
|
38
|
+
"type": "checkbox",
|
|
39
|
+
"sm": 12,
|
|
40
|
+
"md": 6,
|
|
41
|
+
"lg": 3,
|
|
42
|
+
"label": "_extendedLogging"
|
|
29
43
|
}
|
|
30
44
|
}
|
|
31
45
|
}
|
package/build/main.js
CHANGED
|
@@ -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"));
|
|
@@ -39,6 +40,8 @@ const scanMessage = { msg: { cmd: "scan", data: { account_topic: "reserved" } }
|
|
|
39
40
|
const requestStatusMessage = { msg: { cmd: "devStatus", data: {} } };
|
|
40
41
|
let searchInterval;
|
|
41
42
|
const intervals = {};
|
|
43
|
+
const devices = {};
|
|
44
|
+
const loggedDevices = [];
|
|
42
45
|
class GoveeLocal extends utils.Adapter {
|
|
43
46
|
constructor(options = {}) {
|
|
44
47
|
super({
|
|
@@ -50,21 +53,10 @@ class GoveeLocal extends utils.Adapter {
|
|
|
50
53
|
this.on("unload", this.onUnload.bind(this));
|
|
51
54
|
}
|
|
52
55
|
async onReady() {
|
|
53
|
-
this.setObjectNotExists("info.connection", {
|
|
54
|
-
type: "state",
|
|
55
|
-
common: {
|
|
56
|
-
name: "Device discovery running",
|
|
57
|
-
type: "boolean",
|
|
58
|
-
role: "indicator.connected",
|
|
59
|
-
read: true,
|
|
60
|
-
write: false
|
|
61
|
-
},
|
|
62
|
-
native: {}
|
|
63
|
-
});
|
|
64
56
|
server.on("message", this.onUdpMessage.bind(this));
|
|
65
57
|
server.on("error", (error) => {
|
|
66
58
|
this.log.error("server bind error : " + error.message);
|
|
67
|
-
this.
|
|
59
|
+
this.setStateChanged("info.connection", { val: false, ack: true });
|
|
68
60
|
});
|
|
69
61
|
server.bind(LOCAL_PORT, this.serverBound.bind(this));
|
|
70
62
|
this.subscribeStates("*.devStatus.*");
|
|
@@ -73,7 +65,7 @@ class GoveeLocal extends utils.Adapter {
|
|
|
73
65
|
server.setBroadcast(true);
|
|
74
66
|
server.setMulticastTTL(128);
|
|
75
67
|
server.addMembership(M_CAST);
|
|
76
|
-
this.
|
|
68
|
+
this.setStateChanged("info.connection", { val: true, ack: true });
|
|
77
69
|
this.log.debug("UDP listening on " + server.address().address + ":" + server.address().port);
|
|
78
70
|
const result = this.setInterval(this.sendScan.bind(this), this.config.searchInterval * 1e3);
|
|
79
71
|
if (result !== void 0) {
|
|
@@ -87,6 +79,7 @@ class GoveeLocal extends utils.Adapter {
|
|
|
87
79
|
for (const key of Object.keys(messageObject.msg.data)) {
|
|
88
80
|
if (key != "device") {
|
|
89
81
|
const deviceName = messageObject.msg.data.device.replace(this.FORBIDDEN_CHARS, "_");
|
|
82
|
+
devices[remote.address] = deviceName;
|
|
90
83
|
this.setObjectNotExists(deviceName, {
|
|
91
84
|
type: "device",
|
|
92
85
|
common: {
|
|
@@ -123,72 +116,73 @@ class GoveeLocal extends utils.Adapter {
|
|
|
123
116
|
}
|
|
124
117
|
break;
|
|
125
118
|
case "devStatus":
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
if (
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
this.setObjectNotExists(`${sendingDevice}.devStatus.onOff`, {
|
|
132
|
-
type: "state",
|
|
133
|
-
common: {
|
|
134
|
-
name: "On / Off state of the lamp",
|
|
135
|
-
type: "boolean",
|
|
136
|
-
role: "switch",
|
|
137
|
-
read: true,
|
|
138
|
-
write: true
|
|
139
|
-
},
|
|
140
|
-
native: {}
|
|
141
|
-
});
|
|
142
|
-
this.setState(`${sendingDevice}.devStatus.onOff`, {
|
|
143
|
-
val: devStatusMessageObject.msg.data.onOff == 1,
|
|
144
|
-
ack: true
|
|
145
|
-
});
|
|
146
|
-
this.setObjectNotExists(`${sendingDevice}.devStatus.brightness`, {
|
|
147
|
-
type: "state",
|
|
148
|
-
common: {
|
|
149
|
-
name: "Brightness of the light",
|
|
150
|
-
type: "number",
|
|
151
|
-
role: "level.dimmer",
|
|
152
|
-
read: true,
|
|
153
|
-
write: true
|
|
154
|
-
},
|
|
155
|
-
native: {}
|
|
156
|
-
});
|
|
157
|
-
this.setState(`${sendingDevice}.devStatus.brightness`, {
|
|
158
|
-
val: devStatusMessageObject.msg.data.brightness,
|
|
159
|
-
ack: true
|
|
160
|
-
});
|
|
161
|
-
this.setObjectNotExists(`${sendingDevice}.devStatus.color`, {
|
|
162
|
-
type: "state",
|
|
163
|
-
common: {
|
|
164
|
-
name: "Current showing color of the lamp",
|
|
165
|
-
type: "string",
|
|
166
|
-
role: "level.color.rgb",
|
|
167
|
-
read: true,
|
|
168
|
-
write: true
|
|
169
|
-
},
|
|
170
|
-
native: {}
|
|
171
|
-
});
|
|
172
|
-
this.setState(`${sendingDevice}.devStatus.color`, {
|
|
173
|
-
val: "#" + componentToHex(devStatusMessageObject.msg.data.color.r) + componentToHex(devStatusMessageObject.msg.data.color.g) + componentToHex(devStatusMessageObject.msg.data.color.b),
|
|
174
|
-
ack: true
|
|
175
|
-
});
|
|
176
|
-
this.setObjectNotExists(`${sendingDevice}.devStatus.colorTemInKelvin`, {
|
|
177
|
-
type: "state",
|
|
178
|
-
common: {
|
|
179
|
-
name: "If staying in white light, the color temperature",
|
|
180
|
-
type: "number",
|
|
181
|
-
role: "level.color.temperature",
|
|
182
|
-
read: true,
|
|
183
|
-
write: true
|
|
184
|
-
},
|
|
185
|
-
native: {}
|
|
186
|
-
});
|
|
187
|
-
this.setState(`${sendingDevice}.devStatus.colorTemInKelvin`, {
|
|
188
|
-
val: devStatusMessageObject.msg.data.colorTemInKelvin,
|
|
189
|
-
ack: true
|
|
190
|
-
});
|
|
119
|
+
const sendingDevice = devices[remote.address];
|
|
120
|
+
if (sendingDevice) {
|
|
121
|
+
if (this.config.extendedLogging && !loggedDevices.includes(remote.address.toString())) {
|
|
122
|
+
this.log.info(`deivce status message data: ${JSON.stringify(messageObject)}`);
|
|
123
|
+
loggedDevices.push(remote.address.toString());
|
|
191
124
|
}
|
|
125
|
+
const devStatusMessageObject = JSON.parse(message.toString());
|
|
126
|
+
this.setObjectNotExists(`${sendingDevice}.devStatus.onOff`, {
|
|
127
|
+
type: "state",
|
|
128
|
+
common: {
|
|
129
|
+
name: "On / Off state of the lamp",
|
|
130
|
+
type: "boolean",
|
|
131
|
+
role: "switch",
|
|
132
|
+
read: true,
|
|
133
|
+
write: true
|
|
134
|
+
},
|
|
135
|
+
native: {}
|
|
136
|
+
});
|
|
137
|
+
this.setState(`${sendingDevice}.devStatus.onOff`, {
|
|
138
|
+
val: devStatusMessageObject.msg.data.onOff == 1,
|
|
139
|
+
ack: true
|
|
140
|
+
});
|
|
141
|
+
this.setObjectNotExists(`${sendingDevice}.devStatus.brightness`, {
|
|
142
|
+
type: "state",
|
|
143
|
+
common: {
|
|
144
|
+
name: "Brightness of the light",
|
|
145
|
+
type: "number",
|
|
146
|
+
role: "level.dimmer",
|
|
147
|
+
read: true,
|
|
148
|
+
write: true
|
|
149
|
+
},
|
|
150
|
+
native: {}
|
|
151
|
+
});
|
|
152
|
+
this.setState(`${sendingDevice}.devStatus.brightness`, {
|
|
153
|
+
val: devStatusMessageObject.msg.data.brightness,
|
|
154
|
+
ack: true
|
|
155
|
+
});
|
|
156
|
+
this.setObjectNotExists(`${sendingDevice}.devStatus.color`, {
|
|
157
|
+
type: "state",
|
|
158
|
+
common: {
|
|
159
|
+
name: "Current showing color of the lamp",
|
|
160
|
+
type: "string",
|
|
161
|
+
role: "level.color.rgb",
|
|
162
|
+
read: true,
|
|
163
|
+
write: true
|
|
164
|
+
},
|
|
165
|
+
native: {}
|
|
166
|
+
});
|
|
167
|
+
this.setState(`${sendingDevice}.devStatus.color`, {
|
|
168
|
+
val: "#" + componentToHex(devStatusMessageObject.msg.data.color.r) + componentToHex(devStatusMessageObject.msg.data.color.g) + componentToHex(devStatusMessageObject.msg.data.color.b),
|
|
169
|
+
ack: true
|
|
170
|
+
});
|
|
171
|
+
this.setObjectNotExists(`${sendingDevice}.devStatus.colorTemInKelvin`, {
|
|
172
|
+
type: "state",
|
|
173
|
+
common: {
|
|
174
|
+
name: "If staying in white light, the color temperature",
|
|
175
|
+
type: "number",
|
|
176
|
+
role: "level.color.temperature",
|
|
177
|
+
read: true,
|
|
178
|
+
write: true
|
|
179
|
+
},
|
|
180
|
+
native: {}
|
|
181
|
+
});
|
|
182
|
+
this.setState(`${sendingDevice}.devStatus.colorTemInKelvin`, {
|
|
183
|
+
val: devStatusMessageObject.msg.data.colorTemInKelvin,
|
|
184
|
+
ack: true
|
|
185
|
+
});
|
|
192
186
|
}
|
|
193
187
|
break;
|
|
194
188
|
default:
|
|
@@ -196,7 +190,6 @@ class GoveeLocal extends utils.Adapter {
|
|
|
196
190
|
}
|
|
197
191
|
}
|
|
198
192
|
requestDeviceStatus(receiver) {
|
|
199
|
-
console.log("request device status " + receiver);
|
|
200
193
|
const requestDeviceStatusBuffer = Buffer.from(JSON.stringify(requestStatusMessage));
|
|
201
194
|
client.send(requestDeviceStatusBuffer, 0, requestDeviceStatusBuffer.length, CONTROL_PORT, receiver);
|
|
202
195
|
}
|
|
@@ -217,7 +210,7 @@ class GoveeLocal extends utils.Adapter {
|
|
|
217
210
|
}
|
|
218
211
|
}
|
|
219
212
|
async onStateChange(id, state) {
|
|
220
|
-
var _a;
|
|
213
|
+
var _a, _b;
|
|
221
214
|
if (state && !state.ack) {
|
|
222
215
|
const ipOfDevice = await this.getStateAsync(id.split(".")[2] + ".deviceInfo.ip");
|
|
223
216
|
if (ipOfDevice) {
|
|
@@ -225,6 +218,7 @@ class GoveeLocal extends utils.Adapter {
|
|
|
225
218
|
switch (id.split(".")[4]) {
|
|
226
219
|
case "onOff":
|
|
227
220
|
const turnMessage = { msg: { cmd: "turn", data: { value: state.val ? 1 : 0 } } };
|
|
221
|
+
this.log.info("turn message : " + JSON.stringify(turnMessage));
|
|
228
222
|
const turnMessageBuffer = Buffer.from(JSON.stringify(turnMessage));
|
|
229
223
|
client.send(turnMessageBuffer, 0, turnMessageBuffer.length, CONTROL_PORT, receiver);
|
|
230
224
|
break;
|
|
@@ -237,6 +231,16 @@ class GoveeLocal extends utils.Adapter {
|
|
|
237
231
|
const colorTempMessage = { msg: { cmd: "colorTemInKelvin", data: { value: state.val } } };
|
|
238
232
|
const colorTempMessageBuffer = Buffer.from(JSON.stringify(colorTempMessage));
|
|
239
233
|
client.send(colorTempMessageBuffer, 0, colorTempMessageBuffer.length, CONTROL_PORT, receiver);
|
|
234
|
+
break;
|
|
235
|
+
case "color":
|
|
236
|
+
const colorValue = (_b = state.val) == null ? void 0 : _b.toString();
|
|
237
|
+
if (colorValue) {
|
|
238
|
+
const rgb = hexToRgb(colorValue);
|
|
239
|
+
const colorMessage = { msg: { cmd: "colorwc", data: { color: rgb } } };
|
|
240
|
+
const colorMessageBuffer = Buffer.from(JSON.stringify(colorMessage));
|
|
241
|
+
client.send(colorMessageBuffer, 0, colorMessageBuffer.length, CONTROL_PORT, receiver);
|
|
242
|
+
}
|
|
243
|
+
break;
|
|
240
244
|
}
|
|
241
245
|
} else {
|
|
242
246
|
this.log.error("device not found");
|
|
@@ -271,8 +275,19 @@ function componentToHex(c) {
|
|
|
271
275
|
const hex = c.toString(16);
|
|
272
276
|
return hex.length == 1 ? "0" + hex : hex;
|
|
273
277
|
}
|
|
278
|
+
function hexToRgb(hexString) {
|
|
279
|
+
if (!/^#[0-9a-fA-F]{6}$/i.test(hexString)) {
|
|
280
|
+
throw new Error("Invalid hex string");
|
|
281
|
+
}
|
|
282
|
+
return {
|
|
283
|
+
r: parseInt(hexString.slice(1, 3), 16),
|
|
284
|
+
g: parseInt(hexString.slice(3, 5), 16),
|
|
285
|
+
b: parseInt(hexString.slice(5, 7), 16)
|
|
286
|
+
};
|
|
287
|
+
}
|
|
274
288
|
// Annotate the CommonJS export names for ESM import in node:
|
|
275
289
|
0 && (module.exports = {
|
|
276
|
-
componentToHex
|
|
290
|
+
componentToHex,
|
|
291
|
+
hexToRgb
|
|
277
292
|
});
|
|
278
293
|
//# 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// import * as fs from \"fs\";\n\nconst LOCAL_PORT = 4002;\nconst SEND_SCAN_PORT = 4001;\nconst CONTROL_PORT = 4003;\nconst M_CAST = '239.255.255.250';\n\nconst server = dgram.createSocket('udp4');\nconst client = dgram.createSocket('udp4');\n\nconst scanMessage = { msg: { cmd: 'scan', data: { account_topic: 'reserved' } } };\nconst requestStatusMessage = { msg: { cmd: 'devStatus', data: {} } };\n\nlet searchInterval: NodeJS.Timeout;\n\nconst intervals: { [device: string]: NodeJS.Timeout } = {};\n\nclass GoveeLocal extends utils.Adapter {\n\tpublic constructor(options: Partial<utils.AdapterOptions> = {}) {\n\t\tsuper({\n\t\t\t...options,\n\t\t\tname: 'govee-local',\n\t\t});\n\t\tthis.on('ready', this.onReady.bind(this));\n\t\tthis.on('stateChange', this.onStateChange.bind(this));\n\t\t// this.on('objectChange', this.onObjectChange.bind(this));\n\t\t// this.on('message', this.onMessage.bind(this));\n\t\tthis.on('unload', this.onUnload.bind(this));\n\t}\n\n\t/**\n\t * Is called when databases are connected and adapter received configuration.\n\t */\n\tprivate async onReady(): Promise<void> {\n\t\tthis.setObjectNotExists('info.connection', {\n\t\t\ttype: 'state',\n\t\t\tcommon: {\n\t\t\t\tname: 'Device discovery running',\n\t\t\t\ttype: 'boolean',\n\t\t\t\trole: 'indicator.connected',\n\t\t\t\tread: true,\n\t\t\t\twrite: false,\n\t\t\t},\n\t\t\tnative: {},\n\t\t});\n\t\tserver.on('message', this.onUdpMessage.bind(this));\n\t\tserver.on('error', (error) => {\n\t\t\tthis.log.error('server bind error : ' + error.message);\n\t\t\tthis.setState('info.connection', { val: false, ack: true });\n\t\t});\n\n\t\tserver.bind(LOCAL_PORT, this.serverBound.bind(this));\n\n\t\tthis.subscribeStates('*.devStatus.*');\n\t}\n\n\t/**\n\t * handles when udp socket is up\n\t * configure multicast membership\n\t * start periodic scan for devices\n\t */\n\tprivate async serverBound(): Promise<void> {\n\t\tserver.setBroadcast(true);\n\t\tserver.setMulticastTTL(128);\n\t\tserver.addMembership(M_CAST);\n\t\tthis.setState('info.connection', { val: true, ack: true });\n\t\tthis.log.debug('UDP listening on ' + server.address().address + ':' + server.address().port);\n\n\t\tconst result = this.setInterval(this.sendScan.bind(this), this.config.searchInterval * 1000);\n\t\tif (result !== void 0) {\n\t\t\tsearchInterval = result;\n\t\t}\n\t\t// this.sendScan();\n\t}\n\n\t/**\n\t * handle icoming messages on the udp socket\n\t * @param message the message itself\n\t * @param remote the sender of the message\n\t */\n\tprivate async onUdpMessage(message: Buffer, remote: dgram.RemoteInfo): Promise<void> {\n\t\tconst messageObject = JSON.parse(message.toString());\n\t\tswitch (messageObject.msg.cmd) {\n\t\t\tcase 'scan':\n\t\t\t\tfor (const key of Object.keys(messageObject.msg.data)) {\n\t\t\t\t\tif (key != 'device') {\n\t\t\t\t\t\tconst deviceName = messageObject.msg.data.device.replace(this.FORBIDDEN_CHARS, '_');\n\t\t\t\t\t\tthis.setObjectNotExists(deviceName, {\n\t\t\t\t\t\t\ttype: 'device',\n\t\t\t\t\t\t\tcommon: {\n\t\t\t\t\t\t\t\tname: messageObject.msg.data.sku,\n\t\t\t\t\t\t\t\trole: 'group',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tnative: {},\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.setObjectNotExists(`${deviceName}.deviceInfo.${key}`, {\n\t\t\t\t\t\t\ttype: 'state',\n\t\t\t\t\t\t\tcommon: {\n\t\t\t\t\t\t\t\tname: getDatapointDescription(key),\n\t\t\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\t\t\trole: 'state',\n\t\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\t\twrite: false,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tnative: {},\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.setState(`${deviceName}.deviceInfo.${key}`, {\n\t\t\t\t\t\t\tval: messageObject.msg.data[key],\n\t\t\t\t\t\t\tack: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!(messageObject.msg.data.device in intervals)) {\n\t\t\t\t\tconst result = this.setInterval(\n\t\t\t\t\t\t() => this.requestDeviceStatus(messageObject.msg.data.ip),\n\t\t\t\t\t\tthis.config.deviceStatusRefreshInterval * 1000,\n\t\t\t\t\t);\n\t\t\t\t\tif (result !== void 0) {\n\t\t\t\t\t\tintervals[messageObject.msg.data.device] = result;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'devStatus':\n\t\t\t\tconst devices = await this.getStatesAsync(this.name + '.' + this.instance + '.*.deviceInfo.ip');\n\t\t\t\tfor (const key in devices) {\n\t\t\t\t\tif (devices[key as keyof typeof devices].val == remote.address) {\n\t\t\t\t\t\tconst sendingDevice = key.split('.')[2].replace(this.FORBIDDEN_CHARS, '_');\n\t\t\t\t\t\tconst devStatusMessageObject = JSON.parse(message.toString());\n\t\t\t\t\t\tthis.setObjectNotExists(`${sendingDevice}.devStatus.onOff`, {\n\t\t\t\t\t\t\ttype: 'state',\n\t\t\t\t\t\t\tcommon: {\n\t\t\t\t\t\t\t\tname: 'On / Off state of the lamp',\n\t\t\t\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\t\t\t\trole: 'switch',\n\t\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\t\twrite: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tnative: {},\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.setState(`${sendingDevice}.devStatus.onOff`, {\n\t\t\t\t\t\t\tval: devStatusMessageObject.msg.data.onOff == 1,\n\t\t\t\t\t\t\tack: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.setObjectNotExists(`${sendingDevice}.devStatus.brightness`, {\n\t\t\t\t\t\t\ttype: 'state',\n\t\t\t\t\t\t\tcommon: {\n\t\t\t\t\t\t\t\tname: 'Brightness of the light',\n\t\t\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t\t\t\trole: 'level.dimmer',\n\t\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\t\twrite: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tnative: {},\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.setState(`${sendingDevice}.devStatus.brightness`, {\n\t\t\t\t\t\t\tval: devStatusMessageObject.msg.data.brightness,\n\t\t\t\t\t\t\tack: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.setObjectNotExists(`${sendingDevice}.devStatus.color`, {\n\t\t\t\t\t\t\ttype: 'state',\n\t\t\t\t\t\t\tcommon: {\n\t\t\t\t\t\t\t\tname: 'Current showing color of the lamp',\n\t\t\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\t\t\trole: 'level.color.rgb',\n\t\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\t\twrite: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tnative: {},\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.setState(`${sendingDevice}.devStatus.color`, {\n\t\t\t\t\t\t\tval:\n\t\t\t\t\t\t\t\t'#' +\n\t\t\t\t\t\t\t\tcomponentToHex(devStatusMessageObject.msg.data.color.r) +\n\t\t\t\t\t\t\t\tcomponentToHex(devStatusMessageObject.msg.data.color.g) +\n\t\t\t\t\t\t\t\tcomponentToHex(devStatusMessageObject.msg.data.color.b),\n\t\t\t\t\t\t\tack: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.setObjectNotExists(`${sendingDevice}.devStatus.colorTemInKelvin`, {\n\t\t\t\t\t\t\ttype: 'state',\n\t\t\t\t\t\t\tcommon: {\n\t\t\t\t\t\t\t\tname: 'If staying in white light, the color temperature',\n\t\t\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t\t\t\trole: 'level.color.temperature',\n\t\t\t\t\t\t\t\tread: true,\n\t\t\t\t\t\t\t\twrite: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tnative: {},\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis.setState(`${sendingDevice}.devStatus.colorTemInKelvin`, {\n\t\t\t\t\t\t\tval: devStatusMessageObject.msg.data.colorTemInKelvin,\n\t\t\t\t\t\t\tack: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tthis.log.error('message from: ' + remote.address + ':' + remote.port + ' - ' + message);\n\t\t}\n\t}\n\n\t/**\n\t * sends the device status request to one specific device\n\t * @param receiver the ip ( / hsotname ) of the device that should be queried\n\t */\n\tprivate requestDeviceStatus(receiver: string): void {\n\t\tconsole.log('request device status ' + receiver);\n\t\tconst requestDeviceStatusBuffer = Buffer.from(JSON.stringify(requestStatusMessage));\n\t\tclient.send(requestDeviceStatusBuffer, 0, requestDeviceStatusBuffer.length, CONTROL_PORT, receiver);\n\t}\n\n\t/**\n\t * send the scan message to the udp multicast address\n\t */\n\tprivate async sendScan(): Promise<void> {\n\t\tconst scanMessageBuffer = Buffer.from(JSON.stringify(scanMessage));\n\t\tclient.send(scanMessageBuffer, 0, scanMessageBuffer.length, SEND_SCAN_PORT, M_CAST);\n\t}\n\n\t/**\n\t * Is called when adapter shuts down - callback has to be called under any circumstances!\n\t */\n\tprivate onUnload(callback: () => void): void {\n\t\ttry {\n\t\t\tthis.clearInterval(searchInterval);\n\t\t\tObject.entries(intervals).forEach(([_, interval]) => this.clearInterval(interval));\n\t\t\tclient.close();\n\t\t\tserver.close();\n\t\t\tthis.setState('info.connection', { val: false, ack: true });\n\t\t\tcallback();\n\t\t} catch (e) {\n\t\t\tcallback();\n\t\t}\n\t}\n\n\t/**\n\t * Is called if a subscribed state changes\n\t */\n\tprivate async onStateChange(id: string, state: ioBroker.State | null | undefined): Promise<void> {\n\t\tif (state && !state.ack) {\n\t\t\tconst ipOfDevice = await this.getStateAsync(id.split('.')[2] + '.deviceInfo.ip');\n\t\t\tif (ipOfDevice) {\n\t\t\t\tconst receiver = ipOfDevice.val?.toString();\n\t\t\t\tswitch (id.split('.')[4]) {\n\t\t\t\t\tcase 'onOff':\n\t\t\t\t\t\tconst turnMessage = { msg: { cmd: 'turn', data: { value: state.val ? 1 : 0 } } };\n\t\t\t\t\t\tconst turnMessageBuffer = Buffer.from(JSON.stringify(turnMessage));\n\t\t\t\t\t\tclient.send(turnMessageBuffer, 0, turnMessageBuffer.length, CONTROL_PORT, receiver);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'brightness':\n\t\t\t\t\t\tconst brightnessMessage = { msg: { cmd: 'brightness', data: { value: state.val } } };\n\t\t\t\t\t\tconst brightnessMessageBuffer = Buffer.from(JSON.stringify(brightnessMessage));\n\t\t\t\t\t\tclient.send(brightnessMessageBuffer, 0, brightnessMessageBuffer.length, CONTROL_PORT, receiver);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'colorTemInKelvin':\n\t\t\t\t\t\tconst colorTempMessage = { msg: { cmd: 'colorTemInKelvin', data: { value: state.val } } };\n\t\t\t\t\t\tconst colorTempMessageBuffer = Buffer.from(JSON.stringify(colorTempMessage));\n\t\t\t\t\t\tclient.send(colorTempMessageBuffer, 0, colorTempMessageBuffer.length, CONTROL_PORT, receiver);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.log.error('device not found');\n\t\t\t}\n\t\t}\n\t}\n}\n\nif (require.main !== module) {\n\t// Export the constructor in compact mode\n\tmodule.exports = (options: Partial<utils.AdapterOptions> | undefined) => new GoveeLocal(options);\n} else {\n\t// otherwise start the instance directly\n\t(() => new GoveeLocal())();\n}\n\n/**\n * This method returns the description for device information datapoints\n * to unbloat the upper methods.\n * tanslations would be great here\n * @param name the name of the parameter retrieved from the device\n * @returns the description, that should be set to the datapoint\n */\nfunction getDatapointDescription(name: string): string {\n\tswitch (name) {\n\t\tcase 'model':\n\t\t\treturn 'Specific model of the Lamp';\n\t\tcase 'ip':\n\t\t\treturn 'IP address of the Lamp';\n\t\tcase 'bleVersionHard':\n\t\t\treturn 'Bluetooth Low Energy Hardware Version';\n\t\tcase 'bleVersionSoft':\n\t\t\treturn 'Bluetooth Low Energy Software Version';\n\t\tcase 'wifiVersionHard':\n\t\t\treturn 'WiFi Hardware Version';\n\t\tcase 'wifiVersionSoft':\n\t\t\treturn 'WiFi Software Version';\n\t\tdefault:\n\t\t\treturn '';\n\t}\n}\n\n/**\n * Convert number (<255) to two digit hex for colorcode\n * @param the int value, should me < 255\n * @returns the hex value as string\n */\nfunction componentToHex(c: number): string {\n\tconst hex = c.toString(16);\n\treturn hex.length == 1 ? '0' + hex : hex;\n}\n\nexport { componentToHex };\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,YAAuB;AACvB,YAAuB;
|
|
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": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "govee-local",
|
|
4
|
-
"version": "0.1
|
|
4
|
+
"version": "0.2.1",
|
|
5
5
|
"news": {
|
|
6
|
+
"0.2.1": {
|
|
7
|
+
"en": "repair onOff / all other actions Fixes: #65\nfix log spamming because of wildcard",
|
|
8
|
+
"de": "reparatur onOff / alle anderen Aktionen Behebungen: #65\nprotokoll spamming wegen wildcard",
|
|
9
|
+
"ru": "ремонт onOff / все другие действия Исправления: #65\nисправить спамирование лога из-за дикой карты",
|
|
10
|
+
"pt": "reparação emOff / todas as outras ações Correções: #65 #\ncorrigir spam de log por causa do wildcard",
|
|
11
|
+
"nl": "vertaling: Vertaling: 65\nvertaling:",
|
|
12
|
+
"fr": "réparation onOff / toutes les autres actions Fixes: #65\ncorriger l'éblouissement du journal à cause de wildcard",
|
|
13
|
+
"it": "riparazione onOff / tutte le altre azioni Fissi: #65\nsistemare il log spamming a causa di jolly",
|
|
14
|
+
"es": "reparación onOff / todas las demás acciones Arreglos: #65\nfijar registro de spam debido a wildcard",
|
|
15
|
+
"pl": "remontowanie Off / wszystkie inne działania Fiksy #65\nusunąć z powodu dzikiej karty",
|
|
16
|
+
"uk": "ремонт наОфф / всі інші дії Виправлення: #65\nфіксація спамерування колод через дикийкарт",
|
|
17
|
+
"zh-cn": "b. 修理效率/所有其他行动 固定: #65\nfix 由于野生素卡的投机"
|
|
18
|
+
},
|
|
19
|
+
"0.2.0": {
|
|
20
|
+
"en": "support controlling the color\nextended logging mode",
|
|
21
|
+
"de": "unterstützung controlling der farbe\nerweiterter logging-modus",
|
|
22
|
+
"ru": "поддержка контролируя цвет\nрасширенный режим входа",
|
|
23
|
+
"pt": "suporte controlando a cor\nmodo de registro estendido",
|
|
24
|
+
"nl": "de kleur controleren\nverlengde logging mode",
|
|
25
|
+
"fr": "support de contrôle de la couleur\nmode d ' enregistrement élargi",
|
|
26
|
+
"it": "supporto che controlla il colore\nmodalità di registrazione estesa",
|
|
27
|
+
"es": "soporte controlando el color\nmodo de registro ampliado",
|
|
28
|
+
"pl": "kontrolować kolor\nrozszerzony tryb logowania",
|
|
29
|
+
"uk": "супровід управління кольором\nрозширений режим входу",
|
|
30
|
+
"zh-cn": "控制颜色的支助\n扩大的伐木模式"
|
|
31
|
+
},
|
|
6
32
|
"0.1.2": {
|
|
7
33
|
"en": "change icon path and resolution",
|
|
8
34
|
"de": "icon pfad und auflösung ändern",
|
|
@@ -67,32 +93,6 @@
|
|
|
67
93
|
"pl": "rurociąg",
|
|
68
94
|
"uk": "зведення трубопроводів",
|
|
69
95
|
"zh-cn": "管道"
|
|
70
|
-
},
|
|
71
|
-
"0.0.4": {
|
|
72
|
-
"en": "make device status refresh invertal indepentent from device search interval",
|
|
73
|
-
"de": "die gerätestatus erfrischen invertal indepentent von der gerätesuche intervall",
|
|
74
|
-
"ru": "сделать статус устройства обновленный инвертальный непонятный с интервала поиска устройства",
|
|
75
|
-
"pt": "fazer o status do dispositivo atualizar indepente invertal do intervalo de pesquisa do dispositivo",
|
|
76
|
-
"nl": "maak de status verfrissend onafhankelijk van het apparaat",
|
|
77
|
-
"fr": "faire rafraîchir l'état de l'appareil indépentant de l'intervalle de recherche de l'appareil",
|
|
78
|
-
"it": "rendere lo stato del dispositivo aggiornare invertal indipendente dall'intervallo di ricerca del dispositivo",
|
|
79
|
-
"es": "hacer actualización del estado del dispositivo indepentente invertal del intervalo de búsqueda del dispositivo",
|
|
80
|
-
"pl": "status odświeżający",
|
|
81
|
-
"uk": "зробити стан пристрою, освіжаючи інверторний індикент з інтервалу пошуку пристрою",
|
|
82
|
-
"zh-cn": "利用装置搜寻装置进行喷雾装置的装置"
|
|
83
|
-
},
|
|
84
|
-
"0.0.3": {
|
|
85
|
-
"en": "update dependecies",
|
|
86
|
-
"de": "aktualisierung der abhängigkeiten",
|
|
87
|
-
"ru": "обновление зависимостей",
|
|
88
|
-
"pt": "atualizações",
|
|
89
|
-
"nl": "vertaling:",
|
|
90
|
-
"fr": "mettre à jour les dépendances",
|
|
91
|
-
"it": "dipendenze di aggiornamento",
|
|
92
|
-
"es": "dependencias de actualización",
|
|
93
|
-
"pl": "aktualizacja",
|
|
94
|
-
"uk": "оновлення залежності",
|
|
95
|
-
"zh-cn": "a. 最新依赖情况"
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"titleLang": {
|
|
@@ -158,7 +158,8 @@
|
|
|
158
158
|
},
|
|
159
159
|
"native": {
|
|
160
160
|
"searchInterval": 10,
|
|
161
|
-
"deviceStatusRefreshInterval": 1
|
|
161
|
+
"deviceStatusRefreshInterval": 1,
|
|
162
|
+
"extendedLogging": false
|
|
162
163
|
},
|
|
163
164
|
"objects": [],
|
|
164
165
|
"instanceObjects": []
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.govee-local",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Control Govee devices via local access (no cloud)",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Børge Grunicke",
|
|
@@ -21,36 +21,37 @@
|
|
|
21
21
|
"node": ">= 16.0"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@iobroker/adapter-core": "^3.0.
|
|
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",
|
|
31
31
|
"@iobroker/adapter-dev": "^1.2.0",
|
|
32
32
|
"@iobroker/testing": "^4.1.0",
|
|
33
33
|
"@tsconfig/node14": "^14.1.0",
|
|
34
|
-
"@tsconfig/node18": "^18.2.
|
|
35
|
-
"@
|
|
36
|
-
"@types/chai
|
|
34
|
+
"@tsconfig/node18": "^18.2.2",
|
|
35
|
+
"@tsconfig/node20": "^20.1.2",
|
|
36
|
+
"@types/chai": "^4.3.11",
|
|
37
|
+
"@types/chai-as-promised": "^7.1.7",
|
|
37
38
|
"@types/mocha": "^10.0.1",
|
|
38
|
-
"@types/node": "^20.
|
|
39
|
+
"@types/node": "^20.10.1",
|
|
39
40
|
"@types/proxyquire": "^1.3.28",
|
|
40
41
|
"@types/sinon": "^10.0.13",
|
|
41
|
-
"@types/sinon-chai": "^3.2.
|
|
42
|
+
"@types/sinon-chai": "^3.2.12",
|
|
42
43
|
"@typescript-eslint/eslint-plugin": "^6.2.1",
|
|
43
|
-
"@typescript-eslint/parser": "^6.
|
|
44
|
-
"chai": "^4.3.
|
|
44
|
+
"@typescript-eslint/parser": "^6.13.1",
|
|
45
|
+
"chai": "^4.3.10",
|
|
45
46
|
"chai-as-promised": "^7.1.1",
|
|
46
|
-
"eslint": "^8.
|
|
47
|
+
"eslint": "^8.50.0",
|
|
47
48
|
"eslint-config-prettier": "^9.0.0",
|
|
48
49
|
"eslint-plugin-prettier": "^5.0.0",
|
|
49
50
|
"mocha": "^10.2.0",
|
|
50
|
-
"prettier": "^3.0
|
|
51
|
+
"prettier": "^3.1.0",
|
|
51
52
|
"proxyquire": "^2.1.3",
|
|
52
|
-
"rimraf": "^
|
|
53
|
-
"sinon": "^
|
|
53
|
+
"rimraf": "^5.0.5",
|
|
54
|
+
"sinon": "^17.0.0",
|
|
54
55
|
"sinon-chai": "^3.7.0",
|
|
55
56
|
"source-map-support": "^0.5.21",
|
|
56
57
|
"ts-node": "^10.9.1",
|