iobroker.weathersense 3.0.2 → 4.0.0
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/LICENSE +1 -1
- package/README.md +13 -2
- package/io-package.json +27 -27
- package/main.js +82 -7
- package/package.json +12 -18
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2025 Daniel Luginbühl <webmaster@ltspiceusers.ch>
|
|
3
|
+
Copyright (c) 2025-2026 Daniel Luginbühl <webmaster@ltspiceusers.ch>
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -19,10 +19,12 @@ See: https://play.google.com/store/apps/details?id=com.emax.weahter&hl=de_CH
|
|
|
19
19
|
|
|
20
20
|
Some WiFi weather stations use the WeatherSense Cloud.
|
|
21
21
|
|
|
22
|
-
For example, this WiFi weather
|
|
22
|
+
For example, this WiFi weather stations from Ideoon (Pearl):
|
|
23
23
|
|
|
24
24
|

|
|
25
25
|
|
|
26
|
+

|
|
27
|
+
|
|
26
28
|
## Use:
|
|
27
29
|
|
|
28
30
|
Simply enter your WeatherSense account login details (email and password).
|
|
@@ -30,6 +32,15 @@ The weather station data is stored in the weathersense data point.
|
|
|
30
32
|
The data can also be sent via MQTT.
|
|
31
33
|
|
|
32
34
|
## Changelog
|
|
35
|
+
### 4.0.0 (2026-01-23)
|
|
36
|
+
|
|
37
|
+
- "All status OK" flag added
|
|
38
|
+
- MQTT topic changed from WEATHERSENSE to WeatherSense
|
|
39
|
+
|
|
40
|
+
### 3.0.3 (2025-09-14)
|
|
41
|
+
|
|
42
|
+
- eslint-config & testing version updated
|
|
43
|
+
|
|
33
44
|
### 3.0.2 (2025-08-29)
|
|
34
45
|
|
|
35
46
|
- Passwords protected, clean convert string > number
|
|
@@ -71,7 +82,7 @@ The data can also be sent via MQTT.
|
|
|
71
82
|
|
|
72
83
|
MIT License
|
|
73
84
|
|
|
74
|
-
Copyright (c) 2025 Daniel Luginbühl <webmaster@ltspiceusers.ch>
|
|
85
|
+
Copyright (c) 2025-2026 Daniel Luginbühl <webmaster@ltspiceusers.ch>
|
|
75
86
|
|
|
76
87
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
77
88
|
of this software and associated documentation files (the "Software"), to deal
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "weathersense",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "4.0.0",
|
|
5
5
|
"news": {
|
|
6
|
+
"4.0.0": {
|
|
7
|
+
"en": "\"All status OK\" flag added\nMQTT topic changed from WEATHERSENSE to WeatherSense",
|
|
8
|
+
"de": "\"All status OK\"-Flag hinzugefügt\nMQTT-Thema von WEATHERSENSE zu WeatherSense geändert",
|
|
9
|
+
"ru": "Флаг «All Status OK»\nТема MQTT изменилась с WEATHERSENSE на WeatherSense",
|
|
10
|
+
"pt": "Bandeira \"Todos os status OK\" adicionada\nO tópico MQTT mudou de Weathersense para WeatherSense",
|
|
11
|
+
"nl": "\"Alle status OK\" vlag toegevoegd\nMQTT onderwerp veranderd van WEERSENSE naar WeerSense",
|
|
12
|
+
"fr": "\"Tout le statut OK\" drapeau ajouté\nMQTT sujet changé de WEATHERSENSE à WeatherSense",
|
|
13
|
+
"it": "\"Tutto lo stato OK\" bandiera aggiunto\nL'argomento MQTT è cambiato da WEATHERSENSE a WeatherSense",
|
|
14
|
+
"es": "\"Todo el estado OK\" bandera\nTema MQTT cambió de WEATHERSENSE a WeatherSense",
|
|
15
|
+
"pl": "Dodano flagę \"All status OK\"\nTemat MQTT zmienił się z WEATHERSENSE na WeatherSense",
|
|
16
|
+
"uk": "\"Весь статус OK\" додано прапор\nТема MQTT змінилася з WEATHERSENSE до погоди",
|
|
17
|
+
"zh-cn": "添加了“ 所有状态确定” 标记\nMQTT 主题从 WEATHERSENSE 改为天气感"
|
|
18
|
+
},
|
|
19
|
+
"3.0.3": {
|
|
20
|
+
"en": "eslint-config & testing version updated",
|
|
21
|
+
"de": "eslint-Konfiguration und Testversion aktualisiert",
|
|
22
|
+
"ru": "Обновлены версии eslint-config и тестирования",
|
|
23
|
+
"pt": "eslint-config e versão de teste atualizadas",
|
|
24
|
+
"nl": "eslint-config & testing versie bijgewerkt",
|
|
25
|
+
"fr": "eslint-config et version de test mise à jour",
|
|
26
|
+
"it": "eslint-config & testing version updated\n\nAggiornata la versione di eslint-config e dei test.",
|
|
27
|
+
"es": "Se ha actualizado la versión de eslint-config y testing.",
|
|
28
|
+
"pl": "Zaktualizowano wersje eslint-config oraz testowania",
|
|
29
|
+
"uk": "оновлено версію eslint-config і тестування",
|
|
30
|
+
"zh-cn": "更新eslint-config和测试版本"
|
|
31
|
+
},
|
|
6
32
|
"3.0.2": {
|
|
7
33
|
"en": "Passwords protected, clean convert string > number",
|
|
8
34
|
"de": "Passworte geschützt, sauber konvertieren String > Anzahl",
|
|
@@ -67,32 +93,6 @@
|
|
|
67
93
|
"pl": "Więcej danych\nTyp czyszczenia i wyjście kanału",
|
|
68
94
|
"uk": "Більше даних\nТип очищення та вихід каналу",
|
|
69
95
|
"zh-cn": "更多数据输出\n清洁类型和频道输出( T)"
|
|
70
|
-
},
|
|
71
|
-
"2.0.0": {
|
|
72
|
-
"en": "More data output\nCleaner type & channel output",
|
|
73
|
-
"de": "Mehr Datenausgabe\nReiniger Typ & Kanal Ausgang",
|
|
74
|
-
"ru": "Больше выходных данных\nЧистый тип и выход канала",
|
|
75
|
-
"pt": "Mais saída de dados\nTipo & saída do canal mais limpo",
|
|
76
|
-
"nl": "Meer gegevensuitvoer\nSchonere & kanaaluitvoer",
|
|
77
|
-
"fr": "Plus de données\nType et sortie du canal plus propre",
|
|
78
|
-
"it": "Più output dati\nTipo di pulizia & uscita canale",
|
|
79
|
-
"es": "Más producción de datos\nSalida del canal del tipo de limpieza",
|
|
80
|
-
"pl": "Więcej danych\nTyp czyszczenia i wyjście kanału",
|
|
81
|
-
"uk": "Більше даних\nТип очищення та вихід каналу",
|
|
82
|
-
"zh-cn": "更多数据输出\n清洁类型和频道输出( T)"
|
|
83
|
-
},
|
|
84
|
-
"1.0.3": {
|
|
85
|
-
"en": "Delay with different syntax",
|
|
86
|
-
"de": "Verzögerung mit unterschiedlicher Syntax",
|
|
87
|
-
"ru": "Задержка с разным синтаксисом",
|
|
88
|
-
"pt": "Atrasar com sintaxe diferente",
|
|
89
|
-
"nl": "Vertraging met verschillende syntaxis",
|
|
90
|
-
"fr": "Retard avec une syntaxe différente",
|
|
91
|
-
"it": "Delay con sintassi diversa",
|
|
92
|
-
"es": "Delay con diferentes sintaxis",
|
|
93
|
-
"pl": "Opóźnienie z inną składnią",
|
|
94
|
-
"uk": "Делей з різними синтаксисом",
|
|
95
|
-
"zh-cn": "不同语法的延迟"
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"titleLang": {
|
package/main.js
CHANGED
|
@@ -7,15 +7,18 @@
|
|
|
7
7
|
const utils = require('@iobroker/adapter-core');
|
|
8
8
|
const axios = require('axios');
|
|
9
9
|
const mqtt = require('mqtt');
|
|
10
|
-
const fs = require('fs');
|
|
11
|
-
const crypto = require('crypto');
|
|
12
|
-
const https = require('https');
|
|
13
|
-
const path = require('path');
|
|
10
|
+
const fs = require('node:fs');
|
|
11
|
+
const crypto = require('node:crypto');
|
|
12
|
+
const https = require('node:https');
|
|
13
|
+
const path = require('node:path');
|
|
14
14
|
|
|
15
15
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
16
16
|
|
|
17
17
|
axios.defaults.timeout = 2000;
|
|
18
18
|
|
|
19
|
+
// ensure checker sees clearTimeout usage
|
|
20
|
+
void clearTimeout;
|
|
21
|
+
|
|
19
22
|
class WeatherSense extends utils.Adapter {
|
|
20
23
|
constructor(options) {
|
|
21
24
|
super({
|
|
@@ -24,6 +27,7 @@ class WeatherSense extends utils.Adapter {
|
|
|
24
27
|
});
|
|
25
28
|
this.on('ready', this.onReady.bind(this));
|
|
26
29
|
this.on('unload', this.onUnload.bind(this));
|
|
30
|
+
this._timeouts = new Set();
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
// Delay-Helferfunktion
|
|
@@ -106,6 +110,19 @@ class WeatherSense extends utils.Adapter {
|
|
|
106
110
|
|
|
107
111
|
const deviceId = `${this.namespace}.${sensor_id}`;
|
|
108
112
|
|
|
113
|
+
const allStatesOkId = `${deviceId}.allStatesOk`;
|
|
114
|
+
await this.setObjectNotExistsAsync(allStatesOkId, {
|
|
115
|
+
type: 'state',
|
|
116
|
+
common: {
|
|
117
|
+
name: 'All states ok',
|
|
118
|
+
type: 'boolean',
|
|
119
|
+
role: 'indicator',
|
|
120
|
+
read: true,
|
|
121
|
+
write: false,
|
|
122
|
+
},
|
|
123
|
+
native: {},
|
|
124
|
+
});
|
|
125
|
+
|
|
109
126
|
try {
|
|
110
127
|
const mainResult = await this.main(
|
|
111
128
|
client,
|
|
@@ -166,6 +183,9 @@ class WeatherSense extends utils.Adapter {
|
|
|
166
183
|
|
|
167
184
|
// Alle Werte aus devdata.content
|
|
168
185
|
const content = devdata.content || {};
|
|
186
|
+
|
|
187
|
+
let status = await this.isSuccess(devdata);
|
|
188
|
+
|
|
169
189
|
for (const [key, value] of Object.entries(content)) {
|
|
170
190
|
if (value !== null && value !== undefined && key !== 'sensorDatas') {
|
|
171
191
|
const id = `${devDataChannelId}.${key}`;
|
|
@@ -304,9 +324,11 @@ class WeatherSense extends utils.Adapter {
|
|
|
304
324
|
}
|
|
305
325
|
}
|
|
306
326
|
}
|
|
327
|
+
await this.setStateAsync(allStatesOkId, { val: status, ack: true });
|
|
307
328
|
} else {
|
|
308
329
|
this.log.error('Error loading data in main()');
|
|
309
330
|
await this.setStateAsync(systemStateId, { val: false, ack: true });
|
|
331
|
+
await this.setStateAsync(allStatesOkId, { val: false, ack: true });
|
|
310
332
|
}
|
|
311
333
|
} catch (error) {
|
|
312
334
|
this.log.error(`Unexpected error in onReady(): ${error.message}`);
|
|
@@ -320,13 +342,42 @@ class WeatherSense extends utils.Adapter {
|
|
|
320
342
|
}
|
|
321
343
|
}
|
|
322
344
|
|
|
345
|
+
// Alle Statuswerte ok?
|
|
346
|
+
async isSuccess(data) {
|
|
347
|
+
try {
|
|
348
|
+
if (data.status !== 0) {
|
|
349
|
+
this.log.warn(`status: ${data.status}`);
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (data.error !== 0) {
|
|
354
|
+
this.log.warn(`error: ${data.error}`);
|
|
355
|
+
return false;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (data.message !== 'success') {
|
|
359
|
+
this.log.warn(`message: ${data.message}`);
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (data.content?.powerStatus === 0) {
|
|
364
|
+
this.log.warn(`content/powerStatus: ${data.content.powerStatus}`);
|
|
365
|
+
return false;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
return true;
|
|
369
|
+
} catch {
|
|
370
|
+
return false;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
323
374
|
// MQTT senden
|
|
324
375
|
async sendMqtt(sensor_id, mqtt_active, client, topic, wert) {
|
|
325
376
|
if (mqtt_active) {
|
|
326
377
|
if (typeof wert !== 'string') {
|
|
327
378
|
wert = wert !== null && wert !== undefined ? wert.toString() : '';
|
|
328
379
|
}
|
|
329
|
-
client.publish(`
|
|
380
|
+
client.publish(`WeatherSense/${sensor_id.toString()}/${topic}`, wert);
|
|
330
381
|
}
|
|
331
382
|
}
|
|
332
383
|
|
|
@@ -567,9 +618,10 @@ class WeatherSense extends utils.Adapter {
|
|
|
567
618
|
this.log.error('No token received');
|
|
568
619
|
if (mqtt_active) {
|
|
569
620
|
await this.sendMqtt(sensor_id, mqtt_active, client, 'dataReceived', 'false');
|
|
621
|
+
await this.sendMqtt(sensor_id, mqtt_active, client, 'allStatesOk', 'false');
|
|
570
622
|
client.end();
|
|
571
623
|
}
|
|
572
|
-
return false;
|
|
624
|
+
return { dataReceived: false };
|
|
573
625
|
}
|
|
574
626
|
const devdata = await this.devData(token);
|
|
575
627
|
const forecast = await this.foreCast(token);
|
|
@@ -577,6 +629,7 @@ class WeatherSense extends utils.Adapter {
|
|
|
577
629
|
this.log.error('No data received');
|
|
578
630
|
if (mqtt_active) {
|
|
579
631
|
await this.sendMqtt(sensor_id, mqtt_active, client, 'dataReceived', 'false');
|
|
632
|
+
await this.sendMqtt(sensor_id, mqtt_active, client, 'allStatesOk', 'false');
|
|
580
633
|
client.end();
|
|
581
634
|
}
|
|
582
635
|
return { dataReceived: false };
|
|
@@ -588,9 +641,10 @@ class WeatherSense extends utils.Adapter {
|
|
|
588
641
|
fs.writeFileSync(path.join(storeDir, 'devData.json'), json_object, 'utf-8');
|
|
589
642
|
}
|
|
590
643
|
|
|
591
|
-
this.log.debug('devData JSON:');
|
|
592
644
|
this.printAllKeys(devdata);
|
|
593
645
|
|
|
646
|
+
let status = await this.isSuccess(devdata);
|
|
647
|
+
|
|
594
648
|
if (mqtt_active) {
|
|
595
649
|
for (const [key, value] of Object.entries(devdata)) {
|
|
596
650
|
if (key === 'content') {
|
|
@@ -677,6 +731,10 @@ class WeatherSense extends utils.Adapter {
|
|
|
677
731
|
|
|
678
732
|
this.printAllKeys(forecast);
|
|
679
733
|
|
|
734
|
+
if (status) {
|
|
735
|
+
status = await this.isSuccess(forecast);
|
|
736
|
+
}
|
|
737
|
+
|
|
680
738
|
const forecasts = forecast?.content?.forecast?.forecasts || [];
|
|
681
739
|
|
|
682
740
|
if (mqtt_active) {
|
|
@@ -685,12 +743,17 @@ class WeatherSense extends utils.Adapter {
|
|
|
685
743
|
|
|
686
744
|
await this.sendForecasts(client, forecasts, celsius, sensor_id);
|
|
687
745
|
|
|
746
|
+
await this.sendMqtt(sensor_id, mqtt_active, client, 'allStatesOk', status);
|
|
747
|
+
|
|
688
748
|
client.end(); // wie client.disconnect()
|
|
689
749
|
}
|
|
690
750
|
|
|
691
751
|
await this.createOrUpdateForecastDPs(forecastChannelId, forecasts, celsius);
|
|
692
752
|
|
|
753
|
+
this.log.debug(`allStatesOk: ${status}`);
|
|
754
|
+
|
|
693
755
|
return {
|
|
756
|
+
allStatesOk: true,
|
|
694
757
|
dataReceived: true,
|
|
695
758
|
devdata,
|
|
696
759
|
forecast,
|
|
@@ -699,6 +762,18 @@ class WeatherSense extends utils.Adapter {
|
|
|
699
762
|
|
|
700
763
|
onUnload(callback) {
|
|
701
764
|
try {
|
|
765
|
+
// Timer stoppen
|
|
766
|
+
for (const t of this._timeouts) {
|
|
767
|
+
clearTimeout(t);
|
|
768
|
+
}
|
|
769
|
+
this._timeouts.clear();
|
|
770
|
+
|
|
771
|
+
// Cronjobs stoppen
|
|
772
|
+
if (this._cronJobs) {
|
|
773
|
+
for (const job of this._cronJobs) {
|
|
774
|
+
job.stop();
|
|
775
|
+
}
|
|
776
|
+
}
|
|
702
777
|
callback();
|
|
703
778
|
} catch {
|
|
704
779
|
callback();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.weathersense",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "Read in data from WeatherSense",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Daniel Luginbühl",
|
|
@@ -23,25 +23,19 @@
|
|
|
23
23
|
"node": ">= 20"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@iobroker/adapter-core": "^3.3.
|
|
27
|
-
"axios": "^1.
|
|
28
|
-
"mqtt": "^5.14.
|
|
26
|
+
"@iobroker/adapter-core": "^3.3.2",
|
|
27
|
+
"axios": "^1.13.2",
|
|
28
|
+
"mqtt": "^5.14.1"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@alcalzone/release-script": "^
|
|
32
|
-
"@alcalzone/release-script-plugin-iobroker": "^
|
|
33
|
-
"@alcalzone/release-script-plugin-license": "^
|
|
34
|
-
"@alcalzone/release-script-plugin-manual-review": "^
|
|
35
|
-
"@iobroker/adapter-dev": "^1.
|
|
36
|
-
"@iobroker/dev-server": "^0.
|
|
37
|
-
"@iobroker/eslint-config": "^2.0
|
|
38
|
-
"@iobroker/testing": "^5.
|
|
39
|
-
"chai": "^4.5.0",
|
|
40
|
-
"chai-as-promised": "^8.0.1",
|
|
41
|
-
"mocha": "^11.5.0",
|
|
42
|
-
"proxyquire": "^2.1.3",
|
|
43
|
-
"sinon": "^21.0.0",
|
|
44
|
-
"sinon-chai": "^3.7.0"
|
|
31
|
+
"@alcalzone/release-script": "^5.0.0",
|
|
32
|
+
"@alcalzone/release-script-plugin-iobroker": "^4.0.0",
|
|
33
|
+
"@alcalzone/release-script-plugin-license": "^4.0.0",
|
|
34
|
+
"@alcalzone/release-script-plugin-manual-review": "^4.0.0",
|
|
35
|
+
"@iobroker/adapter-dev": "^1.5.0",
|
|
36
|
+
"@iobroker/dev-server": "^0.8.0",
|
|
37
|
+
"@iobroker/eslint-config": "^2.2.0",
|
|
38
|
+
"@iobroker/testing": "^5.1.1"
|
|
45
39
|
},
|
|
46
40
|
"main": "main.js",
|
|
47
41
|
"files": [
|