homebridge-gree-ac 2.1.2 → 2.1.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/CHANGELOG.md +32 -1
- package/README.md +33 -15
- package/config.schema.json +42 -20
- package/dist/platform.d.ts +9 -3
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +94 -46
- package/dist/platform.js.map +1 -1
- package/dist/platformAccessory.d.ts +7 -8
- package/dist/platformAccessory.d.ts.map +1 -1
- package/dist/platformAccessory.js +125 -101
- package/dist/platformAccessory.js.map +1 -1
- package/dist/settings.d.ts +3 -0
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +4 -3
- package/dist/settings.js.map +1 -1
- package/dist/tsAccessory.d.ts +3 -6
- package/dist/tsAccessory.d.ts.map +1 -1
- package/dist/tsAccessory.js +9 -7
- package/dist/tsAccessory.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
- package/uiconfig.jpg +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,41 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.1.4] - 2024-11-11
|
|
4
|
+
|
|
5
|
+
**<ins>Reminder:</ins> New (v2) network encryption protocol supported since v2.1.0**
|
|
6
|
+
|
|
7
|
+
When upgrading from v2.0.0 - v2.1.1 to v2.1.2 or later, configuration settings should be updated.
|
|
8
|
+
|
|
9
|
+
### New features
|
|
10
|
+
- Added support of devices with hardware version V3.x which use a mix of V1 and V2 network encryption
|
|
11
|
+
- Reorganized device registration with binding error detection
|
|
12
|
+
|
|
13
|
+
### Fixes
|
|
14
|
+
- Fixed error on disabling device after successful registration
|
|
15
|
+
- After homebridge startup, don't wait before scanning devices on the network
|
|
16
|
+
- Handling conflicting port numbers
|
|
17
|
+
|
|
18
|
+
## [2.1.3] - 2024-11-05
|
|
19
|
+
|
|
20
|
+
**<ins>Reminder:</ins> New (v2) network encryption protocol supported since v2.1.0**
|
|
21
|
+
|
|
22
|
+
When upgrading from v2.0.0 - v2.1.1 to v2.1.2 or later, configuration settings should be updated.
|
|
23
|
+
|
|
24
|
+
#### Updated dependencies
|
|
25
|
+
- added Node.js v22 to supported versions (18.15.0 or later, 20.7.0 or later and 22.0.0 or later are supported)
|
|
26
|
+
|
|
27
|
+
### New features
|
|
28
|
+
- new optional IP address parameter to support devices on different subnets
|
|
29
|
+
- new optional device port parameter to support cases when automatic port assigment is not appropriate
|
|
30
|
+
|
|
31
|
+
### Fixes
|
|
32
|
+
- consistent xFan default setting in configuration UI and in plugin behaviour
|
|
33
|
+
|
|
3
34
|
## [2.1.2] - 2024-10-01
|
|
4
35
|
|
|
5
36
|
**<ins>Reminder:</ins> New (v2) network encryption protocol supported since v2.1.0**
|
|
6
37
|
|
|
7
|
-
When upgrading from v2.0.0 - v2.1.1 to v2.1.2 configuration settings should be updated.
|
|
38
|
+
When upgrading from v2.0.0 - v2.1.1 to v2.1.2, configuration settings should be updated.
|
|
8
39
|
|
|
9
40
|
#### Configuration update steps
|
|
10
41
|
|
package/README.md
CHANGED
|
@@ -31,10 +31,10 @@ This plugin is designed to be as simple and clear as possible and supports prima
|
|
|
31
31
|
|
|
32
32
|
## Requirements
|
|
33
33
|
|
|
34
|
-
* Node.js (>= 18.15.0 || >= 20.
|
|
34
|
+
* Node.js (>= 18.15.0 || >= 20.7.0 || >= 22.0.0) with NPM
|
|
35
35
|
* Homebridge (>= 1.8.0 || >= 2.0.0-beta.0)
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
The plugin finds all supported units automatically if they are located on the same subnet but controls only those which MAC address is added to the configuration. AC units on different subnets are also supported if the unit's IP address is set in the configuration. (MAC address have to be set correctly in this case also.)
|
|
38
38
|
|
|
39
39
|
IPv4 address is required. GREE Air Conditioners do not support IPv6 nor other network protocols.
|
|
40
40
|
|
|
@@ -48,7 +48,7 @@ This is not plugin dependency but its good to know that Homebridge server host a
|
|
|
48
48
|
|
|
49
49
|
> If you get _"error:1C80006B:Provider routines::wrong final block length"_ error message then your device is not supported.
|
|
50
50
|
>
|
|
51
|
-
> If you
|
|
51
|
+
> If you get _"Error: Device is not bound ..."_ error message then your device may not be supported. (The same error occures when device is malfunctioning but if turning the power supply off and on does not solve the problem then your device is not supported.)
|
|
52
52
|
|
|
53
53
|
By default this plugin tries to auto detect the network protocol encryption version. If not the right version is selected there can get errors and the AC device will not correctly work. It is possible to force a network protocol encryption version in configuration file. If auto detection does not work then it is recommended to try all possible values to check if the device is compatible or not.
|
|
54
54
|
|
|
@@ -64,7 +64,6 @@ This plugin was designed to support the Home App's Heater Cooler functionality u
|
|
|
64
64
|
* Not all half a degree values are supported in °C mode (GREE AC units are designed to support only integer °C and °F values). Unsupported values are automatically updated to the nearest supported values.
|
|
65
65
|
* There is no way to get current heating-cooling state from the AC unit in auto mode, so displayed state in the Home App is based on temperature measurement, but internal sensor is not precise enough to always display the correct state.
|
|
66
66
|
* Cooling / Heating temperature threshold limits (minimum and maximum values) can only be set in active cooling / heating mode. So the gauge in Home App may show invalid minimum and maximum values for the first use of cooling and heating modes. If so please restart Home App. Next time the correct values will be displayed.
|
|
67
|
-
* Homebridge and AC unit on different subnets is a not supported configuration.
|
|
68
67
|
* Devices without a built-in temperature sensor display the target temperature as current temperature not the measured one. (Some AC firmware versions do not report the measured temperature but the unit has a built-in sensor. They are handled by the plugin as devices without a sensor.)
|
|
69
68
|
|
|
70
69
|
## Installation instructions
|
|
@@ -126,15 +125,17 @@ _Only the relevant part of the configuration file is displayed:_
|
|
|
126
125
|
{
|
|
127
126
|
"mac": "502cc6000000",
|
|
128
127
|
"name": "Living room AC",
|
|
128
|
+
"ip": "192.168.1.2",
|
|
129
|
+
"port": 7003
|
|
130
|
+
"statusUpdateInterval": 10,
|
|
131
|
+
"encryptionVersion": 0,
|
|
129
132
|
"model": "Pulse 3.2kW GWH12AGB-K6DNA1A/I",
|
|
130
133
|
"speedSteps": 5,
|
|
131
|
-
"encryptionVersion": 0,
|
|
132
|
-
"statusUpdateInterval": 10,
|
|
133
|
-
"sensorOffset": 40,
|
|
134
134
|
"minimumTargetTemperature": 16,
|
|
135
135
|
"maximumTargetTemperature": 30,
|
|
136
|
-
"
|
|
136
|
+
"sensorOffset": 40,
|
|
137
137
|
"temperatureSensor": "disabled",
|
|
138
|
+
"xFanEnabled": true,
|
|
138
139
|
"overrideDefaultVerticalSwing": 0,
|
|
139
140
|
"defaultVerticalSwing": 0,
|
|
140
141
|
"disabled": false
|
|
@@ -143,28 +144,32 @@ _Only the relevant part of the configuration file is displayed:_
|
|
|
143
144
|
}
|
|
144
145
|
]
|
|
145
146
|
```
|
|
146
|
-
_It's not recommended to add the port
|
|
147
|
+
_It's not recommended to add the port and ip parameters. The above example contains them but only for showing all optional parameters also._
|
|
147
148
|
|
|
148
149
|
* name - Unique name of the platform plugin
|
|
149
150
|
* platform - **GREEAirConditioner** (fixed name, it identifies the plugin)
|
|
150
|
-
* port - free UDP port (optional) (
|
|
151
|
+
* port - free UDP port (optional) (plugin will use this port for network communication; valid values: 1025 - 65535) **Do not specify a port unless you have trouble with automatic port assignment!**
|
|
151
152
|
* scanInterval - time period in seconds between device query retries (defaults to 60 sec if missing)
|
|
152
153
|
* devices - devices should be listed in this block (specify as many devices as you have on your network)
|
|
153
154
|
* mac - MAC address (Serial Number) of the device
|
|
154
155
|
* name - custom name of the device (optional) Please use only alphanumeric, space, and apostrophe characters. Ensure it starts and ends with an alphabetic or numeric character, and avoid emojis.
|
|
156
|
+
* ip - device IP address (optional) Address is auto detected if this parameter is missing. **Specify only if device is located on a different subnet then homebridge!**
|
|
157
|
+
* port - free UDP port (optional) (plugin will listen on this port for data received from the device; valid values: 1025 - 65535) **Do not specify a port unless you have trouble with automatic port assignment!**
|
|
158
|
+
* statusUpdateInterval - device status will be refreshed based on this interval (in seconds, default is 10 seconds)
|
|
159
|
+
* encryptionVersion - Auto (0) is fine for most AC units. If auto does not work then you can force v1 (1) or v2 (2) encryption version to use in network communication
|
|
155
160
|
* model - model name, information only (optional)
|
|
156
161
|
* speedSteps - fan speed steps of the unit (valid values are: 3 and 5)
|
|
157
|
-
* encryptionVersion - Auto (0) is fine for most AC units. If auto does not work then you can force v1 (1) or v2 (2) encryption version to use in network communication
|
|
158
|
-
* statusUpdateInterval - device status will be refreshed based on this interval (in seconds)
|
|
159
|
-
* sensorOffset - device temperature sensor offset value for current temperature calibration (default is 40 °C, must be specified in °C)
|
|
160
162
|
* minimumTargetTemperature - minimum target temperature accepted by the device (default is 16 °C, must be specified in °C, valid values: 16-30)
|
|
161
163
|
* maximumTargetTemperature - maximum target temperature accepted by the device (default is 30 °C, must be specified in °C, valid values: 16-30)
|
|
162
|
-
*
|
|
164
|
+
* sensorOffset - device temperature sensor offset value for current temperature calibration (default is 40 °C, must be specified in °C)
|
|
163
165
|
* temperatureSensor - control additional temperature sensor accessory in Home App (disabled = do not add to Home App / child = add as a child accessory / separate = add as a separate (independent) accessory)
|
|
166
|
+
* xFanEnabled - automatically turn on xFan functionality in supported device modes (xFan actual setting is not modified by the Home App if disabled)
|
|
164
167
|
* overrideDefaultVerticalSwing - by default this plugin does not change the vertical swing position of the AC unit but some devices do not keep the original vertical position set by the remote control if controlled from Homebridge and return back to device default position; this setting allows to override the default position -> if AC unit is set to default vertical swing position Homebridge modifies it to a predefined position (set by defaultVerticalSwing) (Never (0) = turn off override, let device use default / After power on (1) = override default position on each power on / After power on and swing disable (2) = override default position on each power on and each time when swing is switched to disabled)
|
|
165
168
|
* defaultVerticalSwing - specify the vertical swing position to be used instead of device default when overriding is enabled (Device default (0) = use device default, same position as used by device by default without overriding / one of the following 5 positions: fixed Highest (2), fixed Higher (3), fixed Middle (4), fixed Lower (5), fixed Lowest (6))
|
|
166
169
|
* disabled - set to true if you do not want to control this device in the Home App _(can be used also to temporarily remove the device from Home App but not if the device is not responding any more on the network)_
|
|
167
170
|
|
|
171
|
+
Recommended configuration:
|
|
172
|
+
|
|
168
173
|

|
|
169
174
|
|
|
170
175
|
## Tips
|
|
@@ -199,6 +204,19 @@ Some settings are initialized by Home App only once (when enabling the device).
|
|
|
199
204
|
|
|
200
205
|
All other settings are applied when starting up Homebridge. You have to restart Homebridge to apply changes in configuration settings.
|
|
201
206
|
|
|
207
|
+
### IP address
|
|
208
|
+
|
|
209
|
+
IP addresses of the AC units are determined automatically by the plugin. However this auto detection works only if the AC unit is on the same subnet as homebridge. There is an optional IP address parameter which can be used to specifiy the unit's IP address if it is on a different subnet. (Routing should be correctly set up to communicate with units on different subnets.)
|
|
210
|
+
|
|
211
|
+
### Port
|
|
212
|
+
|
|
213
|
+
Network communication uses UDP ports. There are two kind of ports:
|
|
214
|
+
|
|
215
|
+
- Plugin port. This port is used by the plugin to communicate on the network.
|
|
216
|
+
- Device specific port. The plugin is listening for data received from the device using this port.
|
|
217
|
+
|
|
218
|
+
All ports are set up automatically by default. In some cases auto detection is not appropriate. (E.g. when firewall rules should be set up) It is possible to overwrite the default ports by optional port parameters (for the plugin and also for each devices). _Note that the ports must be unique._
|
|
219
|
+
|
|
202
220
|
### Temperature display units
|
|
203
221
|
|
|
204
222
|
Home App allows to set the device temperature display units but it is independent from the temperature units shown in Home App. Home App always displays temperature values as specified by iOS/MacOS (can be changed in Preferences / Regional settings section). Display unit conversion is made by the Home App device (e.g. iPhone).
|
|
@@ -209,7 +227,7 @@ Temperature measurement is not perfect if using the built-in sensor. It is highl
|
|
|
209
227
|
|
|
210
228
|
### Invalid room temperature
|
|
211
229
|
|
|
212
|
-
Some AC units have a built-in temperature sensor but the actual room temperature is not displayed in Home App. This is an AC firmware problem. Older
|
|
230
|
+
Some AC units have a built-in temperature sensor but the actual room temperature is not displayed in Home App. This is an AC firmware problem. Older firmware versions do not report temperature values at all and there are some firmware versions which report a fixed value (e.g. zero) instead of the measured one. This plugin replaces the missing value and the fixed zero value by the desired target temperature. To get the correct measured temperature please try to upgrade or downgrade the AC firmware.
|
|
213
231
|
|
|
214
232
|
### Fan speed
|
|
215
233
|
|
package/config.schema.json
CHANGED
|
@@ -62,28 +62,28 @@
|
|
|
62
62
|
"type": "integer",
|
|
63
63
|
"required": false,
|
|
64
64
|
"minimum": 1,
|
|
65
|
-
"
|
|
65
|
+
"placeholder": 10
|
|
66
66
|
},
|
|
67
67
|
"sensorOffset": {
|
|
68
68
|
"type": "integer",
|
|
69
69
|
"required": false,
|
|
70
|
-
"
|
|
70
|
+
"placeholder": 40
|
|
71
71
|
},
|
|
72
72
|
"minimumTargetTemperature": {
|
|
73
73
|
"type": "integer",
|
|
74
74
|
"required": false,
|
|
75
75
|
"minimum": 16,
|
|
76
|
-
"
|
|
76
|
+
"placeholder": 16
|
|
77
77
|
},
|
|
78
78
|
"maximumTargetTemperature": {
|
|
79
79
|
"type": "integer",
|
|
80
80
|
"required": false,
|
|
81
81
|
"maximum": 30,
|
|
82
|
-
"
|
|
82
|
+
"placeholder": 30
|
|
83
83
|
},
|
|
84
84
|
"xFanEnabled": {
|
|
85
85
|
"type": "boolean",
|
|
86
|
-
"default":
|
|
86
|
+
"default": true
|
|
87
87
|
},
|
|
88
88
|
"temperatureSensor": {
|
|
89
89
|
"type": "string",
|
|
@@ -205,6 +205,16 @@
|
|
|
205
205
|
]
|
|
206
206
|
}
|
|
207
207
|
]
|
|
208
|
+
},
|
|
209
|
+
"port": {
|
|
210
|
+
"type": "integer",
|
|
211
|
+
"required": false,
|
|
212
|
+
"minimum": 1025
|
|
213
|
+
},
|
|
214
|
+
"ip": {
|
|
215
|
+
"type": "string",
|
|
216
|
+
"required": false,
|
|
217
|
+
"format": "ipv4"
|
|
208
218
|
}
|
|
209
219
|
}
|
|
210
220
|
}
|
|
@@ -224,7 +234,7 @@
|
|
|
224
234
|
"key": "port",
|
|
225
235
|
"flex": "1 1 50%",
|
|
226
236
|
"title": "Port:",
|
|
227
|
-
"description": "
|
|
237
|
+
"description": "Platform level UDP port (auto if empty)"
|
|
228
238
|
},
|
|
229
239
|
{
|
|
230
240
|
"key": "scanInterval",
|
|
@@ -269,17 +279,19 @@
|
|
|
269
279
|
}
|
|
270
280
|
},
|
|
271
281
|
{
|
|
272
|
-
"key": "devices[].
|
|
282
|
+
"key": "devices[].ip",
|
|
273
283
|
"flex": "1 1 50%",
|
|
274
|
-
"title": "
|
|
284
|
+
"title": "IP address:",
|
|
285
|
+
"description": "Device IP address (auto if empty)",
|
|
275
286
|
"condition": {
|
|
276
287
|
"functionBody": "return (model.devices && model.devices[arrayIndices] && model.devices[arrayIndices].mac && /^[a-f0-9]{12}$/.test(model.devices[arrayIndices].mac) && model.devices[arrayIndices].disabled !== true);"
|
|
277
288
|
}
|
|
278
289
|
},
|
|
279
290
|
{
|
|
280
|
-
"key": "devices[].
|
|
291
|
+
"key": "devices[].port",
|
|
281
292
|
"flex": "1 1 50%",
|
|
282
|
-
"title": "
|
|
293
|
+
"title": "Port:",
|
|
294
|
+
"description": "Device specific UDP port (auto if empty)",
|
|
283
295
|
"condition": {
|
|
284
296
|
"functionBody": "return (model.devices && model.devices[arrayIndices] && model.devices[arrayIndices].mac && /^[a-f0-9]{12}$/.test(model.devices[arrayIndices].mac) && model.devices[arrayIndices].disabled !== true);"
|
|
285
297
|
}
|
|
@@ -302,6 +314,22 @@
|
|
|
302
314
|
"functionBody": "return (model.devices && model.devices[arrayIndices] && model.devices[arrayIndices].mac && /^[a-f0-9]{12}$/.test(model.devices[arrayIndices].mac) && model.devices[arrayIndices].disabled !== true);"
|
|
303
315
|
}
|
|
304
316
|
},
|
|
317
|
+
{
|
|
318
|
+
"key": "devices[].model",
|
|
319
|
+
"flex": "1 1 50%",
|
|
320
|
+
"title": "Device model:",
|
|
321
|
+
"condition": {
|
|
322
|
+
"functionBody": "return (model.devices && model.devices[arrayIndices] && model.devices[arrayIndices].mac && /^[a-f0-9]{12}$/.test(model.devices[arrayIndices].mac) && model.devices[arrayIndices].disabled !== true);"
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
"key": "devices[].speedSteps",
|
|
327
|
+
"flex": "1 1 50%",
|
|
328
|
+
"title": "Fan speed steps:",
|
|
329
|
+
"condition": {
|
|
330
|
+
"functionBody": "return (model.devices && model.devices[arrayIndices] && model.devices[arrayIndices].mac && /^[a-f0-9]{12}$/.test(model.devices[arrayIndices].mac) && model.devices[arrayIndices].disabled !== true);"
|
|
331
|
+
}
|
|
332
|
+
},
|
|
305
333
|
{
|
|
306
334
|
"key": "devices[].minimumTargetTemperature",
|
|
307
335
|
"flex": "1 1 50%",
|
|
@@ -329,15 +357,6 @@
|
|
|
329
357
|
"functionBody": "return (model.devices && model.devices[arrayIndices] && model.devices[arrayIndices].mac && /^[a-f0-9]{12}$/.test(model.devices[arrayIndices].mac) && model.devices[arrayIndices].disabled !== true);"
|
|
330
358
|
}
|
|
331
359
|
},
|
|
332
|
-
{
|
|
333
|
-
"key": "devices[].xFanEnabled",
|
|
334
|
-
"flex": "1 1 50%",
|
|
335
|
-
"title": "xFan enabled",
|
|
336
|
-
"description": "If enabled, then xFan functionality is turned on automatically on the device",
|
|
337
|
-
"condition": {
|
|
338
|
-
"functionBody": "return (model.devices && model.devices[arrayIndices] && model.devices[arrayIndices].mac && /^[a-f0-9]{12}$/.test(model.devices[arrayIndices].mac) && model.devices[arrayIndices].disabled !== true);"
|
|
339
|
-
}
|
|
340
|
-
},
|
|
341
360
|
{
|
|
342
361
|
"key": "devices[].temperatureSensor",
|
|
343
362
|
"flex": "1 1 50%",
|
|
@@ -348,7 +367,10 @@
|
|
|
348
367
|
}
|
|
349
368
|
},
|
|
350
369
|
{
|
|
351
|
-
"
|
|
370
|
+
"key": "devices[].xFanEnabled",
|
|
371
|
+
"flex": "1 1 100%",
|
|
372
|
+
"title": "xFan enabled",
|
|
373
|
+
"description": "If enabled, then xFan functionality is turned on automatically on the device",
|
|
352
374
|
"condition": {
|
|
353
375
|
"functionBody": "return (model.devices && model.devices[arrayIndices] && model.devices[arrayIndices].mac && /^[a-f0-9]{12}$/.test(model.devices[arrayIndices].mac) && model.devices[arrayIndices].disabled !== true);"
|
|
354
376
|
}
|
package/dist/platform.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { API, DynamicPlatformPlugin, Logger, PlatformAccessory, PlatformConfig, Service, Characteristic } from 'homebridge';
|
|
2
|
+
export interface MyPlatformAccessory extends PlatformAccessory {
|
|
3
|
+
bound?: boolean;
|
|
4
|
+
registered?: boolean;
|
|
5
|
+
}
|
|
2
6
|
/**
|
|
3
7
|
* HomebridgePlatform
|
|
4
8
|
* This class is the main constructor for your plugin, this is where you should
|
|
@@ -11,16 +15,17 @@ export declare class GreeACPlatform implements DynamicPlatformPlugin {
|
|
|
11
15
|
readonly Service: typeof Service;
|
|
12
16
|
readonly Characteristic: typeof Characteristic;
|
|
13
17
|
private devices;
|
|
14
|
-
private
|
|
18
|
+
private processedDevices;
|
|
15
19
|
private skippedDevices;
|
|
16
20
|
private socket;
|
|
17
21
|
private pluginAddresses;
|
|
22
|
+
ports: number[];
|
|
18
23
|
constructor(log: Logger, config: PlatformConfig, api: API);
|
|
19
24
|
/**
|
|
20
25
|
* This function is invoked when homebridge restores cached accessories from disk at startup.
|
|
21
26
|
* It should be used to setup event handlers for characteristics and update respective values.
|
|
22
27
|
*/
|
|
23
|
-
configureAccessory(accessory:
|
|
28
|
+
configureAccessory(accessory: MyPlatformAccessory): void;
|
|
24
29
|
/**
|
|
25
30
|
* Accessories must only be registered once, previously created accessories
|
|
26
31
|
* must not be registered again to prevent "duplicate UUID" errors.
|
|
@@ -29,7 +34,8 @@ export declare class GreeACPlatform implements DynamicPlatformPlugin {
|
|
|
29
34
|
discoverDevices(): void;
|
|
30
35
|
handleMessage: (msg: any, rinfo: any) => void;
|
|
31
36
|
registerDevice: (deviceInfo: any) => void;
|
|
32
|
-
|
|
37
|
+
sendScan(): void;
|
|
33
38
|
getNetworkAddresses(): {};
|
|
39
|
+
getAccessory(mac: string): MyPlatformAccessory;
|
|
34
40
|
}
|
|
35
41
|
//# sourceMappingURL=platform.d.ts.map
|
package/dist/platform.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAE,qBAAqB,EAAE,MAAM,EAAE,iBAAiB,EAAE,cAAc,EAAE,OAAO,EAAE,cAAc,EAAc,MAAM,YAAY,CAAC;AAUxI;;;;GAIG;AACH,qBAAa,cAAe,YAAW,qBAAqB;
|
|
1
|
+
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAE,qBAAqB,EAAE,MAAM,EAAE,iBAAiB,EAAE,cAAc,EAAE,OAAO,EAAE,cAAc,EAAc,MAAM,YAAY,CAAC;AAUxI,MAAM,WAAW,mBAAoB,SAAQ,iBAAiB;IAC5D,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;GAIG;AACH,qBAAa,cAAe,YAAW,qBAAqB;aAaxC,GAAG,EAAE,MAAM;aACX,MAAM,EAAE,cAAc;aACtB,GAAG,EAAE,GAAG;IAd1B,SAAgB,OAAO,EAAE,OAAO,OAAO,CAAwB;IAC/D,SAAgB,cAAc,EAAE,OAAO,cAAc,CAA+B;IAGpF,OAAO,CAAC,OAAO,CAAsC;IACrD,OAAO,CAAC,gBAAgB,CAA0B;IAClD,OAAO,CAAC,cAAc,CAA0B;IAChD,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,eAAe,CAA8B;IAC9C,KAAK,EAAE,MAAM,EAAE,CAAM;gBAGV,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,GAAG;IAsC1B;;;OAGG;IACH,kBAAkB,CAAC,SAAS,EAAE,mBAAmB;IAsBjD;;;OAGG;IACH,YAAY;IAUZ,eAAe;IAUf,aAAa,iCA6CX;IAEF,cAAc,4BA4IZ;IAEF,QAAQ;IAiBR,mBAAmB;IAqDZ,YAAY,CAAC,GAAG,EAAE,MAAM;CAGhC"}
|
package/dist/platform.js
CHANGED
|
@@ -9,7 +9,7 @@ const crypto_1 = __importDefault(require("./crypto"));
|
|
|
9
9
|
const os_1 = require("os");
|
|
10
10
|
const settings_1 = require("./settings");
|
|
11
11
|
const platformAccessory_1 = require("./platformAccessory");
|
|
12
|
-
|
|
12
|
+
//import { GreeAirConditionerTS } from './tsAccessory';
|
|
13
13
|
const commands_1 = __importDefault(require("./commands"));
|
|
14
14
|
const version_1 = require("./version");
|
|
15
15
|
/**
|
|
@@ -25,6 +25,7 @@ class GreeACPlatform {
|
|
|
25
25
|
this.Service = this.api.hap.Service;
|
|
26
26
|
this.Characteristic = this.api.hap.Characteristic;
|
|
27
27
|
this.pluginAddresses = {};
|
|
28
|
+
this.ports = [];
|
|
28
29
|
this.handleMessage = (msg, rinfo) => {
|
|
29
30
|
this.log.debug('handleMessage -> %s', msg.toString());
|
|
30
31
|
try {
|
|
@@ -52,8 +53,9 @@ class GreeACPlatform {
|
|
|
52
53
|
encryptionVersion = 2;
|
|
53
54
|
}
|
|
54
55
|
this.log.debug('handleMessage - Package -> %j', pack);
|
|
55
|
-
if (encryptionVersion === 1 && pack.t === 'dev' && pack.ver && pack.ver.toString().startsWith('
|
|
56
|
-
//
|
|
56
|
+
if (encryptionVersion === 1 && pack.t === 'dev' && pack.ver && !pack.ver.toString().startsWith('V1.')) {
|
|
57
|
+
// some devices respond to scan command with V1 encryption but binding requires V2 encryption
|
|
58
|
+
// we set encryption to V2 if device version is not V1.x
|
|
57
59
|
encryptionVersion = 2;
|
|
58
60
|
}
|
|
59
61
|
if (pack.t === 'dev') {
|
|
@@ -103,6 +105,12 @@ class GreeACPlatform {
|
|
|
103
105
|
deviceConfig[key] = value;
|
|
104
106
|
}
|
|
105
107
|
});
|
|
108
|
+
if (deviceConfig.port !== undefined && (typeof deviceConfig.port !== 'number' || deviceConfig.port !== deviceConfig.port ||
|
|
109
|
+
(typeof deviceConfig.port === 'number' && (deviceConfig.port < 1025 || deviceConfig.port > 65535)))) {
|
|
110
|
+
this.log.warn('Warning: Port is misconfigured (Valid port values: 1025~65535 or leave port empty to auto select) - ' +
|
|
111
|
+
`Accessory ${deviceInfo.mac} listening port overridden: ${deviceConfig.port} -> auto`);
|
|
112
|
+
deviceConfig.port = undefined;
|
|
113
|
+
}
|
|
106
114
|
// force encryption version if set in config
|
|
107
115
|
if (deviceConfig.encryptionVersion !== settings_1.ENCRYPTION_VERSION.auto) {
|
|
108
116
|
deviceInfo.encryptionVersion = deviceConfig.encryptionVersion;
|
|
@@ -119,13 +127,13 @@ class GreeACPlatform {
|
|
|
119
127
|
this.log.debug(`Accessory ${deviceInfo.mac}${devcfg.mac === undefined ? ' not configured -' : ''} skipped`);
|
|
120
128
|
}
|
|
121
129
|
if (accessory) {
|
|
122
|
-
delete this.devices[accessory.context.
|
|
130
|
+
delete this.devices[accessory.context.device.mac];
|
|
123
131
|
this.api.unregisterPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [accessory]);
|
|
124
132
|
this.log.debug(`registerDevice - unregister (${devcfg.mac === undefined ? 'not configured' : 'disabled'}):`, accessory.displayName, accessory.UUID);
|
|
125
133
|
accessory = undefined;
|
|
126
134
|
}
|
|
127
135
|
if (accessory_ts) {
|
|
128
|
-
delete this.devices[accessory_ts.context.
|
|
136
|
+
delete this.devices[accessory_ts.context.device.mac];
|
|
129
137
|
this.api.unregisterPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [accessory_ts]);
|
|
130
138
|
this.log.debug(`registerDevice - unregister (${devcfg.mac === undefined ? 'not configured' : 'disabled'}):`, accessory_ts.displayName, accessory_ts.UUID);
|
|
131
139
|
accessory_ts = undefined;
|
|
@@ -140,28 +148,29 @@ class GreeACPlatform {
|
|
|
140
148
|
if (accessory_ts && deviceInfo.address !== accessory_ts.context.device.address) {
|
|
141
149
|
accessory_ts.context.device.address = deviceInfo.address;
|
|
142
150
|
}
|
|
143
|
-
if (accessory && this.
|
|
151
|
+
if (accessory && this.processedDevices[accessory.UUID]) {
|
|
144
152
|
// already initalized
|
|
145
|
-
this.log.debug('registerDevice - already
|
|
153
|
+
this.log.debug('registerDevice - already processed:', accessory.displayName, accessory.context.device.mac, accessory.UUID);
|
|
146
154
|
return;
|
|
147
155
|
}
|
|
148
|
-
//
|
|
156
|
+
// create heatercooler accessory if not loaded from cache
|
|
149
157
|
const deviceName = (_a = deviceConfig === null || deviceConfig === void 0 ? void 0 : deviceConfig.name) !== null && _a !== void 0 ? _a : (deviceInfo.name || deviceInfo.mac);
|
|
150
158
|
if (!accessory) {
|
|
151
|
-
this.log.debug(`
|
|
159
|
+
this.log.debug(`Creating new accessory ${deviceInfo.mac} with name ${deviceName} ...`);
|
|
152
160
|
const uuid = this.api.hap.uuid.generate(deviceInfo.mac);
|
|
153
161
|
accessory = new this.api.platformAccessory(deviceName, uuid, 21 /* Categories.AIR_CONDITIONER */);
|
|
162
|
+
accessory.bound = false;
|
|
163
|
+
accessory.registered = false;
|
|
154
164
|
this.devices[deviceInfo.mac] = accessory;
|
|
155
|
-
this.api.registerPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [accessory]);
|
|
156
165
|
}
|
|
157
|
-
//
|
|
166
|
+
// create temperaturesensor accessory if configured as separate and not loaded from cache
|
|
158
167
|
const tsDeviceName = 'Temperature Sensor - ' + ((_b = deviceConfig === null || deviceConfig === void 0 ? void 0 : deviceConfig.name) !== null && _b !== void 0 ? _b : (deviceInfo.name || deviceInfo.mac));
|
|
159
168
|
if (!accessory_ts && deviceConfig.temperatureSensor === settings_1.TS_TYPE.separate) {
|
|
160
|
-
this.log.debug(`
|
|
169
|
+
this.log.debug(`Creating new accessory ${deviceInfo.mac}_ts with name ${tsDeviceName} ...`);
|
|
161
170
|
const uuid = this.api.hap.uuid.generate(deviceInfo.mac + '_ts');
|
|
162
171
|
accessory_ts = new this.api.platformAccessory(tsDeviceName, uuid, 10 /* Categories.SENSOR */);
|
|
172
|
+
accessory_ts.registered = false;
|
|
163
173
|
this.devices[deviceInfo.mac + '_ts'] = accessory_ts;
|
|
164
|
-
this.api.registerPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [accessory_ts]);
|
|
165
174
|
}
|
|
166
175
|
// unregister temperaturesensor accessory if configuration has changed from separate to any other
|
|
167
176
|
if (accessory_ts && deviceConfig.temperatureSensor !== settings_1.TS_TYPE.separate) {
|
|
@@ -170,39 +179,36 @@ class GreeACPlatform {
|
|
|
170
179
|
this.log.debug('registerDevice - unregister:', accessory_ts.displayName, accessory_ts.UUID);
|
|
171
180
|
accessory_ts = undefined;
|
|
172
181
|
}
|
|
173
|
-
let tsService = null;
|
|
174
182
|
if (accessory_ts && deviceConfig.temperatureSensor === settings_1.TS_TYPE.separate) {
|
|
175
183
|
// mark temperature sensor device as initialized
|
|
176
184
|
accessory_ts.context.device = { ...deviceInfo };
|
|
177
185
|
accessory_ts.context.device.mac = deviceInfo.mac + '_ts';
|
|
178
186
|
accessory_ts.context.deviceType = 'TemperatureSensor';
|
|
187
|
+
if (deviceConfig.model) {
|
|
188
|
+
accessory_ts.context.device.model = deviceConfig.model;
|
|
189
|
+
}
|
|
179
190
|
accessory_ts.displayName = tsDeviceName;
|
|
180
|
-
this.
|
|
181
|
-
|
|
182
|
-
|
|
191
|
+
this.processedDevices[accessory_ts.UUID] = true;
|
|
192
|
+
this.log.debug(`registerDevice - ${accessory_ts.context.deviceType} created:`, accessory_ts.displayName, accessory_ts.context.device.mac, accessory_ts.UUID);
|
|
193
|
+
// do not load temperature sensor accessory here (it will be loaded from heatercooler accessory)
|
|
183
194
|
}
|
|
184
195
|
if (accessory) {
|
|
185
196
|
// mark heatercooler device as initialized
|
|
186
197
|
accessory.context.device = deviceInfo;
|
|
187
198
|
accessory.context.deviceType = 'HeaterCooler';
|
|
188
199
|
accessory.displayName = deviceName;
|
|
189
|
-
this.
|
|
190
|
-
this.log.debug(`registerDevice - ${accessory.context.deviceType}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
// update registered accessories at the end of initialization
|
|
194
|
-
const accessories = [accessory];
|
|
195
|
-
if (accessory_ts) {
|
|
196
|
-
accessories.push(accessory_ts);
|
|
200
|
+
this.processedDevices[accessory.UUID] = true;
|
|
201
|
+
this.log.debug(`registerDevice - ${accessory.context.deviceType} created:`, accessory.displayName, accessory.context.device.mac, accessory.UUID);
|
|
202
|
+
// load heatercooler accessory
|
|
203
|
+
new platformAccessory_1.GreeAirConditioner(this, accessory, deviceConfig, accessory_ts === null || accessory_ts === void 0 ? void 0 : accessory_ts.context.device.mac);
|
|
197
204
|
}
|
|
198
|
-
this.api.updatePlatformAccessories(accessories);
|
|
199
205
|
};
|
|
200
206
|
this.devices = {};
|
|
201
|
-
this.
|
|
207
|
+
this.processedDevices = {};
|
|
202
208
|
this.skippedDevices = {};
|
|
203
209
|
this.pluginAddresses = this.getNetworkAddresses();
|
|
204
210
|
if (Object.entries(this.pluginAddresses).length > 0) {
|
|
205
|
-
this.log.debug('
|
|
211
|
+
this.log.debug('Device detection address list {(address : netmask) pairs}:', this.pluginAddresses);
|
|
206
212
|
}
|
|
207
213
|
else {
|
|
208
214
|
this.log.error('Error: Homebridge host has no IPv4 address');
|
|
@@ -238,11 +244,14 @@ class GreeACPlatform {
|
|
|
238
244
|
* It should be used to setup event handlers for characteristics and update respective values.
|
|
239
245
|
*/
|
|
240
246
|
configureAccessory(accessory) {
|
|
241
|
-
var _a;
|
|
247
|
+
var _a, _b, _c;
|
|
242
248
|
this.log.debug('Loading accessory from cache:', accessory.displayName, JSON.stringify(accessory.context.device));
|
|
243
249
|
// add the restored accessory to the accessories cache so we can track if it has already been registered
|
|
244
|
-
if ((_a = accessory.context
|
|
245
|
-
accessory.context.
|
|
250
|
+
if ((_b = (_a = accessory.context) === null || _a === void 0 ? void 0 : _a.device) === null || _b === void 0 ? void 0 : _b.mac) {
|
|
251
|
+
if (!accessory.context.deviceType || accessory.context.deviceType === 'HeaterCooler') {
|
|
252
|
+
accessory.bound = false;
|
|
253
|
+
}
|
|
254
|
+
accessory.registered = true;
|
|
246
255
|
this.devices[accessory.context.device.mac] = accessory;
|
|
247
256
|
}
|
|
248
257
|
// clean all invalid accessories found in cache
|
|
@@ -250,6 +259,10 @@ class GreeACPlatform {
|
|
|
250
259
|
this.log.debug('Invalid accessory found in cache - deleting:', accessory.displayName, accessory.UUID);
|
|
251
260
|
this.api.unregisterPlatformAccessories(settings_1.PLUGIN_NAME, settings_1.PLATFORM_NAME, [accessory]);
|
|
252
261
|
}
|
|
262
|
+
// remove deprecated properties from cached accessory
|
|
263
|
+
if (((_c = accessory.context) === null || _c === void 0 ? void 0 : _c.bound) !== undefined) {
|
|
264
|
+
delete accessory.context.bound;
|
|
265
|
+
}
|
|
253
266
|
}
|
|
254
267
|
/**
|
|
255
268
|
* Accessories must only be registered once, previously created accessories
|
|
@@ -257,28 +270,36 @@ class GreeACPlatform {
|
|
|
257
270
|
*/
|
|
258
271
|
bindCallback() {
|
|
259
272
|
this.log.info(`${settings_1.PLATFORM_NAME} (${settings_1.PLUGIN_NAME}) v%s is running on UDP port %d`, version_1.version, this.socket.address().port);
|
|
273
|
+
this.ports.push(this.socket.address().port);
|
|
260
274
|
this.socket.setBroadcast(true);
|
|
275
|
+
this.sendScan();
|
|
261
276
|
setInterval(() => {
|
|
262
|
-
this.
|
|
277
|
+
this.sendScan();
|
|
263
278
|
}, (this.config.scanInterval || settings_1.DEF_SCAN_INTERVAL) * 1000); // scanInterval in seconds (default = 60 sec)
|
|
264
279
|
}
|
|
265
280
|
discoverDevices() {
|
|
266
281
|
if (this.config.port === undefined || (this.config.port !== undefined && typeof this.config.port === 'number' &&
|
|
267
|
-
this.config.port === this.config.port && this.config.port >=
|
|
282
|
+
this.config.port === this.config.port && this.config.port >= 1025 && this.config.port <= 65535)) {
|
|
268
283
|
this.socket.bind(this.config.port, undefined, () => this.bindCallback());
|
|
269
284
|
}
|
|
270
285
|
else {
|
|
271
|
-
this.log.error('Error: Port is misconfigured (Valid port values: 1025~
|
|
286
|
+
this.log.error('Error: Port is misconfigured (Valid port values: 1025~65535 or leave port empty to auto select)');
|
|
272
287
|
this.socket.close();
|
|
273
288
|
}
|
|
274
289
|
}
|
|
275
|
-
|
|
290
|
+
sendScan() {
|
|
276
291
|
const message = Buffer.from(JSON.stringify({ t: 'scan' }));
|
|
277
292
|
Object.entries(this.pluginAddresses).forEach((value) => {
|
|
278
|
-
|
|
279
|
-
|
|
293
|
+
const addr = value[0];
|
|
294
|
+
this.socket.send(message, 0, message.length, settings_1.UDP_SCAN_PORT, addr, (error) => {
|
|
295
|
+
if (this.pluginAddresses[addr] === '255.255.255.255') {
|
|
296
|
+
this.log.debug(`Scanning for device (unicast) '${message}' ${addr}:${settings_1.UDP_SCAN_PORT}`);
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
this.log.debug(`Scanning for devices (broadcast) '${message}' ${addr}:${settings_1.UDP_SCAN_PORT}`);
|
|
300
|
+
}
|
|
280
301
|
if (error) {
|
|
281
|
-
this.log.error('
|
|
302
|
+
this.log.error('Device scan - Error:', error.message);
|
|
282
303
|
}
|
|
283
304
|
});
|
|
284
305
|
});
|
|
@@ -298,21 +319,48 @@ class GreeACPlatform {
|
|
|
298
319
|
const netmaskParts = iface.netmask.split('.');
|
|
299
320
|
const broadcast = addrParts.map((e, i) => ((~Number(netmaskParts[i]) & 0xFF) | Number(e)).toString()).join('.');
|
|
300
321
|
this.log.debug('Interface: \'%s\' Address: %s Netmask: %s Broadcast: %s', name, iface.address, iface.netmask, broadcast);
|
|
301
|
-
|
|
302
|
-
pluginAddresses[broadcast]
|
|
322
|
+
if (pluginAddresses[broadcast] === undefined) {
|
|
323
|
+
pluginAddresses[broadcast] = iface.netmask;
|
|
324
|
+
}
|
|
303
325
|
}
|
|
304
326
|
}
|
|
305
327
|
}
|
|
306
328
|
}
|
|
307
|
-
//
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
329
|
+
// Add IPs from configuration but only if at least one host address found
|
|
330
|
+
if (Object.keys(pluginAddresses).length > 0) {
|
|
331
|
+
const devcfgs = this.config.devices.filter((item) => item.ip && !item.disabled) || [];
|
|
332
|
+
devcfgs.forEach((value) => {
|
|
333
|
+
const ip = value['ip'];
|
|
334
|
+
const ipv4Pattern = /^(25[0-5]|2[0-4]\d|1\d{2}|\d{1,2})(\.(25[0-5]|2[0-4]\d|1\d{2}|\d{1,2})){3}$/;
|
|
335
|
+
if (ipv4Pattern.test(ip)) {
|
|
336
|
+
this.log.debug('Found AC Unit address in configuration:', ip);
|
|
337
|
+
const addrParts = ip.split('.');
|
|
338
|
+
const addresses = {};
|
|
339
|
+
Object.keys(pluginAddresses).forEach((addr) => {
|
|
340
|
+
const netmaskParts = pluginAddresses[addr].split('.');
|
|
341
|
+
const broadcast = addrParts.map((e, i) => ((~Number(netmaskParts[i]) & 0xFF) | Number(e)).toString()).join('.');
|
|
342
|
+
if (addr === broadcast) {
|
|
343
|
+
addresses[ip] = true;
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
const skipAddress = Object.keys(addresses).find((addr) => addr === ip);
|
|
347
|
+
if (skipAddress === undefined) {
|
|
348
|
+
pluginAddresses[ip] = '255.255.255.255';
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
this.log.debug('AC Unit (%s) is already on broadcast list - skipping', skipAddress);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
this.log.warn('Warning: Invalid IP address found in configuration: %s - skipping', ip);
|
|
356
|
+
}
|
|
357
|
+
});
|
|
313
358
|
}
|
|
314
359
|
return pluginAddresses;
|
|
315
360
|
}
|
|
361
|
+
getAccessory(mac) {
|
|
362
|
+
return this.devices[mac];
|
|
363
|
+
}
|
|
316
364
|
}
|
|
317
365
|
exports.GreeACPlatform = GreeACPlatform;
|
|
318
366
|
//# sourceMappingURL=platform.js.map
|