@homebridge-plugins/homebridge-tado 6.0.14

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.
Files changed (38) hide show
  1. package/CHANGELOG.md +152 -0
  2. package/LICENSE +21 -0
  3. package/README.md +560 -0
  4. package/config.schema.json +878 -0
  5. package/homebridge-ui/public/css/style.css +25 -0
  6. package/homebridge-ui/public/images/tado_logo.png +0 -0
  7. package/homebridge-ui/public/index.html +118 -0
  8. package/homebridge-ui/public/js/main.js +1582 -0
  9. package/homebridge-ui/public/js/modules/compareVersions.min.js +1 -0
  10. package/homebridge-ui/public/js/modules/jquery.min.js +2 -0
  11. package/homebridge-ui/public/js/modules/progressbar.min.js +6 -0
  12. package/homebridge-ui/public/js/progressbars.js +48 -0
  13. package/homebridge-ui/public/js/schema.js +864 -0
  14. package/homebridge-ui/server.js +80 -0
  15. package/images/tado_logo.png +0 -0
  16. package/index.js +14 -0
  17. package/package.json +66 -0
  18. package/src/accessories/airquality.js +56 -0
  19. package/src/accessories/contact.js +124 -0
  20. package/src/accessories/faucet.js +63 -0
  21. package/src/accessories/heatercooler.js +333 -0
  22. package/src/accessories/humidity.js +90 -0
  23. package/src/accessories/lightbulb.js +59 -0
  24. package/src/accessories/lightsensor.js +40 -0
  25. package/src/accessories/motion.js +79 -0
  26. package/src/accessories/occupancy.js +45 -0
  27. package/src/accessories/security.js +79 -0
  28. package/src/accessories/switch.js +261 -0
  29. package/src/accessories/temperature.js +95 -0
  30. package/src/accessories/thermostat.js +337 -0
  31. package/src/helper/handler.js +1467 -0
  32. package/src/helper/logger.js +51 -0
  33. package/src/helper/telegram.js +60 -0
  34. package/src/platform.js +337 -0
  35. package/src/tado/tado-api.js +404 -0
  36. package/src/tado/tado-config.js +1032 -0
  37. package/src/types/custom.js +264 -0
  38. package/src/types/eve.js +337 -0
@@ -0,0 +1,333 @@
1
+ 'use strict';
2
+
3
+ const Logger = require('../helper/logger.js');
4
+
5
+ const moment = require('moment');
6
+
7
+ const timeout = (ms) => new Promise((res) => setTimeout(res, ms));
8
+
9
+ class HeaterCoolerAccessory {
10
+ constructor(api, accessory, accessories, tado, deviceHandler, FakeGatoHistoryService) {
11
+ this.api = api;
12
+ this.accessory = accessory;
13
+ this.accessories = accessories;
14
+ this.FakeGatoHistoryService = FakeGatoHistoryService;
15
+
16
+ this.deviceHandler = deviceHandler;
17
+ this.tado = tado;
18
+
19
+ this.autoDelayTimeout = null;
20
+
21
+ this.getService();
22
+ }
23
+
24
+ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
25
+ // Services
26
+ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
27
+
28
+ async getService() {
29
+ let service = this.accessory.getService(this.api.hap.Service.HeaterCooler);
30
+ let serviceThermostat = this.accessory.getService(this.api.hap.Service.Thermostat);
31
+ let serviceSwitch = this.accessory.getService(this.api.hap.Service.Switch);
32
+ let serviceFaucet = this.accessory.getService(this.api.hap.Service.Valve);
33
+
34
+ if (serviceThermostat) {
35
+ Logger.info('Removing Thermostat service', this.accessory.displayName);
36
+ this.accessory.removeService(serviceThermostat);
37
+ }
38
+
39
+ if (serviceSwitch) {
40
+ Logger.info('Removing Switch service', this.accessory.displayName);
41
+ this.accessory.removeService(serviceSwitch);
42
+ }
43
+
44
+ if (serviceFaucet) {
45
+ Logger.info('Removing Faucet service', this.accessory.displayName);
46
+ this.accessory.removeService(serviceFaucet);
47
+ }
48
+
49
+ if (!service) {
50
+ Logger.info('Adding HeaterCooler service', this.accessory.displayName);
51
+ service = this.accessory.addService(
52
+ this.api.hap.Service.HeaterCooler,
53
+ this.accessory.displayName,
54
+ this.accessory.context.config.subtype
55
+ );
56
+ }
57
+
58
+ let batteryService = this.accessory.getService(this.api.hap.Service.BatteryService);
59
+
60
+ if (!this.accessory.context.config.noBattery && this.accessory.context.config.type === 'HEATING') {
61
+ if (!batteryService) {
62
+ Logger.info('Adding Battery service', this.accessory.displayName);
63
+ batteryService = this.accessory.addService(this.api.hap.Service.BatteryService);
64
+ }
65
+ batteryService.setCharacteristic(
66
+ this.api.hap.Characteristic.ChargingState,
67
+ this.api.hap.Characteristic.ChargingState.NOT_CHARGEABLE
68
+ );
69
+ } else {
70
+ if (batteryService) {
71
+ Logger.info('Removing Battery service', this.accessory.displayName);
72
+ this.accessory.removeService(batteryService);
73
+ }
74
+ }
75
+
76
+ //Handle AirQuality
77
+ if (this.accessory.context.config.airQuality && this.accessory.context.config.type !== 'HOT_WATER') {
78
+ if (!service.testCharacteristic(this.api.hap.Characteristic.AirQuality))
79
+ service.addCharacteristic(this.api.hap.Characteristic.AirQuality);
80
+ } else {
81
+ if (service.testCharacteristic(this.api.hap.Characteristic.AirQuality))
82
+ service.removeCharacteristic(service.getCharacteristic(this.api.hap.Characteristic.AirQuality));
83
+ }
84
+
85
+ //Handle DelaySwitch
86
+ if (this.accessory.context.config.delaySwitch && this.accessory.context.config.type !== 'HOT_WATER') {
87
+ if (!service.testCharacteristic(this.api.hap.Characteristic.DelaySwitch))
88
+ service.addCharacteristic(this.api.hap.Characteristic.DelaySwitch);
89
+
90
+ if (!service.testCharacteristic(this.api.hap.Characteristic.DelayTimer))
91
+ service.addCharacteristic(this.api.hap.Characteristic.DelayTimer);
92
+
93
+ if (this.accessory.context.config.autoOffDelay) {
94
+ service
95
+ .getCharacteristic(this.api.hap.Characteristic.DelaySwitch)
96
+ .onSet((value) => {
97
+ if (value && this.accessory.context.delayTimer) {
98
+ this.autoDelayTimeout = setTimeout(() => {
99
+ Logger.info('Timer expired, turning off delay switch', this.accessory.displayName);
100
+ service.getCharacteristic(this.api.hap.Characteristic.DelaySwitch).updateValue(false);
101
+ this.autoDelayTimeout = null;
102
+ }, this.accessory.context.delayTimer * 1000);
103
+ } else {
104
+ if (this.autoDelayTimeout) {
105
+ clearTimeout(this.autoDelayTimeout);
106
+ this.autoDelayTimeout = null;
107
+ }
108
+ }
109
+ })
110
+ .updateValue(false);
111
+ } else {
112
+ service
113
+ .getCharacteristic(this.api.hap.Characteristic.DelaySwitch)
114
+ .onGet(() => {
115
+ return this.accessory.context.delaySwitch || false;
116
+ })
117
+ .onSet((value) => {
118
+ this.accessory.context.delaySwitch = value;
119
+ });
120
+ }
121
+
122
+ service
123
+ .getCharacteristic(this.api.hap.Characteristic.DelayTimer)
124
+ .onGet(() => {
125
+ return this.accessory.context.delayTimer || 0;
126
+ })
127
+ .onSet((value) => {
128
+ this.accessory.context.delayTimer = value;
129
+ });
130
+ } else {
131
+ if (service.testCharacteristic(this.api.hap.Characteristic.DelaySwitch))
132
+ service.removeCharacteristic(service.getCharacteristic(this.api.hap.Characteristic.DelaySwitch));
133
+
134
+ if (service.testCharacteristic(this.api.hap.Characteristic.DelayTimer))
135
+ service.removeCharacteristic(service.getCharacteristic(this.api.hap.Characteristic.DelayTimer));
136
+ }
137
+
138
+ if (!service.testCharacteristic(this.api.hap.Characteristic.HeatingThresholdTemperature))
139
+ service.addCharacteristic(this.api.hap.Characteristic.HeatingThresholdTemperature);
140
+
141
+ if (this.accessory.context.config.type === 'HEATING') {
142
+ if (!service.testCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature))
143
+ service.addCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature);
144
+
145
+ if (!this.accessory.context.config.separateHumidity) {
146
+ if (!service.testCharacteristic(this.api.hap.Characteristic.CurrentRelativeHumidity))
147
+ service.addCharacteristic(this.api.hap.Characteristic.CurrentRelativeHumidity);
148
+ } else {
149
+ if (service.testCharacteristic(this.api.hap.Characteristic.CurrentRelativeHumidity))
150
+ service.removeCharacteristic(service.getCharacteristic(this.api.hap.Characteristic.CurrentRelativeHumidity));
151
+ }
152
+ } else {
153
+ if (service.testCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature))
154
+ service.removeCharacteristic(
155
+ service.getCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature)
156
+ );
157
+ }
158
+
159
+ let minValue =
160
+ this.accessory.context.config.type === 'HOT_WATER'
161
+ ? this.accessory.context.config.temperatureUnit === 'CELSIUS'
162
+ ? 30
163
+ : 86
164
+ : this.accessory.context.config.temperatureUnit === 'CELSIUS'
165
+ ? 5
166
+ : 41;
167
+
168
+ let maxValue =
169
+ this.accessory.context.config.type === 'HOT_WATER'
170
+ ? this.accessory.context.config.temperatureUnit === 'CELSIUS'
171
+ ? 65
172
+ : 149
173
+ : this.accessory.context.config.temperatureUnit === 'CELSIUS'
174
+ ? 25
175
+ : 77;
176
+
177
+ minValue = this.accessory.context.config.minValue < maxValue ? this.accessory.context.config.minValue : minValue;
178
+
179
+ maxValue = this.accessory.context.config.maxValue > minValue ? this.accessory.context.config.maxValue : maxValue;
180
+
181
+ console.log('Before MINSTEP: ' + this.accessory.context.config.minStep, this.accessory.displayName);
182
+
183
+ let minStep = parseFloat(
184
+ (this.accessory.context.config.minStep &&
185
+ !isNaN(this.accessory.context.config.minStep) &&
186
+ this.accessory.context.config.minStep > 0 &&
187
+ this.accessory.context.config.minStep <= 1
188
+ ? parseFloat(this.accessory.context.config.minStep)
189
+ : 1
190
+ ).toFixed(2)
191
+ );
192
+
193
+ console.log('After MINSTEP: ' + minStep, this.accessory.displayName);
194
+
195
+ let maxState = this.accessory.context.config.type === 'HOT_WATER' ? 2 : 3;
196
+
197
+ let validState = this.accessory.context.config.type === 'HOT_WATER' ? [0, 1, 2] : [0, 1, 2, 3];
198
+
199
+ if (service.getCharacteristic(this.api.hap.Characteristic.CurrentHeaterCoolerState).value > maxState)
200
+ service.getCharacteristic(this.api.hap.Characteristic.CurrentHeaterCoolerState).updateValue(maxState);
201
+
202
+ service.getCharacteristic(this.api.hap.Characteristic.CurrentHeaterCoolerState).setProps({
203
+ maxValue: maxState,
204
+ minValue: 0,
205
+ validValues: validState,
206
+ });
207
+
208
+ service.getCharacteristic(this.api.hap.Characteristic.TargetHeaterCoolerState).updateValue(1);
209
+
210
+ service.getCharacteristic(this.api.hap.Characteristic.TargetHeaterCoolerState).setProps({
211
+ maxValue: 1,
212
+ minValue: 1,
213
+ validValues: [1],
214
+ });
215
+
216
+ service.getCharacteristic(this.api.hap.Characteristic.CurrentTemperature).setProps({
217
+ minValue: -255,
218
+ maxValue: 255,
219
+ });
220
+
221
+ if (service.getCharacteristic(this.api.hap.Characteristic.HeatingThresholdTemperature).value < minValue)
222
+ service.getCharacteristic(this.api.hap.Characteristic.HeatingThresholdTemperature).updateValue(minValue);
223
+
224
+ if (service.getCharacteristic(this.api.hap.Characteristic.HeatingThresholdTemperature).value > maxValue)
225
+ service.getCharacteristic(this.api.hap.Characteristic.HeatingThresholdTemperature).updateValue(maxValue);
226
+
227
+ service.getCharacteristic(this.api.hap.Characteristic.HeatingThresholdTemperature).setProps({
228
+ minValue: minValue,
229
+ maxValue: maxValue,
230
+ minStep: minStep,
231
+ });
232
+
233
+ if (this.accessory.context.config.type === 'HEATING') {
234
+ if (service.getCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature).value < minValue)
235
+ service.getCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature).updateValue(minValue);
236
+
237
+ if (service.getCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature).value > maxValue)
238
+ service.getCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature).updateValue(maxValue);
239
+
240
+ service.getCharacteristic(this.api.hap.Characteristic.CoolingThresholdTemperature).setProps({
241
+ minValue: minValue,
242
+ maxValue: maxValue,
243
+ minStep: minStep,
244
+ });
245
+ }
246
+
247
+ if (!service.testCharacteristic(this.api.hap.Characteristic.ValvePosition))
248
+ service.addCharacteristic(this.api.hap.Characteristic.ValvePosition);
249
+
250
+ this.historyService = new this.FakeGatoHistoryService('thermo', this.accessory, {
251
+ storage: 'fs',
252
+ path: this.api.user.storagePath(),
253
+ disableTimer: true,
254
+ });
255
+
256
+ await timeout(250); //wait for historyService to load
257
+
258
+ service
259
+ .getCharacteristic(this.api.hap.Characteristic.Active)
260
+ .onSet((value) => {
261
+ if (this.waitForEndValue) {
262
+ clearTimeout(this.waitForEndValue);
263
+ this.waitForEndValue = null;
264
+ }
265
+
266
+ this.waitForEndValue = setTimeout(() => {
267
+ this.deviceHandler.setStates(this.accessory, this.accessories, 'State', value);
268
+ }, 500);
269
+ })
270
+ .on(
271
+ 'change',
272
+ this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName)
273
+ );
274
+
275
+ service
276
+ .getCharacteristic(this.api.hap.Characteristic.CurrentTemperature)
277
+ .on(
278
+ 'change',
279
+ this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName)
280
+ );
281
+
282
+ service
283
+ .getCharacteristic(this.api.hap.Characteristic.HeatingThresholdTemperature)
284
+ .onSet((value) => {
285
+ if (this.waitForEndValue) {
286
+ clearTimeout(this.waitForEndValue);
287
+ this.waitForEndValue = null;
288
+ }
289
+
290
+ this.waitForEndValue = setTimeout(() => {
291
+ this.deviceHandler.setStates(this.accessory, this.accessories, 'Temperature', value);
292
+ }, 250);
293
+ })
294
+ .on(
295
+ 'change',
296
+ this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName)
297
+ );
298
+
299
+ service
300
+ .getCharacteristic(this.api.hap.Characteristic.ValvePosition)
301
+ .on(
302
+ 'change',
303
+ this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName)
304
+ );
305
+
306
+ this.refreshHistory(service);
307
+ }
308
+
309
+ refreshHistory(service) {
310
+ let currentState = service.getCharacteristic(this.api.hap.Characteristic.CurrentHeaterCoolerState).value;
311
+ let currentTemp = service.getCharacteristic(this.api.hap.Characteristic.CurrentTemperature).value;
312
+ let targetTemp = service.getCharacteristic(this.api.hap.Characteristic.HeatingThresholdTemperature).value;
313
+
314
+ let valvePos =
315
+ currentTemp <= targetTemp && currentState !== 0
316
+ ? Math.round(targetTemp - currentTemp >= 5 ? 100 : (targetTemp - currentTemp) * 20)
317
+ : 0;
318
+
319
+ //Thermo
320
+ this.historyService.addEntry({
321
+ time: moment().unix(),
322
+ currentTemp: currentTemp,
323
+ setTemp: targetTemp,
324
+ valvePosition: valvePos,
325
+ });
326
+
327
+ setTimeout(() => {
328
+ this.refreshHistory(service);
329
+ }, 10 * 60 * 1000);
330
+ }
331
+ }
332
+
333
+ module.exports = HeaterCoolerAccessory;
@@ -0,0 +1,90 @@
1
+ 'use strict';
2
+
3
+ const Logger = require('../helper/logger.js');
4
+
5
+ const moment = require('moment');
6
+
7
+ const timeout = (ms) => new Promise((res) => setTimeout(res, ms));
8
+
9
+ class HumidityAccessory {
10
+ constructor(api, accessory, accessories, tado, deviceHandler, FakeGatoHistoryService) {
11
+ this.api = api;
12
+ this.accessory = accessory;
13
+ this.accessories = accessories;
14
+ this.FakeGatoHistoryService = FakeGatoHistoryService;
15
+
16
+ this.deviceHandler = deviceHandler;
17
+ this.tado = tado;
18
+
19
+ this.getService();
20
+ }
21
+
22
+ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
23
+ // Services
24
+ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
25
+
26
+ async getService() {
27
+ let service = this.accessory.getService(this.api.hap.Service.HumiditySensor);
28
+
29
+ if (!service) {
30
+ Logger.info('Adding HumiditySensor service', this.accessory.displayName);
31
+ service = this.accessory.addService(
32
+ this.api.hap.Service.HumiditySensor,
33
+ this.accessory.displayName,
34
+ this.accessory.context.config.subtype
35
+ );
36
+ }
37
+
38
+ let batteryService = this.accessory.getService(this.api.hap.Service.BatteryService);
39
+
40
+ if (!this.accessory.context.config.noBattery && this.accessory.context.config.type === 'HEATING') {
41
+ if (!batteryService) {
42
+ Logger.info('Adding Battery service', this.accessory.displayName);
43
+ batteryService = this.accessory.addService(this.api.hap.Service.BatteryService);
44
+ }
45
+ batteryService.setCharacteristic(
46
+ this.api.hap.Characteristic.ChargingState,
47
+ this.api.hap.Characteristic.ChargingState.NOT_CHARGEABLE
48
+ );
49
+ } else {
50
+ if (batteryService) {
51
+ Logger.info('Removing Battery service', this.accessory.displayName);
52
+ this.accessory.removeService(batteryService);
53
+ }
54
+ }
55
+
56
+ this.historyService = new this.FakeGatoHistoryService('room', this.accessory, {
57
+ storage: 'fs',
58
+ path: this.api.user.storagePath(),
59
+ disableTimer: true,
60
+ });
61
+
62
+ await timeout(250); //wait for historyService to load
63
+
64
+ service
65
+ .getCharacteristic(this.api.hap.Characteristic.CurrentRelativeHumidity)
66
+ .on(
67
+ 'change',
68
+ this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName)
69
+ );
70
+
71
+ this.refreshHistory(service);
72
+ }
73
+
74
+ refreshHistory(service) {
75
+ let state = service.getCharacteristic(this.api.hap.Characteristic.CurrentRelativeHumidity).value;
76
+
77
+ this.historyService.addEntry({
78
+ time: moment().unix(),
79
+ temp: 0,
80
+ humidity: state,
81
+ ppm: 0,
82
+ });
83
+
84
+ setTimeout(() => {
85
+ this.refreshHistory(service);
86
+ }, 10 * 60 * 1000);
87
+ }
88
+ }
89
+
90
+ module.exports = HumidityAccessory;
@@ -0,0 +1,59 @@
1
+ 'use strict';
2
+
3
+ const Logger = require('../helper/logger.js');
4
+
5
+ class SolarLightbulbAccessory {
6
+ constructor(api, accessory, accessories, tado) {
7
+ this.api = api;
8
+ this.accessory = accessory;
9
+ this.accessories = accessories;
10
+
11
+ this.tado = tado;
12
+
13
+ this.getService();
14
+ }
15
+
16
+ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
17
+ // Services
18
+ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
19
+
20
+ getService() {
21
+ let service = this.accessory.getService(this.api.hap.Service.Lightbulb);
22
+ let serviceOld = this.accessory.getService(this.api.hap.Service.LightSensor);
23
+
24
+ if (serviceOld) {
25
+ Logger.info('Removing LightSensor service', this.accessory.displayName);
26
+ this.accessory.removeService(serviceOld);
27
+ }
28
+
29
+ if (!service) {
30
+ Logger.info('Adding Lightbulb service', this.accessory.displayName);
31
+ service = this.accessory.addService(
32
+ this.api.hap.Service.Lightbulb,
33
+ this.accessory.displayName,
34
+ this.accessory.context.config.subtype
35
+ );
36
+ }
37
+
38
+ if (!service.testCharacteristic(this.api.hap.Characteristic.Brightness))
39
+ service.addCharacteristic(this.api.hap.Characteristic.Brightness);
40
+
41
+ service.getCharacteristic(this.api.hap.Characteristic.On).onSet(() => {
42
+ setTimeout(() => {
43
+ service
44
+ .getCharacteristic(this.api.hap.Characteristic.On)
45
+ .updateValue(this.accessory.context.lightBulbState || false);
46
+ }, 500);
47
+ });
48
+
49
+ service.getCharacteristic(this.api.hap.Characteristic.Brightness).onSet(() => {
50
+ setTimeout(() => {
51
+ service
52
+ .getCharacteristic(this.api.hap.Characteristic.Brightness)
53
+ .updateValue(this.accessory.context.lightBulbBrightness || 0);
54
+ }, 500);
55
+ });
56
+ }
57
+ }
58
+
59
+ module.exports = SolarLightbulbAccessory;
@@ -0,0 +1,40 @@
1
+ 'use strict';
2
+
3
+ const Logger = require('../helper/logger.js');
4
+
5
+ class SolarLightsensorAccessory {
6
+ constructor(api, accessory, accessories, tado) {
7
+ this.api = api;
8
+ this.accessory = accessory;
9
+ this.accessories = accessories;
10
+
11
+ this.tado = tado;
12
+
13
+ this.getService();
14
+ }
15
+
16
+ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
17
+ // Services
18
+ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
19
+
20
+ getService() {
21
+ let service = this.accessory.getService(this.api.hap.Service.LightSensor);
22
+ let serviceOld = this.accessory.getService(this.api.hap.Service.Lightbulb);
23
+
24
+ if (serviceOld) {
25
+ Logger.info('Removing Lightbulb service', this.accessory.displayName);
26
+ this.accessory.removeService(serviceOld);
27
+ }
28
+
29
+ if (!service) {
30
+ Logger.info('Adding LightSensor service', this.accessory.displayName);
31
+ service = this.accessory.addService(
32
+ this.api.hap.Service.LightSensor,
33
+ this.accessory.displayName,
34
+ this.accessory.context.config.subtype
35
+ );
36
+ }
37
+ }
38
+ }
39
+
40
+ module.exports = SolarLightsensorAccessory;
@@ -0,0 +1,79 @@
1
+ 'use strict';
2
+
3
+ const Logger = require('../helper/logger.js');
4
+
5
+ const moment = require('moment');
6
+
7
+ const timeout = (ms) => new Promise((res) => setTimeout(res, ms));
8
+
9
+ class MotionAccessory {
10
+ constructor(api, accessory, accessories, tado, deviceHandler, FakeGatoHistoryService) {
11
+ this.api = api;
12
+ this.accessory = accessory;
13
+ this.accessories = accessories;
14
+ this.FakeGatoHistoryService = FakeGatoHistoryService;
15
+
16
+ this.deviceHandler = deviceHandler;
17
+ this.tado = tado;
18
+
19
+ this.getService();
20
+ }
21
+
22
+ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
23
+ // Services
24
+ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
25
+
26
+ async getService() {
27
+ let service = this.accessory.getService(this.api.hap.Service.MotionSensor);
28
+ let serviceOld = this.accessory.getService(this.api.hap.Service.OccupancySensor);
29
+
30
+ if (serviceOld) {
31
+ Logger.info('Removing Occupancy service', this.accessory.displayName);
32
+ this.accessory.removeService(serviceOld);
33
+ }
34
+
35
+ if (!service) {
36
+ Logger.info('Adding Motion service', this.accessory.displayName);
37
+ service = this.accessory.addService(
38
+ this.api.hap.Service.MotionSensor,
39
+ this.accessory.displayName,
40
+ this.accessory.context.config.subtype
41
+ );
42
+ }
43
+
44
+ if (!service.testCharacteristic(this.api.hap.Characteristic.LastActivation))
45
+ service.addCharacteristic(this.api.hap.Characteristic.LastActivation);
46
+
47
+ this.historyService = new this.FakeGatoHistoryService('motion', this.accessory, {
48
+ storage: 'fs',
49
+ path: this.api.user.storagePath(),
50
+ disableTimer: true,
51
+ });
52
+
53
+ await timeout(250); //wait for historyService to load
54
+
55
+ service
56
+ .getCharacteristic(this.api.hap.Characteristic.MotionDetected)
57
+ .on(
58
+ 'change',
59
+ this.deviceHandler.changedStates.bind(this, this.accessory, this.historyService, this.accessory.displayName)
60
+ );
61
+
62
+ this.refreshHistory(service);
63
+ }
64
+
65
+ async refreshHistory(service) {
66
+ let state = service.getCharacteristic(this.api.hap.Characteristic.MotionDetected).value;
67
+
68
+ this.historyService.addEntry({
69
+ time: moment().unix(),
70
+ status: state ? 1 : 0,
71
+ });
72
+
73
+ setTimeout(() => {
74
+ this.refreshHistory(service);
75
+ }, 10 * 60 * 1000);
76
+ }
77
+ }
78
+
79
+ module.exports = MotionAccessory;
@@ -0,0 +1,45 @@
1
+ 'use strict';
2
+
3
+ const Logger = require('../helper/logger.js');
4
+
5
+ class OccupancyAccessory {
6
+ constructor(api, accessory, accessories, tado, deviceHandler) {
7
+ this.api = api;
8
+ this.accessory = accessory;
9
+ this.accessories = accessories;
10
+
11
+ this.deviceHandler = deviceHandler;
12
+ this.tado = tado;
13
+
14
+ this.getService();
15
+ }
16
+
17
+ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
18
+ // Services
19
+ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
20
+
21
+ async getService() {
22
+ let service = this.accessory.getService(this.api.hap.Service.OccupancySensor);
23
+ let serviceOld = this.accessory.getService(this.api.hap.Service.MotionSensor);
24
+
25
+ if (serviceOld) {
26
+ Logger.info('Removing Motion service', this.accessory.displayName);
27
+ this.accessory.removeService(serviceOld);
28
+ }
29
+
30
+ if (!service) {
31
+ Logger.info('Adding Occupancy service', this.accessory.displayName);
32
+ service = this.accessory.addService(
33
+ this.api.hap.Service.OccupancySensor,
34
+ this.accessory.displayName,
35
+ this.accessory.context.config.subtype
36
+ );
37
+ }
38
+
39
+ service
40
+ .getCharacteristic(this.api.hap.Characteristic.OccupancyDetected)
41
+ .on('change', this.deviceHandler.changedStates.bind(this, this.accessory, false, this.accessory.displayName));
42
+ }
43
+ }
44
+
45
+ module.exports = OccupancyAccessory;