@homebridge-plugins/homebridge-tado 8.5.1-beta.1 → 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 +518 -527
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 = [];
|
|
@@ -746,7 +746,7 @@ export default (api, accessories, config, tado, telegram) => {
|
|
|
746
746
|
}
|
|
747
747
|
try {
|
|
748
748
|
//wait for fakegato history services to be loaded
|
|
749
|
-
await
|
|
749
|
+
await timeout(4000);
|
|
750
750
|
for (const refreshHistory of aRefreshHistoryHandlers) {
|
|
751
751
|
refreshHistory();
|
|
752
752
|
}
|
|
@@ -809,413 +809,391 @@ export default (api, accessories, config, tado, telegram) => {
|
|
|
809
809
|
}
|
|
810
810
|
|
|
811
811
|
async function updateMe() {
|
|
812
|
-
if (
|
|
813
|
-
Logger.debug('Polling User Info...', config.homeName);
|
|
812
|
+
if (settingState) return;
|
|
814
813
|
|
|
815
|
-
|
|
814
|
+
Logger.debug('Polling User Info...', config.homeName);
|
|
816
815
|
|
|
817
|
-
|
|
816
|
+
const me = await tado.getMe();
|
|
818
817
|
|
|
819
|
-
|
|
820
|
-
}
|
|
818
|
+
if (config.homeName !== me.homes[0].name) throw ('Cannot find requested home in the API!', config.homeName);
|
|
821
819
|
|
|
822
|
-
|
|
820
|
+
config.homeId = me.homes[0].id;
|
|
823
821
|
}
|
|
824
822
|
|
|
825
823
|
async function updateHome() {
|
|
826
|
-
if (
|
|
827
|
-
Logger.debug('Polling Home Info...', config.homeName);
|
|
824
|
+
if (settingState) return;
|
|
828
825
|
|
|
829
|
-
|
|
826
|
+
Logger.debug('Polling Home Info...', config.homeName);
|
|
830
827
|
|
|
831
|
-
|
|
828
|
+
const home = await tado.getHome(config.homeId);
|
|
832
829
|
|
|
833
|
-
|
|
830
|
+
if (!config.temperatureUnit) config.temperatureUnit = home.temperatureUnit || 'CELSIUS';
|
|
834
831
|
|
|
835
|
-
|
|
836
|
-
!config.geolocation ||
|
|
837
|
-
(config.geolocation && !config.geolocation.longitude) ||
|
|
838
|
-
!config.geolocation.latitude
|
|
839
|
-
) {
|
|
840
|
-
if (!home.geolocation) home.geolocation = {};
|
|
832
|
+
//config.skills = home.skills || []; //do we need this?
|
|
841
833
|
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
834
|
+
if (
|
|
835
|
+
!config.geolocation ||
|
|
836
|
+
(config.geolocation && !config.geolocation.longitude) ||
|
|
837
|
+
!config.geolocation.latitude
|
|
838
|
+
) {
|
|
839
|
+
if (!home.geolocation) home.geolocation = {};
|
|
848
840
|
|
|
849
|
-
|
|
841
|
+
config.geolocation = {
|
|
842
|
+
longitude: (home.geolocation.longitude || '').toString() || false,
|
|
843
|
+
latitude: (home.geolocation.latitude || '').toString() || false,
|
|
844
|
+
};
|
|
845
|
+
}
|
|
850
846
|
}
|
|
851
847
|
|
|
852
848
|
async function updateZones(idToUpdate) {
|
|
853
849
|
let zoneStates = {};
|
|
854
|
-
if (
|
|
855
|
-
|
|
850
|
+
if (settingState && idToUpdate === undefined) {
|
|
851
|
+
await timeout(10 * 1000);
|
|
852
|
+
if (settingState) return zoneStates;
|
|
853
|
+
}
|
|
856
854
|
|
|
857
|
-
|
|
858
|
-
let inManualMode = 0;
|
|
859
|
-
let inOffMode = 0;
|
|
860
|
-
let inAutoMode = 0;
|
|
855
|
+
Logger.debug('Polling Zones...', config.homeName);
|
|
861
856
|
|
|
862
|
-
|
|
857
|
+
//CentralSwitch
|
|
858
|
+
let inManualMode = 0;
|
|
859
|
+
let inOffMode = 0;
|
|
860
|
+
let inAutoMode = 0;
|
|
863
861
|
|
|
864
|
-
|
|
865
|
-
const allZones = (await tado.getZones(config.homeId)) || [];
|
|
866
|
-
|
|
867
|
-
for (const [index, zone] of config.zones.entries()) {
|
|
868
|
-
allZones.forEach((zoneWithID) => {
|
|
869
|
-
if (zoneWithID.name === zone.name) config.zones[index].id = zoneWithID.id;
|
|
870
|
-
});
|
|
871
|
-
}
|
|
872
|
-
}
|
|
862
|
+
let zonesWithoutID = config.zones.filter((zone) => zone && !zone.id);
|
|
873
863
|
|
|
864
|
+
if (zonesWithoutID.length) {
|
|
874
865
|
const allZones = (await tado.getZones(config.homeId)) || [];
|
|
875
866
|
|
|
876
867
|
for (const [index, zone] of config.zones.entries()) {
|
|
877
868
|
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
|
-
);
|
|
882
|
-
|
|
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
|
-
}
|
|
869
|
+
if (zoneWithID.name === zone.name) config.zones[index].id = zoneWithID.id;
|
|
901
870
|
});
|
|
902
871
|
}
|
|
872
|
+
}
|
|
903
873
|
|
|
904
|
-
|
|
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
|
-
}
|
|
912
|
-
|
|
913
|
-
for (const zone of zonesToUpdate) {
|
|
914
|
-
const zoneState = zoneStates[zone.id];
|
|
874
|
+
const allZones = (await tado.getZones(config.homeId)) || [];
|
|
915
875
|
|
|
916
|
-
|
|
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
|
+
);
|
|
917
882
|
|
|
918
|
-
|
|
919
|
-
|
|
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
|
+
}
|
|
920
903
|
|
|
921
|
-
|
|
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
|
+
}
|
|
922
912
|
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
currentTemp =
|
|
926
|
-
config.temperatureUnit === 'FAHRENHEIT'
|
|
927
|
-
? zoneState.sensorDataPoints.insideTemperature.fahrenheit
|
|
928
|
-
: zoneState.sensorDataPoints.insideTemperature.celsius;
|
|
913
|
+
for (const zone of zonesToUpdate) {
|
|
914
|
+
const zoneState = zoneStates[zone.id];
|
|
929
915
|
|
|
930
|
-
|
|
931
|
-
targetTemp =
|
|
932
|
-
config.temperatureUnit === 'FAHRENHEIT'
|
|
933
|
-
? zoneState.setting.temperature.fahrenheit
|
|
934
|
-
: zoneState.setting.temperature.celsius;
|
|
916
|
+
let currentState, targetState, currentTemp, targetTemp, humidity, active, battery, tempEqual;
|
|
935
917
|
|
|
936
|
-
|
|
918
|
+
if (zoneState.setting.type === 'HEATING') {
|
|
919
|
+
battery = zone.battery === 'NORMAL' ? 100 : 10;
|
|
937
920
|
|
|
938
|
-
|
|
939
|
-
currentState = currentTemp < targetTemp ? 1 : 0;
|
|
921
|
+
if (zoneState.sensorDataPoints.humidity) humidity = zoneState.sensorDataPoints.humidity.percentage;
|
|
940
922
|
|
|
941
|
-
|
|
942
|
-
|
|
923
|
+
//HEATING
|
|
924
|
+
if (zoneState.sensorDataPoints.insideTemperature) {
|
|
925
|
+
currentTemp =
|
|
926
|
+
config.temperatureUnit === 'FAHRENHEIT'
|
|
927
|
+
? zoneState.sensorDataPoints.insideTemperature.fahrenheit
|
|
928
|
+
: zoneState.sensorDataPoints.insideTemperature.celsius;
|
|
943
929
|
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
active = 0;
|
|
950
|
-
}
|
|
930
|
+
if (zoneState.setting.power === 'ON') {
|
|
931
|
+
targetTemp =
|
|
932
|
+
config.temperatureUnit === 'FAHRENHEIT'
|
|
933
|
+
? zoneState.setting.temperature.fahrenheit
|
|
934
|
+
: zoneState.setting.temperature.celsius;
|
|
951
935
|
|
|
952
|
-
|
|
953
|
-
targetState = 3;
|
|
954
|
-
}
|
|
955
|
-
}
|
|
936
|
+
tempEqual = Math.round(currentTemp) === Math.round(targetTemp);
|
|
956
937
|
|
|
957
|
-
|
|
958
|
-
|
|
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
|
-
);
|
|
938
|
+
//show as currently heating if current temp is lower than target temp, otherwise show as temp set
|
|
939
|
+
currentState = currentTemp < targetTemp ? 1 : 0;
|
|
965
940
|
|
|
966
|
-
|
|
967
|
-
|
|
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);
|
|
941
|
+
//check if auto mode is enabled
|
|
942
|
+
targetState = zoneState.overlayType === null ? 3 : 1;
|
|
971
943
|
|
|
972
|
-
|
|
973
|
-
|
|
944
|
+
active = 1;
|
|
945
|
+
} else {
|
|
946
|
+
//heating is switched off
|
|
947
|
+
currentState = 0;
|
|
948
|
+
targetState = 0;
|
|
949
|
+
active = 0;
|
|
950
|
+
}
|
|
974
951
|
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
952
|
+
if (targetState === undefined && zoneState.overlayType === null) {
|
|
953
|
+
targetState = 3;
|
|
954
|
+
}
|
|
955
|
+
}
|
|
978
956
|
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
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
|
+
);
|
|
986
965
|
|
|
987
|
-
|
|
988
|
-
|
|
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);
|
|
989
971
|
|
|
990
|
-
|
|
991
|
-
|
|
972
|
+
let serviceBattery = acc.getService(api.hap.Service.BatteryService);
|
|
973
|
+
let characteristicBattery = api.hap.Characteristic.BatteryLevel;
|
|
992
974
|
|
|
993
|
-
|
|
994
|
-
|
|
975
|
+
if (serviceBattery && zone.battery) {
|
|
976
|
+
serviceBattery.getCharacteristic(characteristicBattery).updateValue(battery);
|
|
977
|
+
}
|
|
995
978
|
|
|
996
|
-
|
|
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;
|
|
997
986
|
|
|
998
|
-
|
|
999
|
-
|
|
987
|
+
if (!isNaN(currentTemp)) {
|
|
988
|
+
acc.context.config.temperatureUnit = acc.context.config.temperatureUnit || config.temperatureUnit;
|
|
1000
989
|
|
|
1001
|
-
|
|
1002
|
-
|
|
990
|
+
let isFahrenheit = serviceThermostat.getCharacteristic(characteristicUnit).value === 1;
|
|
991
|
+
let unitChanged = config.temperatureUnit !== acc.context.config.temperatureUnit;
|
|
1003
992
|
|
|
1004
|
-
|
|
1005
|
-
|
|
993
|
+
let cToF = (c) => Math.round((c * 9) / 5 + 32);
|
|
994
|
+
let fToC = (f) => Math.round(((f - 32) * 5) / 9);
|
|
1006
995
|
|
|
1007
|
-
|
|
1008
|
-
serviceThermostat.getCharacteristic(characteristicTargetState).updateValue(targetState);
|
|
996
|
+
let newValue = unitChanged ? (isFahrenheit ? cToF(currentTemp) : fToC(currentTemp)) : currentTemp;
|
|
1009
997
|
|
|
1010
|
-
|
|
1011
|
-
serviceThermostat.getCharacteristic(characteristicHumidity).updateValue(humidity);
|
|
998
|
+
serviceThermostat.getCharacteristic(characteristicCurrentTemp).updateValue(newValue);
|
|
1012
999
|
}
|
|
1013
1000
|
|
|
1014
|
-
if (
|
|
1015
|
-
|
|
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;
|
|
1001
|
+
if (!isNaN(targetTemp))
|
|
1002
|
+
serviceThermostat.getCharacteristic(characteristicTargetTemp).updateValue(targetTemp);
|
|
1022
1003
|
|
|
1023
|
-
|
|
1004
|
+
if (!isNaN(currentState))
|
|
1005
|
+
serviceThermostat.getCharacteristic(characteristicCurrentState).updateValue(currentState);
|
|
1024
1006
|
|
|
1025
|
-
|
|
1007
|
+
if (!isNaN(targetState))
|
|
1008
|
+
serviceThermostat.getCharacteristic(characteristicTargetState).updateValue(targetState);
|
|
1026
1009
|
|
|
1027
|
-
|
|
1010
|
+
if (!isNaN(humidity) && serviceThermostat.testCharacteristic(characteristicHumidity))
|
|
1011
|
+
serviceThermostat.getCharacteristic(characteristicHumidity).updateValue(humidity);
|
|
1012
|
+
}
|
|
1028
1013
|
|
|
1029
|
-
|
|
1030
|
-
|
|
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;
|
|
1031
1022
|
|
|
1032
|
-
|
|
1033
|
-
serviceHeaterCooler.getCharacteristic(characteristicTargetTempHeating).updateValue(targetTemp);
|
|
1023
|
+
currentState = active ? (targetState === 3 || tempEqual ? 1 : currentState + 1) : 0;
|
|
1034
1024
|
|
|
1035
|
-
|
|
1036
|
-
}
|
|
1025
|
+
targetState = 1;
|
|
1037
1026
|
|
|
1038
|
-
|
|
1039
|
-
serviceHeaterCooler.getCharacteristic(characteristicCurrentState).updateValue(currentState);
|
|
1027
|
+
if (!isNaN(active)) serviceHeaterCooler.getCharacteristic(characteristicActive).updateValue(active);
|
|
1040
1028
|
|
|
1041
|
-
|
|
1042
|
-
|
|
1029
|
+
if (!isNaN(currentTemp))
|
|
1030
|
+
serviceHeaterCooler.getCharacteristic(characteristicCurrentTemp).updateValue(currentTemp);
|
|
1043
1031
|
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
}
|
|
1047
|
-
}
|
|
1048
|
-
});
|
|
1049
|
-
}
|
|
1050
|
-
} else {
|
|
1051
|
-
// Non-HEATING zones (AIR_CONDITIONING, HOT_WATER, etc.)
|
|
1052
|
-
battery = zone.battery === 'NORMAL' ? 100 : 10;
|
|
1032
|
+
if (!isNaN(targetTemp)) {
|
|
1033
|
+
serviceHeaterCooler.getCharacteristic(characteristicTargetTempHeating).updateValue(targetTemp);
|
|
1053
1034
|
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
}
|
|
1035
|
+
serviceHeaterCooler.getCharacteristic(characteristicTargetTempCooling).updateValue(targetTemp);
|
|
1036
|
+
}
|
|
1057
1037
|
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
currentTemp =
|
|
1061
|
-
config.temperatureUnit === 'FAHRENHEIT'
|
|
1062
|
-
? zoneState.sensorDataPoints.insideTemperature.fahrenheit
|
|
1063
|
-
: zoneState.sensorDataPoints.insideTemperature.celsius;
|
|
1064
|
-
}
|
|
1038
|
+
if (!isNaN(currentState))
|
|
1039
|
+
serviceHeaterCooler.getCharacteristic(characteristicCurrentState).updateValue(currentState);
|
|
1065
1040
|
|
|
1066
|
-
|
|
1067
|
-
|
|
1041
|
+
if (!isNaN(targetState))
|
|
1042
|
+
serviceHeaterCooler.getCharacteristic(characteristicTargetState).updateValue(targetState);
|
|
1068
1043
|
|
|
1069
|
-
|
|
1070
|
-
|
|
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;
|
|
1044
|
+
if (!isNaN(humidity) && serviceHeaterCooler.testCharacteristic(characteristicHumidity))
|
|
1045
|
+
serviceHeaterCooler.getCharacteristic(characteristicHumidity).updateValue(humidity);
|
|
1094
1046
|
}
|
|
1095
|
-
} else {
|
|
1096
|
-
// Non-AC zones (HOT_WATER, etc.)
|
|
1097
|
-
currentState = zoneState.overlayType === null ? 1 : 2;
|
|
1098
|
-
targetState = 1;
|
|
1099
1047
|
}
|
|
1100
|
-
}
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
}
|
|
1048
|
+
});
|
|
1049
|
+
}
|
|
1050
|
+
} else {
|
|
1051
|
+
// Non-HEATING zones (AIR_CONDITIONING, HOT_WATER, etc.)
|
|
1052
|
+
battery = zone.battery === 'NORMAL' ? 100 : 10;
|
|
1106
1053
|
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
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');
|
|
1054
|
+
if (zoneState.sensorDataPoints.humidity) {
|
|
1055
|
+
humidity = zoneState.sensorDataPoints.humidity.percentage;
|
|
1056
|
+
}
|
|
1114
1057
|
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
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
|
+
}
|
|
1119
1065
|
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
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
|
+
}
|
|
1126
1106
|
|
|
1127
|
-
|
|
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');
|
|
1128
1114
|
|
|
1129
|
-
|
|
1115
|
+
if (heaterAccessory.length) {
|
|
1116
|
+
heaterAccessory.forEach((acc) => {
|
|
1117
|
+
if (acc.displayName.includes(zone.name)) {
|
|
1118
|
+
let service = acc.getService(api.hap.Service.HeaterCooler);
|
|
1130
1119
|
|
|
1131
|
-
|
|
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;
|
|
1132
1126
|
|
|
1133
|
-
|
|
1134
|
-
if (!isNaN(currentTemp) || acc.context.currentTemp) {
|
|
1135
|
-
if (!isNaN(currentTemp)) acc.context.currentTemp = currentTemp; //store current temp in config
|
|
1127
|
+
service.getCharacteristic(characteristicActive).updateValue(active);
|
|
1136
1128
|
|
|
1137
|
-
|
|
1138
|
-
}
|
|
1129
|
+
service.getCharacteristic(characteristicCurrentState).updateValue(currentState);
|
|
1139
1130
|
|
|
1140
|
-
|
|
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
|
-
}
|
|
1131
|
+
service.getCharacteristic(characteristicTargetState).updateValue(targetState);
|
|
1153
1132
|
|
|
1154
|
-
|
|
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
|
|
1155
1136
|
|
|
1156
|
-
|
|
1157
|
-
if (!isNaN(humidity) && service.testCharacteristic(api.hap.Characteristic.CurrentRelativeHumidity)) {
|
|
1158
|
-
service.getCharacteristic(api.hap.Characteristic.CurrentRelativeHumidity).updateValue(humidity);
|
|
1159
|
-
}
|
|
1137
|
+
service.getCharacteristic(characteristicCurrentTemp).updateValue(acc.context.currentTemp);
|
|
1160
1138
|
}
|
|
1161
|
-
});
|
|
1162
|
-
}
|
|
1163
1139
|
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
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
|
+
}
|
|
1168
1153
|
|
|
1169
|
-
|
|
1154
|
+
// Fan speed polling removed for AIR_CONDITIONING zones
|
|
1170
1155
|
|
|
1171
|
-
|
|
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);
|
|
1172
1159
|
}
|
|
1173
|
-
}
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
if (faucetAccessory.length) {
|
|
1177
|
-
faucetAccessory.forEach((acc) => {
|
|
1178
|
-
if (acc.displayName.includes(zone.name)) {
|
|
1179
|
-
let service = acc.getService(api.hap.Service.Valve);
|
|
1160
|
+
}
|
|
1161
|
+
});
|
|
1162
|
+
}
|
|
1180
1163
|
|
|
1181
|
-
|
|
1182
|
-
|
|
1164
|
+
if (switchAccessory.length) {
|
|
1165
|
+
switchAccessory.forEach((acc) => {
|
|
1166
|
+
if (acc.displayName.includes(zone.name)) {
|
|
1167
|
+
let service = acc.getService(api.hap.Service.Switch);
|
|
1183
1168
|
|
|
1184
|
-
|
|
1169
|
+
let characteristic = api.hap.Characteristic.On;
|
|
1185
1170
|
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
}
|
|
1171
|
+
service.getCharacteristic(characteristic).updateValue(active ? true : false);
|
|
1172
|
+
}
|
|
1173
|
+
});
|
|
1190
1174
|
}
|
|
1191
1175
|
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
if (tempAccessory.length) {
|
|
1196
|
-
tempAccessory.forEach((acc) => {
|
|
1176
|
+
if (faucetAccessory.length) {
|
|
1177
|
+
faucetAccessory.forEach((acc) => {
|
|
1197
1178
|
if (acc.displayName.includes(zone.name)) {
|
|
1198
|
-
let
|
|
1199
|
-
let characteristicBattery = api.hap.Characteristic.BatteryLevel;
|
|
1179
|
+
let service = acc.getService(api.hap.Service.Valve);
|
|
1200
1180
|
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
}
|
|
1181
|
+
let characteristicActive = api.hap.Characteristic.Active;
|
|
1182
|
+
let characteristicInUse = api.hap.Characteristic.InUse;
|
|
1204
1183
|
|
|
1205
|
-
|
|
1206
|
-
let service = acc.getService(api.hap.Service.TemperatureSensor);
|
|
1207
|
-
let characteristic = api.hap.Characteristic.CurrentTemperature;
|
|
1184
|
+
service.getCharacteristic(characteristicActive).updateValue(active ? 1 : 0);
|
|
1208
1185
|
|
|
1209
|
-
|
|
1210
|
-
}
|
|
1186
|
+
service.getCharacteristic(characteristicInUse).updateValue(active ? 1 : 0);
|
|
1211
1187
|
}
|
|
1212
1188
|
});
|
|
1213
1189
|
}
|
|
1190
|
+
}
|
|
1214
1191
|
|
|
1215
|
-
|
|
1216
|
-
|
|
1192
|
+
//TemperatureSensor
|
|
1193
|
+
const tempAccessory = accessories.filter((acc) => acc && acc.context.config.subtype === 'zone-temperature');
|
|
1217
1194
|
|
|
1218
|
-
|
|
1195
|
+
if (tempAccessory.length) {
|
|
1196
|
+
tempAccessory.forEach((acc) => {
|
|
1219
1197
|
if (acc.displayName.includes(zone.name)) {
|
|
1220
1198
|
let serviceBattery = acc.getService(api.hap.Service.BatteryService);
|
|
1221
1199
|
let characteristicBattery = api.hap.Characteristic.BatteryLevel;
|
|
@@ -1224,327 +1202,340 @@ export default (api, accessories, config, tado, telegram) => {
|
|
|
1224
1202
|
serviceBattery.getCharacteristic(characteristicBattery).updateValue(battery);
|
|
1225
1203
|
}
|
|
1226
1204
|
|
|
1227
|
-
if (!isNaN(
|
|
1228
|
-
let service = acc.getService(api.hap.Service.
|
|
1229
|
-
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;
|
|
1230
1208
|
|
|
1231
|
-
service.getCharacteristic(characteristic).updateValue(
|
|
1209
|
+
service.getCharacteristic(characteristic).updateValue(currentTemp);
|
|
1232
1210
|
}
|
|
1233
1211
|
}
|
|
1234
1212
|
});
|
|
1213
|
+
}
|
|
1235
1214
|
|
|
1236
|
-
|
|
1237
|
-
|
|
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
|
-
);
|
|
1243
|
-
|
|
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;
|
|
1215
|
+
//HumiditySensor
|
|
1216
|
+
const humidityAccessory = accessories.filter((acc) => acc && acc.context.config.subtype === 'zone-humidity');
|
|
1249
1217
|
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
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;
|
|
1253
1222
|
|
|
1254
|
-
|
|
1255
|
-
|
|
1223
|
+
if (serviceBattery && !isNaN(battery)) {
|
|
1224
|
+
serviceBattery.getCharacteristic(characteristicBattery).updateValue(battery);
|
|
1225
|
+
}
|
|
1256
1226
|
|
|
1257
|
-
|
|
1227
|
+
if (!isNaN(humidity)) {
|
|
1228
|
+
let service = acc.getService(api.hap.Service.HumiditySensor);
|
|
1229
|
+
let characteristic = api.hap.Characteristic.CurrentRelativeHumidity;
|
|
1258
1230
|
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
});
|
|
1231
|
+
service.getCharacteristic(characteristic).updateValue(humidity);
|
|
1232
|
+
}
|
|
1262
1233
|
}
|
|
1234
|
+
});
|
|
1263
1235
|
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
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
|
+
);
|
|
1269
1243
|
|
|
1270
|
-
|
|
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;
|
|
1271
1249
|
|
|
1272
|
-
|
|
1250
|
+
if (serviceBattery && !isNaN(battery)) {
|
|
1251
|
+
serviceBattery.getCharacteristic(characteristicBattery).updateValue(battery);
|
|
1273
1252
|
}
|
|
1274
|
-
});
|
|
1275
|
-
}
|
|
1276
1253
|
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
if (zoneState.overlayType === null) inAutoMode += 1;
|
|
1254
|
+
let service = acc.getService(api.hap.Service.ContactSensor);
|
|
1255
|
+
let characteristic = api.hap.Characteristic.ContactSensorState;
|
|
1280
1256
|
|
|
1281
|
-
|
|
1257
|
+
let state = zoneState.openWindow || zoneState.openWindowDetected ? 1 : 0;
|
|
1282
1258
|
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
}
|
|
1259
|
+
service.getCharacteristic(characteristic).updateValue(state);
|
|
1260
|
+
}
|
|
1261
|
+
});
|
|
1286
1262
|
}
|
|
1287
1263
|
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
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;
|
|
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;
|
|
1301
1269
|
|
|
1302
|
-
let state =
|
|
1270
|
+
let state = zone.openWindowEnabled ? true : false;
|
|
1303
1271
|
|
|
1304
|
-
|
|
1272
|
+
service.getCharacteristic(characteristic).updateValue(state);
|
|
1273
|
+
}
|
|
1274
|
+
});
|
|
1275
|
+
}
|
|
1305
1276
|
|
|
1306
|
-
|
|
1277
|
+
if (zoneState.setting.type === 'HEATING') {
|
|
1278
|
+
//CentralSwitch
|
|
1279
|
+
if (zoneState.overlayType === null) inAutoMode += 1;
|
|
1307
1280
|
|
|
1308
|
-
|
|
1281
|
+
if (zoneState.overlayType !== null && zoneState.setting.power === 'OFF') inOffMode += 1;
|
|
1309
1282
|
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
});
|
|
1283
|
+
if (zoneState.overlayType !== null && zoneState.setting.power === 'ON' && zoneState.overlay.termination)
|
|
1284
|
+
inManualMode += 1;
|
|
1313
1285
|
}
|
|
1314
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
|
+
}
|
|
1315
1314
|
return zoneStates;
|
|
1316
1315
|
}
|
|
1317
1316
|
|
|
1318
1317
|
async function updateMobileDevices() {
|
|
1319
|
-
if (
|
|
1320
|
-
Logger.debug('Polling MobileDevices...', config.homeName);
|
|
1318
|
+
if (settingState) return;
|
|
1321
1319
|
|
|
1322
|
-
|
|
1320
|
+
Logger.debug('Polling MobileDevices...', config.homeName);
|
|
1323
1321
|
|
|
1324
|
-
|
|
1325
|
-
(user) =>
|
|
1326
|
-
user &&
|
|
1327
|
-
user.context.config.subtype.includes('presence') &&
|
|
1328
|
-
user.displayName !== user.context.config.homeName + ' Anyone'
|
|
1329
|
-
);
|
|
1322
|
+
const mobileDevices = await tado.getMobileDevices(config.homeId);
|
|
1330
1323
|
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
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
|
+
);
|
|
1337
1330
|
|
|
1338
|
-
|
|
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
|
+
);
|
|
1339
1337
|
|
|
1340
|
-
|
|
1341
|
-
userAccessories.forEach((acc) => {
|
|
1342
|
-
if (acc.context.config.homeName + ' ' + device.name === acc.displayName) {
|
|
1343
|
-
let atHome = device.location && device.location.atHome ? 1 : 0;
|
|
1338
|
+
let activeUser = 0;
|
|
1344
1339
|
|
|
1345
|
-
|
|
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;
|
|
1346
1344
|
|
|
1347
|
-
|
|
1348
|
-
acc.getService(api.hap.Service.MotionSensor) || acc.getService(api.hap.Service.OccupancySensor);
|
|
1345
|
+
if (atHome) activeUser += 1;
|
|
1349
1346
|
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
: api.hap.Characteristic.OccupancyDetected;
|
|
1347
|
+
let service =
|
|
1348
|
+
acc.getService(api.hap.Service.MotionSensor) || acc.getService(api.hap.Service.OccupancySensor);
|
|
1353
1349
|
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
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
|
+
}
|
|
1357
1356
|
});
|
|
1357
|
+
});
|
|
1358
1358
|
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1359
|
+
if (anyone.length) {
|
|
1360
|
+
let service =
|
|
1361
|
+
anyone[0].getService(api.hap.Service.MotionSensor) || anyone[0].getService(api.hap.Service.OccupancySensor);
|
|
1362
1362
|
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1363
|
+
let characteristic = service.testCharacteristic(api.hap.Characteristic.MotionDetected)
|
|
1364
|
+
? api.hap.Characteristic.MotionDetected
|
|
1365
|
+
: api.hap.Characteristic.OccupancyDetected;
|
|
1366
1366
|
|
|
1367
|
-
|
|
1368
|
-
}
|
|
1367
|
+
service.getCharacteristic(characteristic).updateValue(activeUser ? 1 : 0);
|
|
1369
1368
|
}
|
|
1370
|
-
|
|
1371
|
-
return;
|
|
1372
1369
|
}
|
|
1373
1370
|
|
|
1374
1371
|
async function updateWeather() {
|
|
1375
|
-
if (
|
|
1376
|
-
const weatherTemperatureAccessory = accessories.filter(
|
|
1377
|
-
(acc) => acc && acc.displayName === acc.context.config.homeName + ' Weather'
|
|
1378
|
-
);
|
|
1372
|
+
if (settingState) return;
|
|
1379
1373
|
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1374
|
+
const weatherTemperatureAccessory = accessories.filter(
|
|
1375
|
+
(acc) => acc && acc.displayName === acc.context.config.homeName + ' Weather'
|
|
1376
|
+
);
|
|
1383
1377
|
|
|
1384
|
-
|
|
1385
|
-
|
|
1378
|
+
const solarIntensityAccessory = accessories.filter(
|
|
1379
|
+
(acc) => acc && acc.displayName === acc.context.config.homeName + ' Solar Intensity'
|
|
1380
|
+
);
|
|
1386
1381
|
|
|
1387
|
-
|
|
1382
|
+
if (weatherTemperatureAccessory.length || solarIntensityAccessory.length) {
|
|
1383
|
+
Logger.debug('Polling Weather...', config.homeName);
|
|
1388
1384
|
|
|
1389
|
-
|
|
1390
|
-
let tempUnit = config.temperatureUnit;
|
|
1391
|
-
let service = weatherTemperatureAccessory[0].getService(api.hap.Service.TemperatureSensor);
|
|
1392
|
-
let characteristic = api.hap.Characteristic.CurrentTemperature;
|
|
1385
|
+
const weather = await tado.getWeather(config.homeId);
|
|
1393
1386
|
|
|
1394
|
-
|
|
1395
|
-
|
|
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;
|
|
1396
1391
|
|
|
1397
|
-
|
|
1398
|
-
|
|
1392
|
+
let temp =
|
|
1393
|
+
tempUnit === 'FAHRENHEIT' ? weather.outsideTemperature.fahrenheit : weather.outsideTemperature.celsius;
|
|
1399
1394
|
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
let brightness = weather.solarIntensity.percentage;
|
|
1395
|
+
service.getCharacteristic(characteristic).updateValue(temp);
|
|
1396
|
+
}
|
|
1403
1397
|
|
|
1404
|
-
|
|
1405
|
-
|
|
1398
|
+
if (solarIntensityAccessory.length && weather.solarIntensity) {
|
|
1399
|
+
let state = weather.solarIntensity.percentage !== 0;
|
|
1400
|
+
let brightness = weather.solarIntensity.percentage;
|
|
1406
1401
|
|
|
1407
|
-
|
|
1408
|
-
|
|
1402
|
+
solarIntensityAccessory[0].context.lightBulbState = state;
|
|
1403
|
+
solarIntensityAccessory[0].context.lightBulbBrightness = brightness;
|
|
1409
1404
|
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
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);
|
|
1413
1407
|
|
|
1414
|
-
|
|
1408
|
+
if (serviceLightbulb) {
|
|
1409
|
+
let characteristicOn = api.hap.Characteristic.On;
|
|
1410
|
+
let characteristicBrightness = api.hap.Characteristic.Brightness;
|
|
1415
1411
|
|
|
1416
|
-
|
|
1417
|
-
} else {
|
|
1418
|
-
let characteristicLux = api.hap.Characteristic.CurrentAmbientLightLevel;
|
|
1412
|
+
serviceLightbulb.getCharacteristic(characteristicOn).updateValue(state);
|
|
1419
1413
|
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
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);
|
|
1424
1421
|
}
|
|
1425
1422
|
}
|
|
1426
1423
|
}
|
|
1427
|
-
|
|
1428
|
-
return;
|
|
1429
1424
|
}
|
|
1430
1425
|
|
|
1431
1426
|
async function updatePresence() {
|
|
1432
|
-
if (
|
|
1433
|
-
const presenceLockAccessory = accessories.filter(
|
|
1434
|
-
(acc) => acc && acc.displayName === acc.context.config.homeName + ' Presence Lock'
|
|
1435
|
-
);
|
|
1427
|
+
if (settingState) return;
|
|
1436
1428
|
|
|
1437
|
-
|
|
1438
|
-
|
|
1429
|
+
const presenceLockAccessory = accessories.filter(
|
|
1430
|
+
(acc) => acc && acc.displayName === acc.context.config.homeName + ' Presence Lock'
|
|
1431
|
+
);
|
|
1439
1432
|
|
|
1440
|
-
|
|
1433
|
+
if (presenceLockAccessory.length) {
|
|
1434
|
+
Logger.debug('Polling PresenceLock...', config.homeName);
|
|
1441
1435
|
|
|
1442
|
-
|
|
1443
|
-
0: Home | true
|
|
1444
|
-
1: Away | true
|
|
1445
|
-
3: Off | false
|
|
1446
|
-
*/
|
|
1436
|
+
const presenceLock = await tado.getState(config.homeId);
|
|
1447
1437
|
|
|
1448
|
-
|
|
1438
|
+
/*
|
|
1439
|
+
0: Home | true
|
|
1440
|
+
1: Away | true
|
|
1441
|
+
3: Off | false
|
|
1442
|
+
*/
|
|
1449
1443
|
|
|
1450
|
-
|
|
1451
|
-
let serviceHomeSwitch = presenceLockAccessory[0].getServiceById(api.hap.Service.Switch, 'HomeSwitch');
|
|
1452
|
-
let serviceAwaySwitch = presenceLockAccessory[0].getServiceById(api.hap.Service.Switch, 'AwaySwitch');
|
|
1444
|
+
let state = presenceLock.presenceLocked ? (presenceLock.presence === 'AWAY' ? 1 : 0) : 3;
|
|
1453
1445
|
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
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');
|
|
1457
1449
|
|
|
1458
|
-
|
|
1450
|
+
if (serviceSecurity) {
|
|
1451
|
+
let characteristicCurrent = api.hap.Characteristic.SecuritySystemCurrentState;
|
|
1452
|
+
let characteristicTarget = api.hap.Characteristic.SecuritySystemTargetState;
|
|
1459
1453
|
|
|
1460
|
-
|
|
1461
|
-
} else if (serviceHomeSwitch || serviceAwaySwitch) {
|
|
1462
|
-
let characteristicOn = api.hap.Characteristic.On;
|
|
1454
|
+
serviceSecurity.getCharacteristic(characteristicCurrent).updateValue(state);
|
|
1463
1455
|
|
|
1464
|
-
|
|
1456
|
+
serviceSecurity.getCharacteristic(characteristicTarget).updateValue(state);
|
|
1457
|
+
} else if (serviceHomeSwitch || serviceAwaySwitch) {
|
|
1458
|
+
let characteristicOn = api.hap.Characteristic.On;
|
|
1465
1459
|
|
|
1466
|
-
|
|
1460
|
+
let homeState = !state ? true : false;
|
|
1467
1461
|
|
|
1468
|
-
|
|
1462
|
+
let awayState = state === 1 ? true : false;
|
|
1469
1463
|
|
|
1470
|
-
|
|
1471
|
-
|
|
1464
|
+
serviceAwaySwitch.getCharacteristic(characteristicOn).updateValue(awayState);
|
|
1465
|
+
|
|
1466
|
+
serviceHomeSwitch.getCharacteristic(characteristicOn).updateValue(homeState);
|
|
1472
1467
|
}
|
|
1473
1468
|
}
|
|
1474
1469
|
}
|
|
1475
1470
|
|
|
1476
1471
|
async function updateRunningTime() {
|
|
1477
|
-
if (
|
|
1478
|
-
const centralSwitchAccessory = accessories.filter(
|
|
1479
|
-
(acc) => acc && acc.displayName === acc.context.config.homeName + ' Central Switch'
|
|
1480
|
-
);
|
|
1472
|
+
if (settingState) return;
|
|
1481
1473
|
|
|
1482
|
-
|
|
1483
|
-
|
|
1474
|
+
const centralSwitchAccessory = accessories.filter(
|
|
1475
|
+
(acc) => acc && acc.displayName === acc.context.config.homeName + ' Central Switch'
|
|
1476
|
+
);
|
|
1484
1477
|
|
|
1485
|
-
|
|
1478
|
+
if (centralSwitchAccessory.length) {
|
|
1479
|
+
Logger.debug('Polling RunningTime...', config.homeName);
|
|
1486
1480
|
|
|
1487
|
-
|
|
1488
|
-
let fromDate =
|
|
1489
|
-
period === 'days'
|
|
1490
|
-
? moment().format('YYYY-MM-DD')
|
|
1491
|
-
: period === 'months'
|
|
1492
|
-
? moment().subtract(1, 'days').subtract(1, period).format('YYYY-MM-DD')
|
|
1493
|
-
: moment().add(1, 'months').startOf('month').subtract(1, period).format('YYYY-MM-DD');
|
|
1481
|
+
let periods = ['days', 'months', 'years'];
|
|
1494
1482
|
|
|
1495
|
-
|
|
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');
|
|
1496
1490
|
|
|
1497
|
-
|
|
1491
|
+
let toDate = period === 'years' ? moment().format('YYYY-MM-DD') : false;
|
|
1498
1492
|
|
|
1499
|
-
|
|
1493
|
+
let time = period.substring(0, period.length - 1);
|
|
1500
1494
|
|
|
1501
|
-
|
|
1502
|
-
let summaryInHours = runningTime.summary.totalRunningTimeInSeconds / 3600;
|
|
1495
|
+
const runningTime = await tado.getRunningTime(config.homeId, time, fromDate, toDate);
|
|
1503
1496
|
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
period === 'years'
|
|
1507
|
-
? api.hap.Characteristic.OverallHeatYear
|
|
1508
|
-
: period === 'months'
|
|
1509
|
-
? api.hap.Characteristic.OverallHeatMonth
|
|
1510
|
-
: api.hap.Characteristic.OverallHeatDay;
|
|
1497
|
+
if (runningTime && runningTime.summary) {
|
|
1498
|
+
let summaryInHours = runningTime.summary.totalRunningTimeInSeconds / 3600;
|
|
1511
1499
|
|
|
1512
|
-
|
|
1513
|
-
|
|
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;
|
|
1514
1507
|
|
|
1515
|
-
|
|
1508
|
+
serviceSwitch.getCharacteristic(characteristic).updateValue(summaryInHours);
|
|
1516
1509
|
}
|
|
1510
|
+
|
|
1511
|
+
await timeout(500);
|
|
1517
1512
|
}
|
|
1518
1513
|
}
|
|
1519
|
-
|
|
1520
|
-
return;
|
|
1521
1514
|
}
|
|
1522
1515
|
|
|
1523
1516
|
async function updateDevices() {
|
|
1524
|
-
if (
|
|
1525
|
-
Logger.debug('Polling Devices...', config.homeName);
|
|
1517
|
+
if (settingState) return;
|
|
1526
1518
|
|
|
1527
|
-
|
|
1519
|
+
Logger.debug('Polling Devices...', config.homeName);
|
|
1528
1520
|
|
|
1529
|
-
|
|
1530
|
-
(acc) => acc && acc.context.config.subtype === 'extra-childswitch'
|
|
1531
|
-
);
|
|
1521
|
+
const devices = await tado.getDevices(config.homeId);
|
|
1532
1522
|
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
let serviceChildLock = childLockAccessories[0].getServiceById(api.hap.Service.Switch, service.subtype);
|
|
1537
|
-
let characteristic = api.hap.Characteristic.On;
|
|
1523
|
+
const childLockAccessories = accessories.filter(
|
|
1524
|
+
(acc) => acc && acc.context.config.subtype === 'extra-childswitch'
|
|
1525
|
+
);
|
|
1538
1526
|
|
|
1539
|
-
|
|
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;
|
|
1540
1532
|
|
|
1541
|
-
|
|
1542
|
-
}
|
|
1543
|
-
});
|
|
1544
|
-
});
|
|
1545
|
-
}
|
|
1533
|
+
let childLockEnabled = device.childLockEnabled || false;
|
|
1546
1534
|
|
|
1547
|
-
|
|
1535
|
+
serviceChildLock.getCharacteristic(characteristic).updateValue(childLockEnabled);
|
|
1536
|
+
}
|
|
1537
|
+
});
|
|
1538
|
+
});
|
|
1548
1539
|
}
|
|
1549
1540
|
|
|
1550
1541
|
function errorHandler(err) {
|