iobroker.nuasense 0.2.1 → 0.2.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/README.md +7 -2
- package/io-package.json +14 -1
- package/main.js +33 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
|
|
10
10
|
## NuaSense adapter for ioBroker
|
|
11
11
|
|
|
12
|
-
What your weather station means for your house and garden, as ioBroker states — and, if you like, your station forwarded from ioBroker to NuaSense. The first three stations on a NuaSense account connect free.
|
|
12
|
+
What your weather station means for your house and garden, as ioBroker states — and, if you like, your station forwarded from ioBroker to [NuaSense](https://nuasense.com). The first three stations on a NuaSense account connect free.
|
|
13
13
|
|
|
14
14
|
### Read
|
|
15
15
|
|
|
16
|
-
Make an API key in the NuaSense console under **API Keys** (scope `ingest:write`; it is what reads your own stations), put it into the adapter, and tell it what the garden mostly is (lawn, vegetables, flower beds and shrubs) and your sprinkler's rate in mm per hour (pop-up sprinkler about 10, drip line 2–4; 0 for millimetres only). Every 15 minutes (configurable) the adapter writes, per station:
|
|
16
|
+
Make an API key in the [NuaSense console](https://platform.nuasense.com) under **API Keys** (scope `ingest:write`; it is what reads your own stations), put it into the adapter, and tell it what the garden mostly is (lawn, vegetables, flower beds and shrubs) and your sprinkler's rate in mm per hour (pop-up sprinkler about 10, drip line 2–4; 0 for millimetres only). Every 15 minutes (configurable) the adapter writes, per station:
|
|
17
17
|
|
|
18
18
|
| state | meaning |
|
|
19
19
|
|---|---|
|
|
@@ -46,6 +46,9 @@ When you connect a station, NuaSense stores its readings and computes your forec
|
|
|
46
46
|
Placeholder for the next version (at the beginning of the line):
|
|
47
47
|
### **WORK IN PROGRESS**
|
|
48
48
|
-->
|
|
49
|
+
### 0.2.2 (2026-11-09)
|
|
50
|
+
* (NuaSense) object structure for the review: folders and channels for all states, valid roles, no null values
|
|
51
|
+
|
|
49
52
|
### 0.2.1 (2026-11-05)
|
|
50
53
|
* (NuaSense) checker fixes: workflow and tooling
|
|
51
54
|
|
|
@@ -58,6 +61,8 @@ When you connect a station, NuaSense stores its readings and computes your forec
|
|
|
58
61
|
### 0.1.0 (2026-11-03)
|
|
59
62
|
* (NuaSense) first release: first look and hourly agronomy as states; optional forwarding of a station from ioBroker to NuaSense
|
|
60
63
|
|
|
64
|
+
Older changes: [CHANGELOG_OLD.md](CHANGELOG_OLD.md)
|
|
65
|
+
|
|
61
66
|
## License
|
|
62
67
|
MIT License
|
|
63
68
|
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "nuasense",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.2",
|
|
5
5
|
"news": {
|
|
6
|
+
"0.2.2": {
|
|
7
|
+
"en": "Object structure for the review: folders and channels for all states, valid roles, no null values",
|
|
8
|
+
"de": "Objektstruktur für das Review: Ordner und Kanäle für alle States, gültige Rollen, keine Nullwerte",
|
|
9
|
+
"ru": "Структура объектов для проверки: папки и каналы для всех состояний, допустимые роли, без значений null",
|
|
10
|
+
"pt": "Estrutura de objetos para a revisão: pastas e canais para todos os estados, funções válidas, sem valores nulos",
|
|
11
|
+
"nl": "Objectstructuur voor de review: mappen en kanalen voor alle states, geldige rollen, geen null-waarden",
|
|
12
|
+
"fr": "Structure des objets pour la revue : dossiers et canaux pour tous les états, rôles valides, aucune valeur nulle",
|
|
13
|
+
"it": "Struttura degli oggetti per la revisione: cartelle e canali per tutti gli stati, ruoli validi, nessun valore nullo",
|
|
14
|
+
"es": "Estructura de objetos para la revisión: carpetas y canales para todos los estados, roles válidos, sin valores nulos",
|
|
15
|
+
"pl": "Struktura obiektów do przeglądu: foldery i kanały dla wszystkich stanów, poprawne role, bez wartości null",
|
|
16
|
+
"uk": "Структура об'єктів для перевірки: папки та канали для всіх станів, допустимі ролі, без значень null",
|
|
17
|
+
"zh-cn": "用于审核的对象结构:所有状态都有文件夹和通道,角色有效,没有空值"
|
|
18
|
+
},
|
|
6
19
|
"0.2.1": {
|
|
7
20
|
"en": "Checker fixes: workflow and tooling",
|
|
8
21
|
"de": "Checker-Korrekturen: Workflow und Werkzeuge",
|
package/main.js
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
const utils = require('@iobroker/adapter-core');
|
|
22
22
|
const { toEcowitt, encodeForm, uploadUrl } = require('./lib/ecowitt');
|
|
23
|
+
const { version } = require('./package.json');
|
|
23
24
|
|
|
24
25
|
const FORWARD_EVERY_MS = 60_000;
|
|
25
26
|
const MIN_POLL_MINUTES = 5;
|
|
@@ -126,11 +127,19 @@ class Nuasense extends utils.Adapter {
|
|
|
126
127
|
|
|
127
128
|
async updateStation(station) {
|
|
128
129
|
const id = `stations.${sanitize(station.station_id)}`;
|
|
130
|
+
await this.setObjectNotExistsAsync('stations', {
|
|
131
|
+
type: 'folder',
|
|
132
|
+
common: { name: 'Stations' },
|
|
133
|
+
native: {},
|
|
134
|
+
});
|
|
129
135
|
await this.extendObjectAsync(id, {
|
|
130
|
-
type: '
|
|
136
|
+
type: 'device',
|
|
131
137
|
common: { name: station.name || station.station_id },
|
|
132
138
|
native: { station_id: station.station_id },
|
|
133
139
|
});
|
|
140
|
+
await this.channel(`${id}.tonight`, 'Tonight');
|
|
141
|
+
await this.channel(`${id}.garden`, 'Garden');
|
|
142
|
+
await this.channel(`${id}.plausibility`, 'Plausibility');
|
|
134
143
|
|
|
135
144
|
const push = station.push || {};
|
|
136
145
|
await this.put(`${id}.lastUpload`, push.last_push_at || null, {
|
|
@@ -204,7 +213,7 @@ class Nuasense extends utils.Adapter {
|
|
|
204
213
|
await this.put(`${id}.garden.rainNext24h`, numOrNull(w.rain_next_24h_mm), {
|
|
205
214
|
name: 'Rain forecast, next 24 h',
|
|
206
215
|
type: 'number',
|
|
207
|
-
role: 'value.precipitation.forecast',
|
|
216
|
+
role: 'value.precipitation.forecast.0',
|
|
208
217
|
unit: 'mm',
|
|
209
218
|
});
|
|
210
219
|
await this.put(`${id}.garden.rainLast24h`, numOrNull(w.rain_last_24h_mm), {
|
|
@@ -253,6 +262,8 @@ class Nuasense extends utils.Adapter {
|
|
|
253
262
|
if (!this.config.advanced) {
|
|
254
263
|
return;
|
|
255
264
|
}
|
|
265
|
+
await this.channel(`${id}.spray`, 'Spray window');
|
|
266
|
+
await this.channel(`${id}.hourly`, 'Hourly agronomy');
|
|
256
267
|
const s = (look && look.spray) || {};
|
|
257
268
|
await this.put(`${id}.spray.window`, s.window ? `${s.window.from}–${s.window.to}` : s.date ? 'none' : null, {
|
|
258
269
|
name: 'Next spray window',
|
|
@@ -267,7 +278,7 @@ class Nuasense extends utils.Adapter {
|
|
|
267
278
|
await this.put(`${id}.spray.windMax`, numOrNull(s.wind_max_ms), {
|
|
268
279
|
name: 'Highest wind in the window',
|
|
269
280
|
type: 'number',
|
|
270
|
-
role: 'value.speed',
|
|
281
|
+
role: 'value.speed.max.wind',
|
|
271
282
|
unit: 'm/s',
|
|
272
283
|
});
|
|
273
284
|
await this.put(`${id}.spray.reason`, s.reason || null, {
|
|
@@ -366,13 +377,30 @@ class Nuasense extends utils.Adapter {
|
|
|
366
377
|
}
|
|
367
378
|
}
|
|
368
379
|
|
|
369
|
-
/**
|
|
380
|
+
/** A channel that groups the states below it. */
|
|
381
|
+
async channel(id, name) {
|
|
382
|
+
await this.setObjectNotExistsAsync(id, {
|
|
383
|
+
type: 'channel',
|
|
384
|
+
common: { name },
|
|
385
|
+
native: {},
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Create the state if needed, then write it acknowledged. With nothing to
|
|
391
|
+
* report the stored value goes away: null would break the declared type, and
|
|
392
|
+
* keeping the old value would show yesterday's answer as today's.
|
|
393
|
+
*/
|
|
370
394
|
async put(id, value, common) {
|
|
371
395
|
await this.setObjectNotExistsAsync(id, {
|
|
372
396
|
type: 'state',
|
|
373
397
|
common: { read: true, write: false, ...common },
|
|
374
398
|
native: {},
|
|
375
399
|
});
|
|
400
|
+
if (value === null || value === undefined) {
|
|
401
|
+
await this.delStateAsync(id);
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
376
404
|
await this.setStateAsync(id, { val: value, ack: true });
|
|
377
405
|
}
|
|
378
406
|
|
|
@@ -420,7 +448,7 @@ class Nuasense extends utils.Adapter {
|
|
|
420
448
|
};
|
|
421
449
|
const fields = toEcowitt(reading, {
|
|
422
450
|
deviceId: cfg.forwardDeviceId || `iobroker-${this.namespace}`,
|
|
423
|
-
stationType:
|
|
451
|
+
stationType: `iobroker.nuasense_V${version}`,
|
|
424
452
|
});
|
|
425
453
|
if (Object.keys(fields).length <= 3) {
|
|
426
454
|
// PASSKEY, stationtype, dateutc and nothing else: no mapped state had a value.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.nuasense",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "NuaSense for ioBroker: what your weather station means for your house and garden (frost tonight, watering today, rain next 24 h, plausibility), and optionally forward a station from ioBroker to NuaSense",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "NuaSense",
|