@homebridge-plugins/homebridge-tado 8.6.0-beta.2 → 8.6.0-beta.3
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 +9 -4
- package/homebridge-ui/server.js +1 -1
- package/package.json +1 -1
- package/src/helper/handler.js +84 -78
- package/src/tado/tado-api.js +55 -13
- package/src/tado/tado-config.js +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## v8.6.0 - 2025-10-
|
|
4
|
-
- BREAKING CHANGE: If you use tadoApiUrl or skipAuth,
|
|
5
|
-
- Refactor configuration:
|
|
6
|
-
- Persist
|
|
3
|
+
## v8.6.0 - 2025-10-31
|
|
4
|
+
- BREAKING CHANGE: If you use tadoApiUrl or skipAuth, they must now be defined under each corresponding home in your configuration (#176)
|
|
5
|
+
- Refactor configuration: Moved tadoApiUrl and skipAuth into individual home configs to support multiple API URLs (#176)
|
|
6
|
+
- Persist Tado zone states after zone state updates
|
|
7
7
|
- Improved zone update logic: when setting a state, all zones are now updated immediately if the next scheduled update is more than 10 seconds away
|
|
8
|
+
- Advanced queue handling for update and persistence tasks
|
|
9
|
+
- Tado API counter now tracks and persists for each authenticated user
|
|
10
|
+
- Fix: Polling and tasks for multiple homes (#178)
|
|
8
11
|
- Fix: Corrected zone update handling that could previously cause unintended heating changes (#178)
|
|
12
|
+
- Added additional debug log messages for zone updates
|
|
13
|
+
- Note: This update will reset your tado api counter for the current day to zero.
|
|
9
14
|
|
|
10
15
|
## v8.5.0 - 2025-10-27
|
|
11
16
|
- Change minimum polling interval to 30s due to improvements made in v8.2.0
|
package/homebridge-ui/server.js
CHANGED
package/package.json
CHANGED
package/src/helper/handler.js
CHANGED
|
@@ -1,42 +1,35 @@
|
|
|
1
1
|
import Logger from '../helper/logger.js';
|
|
2
2
|
import moment from 'moment';
|
|
3
|
-
import { writeFile
|
|
3
|
+
import { writeFile } from 'fs/promises';
|
|
4
4
|
import { join } from "path";
|
|
5
5
|
|
|
6
|
-
let settingState = false;
|
|
7
|
-
let tasksInitialized = false;
|
|
8
|
-
let lastGetStates = 0;
|
|
9
|
-
const delayTimer = {};
|
|
10
|
-
|
|
11
6
|
const timeout = (ms) => new Promise((res) => setTimeout(res, ms));
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
export async function getPersistedStates(storagePath) {
|
|
15
|
-
try {
|
|
16
|
-
const sFilePath = join(storagePath, "tado-states.json");
|
|
17
|
-
await access(sFilePath);
|
|
18
|
-
const sData = (await readFile(sFilePath, "utf-8"));
|
|
19
|
-
if (sData) return JSON.parse(sData);
|
|
20
|
-
} catch (error) {
|
|
21
|
-
//no states data => ignore
|
|
22
|
-
Logger.debug(`Failed to read tado states file: ${error.message || error}`);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
7
|
+
const helpers = {};
|
|
25
8
|
|
|
26
9
|
export default (api, accessories, config, tado, telegram) => {
|
|
27
|
-
|
|
28
|
-
|
|
10
|
+
//init helper variables for current home scope
|
|
11
|
+
if (!helpers[config.homeId]) {
|
|
12
|
+
helpers[config.homeId] = {
|
|
13
|
+
settingState: false,
|
|
14
|
+
tasksInitialized: false,
|
|
15
|
+
lastGetStates: 0,
|
|
16
|
+
lastPersistZoneStates: 0,
|
|
17
|
+
persistPromise: Promise.resolve(),
|
|
18
|
+
updateZonesRunning: false,
|
|
19
|
+
updateZonesNextQueued: false,
|
|
20
|
+
delayTimer: {},
|
|
21
|
+
refreshHistoryHandlers: [],
|
|
22
|
+
statesIntervalTime: Math.max(config.polling, 30) * 1000,
|
|
23
|
+
storagePath: api.user.storagePath(),
|
|
24
|
+
}
|
|
25
|
+
}
|
|
29
26
|
|
|
30
27
|
async function setStates(accessory, accs, target, value) {
|
|
31
28
|
let zoneUpdated = false;
|
|
32
|
-
|
|
33
29
|
accessories = accs.filter((acc) => acc && acc.context.config.homeName === config.homeName);
|
|
34
|
-
|
|
35
30
|
try {
|
|
36
|
-
settingState = true;
|
|
37
|
-
|
|
31
|
+
helpers[config.homeId].settingState = true;
|
|
38
32
|
value = typeof value === 'number' ? parseFloat(value.toFixed(2)) : value;
|
|
39
|
-
|
|
40
33
|
Logger.info(target + ': ' + value, accessory.displayName);
|
|
41
34
|
|
|
42
35
|
switch (accessory.context.config.subtype) {
|
|
@@ -63,10 +56,10 @@ export default (api, accessories, config, tado, telegram) => {
|
|
|
63
56
|
value < 5
|
|
64
57
|
) {
|
|
65
58
|
if (value === 0) {
|
|
66
|
-
if (delayTimer[accessory.displayName]) {
|
|
59
|
+
if (helpers[config.homeId].delayTimer[accessory.displayName]) {
|
|
67
60
|
Logger.info('Resetting delay timer', accessory.displayName);
|
|
68
|
-
clearTimeout(delayTimer[accessory.displayName]);
|
|
69
|
-
delayTimer[accessory.displayName] = null;
|
|
61
|
+
clearTimeout(helpers[config.homeId].delayTimer[accessory.displayName]);
|
|
62
|
+
helpers[config.homeId].delayTimer[accessory.displayName] = null;
|
|
70
63
|
}
|
|
71
64
|
|
|
72
65
|
power = 'OFF';
|
|
@@ -111,14 +104,14 @@ export default (api, accessories, config, tado, telegram) => {
|
|
|
111
104
|
let timer = accessory.context.delayTimer;
|
|
112
105
|
let tarState = value === 1 ? 'HEAT' : 'AUTO';
|
|
113
106
|
|
|
114
|
-
if (delayTimer[accessory.displayName]) {
|
|
115
|
-
clearTimeout(delayTimer[accessory.displayName]);
|
|
116
|
-
delayTimer[accessory.displayName] = null;
|
|
107
|
+
if (helpers[config.homeId].delayTimer[accessory.displayName]) {
|
|
108
|
+
clearTimeout(helpers[config.homeId].delayTimer[accessory.displayName]);
|
|
109
|
+
helpers[config.homeId].delayTimer[accessory.displayName] = null;
|
|
117
110
|
}
|
|
118
111
|
|
|
119
112
|
Logger.info('Wait ' + timer + ' seconds before switching state', accessory.displayName);
|
|
120
113
|
|
|
121
|
-
delayTimer[accessory.displayName] = setTimeout(async () => {
|
|
114
|
+
helpers[config.homeId].delayTimer[accessory.displayName] = setTimeout(async () => {
|
|
122
115
|
Logger.info('Delay timer finished, switching state to ' + tarState, accessory.displayName);
|
|
123
116
|
|
|
124
117
|
//targetState
|
|
@@ -172,7 +165,7 @@ export default (api, accessories, config, tado, telegram) => {
|
|
|
172
165
|
);
|
|
173
166
|
}
|
|
174
167
|
|
|
175
|
-
delayTimer[accessory.displayName] = null;
|
|
168
|
+
helpers[config.homeId].delayTimer[accessory.displayName] = null;
|
|
176
169
|
}, timer * 1000);
|
|
177
170
|
}
|
|
178
171
|
} else {
|
|
@@ -567,11 +560,11 @@ export default (api, accessories, config, tado, telegram) => {
|
|
|
567
560
|
} catch (err) {
|
|
568
561
|
errorHandler(err);
|
|
569
562
|
} finally {
|
|
570
|
-
settingState = false;
|
|
563
|
+
helpers[config.homeId].settingState = false;
|
|
571
564
|
//update zones to ensure correct state in Apple Home
|
|
572
|
-
const timeSinceLastGetStates = Date.now() - lastGetStates;
|
|
573
|
-
const statesIntervalTimeLeft = statesIntervalTime - timeSinceLastGetStates;
|
|
574
|
-
if (zoneUpdated && statesIntervalTimeLeft >
|
|
565
|
+
const timeSinceLastGetStates = helpers[config.homeId].lastGetStates === 0 ? 0 : (Date.now() - helpers[config.homeId].lastGetStates);
|
|
566
|
+
const statesIntervalTimeLeft = helpers[config.homeId].statesIntervalTime - timeSinceLastGetStates;
|
|
567
|
+
if (zoneUpdated && statesIntervalTimeLeft > (10 * 1000)) await updateZones();
|
|
575
568
|
}
|
|
576
569
|
}
|
|
577
570
|
|
|
@@ -729,61 +722,49 @@ export default (api, accessories, config, tado, telegram) => {
|
|
|
729
722
|
}
|
|
730
723
|
}
|
|
731
724
|
|
|
732
|
-
|
|
725
|
+
function persistZoneStates(homeId, zoneStates) {
|
|
726
|
+
helpers[config.homeId].persistPromise = helpers[config.homeId].persistPromise.then(() => _persistZoneStates(homeId, zoneStates));
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
async function _persistZoneStates(homeId, zoneStates) {
|
|
730
|
+
if ((Date.now() - helpers[config.homeId].lastPersistZoneStates) < (10 * 1000)) return;
|
|
733
731
|
try {
|
|
734
732
|
if (zoneStates && Object.keys(zoneStates).length) {
|
|
735
733
|
const homeData = {};
|
|
736
734
|
homeData.zoneStates = zoneStates;
|
|
737
|
-
await writeFile(join(storagePath, `tado-states-${homeId}.json`), JSON.stringify(homeData, null, 2), "utf-8");
|
|
735
|
+
await writeFile(join(helpers[config.homeId].storagePath, `tado-states-${homeId}.json`), JSON.stringify(homeData, null, 2), "utf-8");
|
|
736
|
+
helpers[config.homeId].lastPersistZoneStates = Date.now();
|
|
738
737
|
} else {
|
|
739
|
-
Logger.
|
|
738
|
+
Logger.warn(`Skipping persistence of tado states file for home ${homeId}: zone states are empty.`);
|
|
740
739
|
}
|
|
741
740
|
} catch (error) {
|
|
742
741
|
Logger.error(`Error while updating the tado states file for home ${homeId}: ${error.message || error}`);
|
|
743
742
|
}
|
|
744
743
|
}
|
|
745
744
|
|
|
746
|
-
async function
|
|
747
|
-
|
|
748
|
-
const data = {};
|
|
749
|
-
data.counterData = await tado.getCounterData();
|
|
750
|
-
await writeFile(join(storagePath, "tado-states.json"), JSON.stringify(data, null, 2), "utf-8");
|
|
751
|
-
} catch (error) {
|
|
752
|
-
Logger.error(`Error while updating the tado states file: ${error.message || error}`);
|
|
753
|
-
}
|
|
745
|
+
async function refreshHistoryServices() {
|
|
746
|
+
if (!helpers[config.homeId].refreshHistoryHandlers.length) return;
|
|
754
747
|
try {
|
|
755
748
|
//wait for fakegato history services to be loaded
|
|
756
749
|
await timeout(4000);
|
|
757
|
-
for (const refreshHistory of
|
|
750
|
+
for (const refreshHistory of helpers[config.homeId].refreshHistoryHandlers) {
|
|
758
751
|
refreshHistory();
|
|
759
752
|
}
|
|
760
753
|
} catch (error) {
|
|
761
|
-
Logger.error(`Error while refreshing history: ${error.message || error}`);
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
async function logCounter() {
|
|
766
|
-
try {
|
|
767
|
-
const iCounter = (await tado.getCounterData()).counter;
|
|
768
|
-
Logger.info(`Tado API counter: ${iCounter.toLocaleString('en-US')}`);
|
|
769
|
-
} catch (error) {
|
|
770
|
-
Logger.warn(`Failed to get Tado API counter: ${error.message || error}`);
|
|
754
|
+
Logger.error(`Error while refreshing history services: ${error.message || error}`);
|
|
771
755
|
}
|
|
772
756
|
}
|
|
773
757
|
|
|
774
758
|
function initTasks() {
|
|
775
|
-
if (tasksInitialized) return;
|
|
776
|
-
tasksInitialized = true;
|
|
759
|
+
if (helpers[config.homeId].tasksInitialized) return;
|
|
760
|
+
helpers[config.homeId].tasksInitialized = true;
|
|
777
761
|
|
|
778
762
|
void getStates();
|
|
779
|
-
setInterval(() => getStates(), statesIntervalTime);
|
|
780
|
-
|
|
781
|
-
void logCounter();
|
|
782
|
-
setInterval(() => logCounter(), 60 * 60 * 1000);
|
|
763
|
+
setInterval(() => void getStates(), helpers[config.homeId].statesIntervalTime);
|
|
783
764
|
}
|
|
784
765
|
|
|
785
766
|
async function getStates() {
|
|
786
|
-
lastGetStates = Date.now();
|
|
767
|
+
helpers[config.homeId].lastGetStates = Date.now();
|
|
787
768
|
try {
|
|
788
769
|
//ME
|
|
789
770
|
if (!config.homeId) await updateMe();
|
|
@@ -811,12 +792,12 @@ export default (api, accessories, config, tado, telegram) => {
|
|
|
811
792
|
} catch (err) {
|
|
812
793
|
errorHandler(err);
|
|
813
794
|
} finally {
|
|
814
|
-
void
|
|
795
|
+
void refreshHistoryServices();
|
|
815
796
|
}
|
|
816
797
|
}
|
|
817
798
|
|
|
818
799
|
async function updateMe() {
|
|
819
|
-
if (settingState) return;
|
|
800
|
+
if (helpers[config.homeId].settingState) return;
|
|
820
801
|
|
|
821
802
|
Logger.debug('Polling User Info...', config.homeName);
|
|
822
803
|
|
|
@@ -828,7 +809,7 @@ export default (api, accessories, config, tado, telegram) => {
|
|
|
828
809
|
}
|
|
829
810
|
|
|
830
811
|
async function updateHome() {
|
|
831
|
-
if (settingState) return;
|
|
812
|
+
if (helpers[config.homeId].settingState) return;
|
|
832
813
|
|
|
833
814
|
Logger.debug('Polling Home Info...', config.homeName);
|
|
834
815
|
|
|
@@ -853,7 +834,32 @@ export default (api, accessories, config, tado, telegram) => {
|
|
|
853
834
|
}
|
|
854
835
|
|
|
855
836
|
async function updateZones() {
|
|
856
|
-
if (
|
|
837
|
+
if (helpers[config.homeId].updateZonesRunning) {
|
|
838
|
+
helpers[config.homeId].updateZonesNextQueued = true;
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
841
|
+
helpers[config.homeId].updateZonesRunning = true;
|
|
842
|
+
try {
|
|
843
|
+
while (true) {
|
|
844
|
+
try {
|
|
845
|
+
await _updateZones();
|
|
846
|
+
} catch (error) {
|
|
847
|
+
Logger.error(`Failed to update zones: ${error.message || error}`);
|
|
848
|
+
}
|
|
849
|
+
if (helpers[config.homeId].updateZonesNextQueued) {
|
|
850
|
+
helpers[config.homeId].updateZonesNextQueued = false;
|
|
851
|
+
//continue with loop
|
|
852
|
+
} else {
|
|
853
|
+
break;
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
} finally {
|
|
857
|
+
helpers[config.homeId].updateZonesRunning = false;
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
async function _updateZones() {
|
|
862
|
+
if (helpers[config.homeId].settingState) return;
|
|
857
863
|
|
|
858
864
|
Logger.debug('Polling Zones...', config.homeName);
|
|
859
865
|
|
|
@@ -1316,7 +1322,7 @@ export default (api, accessories, config, tado, telegram) => {
|
|
|
1316
1322
|
}
|
|
1317
1323
|
|
|
1318
1324
|
async function updateMobileDevices() {
|
|
1319
|
-
if (settingState) return;
|
|
1325
|
+
if (helpers[config.homeId].settingState) return;
|
|
1320
1326
|
|
|
1321
1327
|
Logger.debug('Polling MobileDevices...', config.homeName);
|
|
1322
1328
|
|
|
@@ -1370,7 +1376,7 @@ export default (api, accessories, config, tado, telegram) => {
|
|
|
1370
1376
|
}
|
|
1371
1377
|
|
|
1372
1378
|
async function updateWeather() {
|
|
1373
|
-
if (settingState) return;
|
|
1379
|
+
if (helpers[config.homeId].settingState) return;
|
|
1374
1380
|
|
|
1375
1381
|
const weatherTemperatureAccessory = accessories.filter(
|
|
1376
1382
|
(acc) => acc && acc.displayName === acc.context.config.homeName + ' Weather'
|
|
@@ -1425,7 +1431,7 @@ export default (api, accessories, config, tado, telegram) => {
|
|
|
1425
1431
|
}
|
|
1426
1432
|
|
|
1427
1433
|
async function updatePresence() {
|
|
1428
|
-
if (settingState) return;
|
|
1434
|
+
if (helpers[config.homeId].settingState) return;
|
|
1429
1435
|
|
|
1430
1436
|
const presenceLockAccessory = accessories.filter(
|
|
1431
1437
|
(acc) => acc && acc.displayName === acc.context.config.homeName + ' Presence Lock'
|
|
@@ -1470,7 +1476,7 @@ export default (api, accessories, config, tado, telegram) => {
|
|
|
1470
1476
|
}
|
|
1471
1477
|
|
|
1472
1478
|
async function updateRunningTime() {
|
|
1473
|
-
if (settingState) return;
|
|
1479
|
+
if (helpers[config.homeId].settingState) return;
|
|
1474
1480
|
|
|
1475
1481
|
const centralSwitchAccessory = accessories.filter(
|
|
1476
1482
|
(acc) => acc && acc.displayName === acc.context.config.homeName + ' Central Switch'
|
|
@@ -1515,7 +1521,7 @@ export default (api, accessories, config, tado, telegram) => {
|
|
|
1515
1521
|
}
|
|
1516
1522
|
|
|
1517
1523
|
async function updateDevices() {
|
|
1518
|
-
if (settingState) return;
|
|
1524
|
+
if (helpers[config.homeId].settingState) return;
|
|
1519
1525
|
|
|
1520
1526
|
Logger.debug('Polling Devices...', config.homeName);
|
|
1521
1527
|
|
|
@@ -1586,6 +1592,6 @@ export default (api, accessories, config, tado, telegram) => {
|
|
|
1586
1592
|
getStates: getStates,
|
|
1587
1593
|
setStates: setStates,
|
|
1588
1594
|
changedStates: changedStates,
|
|
1589
|
-
refreshHistoryHandlers:
|
|
1595
|
+
refreshHistoryHandlers: helpers[config.homeId].refreshHistoryHandlers
|
|
1590
1596
|
};
|
|
1591
|
-
};
|
|
1597
|
+
};
|
package/src/tado/tado-api.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import Logger from '../helper/logger.js';
|
|
2
|
-
import { getPersistedStates } from '../helper/handler.js';
|
|
3
2
|
import got from 'got';
|
|
4
3
|
import { join } from 'path';
|
|
5
4
|
import { access, readFile, writeFile } from 'fs/promises';
|
|
@@ -8,8 +7,17 @@ const tado_url = "https://my.tado.com";
|
|
|
8
7
|
const tado_auth_url = "https://login.tado.com/oauth2";
|
|
9
8
|
const tado_client_id = "1bb50063-6b0c-4d11-bd99-387f4a91cc46";
|
|
10
9
|
|
|
10
|
+
function _getSimpleHash(str) {
|
|
11
|
+
let hash = 0;
|
|
12
|
+
for (let i = 0; i < str.length; i++) {
|
|
13
|
+
const char = str.charCodeAt(i);
|
|
14
|
+
hash = (hash << 5) - hash + char;
|
|
15
|
+
}
|
|
16
|
+
return (hash >>> 0).toString(36).padStart(7, '0');
|
|
17
|
+
}
|
|
18
|
+
|
|
11
19
|
export default class Tado {
|
|
12
|
-
constructor(name, auth, storagePath) {
|
|
20
|
+
constructor(name, auth, storagePath, counterActivated) {
|
|
13
21
|
this.tadoApiUrl = auth.tadoApiUrl || tado_url;
|
|
14
22
|
this.customTadoApiUrlActive = !!auth.tadoApiUrl;
|
|
15
23
|
this.skipAuth = auth.skipAuth?.toString() === "true";
|
|
@@ -17,28 +25,42 @@ export default class Tado {
|
|
|
17
25
|
this.name = name;
|
|
18
26
|
const usesExternalTokenFile = auth.username?.toLowerCase().endsWith(".json");
|
|
19
27
|
this._tadoExternalTokenFilePath = usesExternalTokenFile ? auth.username : undefined;
|
|
20
|
-
|
|
21
|
-
let hash = 0;
|
|
22
|
-
for (let i = 0; i < str.length; i++) {
|
|
23
|
-
const char = str.charCodeAt(i);
|
|
24
|
-
hash = (hash << 5) - hash + char;
|
|
25
|
-
}
|
|
26
|
-
return (hash >>> 0).toString(36).padStart(7, '0');
|
|
27
|
-
};
|
|
28
|
+
this.hashedUsername = _getSimpleHash(auth.username);
|
|
28
29
|
this.username = usesExternalTokenFile ? undefined : auth.username;
|
|
29
|
-
this._tadoInternalTokenFilePath = usesExternalTokenFile ? undefined : join(this.storagePath, `.tado-token-${
|
|
30
|
+
this._tadoInternalTokenFilePath = usesExternalTokenFile ? undefined : join(this.storagePath, `.tado-token-${this.hashedUsername}.json`);
|
|
30
31
|
this._tadoApiClientId = tado_client_id;
|
|
31
32
|
this._tadoTokenPromise = undefined;
|
|
32
33
|
this._tadoAuthenticationCallback = undefined;
|
|
34
|
+
this._counterActivated = counterActivated?.toString() === "true";
|
|
33
35
|
this._counterInitPromise = this._initCounter();
|
|
34
36
|
Logger.debug("API successfull initialized", this.name);
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
async _initCounter() {
|
|
38
|
-
|
|
40
|
+
if (!this._counterActivated) return;
|
|
41
|
+
const persistedCounterData = (await this._getPersistedCounter())?.counterData;
|
|
39
42
|
this._counter = persistedCounterData?.counter ?? 0;
|
|
40
43
|
this._counterTimestamp = persistedCounterData?.counterTimestamp ?? new Date().toISOString();
|
|
41
44
|
this._checkCounterMidnightReset();
|
|
45
|
+
//wait some seconds to catch recent api calls
|
|
46
|
+
setTimeout(() => {
|
|
47
|
+
void this._logCounter();
|
|
48
|
+
setInterval(() => void this._logCounter(), 60 * 60 * 1000);
|
|
49
|
+
void this._persistCounterData();
|
|
50
|
+
setInterval(() => void this._persistCounterData(), 5 * 60 * 1000);
|
|
51
|
+
}, 4 * 1000);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async _getPersistedCounter() {
|
|
55
|
+
try {
|
|
56
|
+
const filePath = join(this.storagePath, `tado-api-${this.hashedUsername}.json`);
|
|
57
|
+
await access(filePath);
|
|
58
|
+
const data = (await readFile(filePath, "utf-8"));
|
|
59
|
+
if (data) return JSON.parse(data);
|
|
60
|
+
} catch (error) {
|
|
61
|
+
//no persisted counter data => ignore
|
|
62
|
+
Logger.debug(`Failed to read tado api file for user ${this.hashedUsername}: ${error.message || error}`);
|
|
63
|
+
}
|
|
42
64
|
}
|
|
43
65
|
|
|
44
66
|
_checkCounterMidnightReset() {
|
|
@@ -53,6 +75,7 @@ export default class Tado {
|
|
|
53
75
|
}
|
|
54
76
|
|
|
55
77
|
async _increaseCounter() {
|
|
78
|
+
if (!this._counterActivated) return;
|
|
56
79
|
try {
|
|
57
80
|
await this._counterInitPromise;
|
|
58
81
|
this._checkCounterMidnightReset();
|
|
@@ -63,7 +86,7 @@ export default class Tado {
|
|
|
63
86
|
}
|
|
64
87
|
}
|
|
65
88
|
|
|
66
|
-
async
|
|
89
|
+
async _getCounterData() {
|
|
67
90
|
await this._counterInitPromise;
|
|
68
91
|
return {
|
|
69
92
|
counter: this._counter,
|
|
@@ -71,6 +94,25 @@ export default class Tado {
|
|
|
71
94
|
};
|
|
72
95
|
}
|
|
73
96
|
|
|
97
|
+
async _persistCounterData() {
|
|
98
|
+
try {
|
|
99
|
+
const data = {};
|
|
100
|
+
data.counterData = await this._getCounterData();
|
|
101
|
+
await writeFile(join(this.storagePath, `tado-api-${this.hashedUsername}.json`), JSON.stringify(data, null, 2), "utf-8");
|
|
102
|
+
} catch (error) {
|
|
103
|
+
Logger.error(`Error while updating the tado api file for user ${this.hashedUsername}: ${error.message || error}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async _logCounter() {
|
|
108
|
+
try {
|
|
109
|
+
const counter = (await this._getCounterData()).counter;
|
|
110
|
+
Logger.info(`Tado API counter: ${counter.toLocaleString('en-US')}`);
|
|
111
|
+
} catch (error) {
|
|
112
|
+
Logger.warn(`Failed to get Tado API counter: ${error.message || error}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
74
116
|
async getToken() {
|
|
75
117
|
Logger.debug('Get access token...', this.name);
|
|
76
118
|
if (!this._tadoTokenPromise) {
|
package/src/tado/tado-config.js
CHANGED
|
@@ -23,7 +23,7 @@ export default {
|
|
|
23
23
|
|
|
24
24
|
for (const auth of auths) {
|
|
25
25
|
|
|
26
|
-
const tado = new TadoApi('Configuration', auth, storagePath);
|
|
26
|
+
const tado = new TadoApi('Configuration', auth, storagePath, false);
|
|
27
27
|
|
|
28
28
|
const me = await tado.getMe();
|
|
29
29
|
|
|
@@ -160,7 +160,7 @@ export default {
|
|
|
160
160
|
username: auth.username,
|
|
161
161
|
tadoApiUrl: auth.tadoApiUrl,
|
|
162
162
|
skipAuth: auth.skipAuth
|
|
163
|
-
}, storagePath);
|
|
163
|
+
}, storagePath, false);
|
|
164
164
|
|
|
165
165
|
const me = await tado.getMe();
|
|
166
166
|
|
|
@@ -208,7 +208,7 @@ export default {
|
|
|
208
208
|
|
|
209
209
|
refresh: async function (currentHome, config, auth, storagePath) {
|
|
210
210
|
|
|
211
|
-
const tado = new TadoApi('Configuration', auth, storagePath);
|
|
211
|
+
const tado = new TadoApi('Configuration', auth, storagePath, false);
|
|
212
212
|
|
|
213
213
|
//Home Informations
|
|
214
214
|
let home = config.homes.find((home) => home && home.name === currentHome);
|
|
@@ -505,7 +505,7 @@ export default {
|
|
|
505
505
|
username: home.username,
|
|
506
506
|
tadoApiUrl: home.tadoApiUrl,
|
|
507
507
|
skipAuth: home.skipAuth
|
|
508
|
-
}, storagePath);
|
|
508
|
+
}, storagePath, true);
|
|
509
509
|
|
|
510
510
|
const accessoryConfig = {
|
|
511
511
|
homeId: home.id,
|