homebridge-edomoticz 2.1.49 → 3.0.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/README.md +3 -1
- package/index.js +20 -35
- package/lib/domoticz.js +1 -3
- package/lib/domoticz_accessory.js +1 -1
- package/lib/helper.js +60 -1
- package/lib/services.js +488 -357
- package/package.json +8 -5
- package/test/load-plugin.js +227 -0
- package/.npmignore +0 -3
package/README.md
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
[](https://github.com/homebridge/homebridge/wiki/Verified-Plugins)
|
|
4
4
|
|
|
5
5
|
# Homebridge-eDomoticz
|
|
6
|
-
This is a plugin for [Homebridge](https://github.com/nfarina/homebridge) and [Homebridge Config UI X Support](https://github.com/oznu/homebridge-config-ui-x) and [Domoticz](https://github.com/domoticz/domoticz).
|
|
6
|
+
This is a plugin for [Homebridge](https://github.com/nfarina/homebridge) v1.x and [Homebridge Config UI X Support](https://github.com/oznu/homebridge-config-ui-x) and [Domoticz](https://github.com/domoticz/domoticz).
|
|
7
|
+
|
|
8
|
+
It doesn't work with Homebridge v2.x
|
|
7
9
|
|
|
8
10
|
## Supports:
|
|
9
11
|
<details>
|
package/index.js
CHANGED
|
@@ -14,7 +14,9 @@ var Mqtt = require('./lib/mqtt.js').Mqtt;
|
|
|
14
14
|
var eDomoticzAccessory = require('./lib/domoticz_accessory.js');
|
|
15
15
|
var Constants = require('./lib/constants.js');
|
|
16
16
|
var Helper = require('./lib/helper.js').Helper;
|
|
17
|
-
var
|
|
17
|
+
var Services = require('./lib/services.js');
|
|
18
|
+
var eDomoticzServices = Services.eDomoticzServices;
|
|
19
|
+
var initServices = Services.initServices;
|
|
18
20
|
const util = require('util');
|
|
19
21
|
|
|
20
22
|
module.exports = function(homebridge) {
|
|
@@ -24,40 +26,11 @@ module.exports = function(homebridge) {
|
|
|
24
26
|
Types = homebridge.hapLegacyTypes;
|
|
25
27
|
UUID = homebridge.hap.uuid;
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
util.inherits
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
util.inherits(eDomoticzServices.GasDeviceService, Service);
|
|
33
|
-
util.inherits(eDomoticzServices.Ampere, Characteristic);
|
|
34
|
-
util.inherits(eDomoticzServices.AMPDeviceService, Service);
|
|
35
|
-
util.inherits(eDomoticzServices.Volt, Characteristic);
|
|
36
|
-
util.inherits(eDomoticzServices.VOLTDeviceService, Service);
|
|
37
|
-
util.inherits(eDomoticzServices.CurrentUsage, Characteristic);
|
|
38
|
-
util.inherits(eDomoticzServices.UsageDeviceService, Service);
|
|
39
|
-
util.inherits(eDomoticzServices.TodayConsumption, Characteristic);
|
|
40
|
-
util.inherits(eDomoticzServices.Barometer, Characteristic);
|
|
41
|
-
util.inherits(eDomoticzServices.WaterFlow, Characteristic);
|
|
42
|
-
util.inherits(eDomoticzServices.TotalWaterFlow, Characteristic);
|
|
43
|
-
util.inherits(eDomoticzServices.WaterDeviceService, Service);
|
|
44
|
-
util.inherits(eDomoticzServices.WeatherService, Service);
|
|
45
|
-
util.inherits(eDomoticzServices.WindSpeed, Characteristic);
|
|
46
|
-
util.inherits(eDomoticzServices.WindChill, Characteristic);
|
|
47
|
-
util.inherits(eDomoticzServices.WindDirection, Characteristic);
|
|
48
|
-
util.inherits(eDomoticzServices.WindDeviceService, Service);
|
|
49
|
-
util.inherits(eDomoticzServices.Rainfall, Characteristic);
|
|
50
|
-
util.inherits(eDomoticzServices.RainDeviceService, Service);
|
|
51
|
-
util.inherits(eDomoticzServices.Visibility, Characteristic);
|
|
52
|
-
util.inherits(eDomoticzServices.VisibilityDeviceService, Service);
|
|
53
|
-
util.inherits(eDomoticzServices.SolRad, Characteristic);
|
|
54
|
-
util.inherits(eDomoticzServices.SolRadDeviceService, Service);
|
|
55
|
-
util.inherits(eDomoticzServices.LocationService, Service);
|
|
56
|
-
util.inherits(eDomoticzServices.Location, Characteristic);
|
|
57
|
-
util.inherits(eDomoticzServices.InfotextDeviceService, Service);
|
|
58
|
-
util.inherits(eDomoticzServices.Infotext, Characteristic);
|
|
59
|
-
util.inherits(eDomoticzServices.UVDeviceService, Service);
|
|
60
|
-
util.inherits(eDomoticzServices.UVIndex, Characteristic);
|
|
29
|
+
// Populate eDomoticzServices with ES6 class definitions now that HAP refs
|
|
30
|
+
// (Service / Characteristic) are available. Replaces the previous pattern
|
|
31
|
+
// of pre-ES6 constructors + util.inherits, which crashes under HAP-NodeJS
|
|
32
|
+
// v2 ("Class constructor Service cannot be invoked without 'new'").
|
|
33
|
+
initServices(Service, Characteristic, UUID, homebridge.hap);
|
|
61
34
|
|
|
62
35
|
//homebridge.registerAccessory("homebridge-edomoticz", "eDomoticz", eDomoticzAccessory);
|
|
63
36
|
homebridge.registerPlatform("homebridge-edomoticz", "eDomoticz", eDomoticzPlatform, true);
|
|
@@ -243,6 +216,18 @@ eDomoticzPlatform.prototype = {
|
|
|
243
216
|
var uuid = platformAccessory.context.uuid;
|
|
244
217
|
var eve = platformAccessory.context.eve;
|
|
245
218
|
|
|
219
|
+
// Cached characteristics come back with the perms that were persisted
|
|
220
|
+
// when the cache was written. A cache produced by 3.0.0-3.0.2 under
|
|
221
|
+
// HAP v2 carries perms [null, "ev"] on every custom characteristic,
|
|
222
|
+
// which makes iOS refuse to pair. Re-apply the canonical perms.
|
|
223
|
+
var pairedRead = (this.api.hap.Perms && this.api.hap.Perms.PAIRED_READ)
|
|
224
|
+
|| (Characteristic.Perms && Characteristic.Perms.PAIRED_READ)
|
|
225
|
+
|| 'pr';
|
|
226
|
+
var healed = Helper.healCustomCharacteristicPerms(platformAccessory, eDomoticzServices, Characteristic, pairedRead);
|
|
227
|
+
if (healed > 0) {
|
|
228
|
+
this.log("Repaired " + healed + " cached custom characteristic perms on " + device.Name);
|
|
229
|
+
}
|
|
230
|
+
|
|
246
231
|
// Generate the already cached accessory again
|
|
247
232
|
var accessory = new eDomoticzAccessory(this, platformAccessory, false, device.Used, device.idx, device.Name, uuid, device.HaveDimmer, device.MaxDimLevel, device.SubType, device.Type, device.BatteryLevel, device.SwitchType, device.SwitchTypeVal, device.HardwareID, device.HardwareTypeVal, device.Image, eve, device.HaveTimeout, device.Description);
|
|
248
233
|
this.accessories.push(accessory);
|
package/lib/domoticz.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
var request = require("request");
|
|
2
2
|
var Helper = require('./helper.js').Helper;
|
|
3
|
-
var extend =
|
|
3
|
+
var extend = Object.assign;
|
|
4
4
|
|
|
5
5
|
module.exports = {
|
|
6
6
|
Domoticz: Domoticz
|
|
@@ -48,7 +48,6 @@ Domoticz.settings = function(accessory, completion, error) {
|
|
|
48
48
|
Helper.LogConnectionError(this.platform, response, err);
|
|
49
49
|
if (typeof error !== 'undefined' && error !== false) {
|
|
50
50
|
error();
|
|
51
|
-
callback();
|
|
52
51
|
}
|
|
53
52
|
}
|
|
54
53
|
}.bind(accessory));
|
|
@@ -208,7 +207,6 @@ Domoticz.updateWithURL = function(accessory, url, completion) {
|
|
|
208
207
|
}
|
|
209
208
|
else {
|
|
210
209
|
Helper.LogConnectionError(this.platform, response, err);
|
|
211
|
-
callback();
|
|
212
210
|
}
|
|
213
211
|
|
|
214
212
|
if (typeof completion !== 'undefined' && completion !== false) {
|
|
@@ -86,7 +86,7 @@ function eDomoticzAccessory(platform, platformAccessory, IsScene, status, idx, n
|
|
|
86
86
|
}
|
|
87
87
|
this.platformAccessory.reachable = true;
|
|
88
88
|
if (this.swTypeVal == Constants.DeviceTypeMedia) {
|
|
89
|
-
this.platformAccessory.category = Categories.TELEVISION;
|
|
89
|
+
this.platformAccessory.category = platform.api.hap.Categories.TELEVISION;
|
|
90
90
|
}
|
|
91
91
|
this.publishServices();
|
|
92
92
|
}
|
package/lib/helper.js
CHANGED
|
@@ -157,4 +157,63 @@ Helper.LogConnectionError = function(platform, response, err)
|
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
platform.forceLog(errorMessage);
|
|
160
|
-
}
|
|
160
|
+
}
|
|
161
|
+
/*
|
|
162
|
+
* Re-apply canonical perms to custom eDomoticz Characteristics restored from
|
|
163
|
+
* Homebridge's accessory cache.
|
|
164
|
+
*
|
|
165
|
+
* Homebridge persists every Characteristic's `props` (perms, format, unit...)
|
|
166
|
+
* in cachedAccessories and HAP-NodeJS restores them verbatim on startup.
|
|
167
|
+
* Custom characteristics are not known HAP classes, so they come back as
|
|
168
|
+
* generic Characteristic instances carrying whatever props were cached.
|
|
169
|
+
* A cache written by a plugin build that published perms [null, "ev"]
|
|
170
|
+
* (see CHANGELOG 3.0.3) keeps poisoning the bridge after upgrading, and
|
|
171
|
+
* iOS keeps refusing to pair, until the cache is cleared by hand.
|
|
172
|
+
*
|
|
173
|
+
* This walks a restored PlatformAccessory and, for every characteristic
|
|
174
|
+
* whose UUID matches a custom eDomoticz Characteristic class, replaces the
|
|
175
|
+
* perms with the ones the class defines today when the cached ones are
|
|
176
|
+
* missing, contain null/undefined, or lack PAIRED_READ. Only `perms` is
|
|
177
|
+
* touched: format/unit/min/max are left alone on purpose because two
|
|
178
|
+
* custom characteristics share a UUID with different units
|
|
179
|
+
* (CurrentConsumption 'W' vs GasConsumption 'm3').
|
|
180
|
+
*
|
|
181
|
+
* Returns the number of characteristics healed.
|
|
182
|
+
*/
|
|
183
|
+
Helper.healCustomCharacteristicPerms = function (platformAccessory, eDomoticzServices, Characteristic, pairedReadPerm) {
|
|
184
|
+
if (!platformAccessory || !Array.isArray(platformAccessory.services)) {
|
|
185
|
+
return 0;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
var canonicalPerms = {};
|
|
189
|
+
Object.keys(eDomoticzServices).forEach(function (key) {
|
|
190
|
+
var Ctor = eDomoticzServices[key];
|
|
191
|
+
if (typeof Ctor !== 'function' || !(Ctor.prototype instanceof Characteristic)) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
var probe = new Ctor();
|
|
195
|
+
if (!canonicalPerms[probe.UUID] && probe.props && Array.isArray(probe.props.perms)) {
|
|
196
|
+
canonicalPerms[probe.UUID] = probe.props.perms.slice();
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
var healed = 0;
|
|
201
|
+
platformAccessory.services.forEach(function (service) {
|
|
202
|
+
(service.characteristics || []).forEach(function (characteristic) {
|
|
203
|
+
var perms = canonicalPerms[characteristic.UUID];
|
|
204
|
+
if (!perms) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
var current = (characteristic.props && characteristic.props.perms) || [];
|
|
208
|
+
var broken = current.length === 0
|
|
209
|
+
|| current.some(function (p) { return p === null || p === undefined; })
|
|
210
|
+
|| current.indexOf(pairedReadPerm) === -1;
|
|
211
|
+
if (broken) {
|
|
212
|
+
characteristic.setProps({ perms: perms });
|
|
213
|
+
healed++;
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
return healed;
|
|
219
|
+
};
|
package/lib/services.js
CHANGED
|
@@ -1,367 +1,498 @@
|
|
|
1
1
|
var Constants = require('./constants.js');
|
|
2
2
|
|
|
3
|
+
var eDomoticzServices = {};
|
|
4
|
+
|
|
3
5
|
module.exports = {
|
|
4
|
-
eDomoticzServices: eDomoticzServices
|
|
5
|
-
|
|
6
|
+
eDomoticzServices: eDomoticzServices,
|
|
7
|
+
initServices: initServices
|
|
8
|
+
};
|
|
6
9
|
|
|
10
|
+
/*
|
|
11
|
+
* initServices is called from index.js once homebridge has provided its HAP
|
|
12
|
+
* references. It populates the (already exported) eDomoticzServices object
|
|
13
|
+
* with ES6 class definitions. The exported object reference does not change,
|
|
14
|
+
* so consumers that captured it via `require('./services.js').eDomoticzServices`
|
|
15
|
+
* (e.g. lib/domoticz_accessory.js) keep working transparently.
|
|
16
|
+
*
|
|
17
|
+
* Order matters per the migration plan: define the 20 custom Characteristics
|
|
18
|
+
* first, then the 14 custom Services that compose them.
|
|
19
|
+
*/
|
|
20
|
+
function initServices(Service, Characteristic, UUID, hap) {
|
|
7
21
|
|
|
8
|
-
|
|
22
|
+
// HAP-NodeJS v1 exposed Formats / Perms / Units as static enums on the
|
|
23
|
+
// Characteristic class. HAP-NodeJS v2 moved them to the module root (and
|
|
24
|
+
// Characteristic.Formats / .Perms / .Units became undefined). Resolve
|
|
25
|
+
// them via fallback so this plugin works on both Homebridge 1.x and 2.x.
|
|
26
|
+
var Formats = (Characteristic && Characteristic.Formats) || (hap && hap.Formats);
|
|
27
|
+
var Perms = (Characteristic && Characteristic.Perms) || (hap && hap.Perms);
|
|
28
|
+
var Units = (Characteristic && Characteristic.Units) || (hap && hap.Units);
|
|
9
29
|
|
|
10
|
-
|
|
30
|
+
if (!Formats || !Perms || !Units) {
|
|
31
|
+
throw new Error(
|
|
32
|
+
'homebridge-edomoticz: cannot resolve HAP Formats/Perms/Units. ' +
|
|
33
|
+
'Neither Characteristic.* (HAP v1) nor hap.* (HAP v2) provided ' +
|
|
34
|
+
'them. This indicates an unsupported HAP-NodeJS version.'
|
|
35
|
+
);
|
|
36
|
+
}
|
|
11
37
|
|
|
12
|
-
/*
|
|
13
|
-
// PowerMeter Characteristics
|
|
14
|
-
eDomoticzServices.TotalConsumption = function() {
|
|
15
|
-
var charUUID = 'E863F10C-079E-48FF-8F27-9C2605A29F52'; //UUID.generate('eDomoticz:customchar:TotalConsumption');
|
|
16
|
-
Characteristic.call(this, 'Total Consumption', charUUID);
|
|
17
|
-
this.setProps({
|
|
18
|
-
format: Characteristic.Formats.FLOAT,
|
|
19
|
-
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY],
|
|
20
|
-
unit: 'kWh'
|
|
21
|
-
});
|
|
22
|
-
this.value = this.getDefaultValue();
|
|
23
|
-
this.UUID = charUUID;
|
|
24
|
-
};
|
|
25
|
-
eDomoticzServices.TodayConsumption = function() {
|
|
26
|
-
var charUUID = UUID.generate('eDomoticz:customchar:TodayConsumption');
|
|
27
|
-
Characteristic.call(this, 'Today', charUUID);
|
|
28
|
-
this.setProps({
|
|
29
|
-
format: Characteristic.Formats.FLOAT,
|
|
30
|
-
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY],
|
|
31
|
-
unit: 'kWh'
|
|
32
|
-
});
|
|
33
|
-
this.value = this.getDefaultValue();
|
|
34
|
-
this.UUID = charUUID;
|
|
35
|
-
};
|
|
36
|
-
eDomoticzServices.CurrentConsumption = function() {
|
|
37
|
-
var charUUID = 'E863F10D-079E-48FF-8F27-9C2605A29F52'; //UUID.generate('eDomoticz:customchar:CurrentConsumption');
|
|
38
|
-
Characteristic.call(this, 'Consumption', charUUID);
|
|
39
|
-
this.setProps({
|
|
40
|
-
format: Characteristic.Formats.FLOAT,
|
|
41
|
-
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY],
|
|
42
|
-
unit: 'W'
|
|
43
|
-
});
|
|
44
|
-
this.value = this.getDefaultValue();
|
|
45
|
-
this.UUID = charUUID;
|
|
46
|
-
};
|
|
47
|
-
eDomoticzServices.Ampere = function() {
|
|
48
|
-
var charUUID = 'E863F126-079E-48FF-8F27-9C2605A29F52'; //AMPERE
|
|
49
|
-
Characteristic.call(this, 'Amps', charUUID);
|
|
50
|
-
this.setProps({
|
|
51
|
-
format: Characteristic.Formats.FLOAT,
|
|
52
|
-
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY],
|
|
53
|
-
unit: 'A'
|
|
54
|
-
});
|
|
55
|
-
this.value = this.getDefaultValue();
|
|
56
|
-
this.UUID = charUUID;
|
|
57
|
-
};
|
|
58
|
-
eDomoticzServices.Volt = function() {
|
|
59
|
-
var charUUID = 'E863F10A-079E-48FF-8F27-9C2605A29F52'; //VOLT
|
|
60
|
-
Characteristic.call(this, 'Volts', charUUID);
|
|
61
|
-
this.setProps({
|
|
62
|
-
format: Characteristic.Formats.FLOAT,
|
|
63
|
-
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY],
|
|
64
|
-
unit: 'V'
|
|
65
|
-
});
|
|
66
|
-
this.value = this.getDefaultValue();
|
|
67
|
-
this.UUID = charUUID;
|
|
68
|
-
};
|
|
69
|
-
eDomoticzServices.GasConsumption = function() {
|
|
70
|
-
var charUUID = UUID.generate('eDomoticz:customchar:CurrentConsumption');
|
|
71
|
-
Characteristic.call(this, 'Meter Total', charUUID);
|
|
72
|
-
this.setProps({
|
|
73
|
-
format: Characteristic.Formats.FLOAT,
|
|
74
|
-
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY]
|
|
75
|
-
});
|
|
76
|
-
this.value = this.getDefaultValue();
|
|
77
|
-
this.UUID = charUUID;
|
|
78
|
-
};
|
|
79
|
-
eDomoticzServices.WaterFlow = function() {
|
|
80
|
-
var charUUID = UUID.generate('eDomoticz:customchar:WaterFlow');
|
|
81
|
-
Characteristic.call(this, 'Flow Rate', charUUID);
|
|
82
|
-
this.setProps({
|
|
83
|
-
format: Characteristic.Formats.FLOAT,
|
|
84
|
-
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY],
|
|
85
|
-
unit: 'm3'
|
|
86
|
-
});
|
|
87
|
-
this.value = this.getDefaultValue();
|
|
88
|
-
this.UUID = charUUID;
|
|
89
|
-
};
|
|
90
|
-
eDomoticzServices.TotalWaterFlow = function() {
|
|
91
|
-
var charUUID = UUID.generate('eDomoticz:customchar:TotalWaterFlow');
|
|
92
|
-
Characteristic.call(this, 'Flow Total', charUUID);
|
|
93
|
-
this.setProps({
|
|
94
|
-
format: Characteristic.Formats.FLOAT,
|
|
95
|
-
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY],
|
|
96
|
-
unit: 'l'
|
|
97
|
-
});
|
|
98
|
-
this.value = this.getDefaultValue();
|
|
99
|
-
this.UUID = charUUID;
|
|
100
|
-
};
|
|
101
|
-
// Custom SetPoint Minutes characteristic for TempOverride modes
|
|
102
|
-
eDomoticzServices.TempOverride = function() {
|
|
103
|
-
var charUUID = UUID.generate('eDomoticz:customchar:OverrideTime');
|
|
104
|
-
Characteristic.call(this, 'Override (Mins, 0 = Auto, 481 = Permanent)', charUUID);
|
|
105
|
-
this.setProps({
|
|
106
|
-
format: Characteristic.Formats.FLOAT,
|
|
107
|
-
maxValue: 481,
|
|
108
|
-
minValue: 0,
|
|
109
|
-
minStep: 1,
|
|
110
|
-
unit: 'mins',
|
|
111
|
-
perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE, Characteristic.Perms.NOTIFY]
|
|
112
|
-
});
|
|
113
|
-
this.value = this.getDefaultValue();
|
|
114
|
-
this.UUID = charUUID;
|
|
115
|
-
};
|
|
116
|
-
// Ampere Meter
|
|
117
|
-
eDomoticzServices.AMPDeviceService = function(displayName, subtype) {
|
|
118
|
-
var serviceUUID = UUID.generate('eDomoticz:powermeter:customservice');
|
|
119
|
-
Service.call(this, displayName, serviceUUID, subtype);
|
|
120
|
-
this.addCharacteristic(new eDomoticzServices.Ampere());
|
|
121
|
-
};
|
|
122
|
-
// Voltage Meter
|
|
123
|
-
eDomoticzServices.VOLTDeviceService = function(displayName, subtype) {
|
|
124
|
-
var serviceUUID = UUID.generate('eDomoticz:powermeter:customservice');
|
|
125
|
-
Service.call(this, displayName, serviceUUID, subtype);
|
|
126
|
-
this.addCharacteristic(new eDomoticzServices.Volt());
|
|
127
|
-
};
|
|
38
|
+
/* ===== Custom Characteristics (20) ===== */
|
|
128
39
|
|
|
129
|
-
//
|
|
130
|
-
eDomoticzServices.
|
|
40
|
+
// PowerMeter Characteristics
|
|
41
|
+
eDomoticzServices.TotalConsumption = class extends Characteristic {
|
|
42
|
+
constructor() {
|
|
43
|
+
var charUUID = 'E863F10C-079E-48FF-8F27-9C2605A29F52'; //UUID.generate('eDomoticz:customchar:TotalConsumption');
|
|
44
|
+
super('Total Consumption', charUUID);
|
|
45
|
+
this.setProps({
|
|
46
|
+
format: Formats.FLOAT,
|
|
47
|
+
perms: [Perms.PAIRED_READ, Perms.NOTIFY],
|
|
48
|
+
unit: 'kWh'
|
|
49
|
+
});
|
|
50
|
+
this.value = this.getDefaultValue();
|
|
51
|
+
this.UUID = charUUID;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
131
54
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
};
|
|
145
|
-
// P1 Smart Meter -> Gas
|
|
146
|
-
eDomoticzServices.GasDeviceService = function(displayName, subtype) {
|
|
147
|
-
var serviceUUID = UUID.generate('eDomoticz:gasmeter:customservice');
|
|
148
|
-
Service.call(this, displayName, serviceUUID, subtype);
|
|
149
|
-
this.addCharacteristic(new eDomoticzServices.GasConsumption());
|
|
150
|
-
};
|
|
151
|
-
// Usage Meter Characteristics
|
|
152
|
-
eDomoticzServices.CurrentUsage = function() {
|
|
153
|
-
var charUUID = UUID.generate('eDomoticz:customchar:CurrentUsage');
|
|
154
|
-
Characteristic.call(this, 'Current Usage', charUUID);
|
|
155
|
-
this.setProps({
|
|
156
|
-
format: Characteristic.Formats.FLOAT,
|
|
157
|
-
unit: Characteristic.Units.PERCENTAGE,
|
|
158
|
-
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY],
|
|
159
|
-
minValue:0,
|
|
160
|
-
maxValue:100,
|
|
161
|
-
minStep:0.1
|
|
162
|
-
});
|
|
163
|
-
this.value = this.getDefaultValue();
|
|
164
|
-
this.UUID = charUUID;
|
|
165
|
-
};
|
|
166
|
-
// The Usage Meter itself
|
|
167
|
-
eDomoticzServices.UsageDeviceService = function(displayName, subtype) {
|
|
168
|
-
var serviceUUID = UUID.generate('eDomoticz:usagedevice:customservice');
|
|
169
|
-
Service.call(this, displayName, serviceUUID, subtype);
|
|
170
|
-
this.addCharacteristic(new eDomoticzServices.CurrentUsage());
|
|
171
|
-
};
|
|
172
|
-
// Location Meter (sensor should have 'Location' in title)
|
|
173
|
-
eDomoticzServices.Location = function() {
|
|
174
|
-
var charUUID = UUID.generate('eDomoticz:customchar:Location');
|
|
175
|
-
Characteristic.call(this, 'Location', charUUID);
|
|
176
|
-
this.setProps({
|
|
177
|
-
format: Characteristic.Formats.STRING,
|
|
178
|
-
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY]
|
|
179
|
-
});
|
|
180
|
-
this.value = this.getDefaultValue();
|
|
181
|
-
this.UUID = charUUID;
|
|
182
|
-
};
|
|
183
|
-
eDomoticzServices.LocationService = function(displayName, subtype) {
|
|
184
|
-
var serviceUUID = UUID.generate('eDomoticz:location:customservice');
|
|
185
|
-
Service.call(this, displayName, serviceUUID, subtype);
|
|
186
|
-
this.addCharacteristic(new eDomoticzServices.Location());
|
|
187
|
-
};
|
|
188
|
-
// DarkSkies WindSpeed Characteristic
|
|
189
|
-
eDomoticzServices.WindSpeed = function() {
|
|
190
|
-
var charUUID = '49C8AE5A-A3A5-41AB-BF1F-12D5654F9F41';//'9331096F-E49E-4D98-B57B-57803498FA36'; //UUID.generate('eDomoticz:customchar:WindSpeed');
|
|
191
|
-
Characteristic.call(this, 'Wind Speed', charUUID);
|
|
192
|
-
this.setProps({
|
|
193
|
-
format: Characteristic.Formats.FLOAT,
|
|
194
|
-
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY],
|
|
195
|
-
unit:'m/s',
|
|
196
|
-
minValue:0,
|
|
197
|
-
maxValue:360,
|
|
198
|
-
minStep:0.1
|
|
199
|
-
});
|
|
200
|
-
this.value = this.getDefaultValue();
|
|
201
|
-
this.UUID = charUUID;
|
|
202
|
-
};
|
|
203
|
-
// DarkSkies WindChill Characteristic
|
|
204
|
-
eDomoticzServices.WindChill = function() {
|
|
205
|
-
var charUUID = UUID.generate('eDomoticz:customchar:WindChill');
|
|
206
|
-
Characteristic.call(this, 'Wind Chill', charUUID);
|
|
207
|
-
this.setProps({
|
|
208
|
-
format: Characteristic.Formats.FLOAT,
|
|
209
|
-
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY],
|
|
210
|
-
unit: Characteristic.Units.CELSIUS,
|
|
211
|
-
minValue:-50,
|
|
212
|
-
maxValue:100,
|
|
213
|
-
minStep:0.1
|
|
214
|
-
});
|
|
215
|
-
this.value = this.getDefaultValue();
|
|
216
|
-
this.UUID = charUUID;
|
|
217
|
-
};
|
|
218
|
-
// DarkSkies WindDirection Characteristic
|
|
219
|
-
eDomoticzServices.WindDirection = function() {
|
|
220
|
-
var charUUID = '46f1284c-1912-421b-82f5-eb75008b167e';//'6C3F6DFA-7340-4ED4-AFFD-0E0310ECCD9E'; //UUID.generate('eDomoticz:customchar:WindDirection');
|
|
221
|
-
Characteristic.call(this, 'Wind Direction', charUUID);
|
|
222
|
-
this.setProps({
|
|
223
|
-
format: Characteristic.Formats.INT,
|
|
224
|
-
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY],
|
|
225
|
-
unit: Characteristic.Units.ARC_DEGREE,
|
|
226
|
-
minValue:0,
|
|
227
|
-
maxValue:360,
|
|
228
|
-
minStep:1
|
|
229
|
-
});
|
|
230
|
-
this.value = this.getDefaultValue();
|
|
231
|
-
this.UUID = charUUID;
|
|
232
|
-
};
|
|
233
|
-
// DarkSkies Virtual Wind Sensor
|
|
234
|
-
eDomoticzServices.WindDeviceService = function(displayName, subtype) {
|
|
235
|
-
var serviceUUID = '2AFB775E-79E5-4399-B3CD-398474CAE86C'; //UUID.generate('eDomoticz:winddevice:customservice');
|
|
236
|
-
Service.call(this, displayName, serviceUUID, subtype);
|
|
237
|
-
this.addCharacteristic(new eDomoticzServices.WindSpeed());
|
|
238
|
-
this.addOptionalCharacteristic(new eDomoticzServices.WindChill());
|
|
239
|
-
this.addOptionalCharacteristic(new eDomoticzServices.WindDirection());
|
|
240
|
-
this.addOptionalCharacteristic(new Characteristic.CurrentTemperature());
|
|
241
|
-
};
|
|
242
|
-
// DarkSkies Rain Characteristics
|
|
243
|
-
eDomoticzServices.Rainfall = function() {
|
|
244
|
-
var charUUID = 'ccc04890-565b-4376-b39a-3113341d9e0f';//'C53F35CE-C615-4AA4-9112-EBF679C5EB14'; //UUID.generate('eDomoticz:customchar:Rainfall');
|
|
245
|
-
Characteristic.call(this, 'Amount today', charUUID);
|
|
246
|
-
this.setProps({
|
|
247
|
-
format: Characteristic.Formats.FLOAT,
|
|
248
|
-
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY],
|
|
249
|
-
unit: 'mm',
|
|
250
|
-
minValue:0,
|
|
251
|
-
maxValue:360,
|
|
252
|
-
minStep:0.1
|
|
253
|
-
});
|
|
254
|
-
this.value = this.getDefaultValue();
|
|
255
|
-
this.UUID = charUUID;
|
|
256
|
-
};
|
|
257
|
-
// DarkSkies Rain Meter itself
|
|
258
|
-
eDomoticzServices.RainDeviceService = function(displayName, subtype) {
|
|
259
|
-
var serviceUUID = 'D92D5391-92AF-4824-AF4A-356F25F25EA1'; //UUID.generate('eDomoticz:raindevice:customservice');
|
|
260
|
-
Service.call(this, displayName, serviceUUID, subtype);
|
|
261
|
-
this.addCharacteristic(new eDomoticzServices.Rainfall());
|
|
262
|
-
};
|
|
263
|
-
// DarkSkies Visibility Characteristics
|
|
264
|
-
eDomoticzServices.Visibility = function() {
|
|
265
|
-
var charUUID = 'd24ecc1e-6fad-4fb5-8137-5af88bd5e857';//UUID.generate('eDomoticz:customchar:Visibility');
|
|
266
|
-
Characteristic.call(this, 'Distance', charUUID);
|
|
267
|
-
this.setProps({
|
|
268
|
-
format: Characteristic.Formats.FLOAT,
|
|
269
|
-
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY],
|
|
270
|
-
unit: 'miles',
|
|
271
|
-
minValue:0,
|
|
272
|
-
maxValue:20,
|
|
273
|
-
minStep:0.1
|
|
274
|
-
});
|
|
275
|
-
this.value = this.getDefaultValue();
|
|
276
|
-
this.UUID = charUUID;
|
|
277
|
-
};
|
|
278
|
-
// DarkSkies Visibility Meter itself
|
|
279
|
-
eDomoticzServices.VisibilityDeviceService = function(displayName, subtype) {
|
|
280
|
-
var serviceUUID = UUID.generate('eDomoticz:visibilitydevice:customservice');
|
|
281
|
-
Service.call(this, displayName, serviceUUID, subtype);
|
|
282
|
-
this.addCharacteristic(new eDomoticzServices.Visibility());
|
|
283
|
-
};
|
|
284
|
-
// DarkSkies UVIndex Characteristics
|
|
285
|
-
eDomoticzServices.UVIndex = function() {
|
|
286
|
-
var charUUID = '05ba0fe0-b848-4226-906d-5b64272e05ce';//UUID.generate('eDomoticz:customchar:Visibility');
|
|
287
|
-
Characteristic.call(this, 'UVIndex', charUUID);
|
|
288
|
-
this.setProps({
|
|
289
|
-
format: Characteristic.Formats.FLOAT,
|
|
290
|
-
perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY],
|
|
291
|
-
unit: 'UVI',
|
|
292
|
-
minValue:0,
|
|
293
|
-
maxValue:20,
|
|
294
|
-
minStep:0.1
|
|
295
|
-
});
|
|
296
|
-
this.value = this.getDefaultValue();
|
|
297
|
-
this.UUID = charUUID;
|
|
298
|
-
};
|
|
55
|
+
eDomoticzServices.TodayConsumption = class extends Characteristic {
|
|
56
|
+
constructor() {
|
|
57
|
+
var charUUID = UUID.generate('eDomoticz:customchar:TodayConsumption');
|
|
58
|
+
super('Today', charUUID);
|
|
59
|
+
this.setProps({
|
|
60
|
+
format: Formats.FLOAT,
|
|
61
|
+
perms: [Perms.PAIRED_READ, Perms.NOTIFY],
|
|
62
|
+
unit: 'kWh'
|
|
63
|
+
});
|
|
64
|
+
this.value = this.getDefaultValue();
|
|
65
|
+
this.UUID = charUUID;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
299
68
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
};
|
|
327
|
-
|
|
328
|
-
eDomoticzServices.
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
//
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
69
|
+
eDomoticzServices.CurrentConsumption = class extends Characteristic {
|
|
70
|
+
constructor() {
|
|
71
|
+
var charUUID = 'E863F10D-079E-48FF-8F27-9C2605A29F52'; //UUID.generate('eDomoticz:customchar:CurrentConsumption');
|
|
72
|
+
super('Consumption', charUUID);
|
|
73
|
+
this.setProps({
|
|
74
|
+
format: Formats.FLOAT,
|
|
75
|
+
perms: [Perms.PAIRED_READ, Perms.NOTIFY],
|
|
76
|
+
unit: 'W'
|
|
77
|
+
});
|
|
78
|
+
this.value = this.getDefaultValue();
|
|
79
|
+
this.UUID = charUUID;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
eDomoticzServices.Ampere = class extends Characteristic {
|
|
84
|
+
constructor() {
|
|
85
|
+
var charUUID = 'E863F126-079E-48FF-8F27-9C2605A29F52'; //AMPERE
|
|
86
|
+
super('Amps', charUUID);
|
|
87
|
+
this.setProps({
|
|
88
|
+
format: Formats.FLOAT,
|
|
89
|
+
perms: [Perms.PAIRED_READ, Perms.NOTIFY],
|
|
90
|
+
unit: 'A'
|
|
91
|
+
});
|
|
92
|
+
this.value = this.getDefaultValue();
|
|
93
|
+
this.UUID = charUUID;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
eDomoticzServices.Volt = class extends Characteristic {
|
|
98
|
+
constructor() {
|
|
99
|
+
var charUUID = 'E863F10A-079E-48FF-8F27-9C2605A29F52'; //VOLT
|
|
100
|
+
super('Volts', charUUID);
|
|
101
|
+
this.setProps({
|
|
102
|
+
format: Formats.FLOAT,
|
|
103
|
+
perms: [Perms.PAIRED_READ, Perms.NOTIFY],
|
|
104
|
+
unit: 'V'
|
|
105
|
+
});
|
|
106
|
+
this.value = this.getDefaultValue();
|
|
107
|
+
this.UUID = charUUID;
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// NOTE: UUID key intentionally reuses 'CurrentConsumption' string — preserved
|
|
112
|
+
// verbatim from upstream (historical collision, do not "fix").
|
|
113
|
+
eDomoticzServices.GasConsumption = class extends Characteristic {
|
|
114
|
+
constructor() {
|
|
115
|
+
var charUUID = UUID.generate('eDomoticz:customchar:CurrentConsumption');
|
|
116
|
+
super('Meter Total', charUUID);
|
|
117
|
+
this.setProps({
|
|
118
|
+
format: Formats.FLOAT,
|
|
119
|
+
perms: [Perms.PAIRED_READ, Perms.NOTIFY]
|
|
120
|
+
});
|
|
121
|
+
this.value = this.getDefaultValue();
|
|
122
|
+
this.UUID = charUUID;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
eDomoticzServices.WaterFlow = class extends Characteristic {
|
|
127
|
+
constructor() {
|
|
128
|
+
var charUUID = UUID.generate('eDomoticz:customchar:WaterFlow');
|
|
129
|
+
super('Flow Rate', charUUID);
|
|
130
|
+
this.setProps({
|
|
131
|
+
format: Formats.FLOAT,
|
|
132
|
+
perms: [Perms.PAIRED_READ, Perms.NOTIFY],
|
|
133
|
+
unit: 'm3'
|
|
134
|
+
});
|
|
135
|
+
this.value = this.getDefaultValue();
|
|
136
|
+
this.UUID = charUUID;
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
eDomoticzServices.TotalWaterFlow = class extends Characteristic {
|
|
141
|
+
constructor() {
|
|
142
|
+
var charUUID = UUID.generate('eDomoticz:customchar:TotalWaterFlow');
|
|
143
|
+
super('Flow Total', charUUID);
|
|
144
|
+
this.setProps({
|
|
145
|
+
format: Formats.FLOAT,
|
|
146
|
+
perms: [Perms.PAIRED_READ, Perms.NOTIFY],
|
|
147
|
+
unit: 'l'
|
|
148
|
+
});
|
|
149
|
+
this.value = this.getDefaultValue();
|
|
150
|
+
this.UUID = charUUID;
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// Custom SetPoint Minutes characteristic for TempOverride modes
|
|
155
|
+
eDomoticzServices.TempOverride = class extends Characteristic {
|
|
156
|
+
constructor() {
|
|
157
|
+
var charUUID = UUID.generate('eDomoticz:customchar:OverrideTime');
|
|
158
|
+
super('Override (Mins, 0 = Auto, 481 = Permanent)', charUUID);
|
|
159
|
+
this.setProps({
|
|
160
|
+
format: Formats.FLOAT,
|
|
161
|
+
maxValue: 481,
|
|
162
|
+
minValue: 0,
|
|
163
|
+
minStep: 1,
|
|
164
|
+
unit: 'mins',
|
|
165
|
+
perms: [Perms.PAIRED_READ, Perms.PAIRED_WRITE, Perms.NOTIFY]
|
|
166
|
+
});
|
|
167
|
+
this.value = this.getDefaultValue();
|
|
168
|
+
this.UUID = charUUID;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// Usage Meter Characteristics
|
|
173
|
+
eDomoticzServices.CurrentUsage = class extends Characteristic {
|
|
174
|
+
constructor() {
|
|
175
|
+
var charUUID = UUID.generate('eDomoticz:customchar:CurrentUsage');
|
|
176
|
+
super('Current Usage', charUUID);
|
|
177
|
+
this.setProps({
|
|
178
|
+
format: Formats.FLOAT,
|
|
179
|
+
unit: Units.PERCENTAGE,
|
|
180
|
+
perms: [Perms.PAIRED_READ, Perms.NOTIFY],
|
|
181
|
+
minValue: 0,
|
|
182
|
+
maxValue: 100,
|
|
183
|
+
minStep: 0.1
|
|
184
|
+
});
|
|
185
|
+
this.value = this.getDefaultValue();
|
|
186
|
+
this.UUID = charUUID;
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
// Location Characteristic (sensor should have 'Location' in title)
|
|
191
|
+
eDomoticzServices.Location = class extends Characteristic {
|
|
192
|
+
constructor() {
|
|
193
|
+
var charUUID = UUID.generate('eDomoticz:customchar:Location');
|
|
194
|
+
super('Location', charUUID);
|
|
195
|
+
this.setProps({
|
|
196
|
+
format: Formats.STRING,
|
|
197
|
+
perms: [Perms.PAIRED_READ, Perms.NOTIFY]
|
|
198
|
+
});
|
|
199
|
+
this.value = this.getDefaultValue();
|
|
200
|
+
this.UUID = charUUID;
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
// DarkSkies WindSpeed Characteristic
|
|
205
|
+
eDomoticzServices.WindSpeed = class extends Characteristic {
|
|
206
|
+
constructor() {
|
|
207
|
+
var charUUID = '49C8AE5A-A3A5-41AB-BF1F-12D5654F9F41';//'9331096F-E49E-4D98-B57B-57803498FA36'; //UUID.generate('eDomoticz:customchar:WindSpeed');
|
|
208
|
+
super('Wind Speed', charUUID);
|
|
209
|
+
this.setProps({
|
|
210
|
+
format: Formats.FLOAT,
|
|
211
|
+
perms: [Perms.PAIRED_READ, Perms.NOTIFY],
|
|
212
|
+
unit: 'm/s',
|
|
213
|
+
minValue: 0,
|
|
214
|
+
maxValue: 360,
|
|
215
|
+
minStep: 0.1
|
|
216
|
+
});
|
|
217
|
+
this.value = this.getDefaultValue();
|
|
218
|
+
this.UUID = charUUID;
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
// DarkSkies WindChill Characteristic
|
|
223
|
+
eDomoticzServices.WindChill = class extends Characteristic {
|
|
224
|
+
constructor() {
|
|
225
|
+
var charUUID = UUID.generate('eDomoticz:customchar:WindChill');
|
|
226
|
+
super('Wind Chill', charUUID);
|
|
227
|
+
this.setProps({
|
|
228
|
+
format: Formats.FLOAT,
|
|
229
|
+
perms: [Perms.PAIRED_READ, Perms.NOTIFY],
|
|
230
|
+
unit: Units.CELSIUS,
|
|
231
|
+
minValue: -50,
|
|
232
|
+
maxValue: 100,
|
|
233
|
+
minStep: 0.1
|
|
234
|
+
});
|
|
235
|
+
this.value = this.getDefaultValue();
|
|
236
|
+
this.UUID = charUUID;
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
// DarkSkies WindDirection Characteristic
|
|
241
|
+
eDomoticzServices.WindDirection = class extends Characteristic {
|
|
242
|
+
constructor() {
|
|
243
|
+
var charUUID = '46f1284c-1912-421b-82f5-eb75008b167e';//'6C3F6DFA-7340-4ED4-AFFD-0E0310ECCD9E'; //UUID.generate('eDomoticz:customchar:WindDirection');
|
|
244
|
+
super('Wind Direction', charUUID);
|
|
245
|
+
this.setProps({
|
|
246
|
+
format: Formats.INT,
|
|
247
|
+
perms: [Perms.PAIRED_READ, Perms.NOTIFY],
|
|
248
|
+
unit: Units.ARC_DEGREE,
|
|
249
|
+
minValue: 0,
|
|
250
|
+
maxValue: 360,
|
|
251
|
+
minStep: 1
|
|
252
|
+
});
|
|
253
|
+
this.value = this.getDefaultValue();
|
|
254
|
+
this.UUID = charUUID;
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
// DarkSkies Rain Characteristic
|
|
259
|
+
eDomoticzServices.Rainfall = class extends Characteristic {
|
|
260
|
+
constructor() {
|
|
261
|
+
var charUUID = 'ccc04890-565b-4376-b39a-3113341d9e0f';//'C53F35CE-C615-4AA4-9112-EBF679C5EB14'; //UUID.generate('eDomoticz:customchar:Rainfall');
|
|
262
|
+
super('Amount today', charUUID);
|
|
263
|
+
this.setProps({
|
|
264
|
+
format: Formats.FLOAT,
|
|
265
|
+
perms: [Perms.PAIRED_READ, Perms.NOTIFY],
|
|
266
|
+
unit: 'mm',
|
|
267
|
+
minValue: 0,
|
|
268
|
+
maxValue: 360,
|
|
269
|
+
minStep: 0.1
|
|
270
|
+
});
|
|
271
|
+
this.value = this.getDefaultValue();
|
|
272
|
+
this.UUID = charUUID;
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
// DarkSkies Visibility Characteristic
|
|
277
|
+
eDomoticzServices.Visibility = class extends Characteristic {
|
|
278
|
+
constructor() {
|
|
279
|
+
var charUUID = 'd24ecc1e-6fad-4fb5-8137-5af88bd5e857';//UUID.generate('eDomoticz:customchar:Visibility');
|
|
280
|
+
super('Distance', charUUID);
|
|
281
|
+
this.setProps({
|
|
282
|
+
format: Formats.FLOAT,
|
|
283
|
+
perms: [Perms.PAIRED_READ, Perms.NOTIFY],
|
|
284
|
+
unit: 'miles',
|
|
285
|
+
minValue: 0,
|
|
286
|
+
maxValue: 20,
|
|
287
|
+
minStep: 0.1
|
|
288
|
+
});
|
|
289
|
+
this.value = this.getDefaultValue();
|
|
290
|
+
this.UUID = charUUID;
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
// DarkSkies UVIndex Characteristic
|
|
295
|
+
eDomoticzServices.UVIndex = class extends Characteristic {
|
|
296
|
+
constructor() {
|
|
297
|
+
var charUUID = '05ba0fe0-b848-4226-906d-5b64272e05ce';//UUID.generate('eDomoticz:customchar:Visibility');
|
|
298
|
+
super('UVIndex', charUUID);
|
|
299
|
+
this.setProps({
|
|
300
|
+
format: Formats.FLOAT,
|
|
301
|
+
perms: [Perms.PAIRED_READ, Perms.NOTIFY],
|
|
302
|
+
unit: 'UVI',
|
|
303
|
+
minValue: 0,
|
|
304
|
+
maxValue: 20,
|
|
305
|
+
minStep: 0.1
|
|
306
|
+
});
|
|
307
|
+
this.value = this.getDefaultValue();
|
|
308
|
+
this.UUID = charUUID;
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
// DarkSkies Solar Radiation Characteristic
|
|
313
|
+
eDomoticzServices.SolRad = class extends Characteristic {
|
|
314
|
+
constructor() {
|
|
315
|
+
var charUUID = UUID.generate('eDomoticz:customchar:SolRad');
|
|
316
|
+
super('Radiation', charUUID);
|
|
317
|
+
this.setProps({
|
|
318
|
+
format: Formats.FLOAT,
|
|
319
|
+
unit: 'W/m2',
|
|
320
|
+
perms: [Perms.PAIRED_READ, Perms.NOTIFY],
|
|
321
|
+
minValue: 0,
|
|
322
|
+
maxValue: 10000,
|
|
323
|
+
minStep: 0.1
|
|
324
|
+
});
|
|
325
|
+
this.value = this.getDefaultValue();
|
|
326
|
+
this.UUID = charUUID;
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
// Barometer Characteristic
|
|
331
|
+
eDomoticzServices.Barometer = class extends Characteristic {
|
|
332
|
+
constructor() {
|
|
333
|
+
var charUUID = 'E863F10F-079E-48FF-8F27-9C2605A29F52';
|
|
334
|
+
super('Pressure', charUUID);
|
|
335
|
+
this.setProps({
|
|
336
|
+
format: Formats.FLOAT,
|
|
337
|
+
perms: [Perms.PAIRED_READ, Perms.NOTIFY],
|
|
338
|
+
unit: 'hPA',
|
|
339
|
+
minValue: 500,
|
|
340
|
+
maxValue: 2000,
|
|
341
|
+
minStep: 0.1
|
|
342
|
+
});
|
|
343
|
+
this.value = this.getDefaultValue();
|
|
344
|
+
this.UUID = charUUID;
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
// Infotext Characteristic (free-form string)
|
|
349
|
+
eDomoticzServices.Infotext = class extends Characteristic {
|
|
350
|
+
constructor() {
|
|
351
|
+
var charUUID = UUID.generate('eDomoticz:customchar:Infotext');
|
|
352
|
+
super('Infotext', charUUID);
|
|
353
|
+
this.setProps({
|
|
354
|
+
format: 'string',
|
|
355
|
+
perms: [Perms.PAIRED_READ, Perms.NOTIFY]
|
|
356
|
+
});
|
|
357
|
+
this.value = this.getDefaultValue();
|
|
358
|
+
this.UUID = charUUID;
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
/* ===== Custom Services (14) ===== */
|
|
363
|
+
|
|
364
|
+
// Ampere Meter
|
|
365
|
+
// NOTE: serviceUUID key intentionally shared with VOLT and Meter device
|
|
366
|
+
// services (historical upstream behaviour, differentiated by subtype).
|
|
367
|
+
eDomoticzServices.AMPDeviceService = class extends Service {
|
|
368
|
+
constructor(displayName, subtype) {
|
|
369
|
+
var serviceUUID = UUID.generate('eDomoticz:powermeter:customservice');
|
|
370
|
+
super(displayName, serviceUUID, subtype);
|
|
371
|
+
this.addCharacteristic(new eDomoticzServices.Ampere());
|
|
372
|
+
}
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
// Voltage Meter
|
|
376
|
+
eDomoticzServices.VOLTDeviceService = class extends Service {
|
|
377
|
+
constructor(displayName, subtype) {
|
|
378
|
+
var serviceUUID = UUID.generate('eDomoticz:powermeter:customservice');
|
|
379
|
+
super(displayName, serviceUUID, subtype);
|
|
380
|
+
this.addCharacteristic(new eDomoticzServices.Volt());
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
// The PowerMeter itself
|
|
385
|
+
eDomoticzServices.MeterDeviceService = class extends Service {
|
|
386
|
+
constructor(displayName, subtype) {
|
|
387
|
+
var serviceUUID = UUID.generate('eDomoticz:powermeter:customservice');
|
|
388
|
+
super(displayName, serviceUUID, subtype);
|
|
389
|
+
this.addCharacteristic(new eDomoticzServices.CurrentConsumption());
|
|
390
|
+
this.addOptionalCharacteristic(new eDomoticzServices.TotalConsumption());
|
|
391
|
+
this.addOptionalCharacteristic(new eDomoticzServices.TodayConsumption());
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
// Waterflow Meter
|
|
396
|
+
eDomoticzServices.WaterDeviceService = class extends Service {
|
|
397
|
+
constructor(displayName, subtype) {
|
|
398
|
+
var serviceUUID = UUID.generate('eDomoticz:watermeter:customservice');
|
|
399
|
+
super(displayName, serviceUUID, subtype);
|
|
400
|
+
this.addCharacteristic(new eDomoticzServices.WaterFlow());
|
|
401
|
+
this.addOptionalCharacteristic(new eDomoticzServices.TotalWaterFlow());
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
// P1 Smart Meter -> Gas
|
|
406
|
+
eDomoticzServices.GasDeviceService = class extends Service {
|
|
407
|
+
constructor(displayName, subtype) {
|
|
408
|
+
var serviceUUID = UUID.generate('eDomoticz:gasmeter:customservice');
|
|
409
|
+
super(displayName, serviceUUID, subtype);
|
|
410
|
+
this.addCharacteristic(new eDomoticzServices.GasConsumption());
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
// The Usage Meter itself
|
|
415
|
+
eDomoticzServices.UsageDeviceService = class extends Service {
|
|
416
|
+
constructor(displayName, subtype) {
|
|
417
|
+
var serviceUUID = UUID.generate('eDomoticz:usagedevice:customservice');
|
|
418
|
+
super(displayName, serviceUUID, subtype);
|
|
419
|
+
this.addCharacteristic(new eDomoticzServices.CurrentUsage());
|
|
420
|
+
}
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
eDomoticzServices.LocationService = class extends Service {
|
|
424
|
+
constructor(displayName, subtype) {
|
|
425
|
+
var serviceUUID = UUID.generate('eDomoticz:location:customservice');
|
|
426
|
+
super(displayName, serviceUUID, subtype);
|
|
427
|
+
this.addCharacteristic(new eDomoticzServices.Location());
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
// DarkSkies Virtual Wind Sensor
|
|
432
|
+
eDomoticzServices.WindDeviceService = class extends Service {
|
|
433
|
+
constructor(displayName, subtype) {
|
|
434
|
+
var serviceUUID = '2AFB775E-79E5-4399-B3CD-398474CAE86C'; //UUID.generate('eDomoticz:winddevice:customservice');
|
|
435
|
+
super(displayName, serviceUUID, subtype);
|
|
436
|
+
this.addCharacteristic(new eDomoticzServices.WindSpeed());
|
|
437
|
+
this.addOptionalCharacteristic(new eDomoticzServices.WindChill());
|
|
438
|
+
this.addOptionalCharacteristic(new eDomoticzServices.WindDirection());
|
|
439
|
+
this.addOptionalCharacteristic(new Characteristic.CurrentTemperature());
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
// DarkSkies Rain Meter itself
|
|
444
|
+
eDomoticzServices.RainDeviceService = class extends Service {
|
|
445
|
+
constructor(displayName, subtype) {
|
|
446
|
+
var serviceUUID = 'D92D5391-92AF-4824-AF4A-356F25F25EA1'; //UUID.generate('eDomoticz:raindevice:customservice');
|
|
447
|
+
super(displayName, serviceUUID, subtype);
|
|
448
|
+
this.addCharacteristic(new eDomoticzServices.Rainfall());
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
// DarkSkies Visibility Meter itself
|
|
453
|
+
eDomoticzServices.VisibilityDeviceService = class extends Service {
|
|
454
|
+
constructor(displayName, subtype) {
|
|
455
|
+
var serviceUUID = UUID.generate('eDomoticz:visibilitydevice:customservice');
|
|
456
|
+
super(displayName, serviceUUID, subtype);
|
|
457
|
+
this.addCharacteristic(new eDomoticzServices.Visibility());
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
// DarkSkies UV Index Meter itself
|
|
462
|
+
eDomoticzServices.UVDeviceService = class extends Service {
|
|
463
|
+
constructor(displayName, subtype) {
|
|
464
|
+
var serviceUUID = UUID.generate('eDomoticz:uvdevice:customservice');
|
|
465
|
+
super(displayName, serviceUUID, subtype);
|
|
466
|
+
this.addCharacteristic(new eDomoticzServices.UVIndex());
|
|
467
|
+
}
|
|
468
|
+
};
|
|
469
|
+
|
|
470
|
+
// DarkSkies Solar Radiation Meter itself
|
|
471
|
+
eDomoticzServices.SolRadDeviceService = class extends Service {
|
|
472
|
+
constructor(displayName, subtype) {
|
|
473
|
+
var serviceUUID = UUID.generate('eDomoticz:solraddevice:customservice');
|
|
474
|
+
super(displayName, serviceUUID, subtype);
|
|
475
|
+
this.addCharacteristic(new eDomoticzServices.SolRad());
|
|
476
|
+
}
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
// Weather Service (Temp + Humidity + Baro composite, surfaced as Eve Weather)
|
|
480
|
+
eDomoticzServices.WeatherService = class extends Service {
|
|
481
|
+
constructor(displayName, subtype) {
|
|
482
|
+
var serviceUUID = 'debf1b79-312e-47f7-bf82-993d9950f3a2';//'E863F001-079E-48FF-8F27-9C2605A29F52';
|
|
483
|
+
super(displayName, serviceUUID, subtype);
|
|
484
|
+
this.addCharacteristic(new Characteristic.CurrentTemperature());
|
|
485
|
+
this.addOptionalCharacteristic(new Characteristic.CurrentRelativeHumidity());
|
|
486
|
+
this.addOptionalCharacteristic(new eDomoticzServices.Barometer());
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
// Infotext Device Service
|
|
491
|
+
eDomoticzServices.InfotextDeviceService = class extends Service {
|
|
492
|
+
constructor(displayName, subtype) {
|
|
493
|
+
var serviceUUID = UUID.generate('eDomoticz:infotextdevice:customservice');
|
|
494
|
+
super(displayName, serviceUUID, subtype);
|
|
495
|
+
this.addCharacteristic(new eDomoticzServices.Infotext());
|
|
496
|
+
}
|
|
497
|
+
};
|
|
498
|
+
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "homebridge-edomoticz",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.4",
|
|
4
4
|
"description": "homebridge-plugin for Domoticz https://github.com/nfarina/homebridge",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "
|
|
7
|
+
"test": "node test/load-plugin.js"
|
|
8
8
|
},
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
@@ -17,14 +17,18 @@
|
|
|
17
17
|
"Domoticz"
|
|
18
18
|
],
|
|
19
19
|
"engines": {
|
|
20
|
-
"node": ">=
|
|
21
|
-
"homebridge": ">=0
|
|
20
|
+
"node": ">=18.15.0",
|
|
21
|
+
"homebridge": ">=1.8.0 || >=2.0.0"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"inherits": "^2.0.1",
|
|
25
25
|
"mqtt": "^2.15.0",
|
|
26
26
|
"request": "^2.81.0"
|
|
27
27
|
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@homebridge/hap-nodejs": "^2.1.0",
|
|
30
|
+
"homebridge": "^2.0.0"
|
|
31
|
+
},
|
|
28
32
|
"author": {
|
|
29
33
|
"name": "PatchworkBoy",
|
|
30
34
|
"url": "aka Marci"
|
|
@@ -36,7 +40,6 @@
|
|
|
36
40
|
"homepage": "https://github.com/patchworkboy/homebridge-eDomoticz#readme",
|
|
37
41
|
"readme": "# homebridge-eDomoticz\nA fully-fledged up-to-date Homebridge-Plugin\nfor use with [Homebridge](https://github.com/nfarina/homebridge) v0.2.1+\nand [Domoticz](https://github.com/domoticz/domoticz)\n\n##Supports:\n###Standard HomeKit Types:\n- Sockets (on/off) - Domoticz SwitchTypeVal: 0\n- Lamps (on/off) - Domoticz SwitchTypeVal: 0\n- Contact Sensors - Domoticz SwitchTypeVal: 2\n- Blinds - Domoticz SwitchTypeVal: 3\n- Smoke Detectors - Domoticz SwitchTypeVal: 5\n- Blinds (inverted) - Domoticz SwitchTypeVal: 6\n- Lamps (dimmer) - Domoticz SwitchTypeVal: 7\n- Motion Sensors - Domoticz SwitchTypeVal: 8\n- Push Switches - Domoticz SwitchTypeVal: 9\n- Lock Mechanisms - Domoticz SwitchTypeVal: 11\n- Blinds (%) - Domoticz SwitchTypeVal: 13\n- Blinds (& inverted) - Domoticz SwitchTypeVal: 16\n\n##Provides:\n###Custom HomeKit Types:\n- General kWh power meters - Types: General, Current; SubType: kWh, mapped to Eve chars where possible\n- CurrentCost USB power meter - Type: Usage, SubType: Electric, mapped to Eve chars where possible\n- P1 Smart Meter (Electric & Gas), mapped to Eve chars where possible\n- EvoHome** / OpenTherm Thermostat support - Types: Heating, Thermostat; SubTypes: Zone, SetPoint\n- YouLess Meter (Current, Total and Today Total Consumption) - Type: YouLess Meter; SubType: YouLess counter, mapped to Eve chars where possible\n- General Usage % meters (eg: Motherboard Sensors Hardware Device - CPU %, Mem %, HDD % etc) - Type: General; SubType: Percentage\n- Temperature, Temp + Humidity, Temp + Humidity + Baro (Current Temperature, Current Humidity, Current Pressure in hPA) - Type: Temp, Temp + Humidty, Temp + Humidity + Baro [id'd as Eve Weather]\n- DarkSkies Virtual Weather Station Sensors (Wind, Solar Radiation, Rainfall, Visibility, Barometer [id'd as Eve Weather])\n\n** assumes the EvoHome has been setup according to [this script method](https://www.domoticz.com/wiki/Evohome#Scripting_for_RFG100).\n\n###Todo:\n- [ ] homebridge [plugin 2.0](https://github.com/nfarina/homebridge/pull/497) support\n- [x] MQTT-based realtime updates\n- [x] Hue/RGB\n- [x] Blinds\n- [x] m3 (gas usage)\n- [x] Motion sensors\n- [x] Smoke Detectors\n- [x] Brightness/Dimming\n- [x] kWh (electricity usage)\n- [x] General % usage\n- [x] Humidity\n- [x] Pressure\n- [x] YouLess Meter\n- [x] Open/Closed contact sensors\n- [ ] ...more sensors (ongoing)!\n\n## Installation\n```\nsudo npm install -g homebridge-edomoticz\n```\n\n## Update\n```\nsudo npm update -g homebridge-edomoticz\n```\n\n## Configuration\n\n~/.homebridge/config.json example:\n```\n{\n \"bridge\": {\n \"name\": \"Homebridge\",\n \"username\": \"CC:21:3E:E4:DE:33\",\n \"port\": 51826,\n \"pin\": \"031-45-154\"\n },\n \"description\": \"Configuration file for (e)xtended Domoticz platform.\",\n \"platforms\": [\n {\n \"platform\": \"eDomoticz\",\n \"name\": \"eDomoticz\",\n \"server\": \"127.0.0.1\",\n \"port\": \"8080\",\n \"ssl\": 0,\n \"roomid\": 0,\n \"mqttenable\": 1,\n \"mqttserver\": \"127.0.0.1\",\n \"mqttport\": \"1883\",\n \"mqttauth\": 0,\n \"mqttuser\": \"\",\n \"mqttpass\": \"\"\n }\n ],\n \"accessories\": []\n}\n```\n\n## Tips\n\n### Authentication\nIf Domoticz is set up to use basic or form login authentication, set \"server\":\"user:pass@ip\" within config.json. The plugin will internally extract the username and password, base64 encode it and send it as a http authorization header whenever it talks to your Domoticz server.\n\n### SSL\nSet \"ssl\":1 in config.json to turn on SSL (ie: server connects with https:// rather than http://). You will need to specify your SSL port - usually \"port\":\"443\" by default.\n\n### Issues pairing to Homebridge when you have a lot of Domoticz sensors...\nIf you have more than 100 devices in Domoticz, you need to limit the number of devices exposed to HomeKit (HomeKit only supports 100 Accessories on a single bridge - whilst we could combine multiple sensors into a single homekit accessory within the plugin, the possible combinations out there are endless, so we won't).\n\nTherefore, to reduce the number of devices exposed from Domoticz, create a roomplan within Domoticz via Setup > More Options > Plans > roomplan. Add only the devices you wish to be exposed to HomeKit to this new roomplan within Domoticz, and then get it's roomidx number. Set \"roomid\" in your config.json file to this room number.\n\n### Is my <<some accessory>> supported??\nSee [Domoticz API Reference](https://www.domoticz.com/wiki/Domoticz_API/JSON_URL's#Retrieve_status_of_specific_device) - query your device as per the instructions there, and if your device’s SwitchTypeVal isn't in the 'Supports:' list or Type/SubType aren’t in the ’Provides:' list above then it'll just appear as an On/Off switch. [Open a new issue](https://github.com/PatchworkBoy/homebridge-eDomoticz/issues/new) including the output from the json api and I’ll get look into supporting that particular device more fully!\n\n### What does the Override slider represent on the EvoHome Thermostat?\nOverride-Until time in minutes from the current time. Allows setting an override-until time upto 8 hours in the future. Setting this slider to 0 will set the heating mode to Auto. Setting it to 481 will set the override as a PermanentOverride.\n\n### Logging\nComplies with Homebridge's native logging & debugging methodology - see https://github.com/nfarina/homebridge/wiki/Basic-Trouble-Shooting\n",
|
|
38
42
|
"readmeFilename": "README.md",
|
|
39
|
-
"_id": "homebridge-edomoticz@2.1.8",
|
|
40
43
|
"_from": "homebridge-edomoticz",
|
|
41
44
|
"_resolved": "file:homebridge-edomoticz"
|
|
42
45
|
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/*
|
|
3
|
+
* test/load-plugin.js
|
|
4
|
+
*
|
|
5
|
+
* Smoke test for the Homebridge 2.x / HAP-NodeJS v2 compatibility migration.
|
|
6
|
+
*
|
|
7
|
+
* It does NOT load the full plugin (index.js) on purpose: index.js pulls
|
|
8
|
+
* domoticz_accessory.js + request + mqtt etc., and we want a focused check
|
|
9
|
+
* on the migration itself. Instead it replicates what index.js does on
|
|
10
|
+
* startup -- read Service/Characteristic/uuid from HAP, call initServices --
|
|
11
|
+
* and then instantiates a representative battery of subclasses.
|
|
12
|
+
*
|
|
13
|
+
* The original v2.1.50 plugin crashed under HAP-NodeJS v2 with:
|
|
14
|
+
* TypeError: Class constructor Service cannot be invoked without 'new'
|
|
15
|
+
* at new eDomoticzServices.MeterDeviceService (lib/services.js:133:13)
|
|
16
|
+
* This test will catch any regression of that bug.
|
|
17
|
+
*
|
|
18
|
+
* Coverage:
|
|
19
|
+
* - Characteristic with fixed Eve UUID -> CurrentConsumption
|
|
20
|
+
* - Characteristic with UUID.generate -> TodayConsumption
|
|
21
|
+
* - Characteristic with historical UUID collision -> GasConsumption
|
|
22
|
+
* - The 3 Services that share 'eDomoticz:powermeter:customservice'
|
|
23
|
+
* (differentiated only by subtype) -> AMP / VOLT / Meter
|
|
24
|
+
* - Service with fixed UUID -> WindDeviceService
|
|
25
|
+
* - Service that composes a HAP stock Characteristic
|
|
26
|
+
* (Characteristic.CurrentTemperature) -> WeatherService
|
|
27
|
+
*
|
|
28
|
+
* Exit codes:
|
|
29
|
+
* 0 -> all instantiations succeeded
|
|
30
|
+
* 2 -> @homebridge/hap-nodejs not installed (run `npm install` first)
|
|
31
|
+
* 3 -> initServices threw
|
|
32
|
+
* 1 -> at least one instantiation threw
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
let hap;
|
|
36
|
+
try {
|
|
37
|
+
hap = require('@homebridge/hap-nodejs');
|
|
38
|
+
} catch (e) {
|
|
39
|
+
console.error('FAIL: @homebridge/hap-nodejs is not installed. Run `npm install` first.');
|
|
40
|
+
console.error(e && e.stack ? e.stack : e);
|
|
41
|
+
process.exit(2);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 1. Load the migrated services module
|
|
45
|
+
const Services = require('../lib/services.js');
|
|
46
|
+
|
|
47
|
+
// 2. Replicate what index.js does on startup: hand HAP refs to the factory.
|
|
48
|
+
// The 4th argument (the hap module itself) lets initServices resolve the
|
|
49
|
+
// Formats/Perms/Units enums under HAP v2, where they live on the module
|
|
50
|
+
// root rather than on the Characteristic class.
|
|
51
|
+
try {
|
|
52
|
+
Services.initServices(hap.Service, hap.Characteristic, hap.uuid, hap);
|
|
53
|
+
} catch (e) {
|
|
54
|
+
console.error('FAIL: Services.initServices threw.');
|
|
55
|
+
console.error(e && e.stack ? e.stack : e);
|
|
56
|
+
process.exit(3);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const eDomoticzServices = Services.eDomoticzServices;
|
|
60
|
+
|
|
61
|
+
// 3. Instantiate representatives
|
|
62
|
+
const cases = [
|
|
63
|
+
// --- Characteristics ---
|
|
64
|
+
{
|
|
65
|
+
label: 'Characteristic, fixed Eve UUID (CurrentConsumption)',
|
|
66
|
+
run: function () { return new eDomoticzServices.CurrentConsumption(); },
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
label: 'Characteristic, UUID.generate (TodayConsumption)',
|
|
70
|
+
run: function () { return new eDomoticzServices.TodayConsumption(); },
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
label: 'Characteristic, historical UUID collision (GasConsumption)',
|
|
74
|
+
run: function () { return new eDomoticzServices.GasConsumption(); },
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
// --- The 3 Services sharing UUID 'eDomoticz:powermeter:customservice' ---
|
|
78
|
+
{
|
|
79
|
+
label: "Service, shared UUID key, subtype='sub-amp' (AMPDeviceService)",
|
|
80
|
+
run: function () { return new eDomoticzServices.AMPDeviceService('AMP', 'sub-amp'); },
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
label: "Service, shared UUID key, subtype='sub-volt' (VOLTDeviceService)",
|
|
84
|
+
run: function () { return new eDomoticzServices.VOLTDeviceService('VOLT', 'sub-volt'); },
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
label: "Service, shared UUID key, subtype='sub-meter' (MeterDeviceService) -- original crash site",
|
|
88
|
+
run: function () { return new eDomoticzServices.MeterDeviceService('Meter', 'sub-meter'); },
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
// --- Other shapes ---
|
|
92
|
+
{
|
|
93
|
+
label: 'Service, fixed UUID (WindDeviceService)',
|
|
94
|
+
run: function () { return new eDomoticzServices.WindDeviceService('Wind', 'sub-wind'); },
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
label: 'Service composing HAP stock + custom Characteristic (WeatherService)',
|
|
98
|
+
run: function () { return new eDomoticzServices.WeatherService('Weather', 'sub-weather'); },
|
|
99
|
+
},
|
|
100
|
+
];
|
|
101
|
+
|
|
102
|
+
let ok = 0;
|
|
103
|
+
let failed = 0;
|
|
104
|
+
const collisionUUIDs = [];
|
|
105
|
+
|
|
106
|
+
for (const c of cases) {
|
|
107
|
+
try {
|
|
108
|
+
const inst = c.run();
|
|
109
|
+
if (!inst) throw new Error('instance is falsy');
|
|
110
|
+
ok++;
|
|
111
|
+
// Capture the UUID of the three colliding services so we can assert
|
|
112
|
+
// afterwards that they really do share the same UUID and differ only
|
|
113
|
+
// in subtype (the historical upstream invariant).
|
|
114
|
+
if (/AMPDeviceService|VOLTDeviceService|MeterDeviceService/.test(c.label)) {
|
|
115
|
+
collisionUUIDs.push({ label: c.label.split(' (')[1].replace(')', ''), uuid: inst.UUID, subtype: inst.subtype });
|
|
116
|
+
}
|
|
117
|
+
console.log(' OK ' + c.label + ' -> UUID=' + inst.UUID + (inst.subtype ? ', subtype=' + inst.subtype : ''));
|
|
118
|
+
} catch (e) {
|
|
119
|
+
failed++;
|
|
120
|
+
const stack = e && e.stack ? e.stack.split('\n').slice(0, 4).join('\n ') : String(e);
|
|
121
|
+
console.error(' FAIL ' + c.label);
|
|
122
|
+
console.error(' ' + stack);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Assert every custom Characteristic is readable on the wire.
|
|
127
|
+
// HAP-NodeJS v2 removed the deprecated Perms.READ / Perms.WRITE aliases
|
|
128
|
+
// (only PAIRED_READ / PAIRED_WRITE remain), so a stale alias silently
|
|
129
|
+
// resolves to undefined and the characteristic is published with
|
|
130
|
+
// perms [null, "ev"]. iOS rejects the whole bridge at pairing with
|
|
131
|
+
// "Accessory out of compliance" (upstream PR #297 report), and HAP-NodeJS
|
|
132
|
+
// itself answers reads with WRITE_ONLY_CHARACTERISTIC. Regression guard.
|
|
133
|
+
{
|
|
134
|
+
const hapPerms = hap.Perms || (hap.Characteristic && hap.Characteristic.Perms);
|
|
135
|
+
const PR = hapPerms.PAIRED_READ;
|
|
136
|
+
let checked = 0;
|
|
137
|
+
let bad = [];
|
|
138
|
+
for (const name of Object.keys(eDomoticzServices)) {
|
|
139
|
+
const Ctor = eDomoticzServices[name];
|
|
140
|
+
if (typeof Ctor !== 'function' || !(Ctor.prototype instanceof hap.Characteristic)) continue;
|
|
141
|
+
const inst = new Ctor();
|
|
142
|
+
checked++;
|
|
143
|
+
const perms = (inst.props && inst.props.perms) || [];
|
|
144
|
+
if (perms.some(function (x) { return x == null; }) || perms.indexOf(PR) === -1) {
|
|
145
|
+
bad.push(name + ' perms=' + JSON.stringify(perms));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (bad.length) {
|
|
149
|
+
failed++;
|
|
150
|
+
console.error(' FAIL perms invariant: ' + bad.length + ' custom Characteristic(s) not readable / have null perms:');
|
|
151
|
+
bad.forEach(function (b) { console.error(' ' + b); });
|
|
152
|
+
} else {
|
|
153
|
+
console.log(' OK perms invariant: ' + checked + ' custom Characteristics all carry PAIRED_READ and no null perms');
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Assert cached characteristics with poisoned perms get healed on restore.
|
|
158
|
+
// Simulates what Homebridge hands to configureAccessory: a PlatformAccessory
|
|
159
|
+
// whose services were deserialized from cachedAccessories, where custom
|
|
160
|
+
// characteristics are generic hap.Characteristic instances carrying the
|
|
161
|
+
// persisted props. A cache written by 3.0.0-3.0.2 under HAP v2 has
|
|
162
|
+
// perms [null, "ev"]; Helper.healCustomCharacteristicPerms must fix exactly
|
|
163
|
+
// those and leave healthy ones (and non-perms props) alone.
|
|
164
|
+
{
|
|
165
|
+
const Helper = require('../lib/helper.js').Helper;
|
|
166
|
+
const hapPerms = hap.Perms || (hap.Characteristic && hap.Characteristic.Perms);
|
|
167
|
+
const PR = hapPerms.PAIRED_READ;
|
|
168
|
+
const good = new eDomoticzServices.Barometer();
|
|
169
|
+
const poisoned = hap.Characteristic.deserialize({
|
|
170
|
+
displayName: good.displayName,
|
|
171
|
+
UUID: good.UUID,
|
|
172
|
+
props: { format: good.props.format, unit: good.props.unit, perms: [null, 'ev'] },
|
|
173
|
+
value: 1013,
|
|
174
|
+
});
|
|
175
|
+
const healthy = hap.Characteristic.deserialize({
|
|
176
|
+
displayName: 'Consumption',
|
|
177
|
+
UUID: new eDomoticzServices.CurrentConsumption().UUID,
|
|
178
|
+
props: { format: 'float', unit: 'W', perms: [PR, 'ev'] },
|
|
179
|
+
value: 12,
|
|
180
|
+
});
|
|
181
|
+
const svc = new hap.Service('Cached Weather', new eDomoticzServices.WeatherService('x').UUID, 'sub');
|
|
182
|
+
svc.addCharacteristic(poisoned);
|
|
183
|
+
svc.addCharacteristic(healthy);
|
|
184
|
+
const fakePlatformAccessory = { services: [svc] };
|
|
185
|
+
|
|
186
|
+
const healed = Helper.healCustomCharacteristicPerms(fakePlatformAccessory, eDomoticzServices, hap.Characteristic, PR);
|
|
187
|
+
const after = poisoned.props.perms;
|
|
188
|
+
const problems = [];
|
|
189
|
+
if (healed !== 1) problems.push('expected exactly 1 healed characteristic, got ' + healed);
|
|
190
|
+
if (after.indexOf(PR) === -1 || after.some(function (x) { return x == null; })) problems.push('poisoned perms not repaired: ' + JSON.stringify(after));
|
|
191
|
+
if (poisoned.props.unit !== good.props.unit) problems.push('unit was altered: ' + poisoned.props.unit);
|
|
192
|
+
if (JSON.stringify(healthy.props.perms) !== JSON.stringify([PR, 'ev'])) problems.push('healthy perms were altered: ' + JSON.stringify(healthy.props.perms));
|
|
193
|
+
const second = Helper.healCustomCharacteristicPerms(fakePlatformAccessory, eDomoticzServices, hap.Characteristic, PR);
|
|
194
|
+
if (second !== 0) problems.push('heal is not idempotent, second pass healed ' + second);
|
|
195
|
+
if (problems.length) {
|
|
196
|
+
failed++;
|
|
197
|
+
console.error(' FAIL cache heal:');
|
|
198
|
+
problems.forEach(function (m) { console.error(' ' + m); });
|
|
199
|
+
} else {
|
|
200
|
+
console.log(' OK cache heal: poisoned [null,"ev"] -> ' + JSON.stringify(after) + ', healthy untouched, idempotent');
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Assert the historical collision is preserved: same UUID across the 3
|
|
205
|
+
// services, distinct subtypes.
|
|
206
|
+
if (failed === 0 && collisionUUIDs.length === 3) {
|
|
207
|
+
const uniqueUUIDs = new Set(collisionUUIDs.map(function (x) { return x.uuid; }));
|
|
208
|
+
const uniqueSubtypes = new Set(collisionUUIDs.map(function (x) { return x.subtype; }));
|
|
209
|
+
if (uniqueUUIDs.size !== 1) {
|
|
210
|
+
failed++;
|
|
211
|
+
console.error(' FAIL collision invariant: the 3 powermeter services should share one UUID, got ' + uniqueUUIDs.size + ' distinct UUIDs.');
|
|
212
|
+
} else if (uniqueSubtypes.size !== 3) {
|
|
213
|
+
failed++;
|
|
214
|
+
console.error(' FAIL collision invariant: subtypes should be distinct, got ' + uniqueSubtypes.size + '.');
|
|
215
|
+
} else {
|
|
216
|
+
console.log(' OK collision invariant: 3 services share UUID ' + Array.from(uniqueUUIDs)[0] + ' with 3 distinct subtypes');
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (failed) {
|
|
221
|
+
console.error('\n' + failed + ' check(s) failed.');
|
|
222
|
+
process.exit(1);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
console.log('\nOK: ' + ok + ' instanciaciones completadas');
|
|
226
|
+
console.log('Carga + instanciacion OK');
|
|
227
|
+
process.exit(0);
|
package/.npmignore
DELETED