@homebridge-plugins/homebridge-tado 8.5.1-beta.0 → 8.5.1-beta.2
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 +2 -1
- package/package.json +1 -1
- package/src/helper/handler.js +519 -532
package/src/helper/handler.js
CHANGED
|
@@ -3,9 +3,9 @@ import moment from 'moment';
|
|
|
3
3
|
import { writeFile, access, readFile } from 'fs/promises';
|
|
4
4
|
import { join } from "path";
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
var delayTimer = {};
|
|
6
|
+
let settingState = false;
|
|
8
7
|
let tasksInitialized = false;
|
|
8
|
+
const delayTimer = {};
|
|
9
9
|
|
|
10
10
|
const timeout = (ms) => new Promise((res) => setTimeout(res, ms));
|
|
11
11
|
const aRefreshHistoryHandlers = [];
|
|
@@ -27,7 +27,6 @@ export default (api, accessories, config, tado, telegram) => {
|
|
|
27
27
|
|
|
28
28
|
async function setStates(accessory, accs, target, value) {
|
|
29
29
|
let zoneUpdated = false;
|
|
30
|
-
let allZonesUpdated = false;
|
|
31
30
|
|
|
32
31
|
accessories = accs.filter((acc) => acc && acc.context.config.homeName === config.homeName);
|
|
33
32
|
|
|
@@ -376,7 +375,6 @@ export default (api, accessories, config, tado, telegram) => {
|
|
|
376
375
|
}
|
|
377
376
|
}
|
|
378
377
|
|
|
379
|
-
allZonesUpdated = true;
|
|
380
378
|
await tado.setPresenceLock(config.homeId, targetState);
|
|
381
379
|
|
|
382
380
|
break;
|
|
@@ -428,7 +426,6 @@ export default (api, accessories, config, tado, telegram) => {
|
|
|
428
426
|
})
|
|
429
427
|
.filter((id) => id);
|
|
430
428
|
|
|
431
|
-
allZonesUpdated = true;
|
|
432
429
|
await tado.resumeShedule(config.homeId, roomIds);
|
|
433
430
|
|
|
434
431
|
//Turn all back to AUTO/ON
|
|
@@ -553,7 +550,6 @@ export default (api, accessories, config, tado, telegram) => {
|
|
|
553
550
|
.updateValue(false);
|
|
554
551
|
}
|
|
555
552
|
|
|
556
|
-
allZonesUpdated = true;
|
|
557
553
|
await tado.switchAll(config.homeId, rooms);
|
|
558
554
|
|
|
559
555
|
break;
|
|
@@ -570,7 +566,7 @@ export default (api, accessories, config, tado, telegram) => {
|
|
|
570
566
|
errorHandler(err);
|
|
571
567
|
} finally {
|
|
572
568
|
//always update zone to set correct state in Apple Home
|
|
573
|
-
if (zoneUpdated
|
|
569
|
+
if (zoneUpdated) await updateZones(accessory.context.config.zoneId);
|
|
574
570
|
settingState = false;
|
|
575
571
|
}
|
|
576
572
|
}
|
|
@@ -750,7 +746,7 @@ export default (api, accessories, config, tado, telegram) => {
|
|
|
750
746
|
}
|
|
751
747
|
try {
|
|
752
748
|
//wait for fakegato history services to be loaded
|
|
753
|
-
await
|
|
749
|
+
await timeout(4000);
|
|
754
750
|
for (const refreshHistory of aRefreshHistoryHandlers) {
|
|
755
751
|
refreshHistory();
|
|
756
752
|
}
|
|
@@ -813,413 +809,391 @@ export default (api, accessories, config, tado, telegram) => {
|
|
|
813
809
|
}
|
|
814
810
|
|
|
815
811
|
async function updateMe() {
|
|
816
|
-
if (
|
|
817
|
-
Logger.debug('Polling User Info...', config.homeName);
|
|
812
|
+
if (settingState) return;
|
|
818
813
|
|
|
819
|
-
|
|
814
|
+
Logger.debug('Polling User Info...', config.homeName);
|
|
820
815
|
|
|
821
|
-
|
|
816
|
+
const me = await tado.getMe();
|
|
822
817
|
|
|
823
|
-
|
|
824
|
-
}
|
|
818
|
+
if (config.homeName !== me.homes[0].name) throw ('Cannot find requested home in the API!', config.homeName);
|
|
825
819
|
|
|
826
|
-
|
|
820
|
+
config.homeId = me.homes[0].id;
|
|
827
821
|
}
|
|
828
822
|
|
|
829
823
|
async function updateHome() {
|
|
830
|
-
if (
|
|
831
|
-
Logger.debug('Polling Home Info...', config.homeName);
|
|
824
|
+
if (settingState) return;
|
|
832
825
|
|
|
833
|
-
|
|
826
|
+
Logger.debug('Polling Home Info...', config.homeName);
|
|
834
827
|
|
|
835
|
-
|
|
828
|
+
const home = await tado.getHome(config.homeId);
|
|
836
829
|
|
|
837
|
-
|
|
830
|
+
if (!config.temperatureUnit) config.temperatureUnit = home.temperatureUnit || 'CELSIUS';
|
|
838
831
|
|
|
839
|
-
|
|
840
|
-
!config.geolocation ||
|
|
841
|
-
(config.geolocation && !config.geolocation.longitude) ||
|
|
842
|
-
!config.geolocation.latitude
|
|
843
|
-
) {
|
|
844
|
-
if (!home.geolocation) home.geolocation = {};
|
|
832
|
+
//config.skills = home.skills || []; //do we need this?
|
|
845
833
|
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
834
|
+
if (
|
|
835
|
+
!config.geolocation ||
|
|
836
|
+
(config.geolocation && !config.geolocation.longitude) ||
|
|
837
|
+
!config.geolocation.latitude
|
|
838
|
+
) {
|
|
839
|
+
if (!home.geolocation) home.geolocation = {};
|
|
852
840
|
|
|
853
|
-
|
|
841
|
+
config.geolocation = {
|
|
842
|
+
longitude: (home.geolocation.longitude || '').toString() || false,
|
|
843
|
+
latitude: (home.geolocation.latitude || '').toString() || false,
|
|
844
|
+
};
|
|
845
|
+
}
|
|
854
846
|
}
|
|
855
847
|
|
|
856
848
|
async function updateZones(idToUpdate) {
|
|
857
849
|
let zoneStates = {};
|
|
858
|
-
if (
|
|
859
|
-
|
|
850
|
+
if (settingState && idToUpdate === undefined) {
|
|
851
|
+
await timeout(10 * 1000);
|
|
852
|
+
if (settingState) return zoneStates;
|
|
853
|
+
}
|
|
860
854
|
|
|
861
|
-
|
|
862
|
-
let inManualMode = 0;
|
|
863
|
-
let inOffMode = 0;
|
|
864
|
-
let inAutoMode = 0;
|
|
855
|
+
Logger.debug('Polling Zones...', config.homeName);
|
|
865
856
|
|
|
866
|
-
|
|
857
|
+
//CentralSwitch
|
|
858
|
+
let inManualMode = 0;
|
|
859
|
+
let inOffMode = 0;
|
|
860
|
+
let inAutoMode = 0;
|
|
867
861
|
|
|
868
|
-
|
|
869
|
-
const allZones = (await tado.getZones(config.homeId)) || [];
|
|
870
|
-
|
|
871
|
-
for (const [index, zone] of config.zones.entries()) {
|
|
872
|
-
allZones.forEach((zoneWithID) => {
|
|
873
|
-
if (zoneWithID.name === zone.name) config.zones[index].id = zoneWithID.id;
|
|
874
|
-
});
|
|
875
|
-
}
|
|
876
|
-
}
|
|
862
|
+
let zonesWithoutID = config.zones.filter((zone) => zone && !zone.id);
|
|
877
863
|
|
|
864
|
+
if (zonesWithoutID.length) {
|
|
878
865
|
const allZones = (await tado.getZones(config.homeId)) || [];
|
|
879
866
|
|
|
880
867
|
for (const [index, zone] of config.zones.entries()) {
|
|
881
868
|
allZones.forEach((zoneWithID) => {
|
|
882
|
-
if (zoneWithID.name === zone.name)
|
|
883
|
-
const heatAccessory = accessories.filter(
|
|
884
|
-
(acc) => acc && acc.displayName === config.homeName + ' ' + zone.name + ' Heater'
|
|
885
|
-
);
|
|
886
|
-
|
|
887
|
-
if (heatAccessory.length) heatAccessory[0].context.config.zoneId = zoneWithID.id;
|
|
888
|
-
|
|
889
|
-
config.zones[index].id = zoneWithID.id;
|
|
890
|
-
config.zones[index].battery = !config.zones[index].noBattery
|
|
891
|
-
? zoneWithID.devices.filter(
|
|
892
|
-
(device) =>
|
|
893
|
-
device &&
|
|
894
|
-
(zone.type === 'HEATING' || zone.type === 'AIR_CONDITIONING') &&
|
|
895
|
-
typeof device.batteryState === 'string' &&
|
|
896
|
-
!device.batteryState.includes('NORMAL')
|
|
897
|
-
).length
|
|
898
|
-
? zoneWithID.devices.filter((device) => device && !device.batteryState.includes('NORMAL'))[0]
|
|
899
|
-
.batteryState
|
|
900
|
-
: zoneWithID.devices.filter((device) => device && device.duties.includes('ZONE_LEADER'))[0].batteryState
|
|
901
|
-
: false;
|
|
902
|
-
config.zones[index].openWindowEnabled =
|
|
903
|
-
zoneWithID.openWindowDetection && zoneWithID.openWindowDetection.enabled ? true : false;
|
|
904
|
-
}
|
|
869
|
+
if (zoneWithID.name === zone.name) config.zones[index].id = zoneWithID.id;
|
|
905
870
|
});
|
|
906
871
|
}
|
|
872
|
+
}
|
|
907
873
|
|
|
908
|
-
|
|
909
|
-
if (idToUpdate !== undefined) {
|
|
910
|
-
zoneStates[idToUpdate] = await tado.getZoneState(config.homeId, idToUpdate);
|
|
911
|
-
zonesToUpdate = config.zones.filter(zone => zone.id === idToUpdate);
|
|
912
|
-
} else {
|
|
913
|
-
zoneStates = (await tado.getZoneStates(config.homeId))["zoneStates"];
|
|
914
|
-
zonesToUpdate = config.zones;
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
for (const zone of zonesToUpdate) {
|
|
918
|
-
const zoneState = zoneStates[zone.id];
|
|
874
|
+
const allZones = (await tado.getZones(config.homeId)) || [];
|
|
919
875
|
|
|
920
|
-
|
|
876
|
+
for (const [index, zone] of config.zones.entries()) {
|
|
877
|
+
allZones.forEach((zoneWithID) => {
|
|
878
|
+
if (zoneWithID.name === zone.name) {
|
|
879
|
+
const heatAccessory = accessories.filter(
|
|
880
|
+
(acc) => acc && acc.displayName === config.homeName + ' ' + zone.name + ' Heater'
|
|
881
|
+
);
|
|
921
882
|
|
|
922
|
-
|
|
923
|
-
|
|
883
|
+
if (heatAccessory.length) heatAccessory[0].context.config.zoneId = zoneWithID.id;
|
|
884
|
+
|
|
885
|
+
config.zones[index].id = zoneWithID.id;
|
|
886
|
+
config.zones[index].battery = !config.zones[index].noBattery
|
|
887
|
+
? zoneWithID.devices.filter(
|
|
888
|
+
(device) =>
|
|
889
|
+
device &&
|
|
890
|
+
(zone.type === 'HEATING' || zone.type === 'AIR_CONDITIONING') &&
|
|
891
|
+
typeof device.batteryState === 'string' &&
|
|
892
|
+
!device.batteryState.includes('NORMAL')
|
|
893
|
+
).length
|
|
894
|
+
? zoneWithID.devices.filter((device) => device && !device.batteryState.includes('NORMAL'))[0]
|
|
895
|
+
.batteryState
|
|
896
|
+
: zoneWithID.devices.filter((device) => device && device.duties.includes('ZONE_LEADER'))[0].batteryState
|
|
897
|
+
: false;
|
|
898
|
+
config.zones[index].openWindowEnabled =
|
|
899
|
+
zoneWithID.openWindowDetection && zoneWithID.openWindowDetection.enabled ? true : false;
|
|
900
|
+
}
|
|
901
|
+
});
|
|
902
|
+
}
|
|
924
903
|
|
|
925
|
-
|
|
904
|
+
let zonesToUpdate = [];
|
|
905
|
+
if (idToUpdate !== undefined) {
|
|
906
|
+
zoneStates[idToUpdate] = await tado.getZoneState(config.homeId, idToUpdate);
|
|
907
|
+
zonesToUpdate = config.zones.filter(zone => zone.id === idToUpdate);
|
|
908
|
+
} else {
|
|
909
|
+
zoneStates = (await tado.getZoneStates(config.homeId))["zoneStates"];
|
|
910
|
+
zonesToUpdate = config.zones;
|
|
911
|
+
}
|
|
926
912
|
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
currentTemp =
|
|
930
|
-
config.temperatureUnit === 'FAHRENHEIT'
|
|
931
|
-
? zoneState.sensorDataPoints.insideTemperature.fahrenheit
|
|
932
|
-
: zoneState.sensorDataPoints.insideTemperature.celsius;
|
|
913
|
+
for (const zone of zonesToUpdate) {
|
|
914
|
+
const zoneState = zoneStates[zone.id];
|
|
933
915
|
|
|
934
|
-
|
|
935
|
-
targetTemp =
|
|
936
|
-
config.temperatureUnit === 'FAHRENHEIT'
|
|
937
|
-
? zoneState.setting.temperature.fahrenheit
|
|
938
|
-
: zoneState.setting.temperature.celsius;
|
|
916
|
+
let currentState, targetState, currentTemp, targetTemp, humidity, active, battery, tempEqual;
|
|
939
917
|
|
|
940
|
-
|
|
918
|
+
if (zoneState.setting.type === 'HEATING') {
|
|
919
|
+
battery = zone.battery === 'NORMAL' ? 100 : 10;
|
|
941
920
|
|
|
942
|
-
|
|
943
|
-
currentState = currentTemp < targetTemp ? 1 : 0;
|
|
921
|
+
if (zoneState.sensorDataPoints.humidity) humidity = zoneState.sensorDataPoints.humidity.percentage;
|
|
944
922
|
|
|
945
|
-
|
|
946
|
-
|
|
923
|
+
//HEATING
|
|
924
|
+
if (zoneState.sensorDataPoints.insideTemperature) {
|
|
925
|
+
currentTemp =
|
|
926
|
+
config.temperatureUnit === 'FAHRENHEIT'
|
|
927
|
+
? zoneState.sensorDataPoints.insideTemperature.fahrenheit
|
|
928
|
+
: zoneState.sensorDataPoints.insideTemperature.celsius;
|
|
947
929
|
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
active = 0;
|
|
954
|
-
}
|
|
930
|
+
if (zoneState.setting.power === 'ON') {
|
|
931
|
+
targetTemp =
|
|
932
|
+
config.temperatureUnit === 'FAHRENHEIT'
|
|
933
|
+
? zoneState.setting.temperature.fahrenheit
|
|
934
|
+
: zoneState.setting.temperature.celsius;
|
|
955
935
|
|
|
956
|
-
|
|
957
|
-
targetState = 3;
|
|
958
|
-
}
|
|
959
|
-
}
|
|
936
|
+
tempEqual = Math.round(currentTemp) === Math.round(targetTemp);
|
|
960
937
|
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
(acc) =>
|
|
964
|
-
acc &&
|
|
965
|
-
(acc.context.config.subtype === 'zone-thermostat' ||
|
|
966
|
-
acc.context.config.subtype === 'zone-heatercooler' ||
|
|
967
|
-
acc.context.config.subtype === 'zone-heatercooler-ac')
|
|
968
|
-
);
|
|
938
|
+
//show as currently heating if current temp is lower than target temp, otherwise show as temp set
|
|
939
|
+
currentState = currentTemp < targetTemp ? 1 : 0;
|
|
969
940
|
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
if (acc.displayName.includes(zone.name)) {
|
|
973
|
-
let serviceThermostat = acc.getService(api.hap.Service.Thermostat);
|
|
974
|
-
let serviceHeaterCooler = acc.getService(api.hap.Service.HeaterCooler);
|
|
941
|
+
//check if auto mode is enabled
|
|
942
|
+
targetState = zoneState.overlayType === null ? 3 : 1;
|
|
975
943
|
|
|
976
|
-
|
|
977
|
-
|
|
944
|
+
active = 1;
|
|
945
|
+
} else {
|
|
946
|
+
//heating is switched off
|
|
947
|
+
currentState = 0;
|
|
948
|
+
targetState = 0;
|
|
949
|
+
active = 0;
|
|
950
|
+
}
|
|
978
951
|
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
952
|
+
if (targetState === undefined && zoneState.overlayType === null) {
|
|
953
|
+
targetState = 3;
|
|
954
|
+
}
|
|
955
|
+
}
|
|
982
956
|
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
957
|
+
//Thermostat/HeaterCooler
|
|
958
|
+
const thermoAccessory = accessories.filter(
|
|
959
|
+
(acc) =>
|
|
960
|
+
acc &&
|
|
961
|
+
(acc.context.config.subtype === 'zone-thermostat' ||
|
|
962
|
+
acc.context.config.subtype === 'zone-heatercooler' ||
|
|
963
|
+
acc.context.config.subtype === 'zone-heatercooler-ac')
|
|
964
|
+
);
|
|
990
965
|
|
|
991
|
-
|
|
992
|
-
|
|
966
|
+
if (thermoAccessory.length) {
|
|
967
|
+
thermoAccessory.forEach((acc) => {
|
|
968
|
+
if (acc.displayName.includes(zone.name)) {
|
|
969
|
+
let serviceThermostat = acc.getService(api.hap.Service.Thermostat);
|
|
970
|
+
let serviceHeaterCooler = acc.getService(api.hap.Service.HeaterCooler);
|
|
993
971
|
|
|
994
|
-
|
|
995
|
-
|
|
972
|
+
let serviceBattery = acc.getService(api.hap.Service.BatteryService);
|
|
973
|
+
let characteristicBattery = api.hap.Characteristic.BatteryLevel;
|
|
996
974
|
|
|
997
|
-
|
|
998
|
-
|
|
975
|
+
if (serviceBattery && zone.battery) {
|
|
976
|
+
serviceBattery.getCharacteristic(characteristicBattery).updateValue(battery);
|
|
977
|
+
}
|
|
999
978
|
|
|
1000
|
-
|
|
979
|
+
if (serviceThermostat) {
|
|
980
|
+
let characteristicCurrentTemp = api.hap.Characteristic.CurrentTemperature;
|
|
981
|
+
let characteristicTargetTemp = api.hap.Characteristic.TargetTemperature;
|
|
982
|
+
let characteristicCurrentState = api.hap.Characteristic.CurrentHeatingCoolingState;
|
|
983
|
+
let characteristicTargetState = api.hap.Characteristic.TargetHeatingCoolingState;
|
|
984
|
+
let characteristicHumidity = api.hap.Characteristic.CurrentRelativeHumidity;
|
|
985
|
+
let characteristicUnit = api.hap.Characteristic.TemperatureDisplayUnits;
|
|
1001
986
|
|
|
1002
|
-
|
|
1003
|
-
|
|
987
|
+
if (!isNaN(currentTemp)) {
|
|
988
|
+
acc.context.config.temperatureUnit = acc.context.config.temperatureUnit || config.temperatureUnit;
|
|
1004
989
|
|
|
1005
|
-
|
|
1006
|
-
|
|
990
|
+
let isFahrenheit = serviceThermostat.getCharacteristic(characteristicUnit).value === 1;
|
|
991
|
+
let unitChanged = config.temperatureUnit !== acc.context.config.temperatureUnit;
|
|
1007
992
|
|
|
1008
|
-
|
|
1009
|
-
|
|
993
|
+
let cToF = (c) => Math.round((c * 9) / 5 + 32);
|
|
994
|
+
let fToC = (f) => Math.round(((f - 32) * 5) / 9);
|
|
1010
995
|
|
|
1011
|
-
|
|
1012
|
-
serviceThermostat.getCharacteristic(characteristicTargetState).updateValue(targetState);
|
|
996
|
+
let newValue = unitChanged ? (isFahrenheit ? cToF(currentTemp) : fToC(currentTemp)) : currentTemp;
|
|
1013
997
|
|
|
1014
|
-
|
|
1015
|
-
serviceThermostat.getCharacteristic(characteristicHumidity).updateValue(humidity);
|
|
998
|
+
serviceThermostat.getCharacteristic(characteristicCurrentTemp).updateValue(newValue);
|
|
1016
999
|
}
|
|
1017
1000
|
|
|
1018
|
-
if (
|
|
1019
|
-
|
|
1020
|
-
let characteristicCurrentTemp = api.hap.Characteristic.CurrentTemperature;
|
|
1021
|
-
let characteristicTargetTempHeating = api.hap.Characteristic.HeatingThresholdTemperature;
|
|
1022
|
-
let characteristicTargetTempCooling = api.hap.Characteristic.CoolingThresholdTemperature;
|
|
1023
|
-
let characteristicCurrentState = api.hap.Characteristic.CurrentHeaterCoolerState;
|
|
1024
|
-
let characteristicTargetState = api.hap.Characteristic.TargetHeaterCoolerState;
|
|
1025
|
-
let characteristicActive = api.hap.Characteristic.Active;
|
|
1001
|
+
if (!isNaN(targetTemp))
|
|
1002
|
+
serviceThermostat.getCharacteristic(characteristicTargetTemp).updateValue(targetTemp);
|
|
1026
1003
|
|
|
1027
|
-
|
|
1004
|
+
if (!isNaN(currentState))
|
|
1005
|
+
serviceThermostat.getCharacteristic(characteristicCurrentState).updateValue(currentState);
|
|
1028
1006
|
|
|
1029
|
-
|
|
1007
|
+
if (!isNaN(targetState))
|
|
1008
|
+
serviceThermostat.getCharacteristic(characteristicTargetState).updateValue(targetState);
|
|
1030
1009
|
|
|
1031
|
-
|
|
1010
|
+
if (!isNaN(humidity) && serviceThermostat.testCharacteristic(characteristicHumidity))
|
|
1011
|
+
serviceThermostat.getCharacteristic(characteristicHumidity).updateValue(humidity);
|
|
1012
|
+
}
|
|
1032
1013
|
|
|
1033
|
-
|
|
1034
|
-
|
|
1014
|
+
if (serviceHeaterCooler) {
|
|
1015
|
+
let characteristicHumidity = api.hap.Characteristic.CurrentRelativeHumidity;
|
|
1016
|
+
let characteristicCurrentTemp = api.hap.Characteristic.CurrentTemperature;
|
|
1017
|
+
let characteristicTargetTempHeating = api.hap.Characteristic.HeatingThresholdTemperature;
|
|
1018
|
+
let characteristicTargetTempCooling = api.hap.Characteristic.CoolingThresholdTemperature;
|
|
1019
|
+
let characteristicCurrentState = api.hap.Characteristic.CurrentHeaterCoolerState;
|
|
1020
|
+
let characteristicTargetState = api.hap.Characteristic.TargetHeaterCoolerState;
|
|
1021
|
+
let characteristicActive = api.hap.Characteristic.Active;
|
|
1035
1022
|
|
|
1036
|
-
|
|
1037
|
-
serviceHeaterCooler.getCharacteristic(characteristicTargetTempHeating).updateValue(targetTemp);
|
|
1023
|
+
currentState = active ? (targetState === 3 || tempEqual ? 1 : currentState + 1) : 0;
|
|
1038
1024
|
|
|
1039
|
-
|
|
1040
|
-
}
|
|
1025
|
+
targetState = 1;
|
|
1041
1026
|
|
|
1042
|
-
|
|
1043
|
-
serviceHeaterCooler.getCharacteristic(characteristicCurrentState).updateValue(currentState);
|
|
1027
|
+
if (!isNaN(active)) serviceHeaterCooler.getCharacteristic(characteristicActive).updateValue(active);
|
|
1044
1028
|
|
|
1045
|
-
|
|
1046
|
-
|
|
1029
|
+
if (!isNaN(currentTemp))
|
|
1030
|
+
serviceHeaterCooler.getCharacteristic(characteristicCurrentTemp).updateValue(currentTemp);
|
|
1047
1031
|
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
}
|
|
1051
|
-
}
|
|
1052
|
-
});
|
|
1053
|
-
}
|
|
1054
|
-
} else {
|
|
1055
|
-
// Non-HEATING zones (AIR_CONDITIONING, HOT_WATER, etc.)
|
|
1056
|
-
battery = zone.battery === 'NORMAL' ? 100 : 10;
|
|
1032
|
+
if (!isNaN(targetTemp)) {
|
|
1033
|
+
serviceHeaterCooler.getCharacteristic(characteristicTargetTempHeating).updateValue(targetTemp);
|
|
1057
1034
|
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
}
|
|
1035
|
+
serviceHeaterCooler.getCharacteristic(characteristicTargetTempCooling).updateValue(targetTemp);
|
|
1036
|
+
}
|
|
1061
1037
|
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
currentTemp =
|
|
1065
|
-
config.temperatureUnit === 'FAHRENHEIT'
|
|
1066
|
-
? zoneState.sensorDataPoints.insideTemperature.fahrenheit
|
|
1067
|
-
: zoneState.sensorDataPoints.insideTemperature.celsius;
|
|
1068
|
-
}
|
|
1038
|
+
if (!isNaN(currentState))
|
|
1039
|
+
serviceHeaterCooler.getCharacteristic(characteristicCurrentState).updateValue(currentState);
|
|
1069
1040
|
|
|
1070
|
-
|
|
1071
|
-
|
|
1041
|
+
if (!isNaN(targetState))
|
|
1042
|
+
serviceHeaterCooler.getCharacteristic(characteristicTargetState).updateValue(targetState);
|
|
1072
1043
|
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
zoneState.setting.temperature !== null && zoneState.setting.temperature
|
|
1076
|
-
? config.temperatureUnit === 'FAHRENHEIT'
|
|
1077
|
-
? zoneState.setting.temperature.fahrenheit
|
|
1078
|
-
: zoneState.setting.temperature.celsius
|
|
1079
|
-
: undefined;
|
|
1080
|
-
|
|
1081
|
-
// Enhanced AC state handling
|
|
1082
|
-
if (zone.type === 'AIR_CONDITIONING') {
|
|
1083
|
-
const acMode = zoneState.setting.mode || 'COOL';
|
|
1084
|
-
tempEqual = currentTemp && targetTemp ? Math.abs(currentTemp - targetTemp) < 0.5 : false;
|
|
1085
|
-
|
|
1086
|
-
// Map AC modes to HomeKit states
|
|
1087
|
-
switch (acMode.toUpperCase()) {
|
|
1088
|
-
case 'HEAT':
|
|
1089
|
-
targetState = 1; // Heating
|
|
1090
|
-
currentState = tempEqual ? 1 : (currentTemp < targetTemp ? 2 : 1); // Idle or Heating
|
|
1091
|
-
break;
|
|
1092
|
-
case 'COOL':
|
|
1093
|
-
case 'AUTO':
|
|
1094
|
-
default:
|
|
1095
|
-
targetState = 2; // Cooling
|
|
1096
|
-
currentState = tempEqual ? 1 : (currentTemp > targetTemp ? 3 : 1); // Idle or Cooling
|
|
1097
|
-
break;
|
|
1044
|
+
if (!isNaN(humidity) && serviceHeaterCooler.testCharacteristic(characteristicHumidity))
|
|
1045
|
+
serviceHeaterCooler.getCharacteristic(characteristicHumidity).updateValue(humidity);
|
|
1098
1046
|
}
|
|
1099
|
-
} else {
|
|
1100
|
-
// Non-AC zones (HOT_WATER, etc.)
|
|
1101
|
-
currentState = zoneState.overlayType === null ? 1 : 2;
|
|
1102
|
-
targetState = 1;
|
|
1103
1047
|
}
|
|
1104
|
-
}
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
}
|
|
1048
|
+
});
|
|
1049
|
+
}
|
|
1050
|
+
} else {
|
|
1051
|
+
// Non-HEATING zones (AIR_CONDITIONING, HOT_WATER, etc.)
|
|
1052
|
+
battery = zone.battery === 'NORMAL' ? 100 : 10;
|
|
1110
1053
|
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
acc.context.config.subtype === 'zone-heatercooler-ac')
|
|
1115
|
-
);
|
|
1116
|
-
const switchAccessory = accessories.filter((acc) => acc && acc.context.config.subtype === 'zone-switch');
|
|
1117
|
-
const faucetAccessory = accessories.filter((acc) => acc && acc.context.config.subtype === 'zone-faucet');
|
|
1054
|
+
if (zoneState.sensorDataPoints.humidity) {
|
|
1055
|
+
humidity = zoneState.sensorDataPoints.humidity.percentage;
|
|
1056
|
+
}
|
|
1118
1057
|
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1058
|
+
// Get current temperature from sensor data (same as HEATING zones)
|
|
1059
|
+
if (zoneState.sensorDataPoints.insideTemperature) {
|
|
1060
|
+
currentTemp =
|
|
1061
|
+
config.temperatureUnit === 'FAHRENHEIT'
|
|
1062
|
+
? zoneState.sensorDataPoints.insideTemperature.fahrenheit
|
|
1063
|
+
: zoneState.sensorDataPoints.insideTemperature.celsius;
|
|
1064
|
+
}
|
|
1123
1065
|
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1066
|
+
if (zoneState.setting.power === 'ON') {
|
|
1067
|
+
active = 1;
|
|
1068
|
+
|
|
1069
|
+
// Get target temperature from setting
|
|
1070
|
+
targetTemp =
|
|
1071
|
+
zoneState.setting.temperature !== null && zoneState.setting.temperature
|
|
1072
|
+
? config.temperatureUnit === 'FAHRENHEIT'
|
|
1073
|
+
? zoneState.setting.temperature.fahrenheit
|
|
1074
|
+
: zoneState.setting.temperature.celsius
|
|
1075
|
+
: undefined;
|
|
1076
|
+
|
|
1077
|
+
// Enhanced AC state handling
|
|
1078
|
+
if (zone.type === 'AIR_CONDITIONING') {
|
|
1079
|
+
const acMode = zoneState.setting.mode || 'COOL';
|
|
1080
|
+
tempEqual = currentTemp && targetTemp ? Math.abs(currentTemp - targetTemp) < 0.5 : false;
|
|
1081
|
+
|
|
1082
|
+
// Map AC modes to HomeKit states
|
|
1083
|
+
switch (acMode.toUpperCase()) {
|
|
1084
|
+
case 'HEAT':
|
|
1085
|
+
targetState = 1; // Heating
|
|
1086
|
+
currentState = tempEqual ? 1 : (currentTemp < targetTemp ? 2 : 1); // Idle or Heating
|
|
1087
|
+
break;
|
|
1088
|
+
case 'COOL':
|
|
1089
|
+
case 'AUTO':
|
|
1090
|
+
default:
|
|
1091
|
+
targetState = 2; // Cooling
|
|
1092
|
+
currentState = tempEqual ? 1 : (currentTemp > targetTemp ? 3 : 1); // Idle or Cooling
|
|
1093
|
+
break;
|
|
1094
|
+
}
|
|
1095
|
+
} else {
|
|
1096
|
+
// Non-AC zones (HOT_WATER, etc.)
|
|
1097
|
+
currentState = zoneState.overlayType === null ? 1 : 2;
|
|
1098
|
+
targetState = 1;
|
|
1099
|
+
}
|
|
1100
|
+
} else {
|
|
1101
|
+
active = 0;
|
|
1102
|
+
currentState = 0;
|
|
1103
|
+
targetTemp = undefined;
|
|
1104
|
+
targetState = zone.type === 'AIR_CONDITIONING' ? 2 : 1; // Default to cooling for AC, heating for others
|
|
1105
|
+
}
|
|
1130
1106
|
|
|
1131
|
-
|
|
1107
|
+
//Thermostat/HeaterCooler
|
|
1108
|
+
const heaterAccessory = accessories.filter(
|
|
1109
|
+
(acc) => acc && (acc.context.config.subtype === 'zone-heatercooler-boiler' ||
|
|
1110
|
+
acc.context.config.subtype === 'zone-heatercooler-ac')
|
|
1111
|
+
);
|
|
1112
|
+
const switchAccessory = accessories.filter((acc) => acc && acc.context.config.subtype === 'zone-switch');
|
|
1113
|
+
const faucetAccessory = accessories.filter((acc) => acc && acc.context.config.subtype === 'zone-faucet');
|
|
1132
1114
|
|
|
1133
|
-
|
|
1115
|
+
if (heaterAccessory.length) {
|
|
1116
|
+
heaterAccessory.forEach((acc) => {
|
|
1117
|
+
if (acc.displayName.includes(zone.name)) {
|
|
1118
|
+
let service = acc.getService(api.hap.Service.HeaterCooler);
|
|
1134
1119
|
|
|
1135
|
-
|
|
1120
|
+
let characteristicCurrentTemp = api.hap.Characteristic.CurrentTemperature;
|
|
1121
|
+
let characteristicActive = api.hap.Characteristic.Active;
|
|
1122
|
+
let characteristicCurrentState = api.hap.Characteristic.CurrentHeaterCoolerState;
|
|
1123
|
+
let characteristicTargetState = api.hap.Characteristic.TargetHeaterCoolerState;
|
|
1124
|
+
let characteristicTargetTempHeating = api.hap.Characteristic.HeatingThresholdTemperature;
|
|
1125
|
+
let characteristicTargetTempCooling = api.hap.Characteristic.CoolingThresholdTemperature;
|
|
1136
1126
|
|
|
1137
|
-
|
|
1138
|
-
if (!isNaN(currentTemp) || acc.context.currentTemp) {
|
|
1139
|
-
if (!isNaN(currentTemp)) acc.context.currentTemp = currentTemp; //store current temp in config
|
|
1127
|
+
service.getCharacteristic(characteristicActive).updateValue(active);
|
|
1140
1128
|
|
|
1141
|
-
|
|
1142
|
-
}
|
|
1129
|
+
service.getCharacteristic(characteristicCurrentState).updateValue(currentState);
|
|
1143
1130
|
|
|
1144
|
-
|
|
1145
|
-
if (!isNaN(targetTemp)) {
|
|
1146
|
-
// For AC zones, set temperature based on the mode
|
|
1147
|
-
if (zone.type === 'AIR_CONDITIONING') {
|
|
1148
|
-
// Always set both characteristics but log which one is active
|
|
1149
|
-
service.getCharacteristic(characteristicTargetTempHeating).updateValue(targetTemp);
|
|
1150
|
-
service.getCharacteristic(characteristicTargetTempCooling).updateValue(targetTemp);
|
|
1151
|
-
} else {
|
|
1152
|
-
// Non-AC zones (like boiler/hot water)
|
|
1153
|
-
service.getCharacteristic(characteristicTargetTempHeating).updateValue(targetTemp);
|
|
1154
|
-
service.getCharacteristic(characteristicTargetTempCooling).updateValue(targetTemp);
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1131
|
+
service.getCharacteristic(characteristicTargetState).updateValue(targetState);
|
|
1157
1132
|
|
|
1158
|
-
|
|
1133
|
+
// Set current temperature from sensor data
|
|
1134
|
+
if (!isNaN(currentTemp) || acc.context.currentTemp) {
|
|
1135
|
+
if (!isNaN(currentTemp)) acc.context.currentTemp = currentTemp; //store current temp in config
|
|
1159
1136
|
|
|
1160
|
-
|
|
1161
|
-
if (!isNaN(humidity) && service.testCharacteristic(api.hap.Characteristic.CurrentRelativeHumidity)) {
|
|
1162
|
-
service.getCharacteristic(api.hap.Characteristic.CurrentRelativeHumidity).updateValue(humidity);
|
|
1163
|
-
}
|
|
1137
|
+
service.getCharacteristic(characteristicCurrentTemp).updateValue(acc.context.currentTemp);
|
|
1164
1138
|
}
|
|
1165
|
-
});
|
|
1166
|
-
}
|
|
1167
1139
|
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1140
|
+
// Set target temperature for both heating and cooling
|
|
1141
|
+
if (!isNaN(targetTemp)) {
|
|
1142
|
+
// For AC zones, set temperature based on the mode
|
|
1143
|
+
if (zone.type === 'AIR_CONDITIONING') {
|
|
1144
|
+
// Always set both characteristics but log which one is active
|
|
1145
|
+
service.getCharacteristic(characteristicTargetTempHeating).updateValue(targetTemp);
|
|
1146
|
+
service.getCharacteristic(characteristicTargetTempCooling).updateValue(targetTemp);
|
|
1147
|
+
} else {
|
|
1148
|
+
// Non-AC zones (like boiler/hot water)
|
|
1149
|
+
service.getCharacteristic(characteristicTargetTempHeating).updateValue(targetTemp);
|
|
1150
|
+
service.getCharacteristic(characteristicTargetTempCooling).updateValue(targetTemp);
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1172
1153
|
|
|
1173
|
-
|
|
1154
|
+
// Fan speed polling removed for AIR_CONDITIONING zones
|
|
1174
1155
|
|
|
1175
|
-
|
|
1156
|
+
// Update humidity for all zones that support it
|
|
1157
|
+
if (!isNaN(humidity) && service.testCharacteristic(api.hap.Characteristic.CurrentRelativeHumidity)) {
|
|
1158
|
+
service.getCharacteristic(api.hap.Characteristic.CurrentRelativeHumidity).updateValue(humidity);
|
|
1176
1159
|
}
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1179
|
-
|
|
1180
|
-
if (faucetAccessory.length) {
|
|
1181
|
-
faucetAccessory.forEach((acc) => {
|
|
1182
|
-
if (acc.displayName.includes(zone.name)) {
|
|
1183
|
-
let service = acc.getService(api.hap.Service.Valve);
|
|
1160
|
+
}
|
|
1161
|
+
});
|
|
1162
|
+
}
|
|
1184
1163
|
|
|
1185
|
-
|
|
1186
|
-
|
|
1164
|
+
if (switchAccessory.length) {
|
|
1165
|
+
switchAccessory.forEach((acc) => {
|
|
1166
|
+
if (acc.displayName.includes(zone.name)) {
|
|
1167
|
+
let service = acc.getService(api.hap.Service.Switch);
|
|
1187
1168
|
|
|
1188
|
-
|
|
1169
|
+
let characteristic = api.hap.Characteristic.On;
|
|
1189
1170
|
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
}
|
|
1171
|
+
service.getCharacteristic(characteristic).updateValue(active ? true : false);
|
|
1172
|
+
}
|
|
1173
|
+
});
|
|
1194
1174
|
}
|
|
1195
1175
|
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
if (tempAccessory.length) {
|
|
1200
|
-
tempAccessory.forEach((acc) => {
|
|
1176
|
+
if (faucetAccessory.length) {
|
|
1177
|
+
faucetAccessory.forEach((acc) => {
|
|
1201
1178
|
if (acc.displayName.includes(zone.name)) {
|
|
1202
|
-
let
|
|
1203
|
-
let characteristicBattery = api.hap.Characteristic.BatteryLevel;
|
|
1179
|
+
let service = acc.getService(api.hap.Service.Valve);
|
|
1204
1180
|
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
}
|
|
1181
|
+
let characteristicActive = api.hap.Characteristic.Active;
|
|
1182
|
+
let characteristicInUse = api.hap.Characteristic.InUse;
|
|
1208
1183
|
|
|
1209
|
-
|
|
1210
|
-
let service = acc.getService(api.hap.Service.TemperatureSensor);
|
|
1211
|
-
let characteristic = api.hap.Characteristic.CurrentTemperature;
|
|
1184
|
+
service.getCharacteristic(characteristicActive).updateValue(active ? 1 : 0);
|
|
1212
1185
|
|
|
1213
|
-
|
|
1214
|
-
}
|
|
1186
|
+
service.getCharacteristic(characteristicInUse).updateValue(active ? 1 : 0);
|
|
1215
1187
|
}
|
|
1216
1188
|
});
|
|
1217
1189
|
}
|
|
1190
|
+
}
|
|
1218
1191
|
|
|
1219
|
-
|
|
1220
|
-
|
|
1192
|
+
//TemperatureSensor
|
|
1193
|
+
const tempAccessory = accessories.filter((acc) => acc && acc.context.config.subtype === 'zone-temperature');
|
|
1221
1194
|
|
|
1222
|
-
|
|
1195
|
+
if (tempAccessory.length) {
|
|
1196
|
+
tempAccessory.forEach((acc) => {
|
|
1223
1197
|
if (acc.displayName.includes(zone.name)) {
|
|
1224
1198
|
let serviceBattery = acc.getService(api.hap.Service.BatteryService);
|
|
1225
1199
|
let characteristicBattery = api.hap.Characteristic.BatteryLevel;
|
|
@@ -1228,327 +1202,340 @@ export default (api, accessories, config, tado, telegram) => {
|
|
|
1228
1202
|
serviceBattery.getCharacteristic(characteristicBattery).updateValue(battery);
|
|
1229
1203
|
}
|
|
1230
1204
|
|
|
1231
|
-
if (!isNaN(
|
|
1232
|
-
let service = acc.getService(api.hap.Service.
|
|
1233
|
-
let characteristic = api.hap.Characteristic.
|
|
1205
|
+
if (!isNaN(currentTemp)) {
|
|
1206
|
+
let service = acc.getService(api.hap.Service.TemperatureSensor);
|
|
1207
|
+
let characteristic = api.hap.Characteristic.CurrentTemperature;
|
|
1234
1208
|
|
|
1235
|
-
service.getCharacteristic(characteristic).updateValue(
|
|
1209
|
+
service.getCharacteristic(characteristic).updateValue(currentTemp);
|
|
1236
1210
|
}
|
|
1237
1211
|
}
|
|
1238
1212
|
});
|
|
1213
|
+
}
|
|
1239
1214
|
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
(acc) => acc && acc.context.config.subtype === 'zone-window-contact'
|
|
1243
|
-
);
|
|
1244
|
-
const windowSwitchAccessory = accessories.filter(
|
|
1245
|
-
(acc) => acc && acc.displayName === acc.context.config.homeName + ' Open Window'
|
|
1246
|
-
);
|
|
1247
|
-
|
|
1248
|
-
if (windowContactAccessory.length) {
|
|
1249
|
-
windowContactAccessory.forEach((acc) => {
|
|
1250
|
-
if (acc.displayName.includes(zone.name)) {
|
|
1251
|
-
let serviceBattery = acc.getService(api.hap.Service.BatteryService);
|
|
1252
|
-
let characteristicBattery = api.hap.Characteristic.BatteryLevel;
|
|
1215
|
+
//HumiditySensor
|
|
1216
|
+
const humidityAccessory = accessories.filter((acc) => acc && acc.context.config.subtype === 'zone-humidity');
|
|
1253
1217
|
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1218
|
+
humidityAccessory.forEach((acc) => {
|
|
1219
|
+
if (acc.displayName.includes(zone.name)) {
|
|
1220
|
+
let serviceBattery = acc.getService(api.hap.Service.BatteryService);
|
|
1221
|
+
let characteristicBattery = api.hap.Characteristic.BatteryLevel;
|
|
1257
1222
|
|
|
1258
|
-
|
|
1259
|
-
|
|
1223
|
+
if (serviceBattery && !isNaN(battery)) {
|
|
1224
|
+
serviceBattery.getCharacteristic(characteristicBattery).updateValue(battery);
|
|
1225
|
+
}
|
|
1260
1226
|
|
|
1261
|
-
|
|
1227
|
+
if (!isNaN(humidity)) {
|
|
1228
|
+
let service = acc.getService(api.hap.Service.HumiditySensor);
|
|
1229
|
+
let characteristic = api.hap.Characteristic.CurrentRelativeHumidity;
|
|
1262
1230
|
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
});
|
|
1231
|
+
service.getCharacteristic(characteristic).updateValue(humidity);
|
|
1232
|
+
}
|
|
1266
1233
|
}
|
|
1234
|
+
});
|
|
1267
1235
|
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1236
|
+
//WindowSensor
|
|
1237
|
+
const windowContactAccessory = accessories.filter(
|
|
1238
|
+
(acc) => acc && acc.context.config.subtype === 'zone-window-contact'
|
|
1239
|
+
);
|
|
1240
|
+
const windowSwitchAccessory = accessories.filter(
|
|
1241
|
+
(acc) => acc && acc.displayName === acc.context.config.homeName + ' Open Window'
|
|
1242
|
+
);
|
|
1273
1243
|
|
|
1274
|
-
|
|
1244
|
+
if (windowContactAccessory.length) {
|
|
1245
|
+
windowContactAccessory.forEach((acc) => {
|
|
1246
|
+
if (acc.displayName.includes(zone.name)) {
|
|
1247
|
+
let serviceBattery = acc.getService(api.hap.Service.BatteryService);
|
|
1248
|
+
let characteristicBattery = api.hap.Characteristic.BatteryLevel;
|
|
1275
1249
|
|
|
1276
|
-
|
|
1250
|
+
if (serviceBattery && !isNaN(battery)) {
|
|
1251
|
+
serviceBattery.getCharacteristic(characteristicBattery).updateValue(battery);
|
|
1277
1252
|
}
|
|
1278
|
-
});
|
|
1279
|
-
}
|
|
1280
1253
|
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
if (zoneState.overlayType === null) inAutoMode += 1;
|
|
1254
|
+
let service = acc.getService(api.hap.Service.ContactSensor);
|
|
1255
|
+
let characteristic = api.hap.Characteristic.ContactSensorState;
|
|
1284
1256
|
|
|
1285
|
-
|
|
1257
|
+
let state = zoneState.openWindow || zoneState.openWindowDetected ? 1 : 0;
|
|
1286
1258
|
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
}
|
|
1259
|
+
service.getCharacteristic(characteristic).updateValue(state);
|
|
1260
|
+
}
|
|
1261
|
+
});
|
|
1290
1262
|
}
|
|
1291
1263
|
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
if (centralSwitchAccessory.length) {
|
|
1298
|
-
centralSwitchAccessory[0].services.forEach((service) => {
|
|
1299
|
-
if (service.subtype === 'Central') {
|
|
1300
|
-
let serviceSwitch = centralSwitchAccessory[0].getServiceById(api.hap.Service.Switch, service.subtype);
|
|
1301
|
-
let characteristicOn = api.hap.Characteristic.On;
|
|
1302
|
-
let characteristicAuto = api.hap.Characteristic.AutoThermostats;
|
|
1303
|
-
let characteristicOff = api.hap.Characteristic.OfflineThermostats;
|
|
1304
|
-
let characteristicManual = api.hap.Characteristic.ManualThermostats;
|
|
1264
|
+
if (windowSwitchAccessory.length) {
|
|
1265
|
+
windowSwitchAccessory[0].services.forEach((switchService) => {
|
|
1266
|
+
if (switchService.subtype && switchService.subtype.includes(zone.name)) {
|
|
1267
|
+
let service = windowSwitchAccessory[0].getServiceById(api.hap.Service.Switch, switchService.subtype);
|
|
1268
|
+
let characteristic = api.hap.Characteristic.On;
|
|
1305
1269
|
|
|
1306
|
-
let state =
|
|
1270
|
+
let state = zone.openWindowEnabled ? true : false;
|
|
1307
1271
|
|
|
1308
|
-
|
|
1272
|
+
service.getCharacteristic(characteristic).updateValue(state);
|
|
1273
|
+
}
|
|
1274
|
+
});
|
|
1275
|
+
}
|
|
1309
1276
|
|
|
1310
|
-
|
|
1277
|
+
if (zoneState.setting.type === 'HEATING') {
|
|
1278
|
+
//CentralSwitch
|
|
1279
|
+
if (zoneState.overlayType === null) inAutoMode += 1;
|
|
1311
1280
|
|
|
1312
|
-
|
|
1281
|
+
if (zoneState.overlayType !== null && zoneState.setting.power === 'OFF') inOffMode += 1;
|
|
1313
1282
|
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
});
|
|
1283
|
+
if (zoneState.overlayType !== null && zoneState.setting.power === 'ON' && zoneState.overlay.termination)
|
|
1284
|
+
inManualMode += 1;
|
|
1317
1285
|
}
|
|
1318
1286
|
}
|
|
1287
|
+
|
|
1288
|
+
//CentralSwitch
|
|
1289
|
+
const centralSwitchAccessory = accessories.filter(
|
|
1290
|
+
(acc) => acc && acc.displayName === acc.context.config.homeName + ' Central Switch'
|
|
1291
|
+
);
|
|
1292
|
+
|
|
1293
|
+
if (centralSwitchAccessory.length) {
|
|
1294
|
+
centralSwitchAccessory[0].services.forEach((service) => {
|
|
1295
|
+
if (service.subtype === 'Central') {
|
|
1296
|
+
let serviceSwitch = centralSwitchAccessory[0].getServiceById(api.hap.Service.Switch, service.subtype);
|
|
1297
|
+
let characteristicOn = api.hap.Characteristic.On;
|
|
1298
|
+
let characteristicAuto = api.hap.Characteristic.AutoThermostats;
|
|
1299
|
+
let characteristicOff = api.hap.Characteristic.OfflineThermostats;
|
|
1300
|
+
let characteristicManual = api.hap.Characteristic.ManualThermostats;
|
|
1301
|
+
|
|
1302
|
+
let state = (inManualMode || inAutoMode) !== 0;
|
|
1303
|
+
|
|
1304
|
+
serviceSwitch.getCharacteristic(characteristicAuto).updateValue(inAutoMode);
|
|
1305
|
+
|
|
1306
|
+
serviceSwitch.getCharacteristic(characteristicManual).updateValue(inManualMode);
|
|
1307
|
+
|
|
1308
|
+
serviceSwitch.getCharacteristic(characteristicOff).updateValue(inOffMode);
|
|
1309
|
+
|
|
1310
|
+
serviceSwitch.getCharacteristic(characteristicOn).updateValue(state);
|
|
1311
|
+
}
|
|
1312
|
+
});
|
|
1313
|
+
}
|
|
1319
1314
|
return zoneStates;
|
|
1320
1315
|
}
|
|
1321
1316
|
|
|
1322
1317
|
async function updateMobileDevices() {
|
|
1323
|
-
if (
|
|
1324
|
-
Logger.debug('Polling MobileDevices...', config.homeName);
|
|
1318
|
+
if (settingState) return;
|
|
1325
1319
|
|
|
1326
|
-
|
|
1320
|
+
Logger.debug('Polling MobileDevices...', config.homeName);
|
|
1327
1321
|
|
|
1328
|
-
|
|
1329
|
-
(user) =>
|
|
1330
|
-
user &&
|
|
1331
|
-
user.context.config.subtype.includes('presence') &&
|
|
1332
|
-
user.displayName !== user.context.config.homeName + ' Anyone'
|
|
1333
|
-
);
|
|
1322
|
+
const mobileDevices = await tado.getMobileDevices(config.homeId);
|
|
1334
1323
|
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1324
|
+
const userAccessories = accessories.filter(
|
|
1325
|
+
(user) =>
|
|
1326
|
+
user &&
|
|
1327
|
+
user.context.config.subtype.includes('presence') &&
|
|
1328
|
+
user.displayName !== user.context.config.homeName + ' Anyone'
|
|
1329
|
+
);
|
|
1341
1330
|
|
|
1342
|
-
|
|
1331
|
+
const anyone = accessories.filter(
|
|
1332
|
+
(user) =>
|
|
1333
|
+
user &&
|
|
1334
|
+
user.context.config.subtype.includes('presence') &&
|
|
1335
|
+
user.displayName === user.context.config.homeName + ' Anyone'
|
|
1336
|
+
);
|
|
1343
1337
|
|
|
1344
|
-
|
|
1345
|
-
userAccessories.forEach((acc) => {
|
|
1346
|
-
if (acc.context.config.homeName + ' ' + device.name === acc.displayName) {
|
|
1347
|
-
let atHome = device.location && device.location.atHome ? 1 : 0;
|
|
1338
|
+
let activeUser = 0;
|
|
1348
1339
|
|
|
1349
|
-
|
|
1340
|
+
mobileDevices.forEach((device) => {
|
|
1341
|
+
userAccessories.forEach((acc) => {
|
|
1342
|
+
if (acc.context.config.homeName + ' ' + device.name === acc.displayName) {
|
|
1343
|
+
let atHome = device.location && device.location.atHome ? 1 : 0;
|
|
1350
1344
|
|
|
1351
|
-
|
|
1352
|
-
acc.getService(api.hap.Service.MotionSensor) || acc.getService(api.hap.Service.OccupancySensor);
|
|
1345
|
+
if (atHome) activeUser += 1;
|
|
1353
1346
|
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
: api.hap.Characteristic.OccupancyDetected;
|
|
1347
|
+
let service =
|
|
1348
|
+
acc.getService(api.hap.Service.MotionSensor) || acc.getService(api.hap.Service.OccupancySensor);
|
|
1357
1349
|
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1350
|
+
let characteristic = service.testCharacteristic(api.hap.Characteristic.MotionDetected)
|
|
1351
|
+
? api.hap.Characteristic.MotionDetected
|
|
1352
|
+
: api.hap.Characteristic.OccupancyDetected;
|
|
1353
|
+
|
|
1354
|
+
service.getCharacteristic(characteristic).updateValue(atHome);
|
|
1355
|
+
}
|
|
1361
1356
|
});
|
|
1357
|
+
});
|
|
1362
1358
|
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1359
|
+
if (anyone.length) {
|
|
1360
|
+
let service =
|
|
1361
|
+
anyone[0].getService(api.hap.Service.MotionSensor) || anyone[0].getService(api.hap.Service.OccupancySensor);
|
|
1366
1362
|
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1363
|
+
let characteristic = service.testCharacteristic(api.hap.Characteristic.MotionDetected)
|
|
1364
|
+
? api.hap.Characteristic.MotionDetected
|
|
1365
|
+
: api.hap.Characteristic.OccupancyDetected;
|
|
1370
1366
|
|
|
1371
|
-
|
|
1372
|
-
}
|
|
1367
|
+
service.getCharacteristic(characteristic).updateValue(activeUser ? 1 : 0);
|
|
1373
1368
|
}
|
|
1374
|
-
|
|
1375
|
-
return;
|
|
1376
1369
|
}
|
|
1377
1370
|
|
|
1378
1371
|
async function updateWeather() {
|
|
1379
|
-
if (
|
|
1380
|
-
const weatherTemperatureAccessory = accessories.filter(
|
|
1381
|
-
(acc) => acc && acc.displayName === acc.context.config.homeName + ' Weather'
|
|
1382
|
-
);
|
|
1372
|
+
if (settingState) return;
|
|
1383
1373
|
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1374
|
+
const weatherTemperatureAccessory = accessories.filter(
|
|
1375
|
+
(acc) => acc && acc.displayName === acc.context.config.homeName + ' Weather'
|
|
1376
|
+
);
|
|
1387
1377
|
|
|
1388
|
-
|
|
1389
|
-
|
|
1378
|
+
const solarIntensityAccessory = accessories.filter(
|
|
1379
|
+
(acc) => acc && acc.displayName === acc.context.config.homeName + ' Solar Intensity'
|
|
1380
|
+
);
|
|
1390
1381
|
|
|
1391
|
-
|
|
1382
|
+
if (weatherTemperatureAccessory.length || solarIntensityAccessory.length) {
|
|
1383
|
+
Logger.debug('Polling Weather...', config.homeName);
|
|
1392
1384
|
|
|
1393
|
-
|
|
1394
|
-
let tempUnit = config.temperatureUnit;
|
|
1395
|
-
let service = weatherTemperatureAccessory[0].getService(api.hap.Service.TemperatureSensor);
|
|
1396
|
-
let characteristic = api.hap.Characteristic.CurrentTemperature;
|
|
1385
|
+
const weather = await tado.getWeather(config.homeId);
|
|
1397
1386
|
|
|
1398
|
-
|
|
1399
|
-
|
|
1387
|
+
if (weatherTemperatureAccessory.length && weather.outsideTemperature) {
|
|
1388
|
+
let tempUnit = config.temperatureUnit;
|
|
1389
|
+
let service = weatherTemperatureAccessory[0].getService(api.hap.Service.TemperatureSensor);
|
|
1390
|
+
let characteristic = api.hap.Characteristic.CurrentTemperature;
|
|
1400
1391
|
|
|
1401
|
-
|
|
1402
|
-
|
|
1392
|
+
let temp =
|
|
1393
|
+
tempUnit === 'FAHRENHEIT' ? weather.outsideTemperature.fahrenheit : weather.outsideTemperature.celsius;
|
|
1403
1394
|
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
let brightness = weather.solarIntensity.percentage;
|
|
1395
|
+
service.getCharacteristic(characteristic).updateValue(temp);
|
|
1396
|
+
}
|
|
1407
1397
|
|
|
1408
|
-
|
|
1409
|
-
|
|
1398
|
+
if (solarIntensityAccessory.length && weather.solarIntensity) {
|
|
1399
|
+
let state = weather.solarIntensity.percentage !== 0;
|
|
1400
|
+
let brightness = weather.solarIntensity.percentage;
|
|
1410
1401
|
|
|
1411
|
-
|
|
1412
|
-
|
|
1402
|
+
solarIntensityAccessory[0].context.lightBulbState = state;
|
|
1403
|
+
solarIntensityAccessory[0].context.lightBulbBrightness = brightness;
|
|
1413
1404
|
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
let characteristicBrightness = api.hap.Characteristic.Brightness;
|
|
1405
|
+
let serviceLightbulb = solarIntensityAccessory[0].getService(api.hap.Service.Lightbulb);
|
|
1406
|
+
let serviceLightsensor = solarIntensityAccessory[0].getService(api.hap.Service.LightSensor);
|
|
1417
1407
|
|
|
1418
|
-
|
|
1408
|
+
if (serviceLightbulb) {
|
|
1409
|
+
let characteristicOn = api.hap.Characteristic.On;
|
|
1410
|
+
let characteristicBrightness = api.hap.Characteristic.Brightness;
|
|
1419
1411
|
|
|
1420
|
-
|
|
1421
|
-
} else {
|
|
1422
|
-
let characteristicLux = api.hap.Characteristic.CurrentAmbientLightLevel;
|
|
1412
|
+
serviceLightbulb.getCharacteristic(characteristicOn).updateValue(state);
|
|
1423
1413
|
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1414
|
+
serviceLightbulb.getCharacteristic(characteristicBrightness).updateValue(brightness);
|
|
1415
|
+
} else {
|
|
1416
|
+
let characteristicLux = api.hap.Characteristic.CurrentAmbientLightLevel;
|
|
1417
|
+
|
|
1418
|
+
serviceLightsensor
|
|
1419
|
+
.getCharacteristic(characteristicLux)
|
|
1420
|
+
.updateValue(brightness ? brightness * 1000 : 0.0001);
|
|
1428
1421
|
}
|
|
1429
1422
|
}
|
|
1430
1423
|
}
|
|
1431
|
-
|
|
1432
|
-
return;
|
|
1433
1424
|
}
|
|
1434
1425
|
|
|
1435
1426
|
async function updatePresence() {
|
|
1436
|
-
if (
|
|
1437
|
-
const presenceLockAccessory = accessories.filter(
|
|
1438
|
-
(acc) => acc && acc.displayName === acc.context.config.homeName + ' Presence Lock'
|
|
1439
|
-
);
|
|
1427
|
+
if (settingState) return;
|
|
1440
1428
|
|
|
1441
|
-
|
|
1442
|
-
|
|
1429
|
+
const presenceLockAccessory = accessories.filter(
|
|
1430
|
+
(acc) => acc && acc.displayName === acc.context.config.homeName + ' Presence Lock'
|
|
1431
|
+
);
|
|
1443
1432
|
|
|
1444
|
-
|
|
1433
|
+
if (presenceLockAccessory.length) {
|
|
1434
|
+
Logger.debug('Polling PresenceLock...', config.homeName);
|
|
1445
1435
|
|
|
1446
|
-
|
|
1447
|
-
0: Home | true
|
|
1448
|
-
1: Away | true
|
|
1449
|
-
3: Off | false
|
|
1450
|
-
*/
|
|
1436
|
+
const presenceLock = await tado.getState(config.homeId);
|
|
1451
1437
|
|
|
1452
|
-
|
|
1438
|
+
/*
|
|
1439
|
+
0: Home | true
|
|
1440
|
+
1: Away | true
|
|
1441
|
+
3: Off | false
|
|
1442
|
+
*/
|
|
1453
1443
|
|
|
1454
|
-
|
|
1455
|
-
let serviceHomeSwitch = presenceLockAccessory[0].getServiceById(api.hap.Service.Switch, 'HomeSwitch');
|
|
1456
|
-
let serviceAwaySwitch = presenceLockAccessory[0].getServiceById(api.hap.Service.Switch, 'AwaySwitch');
|
|
1444
|
+
let state = presenceLock.presenceLocked ? (presenceLock.presence === 'AWAY' ? 1 : 0) : 3;
|
|
1457
1445
|
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1446
|
+
let serviceSecurity = presenceLockAccessory[0].getService(api.hap.Service.SecuritySystem);
|
|
1447
|
+
let serviceHomeSwitch = presenceLockAccessory[0].getServiceById(api.hap.Service.Switch, 'HomeSwitch');
|
|
1448
|
+
let serviceAwaySwitch = presenceLockAccessory[0].getServiceById(api.hap.Service.Switch, 'AwaySwitch');
|
|
1461
1449
|
|
|
1462
|
-
|
|
1450
|
+
if (serviceSecurity) {
|
|
1451
|
+
let characteristicCurrent = api.hap.Characteristic.SecuritySystemCurrentState;
|
|
1452
|
+
let characteristicTarget = api.hap.Characteristic.SecuritySystemTargetState;
|
|
1463
1453
|
|
|
1464
|
-
|
|
1465
|
-
} else if (serviceHomeSwitch || serviceAwaySwitch) {
|
|
1466
|
-
let characteristicOn = api.hap.Characteristic.On;
|
|
1454
|
+
serviceSecurity.getCharacteristic(characteristicCurrent).updateValue(state);
|
|
1467
1455
|
|
|
1468
|
-
|
|
1456
|
+
serviceSecurity.getCharacteristic(characteristicTarget).updateValue(state);
|
|
1457
|
+
} else if (serviceHomeSwitch || serviceAwaySwitch) {
|
|
1458
|
+
let characteristicOn = api.hap.Characteristic.On;
|
|
1469
1459
|
|
|
1470
|
-
|
|
1460
|
+
let homeState = !state ? true : false;
|
|
1471
1461
|
|
|
1472
|
-
|
|
1462
|
+
let awayState = state === 1 ? true : false;
|
|
1473
1463
|
|
|
1474
|
-
|
|
1475
|
-
|
|
1464
|
+
serviceAwaySwitch.getCharacteristic(characteristicOn).updateValue(awayState);
|
|
1465
|
+
|
|
1466
|
+
serviceHomeSwitch.getCharacteristic(characteristicOn).updateValue(homeState);
|
|
1476
1467
|
}
|
|
1477
1468
|
}
|
|
1478
1469
|
}
|
|
1479
1470
|
|
|
1480
1471
|
async function updateRunningTime() {
|
|
1481
|
-
if (
|
|
1482
|
-
const centralSwitchAccessory = accessories.filter(
|
|
1483
|
-
(acc) => acc && acc.displayName === acc.context.config.homeName + ' Central Switch'
|
|
1484
|
-
);
|
|
1472
|
+
if (settingState) return;
|
|
1485
1473
|
|
|
1486
|
-
|
|
1487
|
-
|
|
1474
|
+
const centralSwitchAccessory = accessories.filter(
|
|
1475
|
+
(acc) => acc && acc.displayName === acc.context.config.homeName + ' Central Switch'
|
|
1476
|
+
);
|
|
1488
1477
|
|
|
1489
|
-
|
|
1478
|
+
if (centralSwitchAccessory.length) {
|
|
1479
|
+
Logger.debug('Polling RunningTime...', config.homeName);
|
|
1490
1480
|
|
|
1491
|
-
|
|
1492
|
-
let fromDate =
|
|
1493
|
-
period === 'days'
|
|
1494
|
-
? moment().format('YYYY-MM-DD')
|
|
1495
|
-
: period === 'months'
|
|
1496
|
-
? moment().subtract(1, 'days').subtract(1, period).format('YYYY-MM-DD')
|
|
1497
|
-
: moment().add(1, 'months').startOf('month').subtract(1, period).format('YYYY-MM-DD');
|
|
1481
|
+
let periods = ['days', 'months', 'years'];
|
|
1498
1482
|
|
|
1499
|
-
|
|
1483
|
+
for (const period of periods) {
|
|
1484
|
+
let fromDate =
|
|
1485
|
+
period === 'days'
|
|
1486
|
+
? moment().format('YYYY-MM-DD')
|
|
1487
|
+
: period === 'months'
|
|
1488
|
+
? moment().subtract(1, 'days').subtract(1, period).format('YYYY-MM-DD')
|
|
1489
|
+
: moment().add(1, 'months').startOf('month').subtract(1, period).format('YYYY-MM-DD');
|
|
1500
1490
|
|
|
1501
|
-
|
|
1491
|
+
let toDate = period === 'years' ? moment().format('YYYY-MM-DD') : false;
|
|
1502
1492
|
|
|
1503
|
-
|
|
1493
|
+
let time = period.substring(0, period.length - 1);
|
|
1504
1494
|
|
|
1505
|
-
|
|
1506
|
-
let summaryInHours = runningTime.summary.totalRunningTimeInSeconds / 3600;
|
|
1495
|
+
const runningTime = await tado.getRunningTime(config.homeId, time, fromDate, toDate);
|
|
1507
1496
|
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
period === 'years'
|
|
1511
|
-
? api.hap.Characteristic.OverallHeatYear
|
|
1512
|
-
: period === 'months'
|
|
1513
|
-
? api.hap.Characteristic.OverallHeatMonth
|
|
1514
|
-
: api.hap.Characteristic.OverallHeatDay;
|
|
1497
|
+
if (runningTime && runningTime.summary) {
|
|
1498
|
+
let summaryInHours = runningTime.summary.totalRunningTimeInSeconds / 3600;
|
|
1515
1499
|
|
|
1516
|
-
|
|
1517
|
-
|
|
1500
|
+
let serviceSwitch = centralSwitchAccessory[0].getServiceById(api.hap.Service.Switch, 'Central');
|
|
1501
|
+
let characteristic =
|
|
1502
|
+
period === 'years'
|
|
1503
|
+
? api.hap.Characteristic.OverallHeatYear
|
|
1504
|
+
: period === 'months'
|
|
1505
|
+
? api.hap.Characteristic.OverallHeatMonth
|
|
1506
|
+
: api.hap.Characteristic.OverallHeatDay;
|
|
1518
1507
|
|
|
1519
|
-
|
|
1508
|
+
serviceSwitch.getCharacteristic(characteristic).updateValue(summaryInHours);
|
|
1520
1509
|
}
|
|
1510
|
+
|
|
1511
|
+
await timeout(500);
|
|
1521
1512
|
}
|
|
1522
1513
|
}
|
|
1523
|
-
|
|
1524
|
-
return;
|
|
1525
1514
|
}
|
|
1526
1515
|
|
|
1527
1516
|
async function updateDevices() {
|
|
1528
|
-
if (
|
|
1529
|
-
Logger.debug('Polling Devices...', config.homeName);
|
|
1517
|
+
if (settingState) return;
|
|
1530
1518
|
|
|
1531
|
-
|
|
1519
|
+
Logger.debug('Polling Devices...', config.homeName);
|
|
1532
1520
|
|
|
1533
|
-
|
|
1534
|
-
(acc) => acc && acc.context.config.subtype === 'extra-childswitch'
|
|
1535
|
-
);
|
|
1521
|
+
const devices = await tado.getDevices(config.homeId);
|
|
1536
1522
|
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
let serviceChildLock = childLockAccessories[0].getServiceById(api.hap.Service.Switch, service.subtype);
|
|
1541
|
-
let characteristic = api.hap.Characteristic.On;
|
|
1523
|
+
const childLockAccessories = accessories.filter(
|
|
1524
|
+
(acc) => acc && acc.context.config.subtype === 'extra-childswitch'
|
|
1525
|
+
);
|
|
1542
1526
|
|
|
1543
|
-
|
|
1527
|
+
devices.forEach((device) => {
|
|
1528
|
+
childLockAccessories[0].services.forEach((service) => {
|
|
1529
|
+
if (device.serialNo === service.subtype) {
|
|
1530
|
+
let serviceChildLock = childLockAccessories[0].getServiceById(api.hap.Service.Switch, service.subtype);
|
|
1531
|
+
let characteristic = api.hap.Characteristic.On;
|
|
1544
1532
|
|
|
1545
|
-
|
|
1546
|
-
}
|
|
1547
|
-
});
|
|
1548
|
-
});
|
|
1549
|
-
}
|
|
1533
|
+
let childLockEnabled = device.childLockEnabled || false;
|
|
1550
1534
|
|
|
1551
|
-
|
|
1535
|
+
serviceChildLock.getCharacteristic(characteristic).updateValue(childLockEnabled);
|
|
1536
|
+
}
|
|
1537
|
+
});
|
|
1538
|
+
});
|
|
1552
1539
|
}
|
|
1553
1540
|
|
|
1554
1541
|
function errorHandler(err) {
|