@mschaeffler/node-red-bthome 1.5.0 → 1.6.1

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 CHANGED
@@ -12,6 +12,9 @@ At the moment these sensors are implemented and tested:
12
12
  - Shelly BLU RC Button 4
13
13
  - Shelly BLU Wall Switch 4
14
14
  - Shelly BLU Motion
15
+ - Shelly BLU Distance
16
+ - Shelly BLU Remote
17
+ - Ecowitt WS90 powered by Shelly
15
18
 
16
19
  ## Capture of Raw Frames
17
20
 
@@ -29,14 +32,18 @@ This node can decrypt [encrypted messages](https://bthome.io/encryption/), if th
29
32
  $ npm install @mschaeffler/node-red-bthome
30
33
  ```
31
34
 
32
- ## Input
35
+ ## bthome Node
36
+
37
+ This node decodes the raw frames.
38
+
39
+ ### Input
33
40
 
34
41
  |msg. | type | description |
35
42
  |:-------|:-------|:----------------------------------|
36
43
  |payload | object | data from Shelly script|
37
44
  |resync | boolean| if set to yes, allow all packed ids; to resync after some issue|
38
45
 
39
- ### msg.payload
46
+ #### msg.payload
40
47
 
41
48
  Only the first two values are needed, the others are optional.
42
49
 
@@ -59,27 +66,27 @@ This is an example of such a message payload:
59
66
  }
60
67
  ```
61
68
 
62
- ## Outputs
69
+ ### Outputs
63
70
 
64
71
  There are two output ports:
65
72
  1. one for meassurement values (states)
66
73
  2. one for actions done with the devices (events)
67
74
 
68
- ### State
75
+ #### State
69
76
 
70
77
  |msg. | type | description |
71
78
  |:-------|:-------|:----------------------------------|
72
79
  |topic | string | `State-Prefix` + name of the device|
73
80
  |payload | object | decoded state data|
74
81
 
75
- ### Events
82
+ #### Events
76
83
 
77
84
  |msg. | type | description |
78
85
  |:-------|:-------|:----------------------------------|
79
86
  |topic | string | `Event-Prefix` + name of the device|
80
87
  |payload | object | data of the decoded event|
81
88
 
82
- ## Parameters
89
+ ### Parameters
83
90
 
84
91
  |config | type | description |
85
92
  |:------------|:-------|:----------------------------------|
@@ -90,7 +97,7 @@ There are two output ports:
90
97
  |Context-Variable| string | name of the variable in flow context storage |
91
98
  |Contextstore | string | context store to be used |
92
99
 
93
- ### Device-Configuration
100
+ #### Device-Configuration
94
101
 
95
102
  With this JSON string the installed [BT-Home](https://bthome.io) devices are configured:
96
103
  ```
@@ -109,7 +116,7 @@ An example for such a config from the unit tests:
109
116
  }
110
117
  ```
111
118
 
112
- ### Context storage
119
+ #### Context storage
113
120
 
114
121
  All recorded data can be stored in a flow context variable for
115
122
  - initialisation
@@ -136,10 +143,83 @@ If content storage is active, statistical data is also stored in a variable with
136
143
  { ok:0, err:0, old:0, dup:0 }
137
144
  ```
138
145
 
146
+ ## ws90 Node
147
+
148
+ This node does additional calulations with the data from an "*Ecowitt WS90 powered by Shelly*" weather station.
149
+
150
+ Normally this data is decoded by the `bthome` node.
151
+
152
+ Similar calculations are done by the Ecowitt base stations.
153
+
154
+ ### Input
155
+
156
+ |msg. | type | description |
157
+ |:-------|:-------|:----------------------------------|
158
+ |payload |object |data from `bthome` node. |
159
+ |reset |boolean |if set to `true`, the output filter is reset and unchanged values will been sent with the next raw data.|
160
+ |newday |boolean |if set to `true`, a new day is started (rain today, rain yesterday and wind max).|
161
+
162
+ This is an example of such a message payload:
163
+ ```
164
+ {
165
+ "lux": 3630,
166
+ "moisture": false,
167
+ "wind": [1.5,1.5],
168
+ "uv": 0,
169
+ "direction": 174,
170
+ "pressure": 948.2,
171
+ "dewpoint": -0.43,
172
+ "humidity": 99,
173
+ "temperature": -0.3,
174
+ "precipitation": 121.5
175
+ }
176
+ ```
177
+
178
+ ### Outputs
179
+
180
+ There are 12 output ports:
181
+
182
+ values are only sent out, if they are changed
183
+
184
+ | topic | explanation |
185
+ |:------|:------------|
186
+ |temperature|no calculation, value directly from the input data|
187
+ |dew point|no calculation, value directly from the input data|
188
+ |humidity|no calculation, value directly from the input data|
189
+ |raining|Is it raining at the moment?<br>It is set to `true`, if `moisture==true` or a delta in `precipitation` is received.<br>It is set to `false` after a timeout of 15min or 20min without any of the above events.<br>If `true` the class is set to `blueValue`.|
190
+ |rain yesterday|rain from yesterday, at `newday==true` it is taken from `rain today`|
191
+ |rain today|accumulated rain today, so since the last `newday==true` received|
192
+ |uv|no calculation, value directly from the input data<br>between 0 and 2 the class is set to `greenValue`, up to 5 to `yellowValue` and above to `redValue`|
193
+ |air pressure|can be either the measured air pressure (QFE) without any further calculation<br>or the air pressure at sea level (QFF) [for the calculation](https://de.wikipedia.org/wiki/Barometrische_H%C3%B6henformel)|
194
+ |direction|no calculation, value directly from the input data|
195
+ |wind|no calculation, value directly from the input data<br>between 0 and 25 the class is set to default, up to 50 to `yellowValue` and above to `redValue`|
196
+ |wind max|maximal wind speed today, so since the last `newday==true` received|
197
+ |illumination|no calculation, value directly from the input data|
198
+
199
+ #### style classes
200
+
201
+ Some values have style classes for the `dashboard 2` attached.
202
+
203
+ This classes should be defined (for an example check the `ui-template` in the
204
+ [examples](https://github.com/m-schaeffler/node-red-my-nodes/raw/main/node-red-bthome/examples/CSS.json)):
205
+ - greenValue
206
+ - yellowValue
207
+ - redValue
208
+ - blueValue
209
+
210
+ ### Parameters
211
+
212
+ |config | type | description |
213
+ |:------------|:-------|:----------------------------------|
214
+ |Contextstore | string | context store to be used. |
215
+ |reference height|number| height of the installation over the sea level, to caculate the relative air pressure (QFF).<br>If set to `0` no caclulation is done and the absolute air pressure (QFE) is outputed.|
216
+
139
217
  ## Example Flow
140
218
 
141
219
  [example flow](https://github.com/m-schaeffler/node-red-my-nodes/raw/main/node-red-bthome/examples/bthome.json)
142
220
 
221
+ [CSS template](https://github.com/m-schaeffler/node-red-my-nodes/raw/main/node-red-bthome/examples/CSS.json)
222
+
143
223
  ## Author
144
224
 
145
225
  [Mathias Schäffler](https://github.com/m-schaeffler)
@@ -0,0 +1,54 @@
1
+ [
2
+ {
3
+ "id": "fb58dd887406a7d3",
4
+ "type": "ui-template",
5
+ "z": "bf934c281a6f35c0",
6
+ "group": "",
7
+ "page": "",
8
+ "ui": "fd06eabec55c4e5d",
9
+ "name": "CSS classes 2.0",
10
+ "order": 0,
11
+ "width": 0,
12
+ "height": 0,
13
+ "head": "",
14
+ "format": ".red label.nrdb-ui-text-label, .red span, .redValue span.nrdb-ui-text-value, span.red {\n color: red !important;\n}\n.green label.nrdb-ui-text-label, .green span, .greenValue span.nrdb-ui-text-value, span.green {\n color: LimeGreen !important;\n}\n.darkgreen label.nrdb-ui-text-label, .darkgreen span, span.darkgreen {\n color: green !important;\n}\n.blue label.nrdb-ui-text-label, .blue span, .blueValue span.nrdb-ui-text-value, span.blue {\n color: aqua !important;\n}\n.yellow label.nrdb-ui-text-label, .yellow span, .yellowValue span.nrdb-ui-text-value, span.yellow {\n color: yellow !important;\n}\n.gray label.nrdb-ui-text-label, .gray span, .grayValue span.nrdb-ui-text-value, span.gray {\n color: gray !important;\n}\n.silver label.nrdb-ui-text-label, .silver span, .silverValue span.nrdb-ui-text-value, span.silver {\n color: #b0b0b0 !important;\n}",
15
+ "storeOutMessages": true,
16
+ "passthru": false,
17
+ "resendOnRefresh": true,
18
+ "templateScope": "site:style",
19
+ "className": "",
20
+ "x": 440,
21
+ "y": 640,
22
+ "wires": [
23
+ []
24
+ ]
25
+ },
26
+ {
27
+ "id": "fd06eabec55c4e5d",
28
+ "type": "ui-base",
29
+ "name": "Dashboard 2.0",
30
+ "path": "/dashboard",
31
+ "appIcon": "",
32
+ "includeClientData": false,
33
+ "acceptsClientConfig": [
34
+ "ui-notification",
35
+ "ui-control"
36
+ ],
37
+ "showPathInSidebar": false,
38
+ "headerContent": "page",
39
+ "navigationStyle": "default",
40
+ "titleBarStyle": "fixed",
41
+ "showReconnectNotification": false,
42
+ "notificationDisplayTime": "5",
43
+ "showDisconnectNotification": false,
44
+ "allowInstall": true
45
+ },
46
+ {
47
+ "id": "7d327676499cd8a2",
48
+ "type": "global-config",
49
+ "env": [],
50
+ "modules": {
51
+ "@flowfuse/node-red-dashboard": "1.29.0"
52
+ }
53
+ }
54
+ ]
@@ -1,8 +1,8 @@
1
1
  [
2
2
  {
3
- "id": "3a9fcdbd98993dbc",
3
+ "id": "da2333b077f13c53",
4
4
  "type": "mqtt in",
5
- "z": "8e0e9a167c607864",
5
+ "z": "1607080a6a66359a",
6
6
  "name": "",
7
7
  "topic": "node-red/bleraw",
8
8
  "qos": "0",
@@ -12,39 +12,42 @@
12
12
  "rap": true,
13
13
  "rh": 0,
14
14
  "inputs": 0,
15
- "x": 140,
16
- "y": 1460,
15
+ "x": 260,
16
+ "y": 560,
17
17
  "wires": [
18
18
  [
19
- "c4df490573c18fc4"
19
+ "da23792a27f30483"
20
20
  ]
21
21
  ]
22
22
  },
23
23
  {
24
- "id": "c4df490573c18fc4",
24
+ "id": "da23792a27f30483",
25
25
  "type": "bthome",
26
- "z": "8e0e9a167c607864",
26
+ "z": "1607080a6a66359a",
27
27
  "name": "",
28
28
  "devices": "{\"11:22:33:44:55:66\":{\"topic\":\"dev_unencrypted_1\"},\"00:01:02:03:04:05\":{\"topic\":\"dev_unencrypted_2\"},\"00:10:20:30:40:50\":{\"topic\":\"dev_encrypted_1\",\"key\":\"00112233445566778899AABBCCDDEEFF\"},\"00:00:00:00:00:00\":{\"topic\":\"dev_encrypted_2\",\"key\":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]}}",
29
+ "counterMode": "none",
29
30
  "statusPrefix": "Status",
30
31
  "eventPrefix": "Event",
31
32
  "contextVar": "bt-home",
32
33
  "contextStore": "memoryOnly",
33
- "x": 340,
34
- "y": 1440,
34
+ "batteryState": false,
35
+ "x": 460,
36
+ "y": 540,
35
37
  "wires": [
36
38
  [
37
- "3c9fee837ed43fc0"
39
+ "45cc12931b5a0b52",
40
+ "02887e37eebfaae5"
38
41
  ],
39
42
  [
40
- "26ebe1833f97c4d4"
43
+ "347a2db3d0351824"
41
44
  ]
42
45
  ]
43
46
  },
44
47
  {
45
- "id": "3c9fee837ed43fc0",
48
+ "id": "45cc12931b5a0b52",
46
49
  "type": "debug",
47
- "z": "8e0e9a167c607864",
50
+ "z": "1607080a6a66359a",
48
51
  "name": "debug 9",
49
52
  "active": true,
50
53
  "tosidebar": true,
@@ -53,14 +56,14 @@
53
56
  "complete": "false",
54
57
  "statusVal": "",
55
58
  "statusType": "auto",
56
- "x": 520,
57
- "y": 1420,
59
+ "x": 640,
60
+ "y": 520,
58
61
  "wires": []
59
62
  },
60
63
  {
61
- "id": "26ebe1833f97c4d4",
64
+ "id": "347a2db3d0351824",
62
65
  "type": "debug",
63
- "z": "8e0e9a167c607864",
66
+ "z": "1607080a6a66359a",
64
67
  "name": "debug 10",
65
68
  "active": true,
66
69
  "tosidebar": true,
@@ -69,14 +72,14 @@
69
72
  "complete": "false",
70
73
  "statusVal": "",
71
74
  "statusType": "auto",
72
- "x": 520,
73
- "y": 1460,
75
+ "x": 640,
76
+ "y": 560,
74
77
  "wires": []
75
78
  },
76
79
  {
77
- "id": "e3ad83be53fa3fe3",
80
+ "id": "5ba4c641b627284d",
78
81
  "type": "inject",
79
- "z": "8e0e9a167c607864",
82
+ "z": "1607080a6a66359a",
80
83
  "name": "",
81
84
  "props": [
82
85
  {
@@ -94,14 +97,63 @@
94
97
  "topic": "",
95
98
  "payload": "{\"addr\":\"11:22:33:44:55:66\",\"rssi\":-85,\"time\":1745395033113,\"gateway\":\"Shelly Gateway\",\"data\":[68,0,164,1,100,46,56,69,43,255]}",
96
99
  "payloadType": "json",
97
- "x": 170,
98
- "y": 1420,
100
+ "x": 290,
101
+ "y": 520,
99
102
  "wires": [
100
103
  [
101
- "c4df490573c18fc4"
104
+ "da23792a27f30483"
102
105
  ]
103
106
  ]
104
107
  },
108
+ {
109
+ "id": "02887e37eebfaae5",
110
+ "type": "switch",
111
+ "z": "1607080a6a66359a",
112
+ "name": "is WS90",
113
+ "property": "payload",
114
+ "propertyType": "msg",
115
+ "rules": [
116
+ {
117
+ "t": "hask",
118
+ "v": "dewpoint",
119
+ "vt": "str"
120
+ }
121
+ ],
122
+ "checkall": "false",
123
+ "repair": false,
124
+ "outputs": 1,
125
+ "x": 480,
126
+ "y": 360,
127
+ "wires": [
128
+ [
129
+ "57b7cd4b7d2e6f25"
130
+ ]
131
+ ]
132
+ },
133
+ {
134
+ "id": "57b7cd4b7d2e6f25",
135
+ "type": "ws90",
136
+ "z": "1607080a6a66359a",
137
+ "name": "",
138
+ "contextStore": "memoryOnly",
139
+ "refheight": "500",
140
+ "x": 630,
141
+ "y": 360,
142
+ "wires": [
143
+ [],
144
+ [],
145
+ [],
146
+ [],
147
+ [],
148
+ [],
149
+ [],
150
+ [],
151
+ [],
152
+ [],
153
+ [],
154
+ []
155
+ ]
156
+ },
105
157
  {
106
158
  "id": "66b8b47e.0f87bc",
107
159
  "type": "mqtt-broker",
@@ -133,5 +185,13 @@
133
185
  "willMsg": {},
134
186
  "userProps": "",
135
187
  "sessionExpiry": ""
188
+ },
189
+ {
190
+ "id": "888386dbbbc56d84",
191
+ "type": "global-config",
192
+ "env": [],
193
+ "modules": {
194
+ "@mschaeffler/node-red-bthome": "1.6.0"
195
+ }
136
196
  }
137
197
  ]
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mschaeffler/node-red-bthome",
3
- "version": "1.5.0",
3
+ "version": "1.6.1",
4
4
  "description": "A Node Red node to decrypt and decode BT-Home frames",
5
5
  "author": {
6
6
  "name": "Mathias Schäffler",
@@ -12,7 +12,8 @@
12
12
  "BT-Home",
13
13
  "bthome",
14
14
  "Shelly BLU",
15
- "BLE"
15
+ "BLE",
16
+ "WS90"
16
17
  ],
17
18
  "bugs": {
18
19
  "url": "https://github.com/m-schaeffler/node-red-my-nodes/tree/main/node-red-bthome/issues"
@@ -25,7 +26,8 @@
25
26
  "node-red": {
26
27
  "version": ">=4.0.0",
27
28
  "nodes": {
28
- "bthome": "bthome.js"
29
+ "bthome": "bthome.js",
30
+ "ws90": "ws90.js"
29
31
  }
30
32
  },
31
33
  "engines": {
package/ws90.html ADDED
@@ -0,0 +1,139 @@
1
+ <script type="text/javascript">
2
+ RED.nodes.registerType('ws90',{
3
+ category: 'input',
4
+ color: '#DEB887',
5
+ defaults: {
6
+ name: {value:""},
7
+ contextStore:{value:"none",required:true},
8
+ refheight:{value:0,validate:RED.validators.number(),required:true}
9
+ },
10
+ inputs:1,
11
+ outputs:12,
12
+ icon: "font-awesome/fa-sun-o",
13
+ label: function() {
14
+ return this.name||"WS 90";
15
+ },
16
+ labelStyle: function() {
17
+ return this.name?"node_label_italic":"";
18
+ },
19
+ paletteLabel: "ws 90",
20
+ inputLabels: 'decoded bthome frame from ws90',
21
+ outputLabels: ['temperature','dew point','humidity','raining','rain yesterday','rain today','uv','air pressure','direction','wind','wind max','illumination'],
22
+ oneditprepare: function() {
23
+ const node = this;
24
+ // populate store names
25
+ $("#node-input-contextStore").empty();
26
+ $("#node-input-contextStore").append(`<option value="none">None</option>`);
27
+ const defaultStore = RED.settings.hasOwnProperty('context') ? RED.settings.context.default : '';
28
+ RED.settings.context.stores.forEach(function(item){
29
+ if( item ) {
30
+ const opt = $(`<option value="${item}">${item}${item===defaultStore?" (default)":""}</option>`);
31
+ $("#node-input-contextStore").append(opt);
32
+ }
33
+ });
34
+ const currentStore = node.contextStore || '';
35
+ // select the current option
36
+ $("#node-input-contextStore").val(currentStore);
37
+ }
38
+ });
39
+ </script>
40
+
41
+ <script type="text/x-red" data-template-name="ws90">
42
+ <div class="form-row">
43
+ <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
44
+ <input type="text" id="node-input-name" placeholder="Name">
45
+ </div>
46
+ <div class="form-row">
47
+ <label for="node-input-contextStore"><i class="fa fa-database"></i> Contextstore</label>
48
+ <select type="text" id="node-input-contextStore"></select>
49
+ </div>
50
+ <div class="form-row">
51
+ <label for="node-input-refheight"><i class="fa fa-level-up"></i> reference height</label>
52
+ <input type="text" id="node-input-refheight">
53
+ </div>
54
+ </script>
55
+
56
+ <script type="text/x-red" data-help-name="ws90">
57
+
58
+ <p>A Node Red node to perform additional calulations with the data from an &ldquo;<em>Ecowitt WS90 powered by Shelly</em>&rdquo; weather station.</p>
59
+ <p>Normally this data is decoded by the <code>bthome</code> node.
60
+
61
+ <h3>Input</h3>
62
+ <dl class="message-properties">
63
+ <dt>payload <span class="property-type">object</span></dt>
64
+ <dd> raw data from <code>bthome</code> node.</dd>
65
+ <dt>reset <span class="property-type">boolean</span></dt>
66
+ <dd> if set to <code>true</code>, the output filter is reset and unchanged values will been sent with the next raw data.</dd>
67
+ <dt>newday <span class="property-type">boolean</span></dt>
68
+ <dd> if set to <code>true</code>, a new day is started (rain today, rain yesterday and wind max).</dd>
69
+ </dl>
70
+
71
+ <p>This is an example of such a message payload:</p>
72
+ <code>{<br>
73
+ "lux": 3630,<br>
74
+ "moisture": false,<br>
75
+ "wind": [1.5,1.5],<br>
76
+ "uv": 0,<br>
77
+ "direction": 174,<br>
78
+ "pressure": 948.2,<br>
79
+ "dewpoint": -0.43,<br>
80
+ "humidity": 99,<br>
81
+ "temperature": -0.3,<br>
82
+ "precipitation": 121.5<br>
83
+ }</code>
84
+
85
+ <h3>Outputs</h3>
86
+ <p>There are 12 output ports</p>
87
+ <p>values are only sent out, if they are changed</p>
88
+ <dl>
89
+ <dt>temperature</dt>
90
+ <dd>no calculation, value directly from the input data</dd>
91
+ <dt>dew point</dt>
92
+ <dd>no calculation, value directly from the input data</dd>
93
+ <dt>humidity</dt>
94
+ <dd>no calculation, value directly from the input data</dd>
95
+ <dt>raining</dt>
96
+ <dd>Is it raining at the moment?<br>
97
+ It is set to <code>true</code>, if <code>moisture==true</code> or a delta in <code>precipitation</code> is received.<br>
98
+ It is set to <code>false</code> after a timeout of 15min or 20min without any of the above events.<br>
99
+ If <code>true</code> the class is set to <code>blueValue</code>.</dd>
100
+ <dt>rain yesterday</dt>
101
+ <dd>rain from yesterday, at <code>newday==true</code> it is taken from <code>rain today</code></dd>
102
+ <dt>rain today</dt>
103
+ <dd>accumulated rain today, so since the last <code>newday==true</code> received</dd>
104
+ <dt>uv</dt>
105
+ <dd>no calculation, directly from the input data<br>
106
+ between 0 and 2 the class is set to <code>greenValue</code>, up to 5 to <code>yellowValue</code> and above to <code>redValue</code></dd>
107
+ <dt>air pressure</dt>
108
+ <dd>can be either the measured air pressure (QFE) without any further calculation<br>or the air pressure at sea level (QFF) (<a htref="https://de.wikipedia.org/wiki/Barometrische_H%C3%B6henformel">for the calculation</a>)</dd>
109
+ <dt>direction</dt>
110
+ <dd>no calculation, value directly from the input data</dd>
111
+ <dt>wind</dt>
112
+ <dd>no calculation, value directly from the input data<br>
113
+ between 0 and 25 the class is set to default, up to 50 to <code>yellowValue</code> and above to <code>redValue</code></dd>
114
+ <dt>wind max</dt>
115
+ <dd>maximal wind speed today, so since the last <code>newday==true</code> received</dd>
116
+ <dt>illumination</dt>
117
+ <dd>no calculation, directly from the input data</dd>
118
+ </dl>
119
+
120
+ <h4>style classes</h4>
121
+ <p>Some values have style classes for the <code>dashboard 2</code> attached.<p>
122
+ <p>This classes should be defined (for an example check the <code>ui-template</code> in the <a href="https://github.com/m-schaeffler/node-red-my-nodes/raw/main/node-red-bthome/examples/CSS.json">examples</a>):<p>
123
+ <ul>
124
+ <li>greenValue</li>
125
+ <li>yellowValue</li>
126
+ <li>redValue</li>
127
+ <li>blueValue</li>
128
+ </ul>
129
+
130
+ <h3>Parameters</h3>
131
+ <dl class="message-properties">
132
+ <dt>Contextstore <span class="property-type">string</span></dt>
133
+ <dd> context store to be used.</dd>
134
+ <dt>reference height <span class="property-type">number</span></dt>
135
+ <dd> height of the installation over the sea level, to caculate the relative air pressure (QFF).
136
+ If set to <code>0</code> no caclulation is done and the absolute air pressure (QFE) is outputed.</dt>
137
+ </dl>
138
+
139
+ </script>
package/ws90.js ADDED
@@ -0,0 +1,158 @@
1
+ module.exports = function(RED) {
2
+
3
+ function Ws90Node(config) {
4
+ RED.nodes.createNode(this,config);
5
+ var node = this;
6
+ var context = this.context();
7
+ this.contextStore = config.contextStore ?? "none";
8
+ this.refheight = Number( config.refheight ?? 0 );
9
+ this.timebase = Number( config.timebase ?? 60 ) * 1000;
10
+ this.last = {};
11
+ this.storage = {Raining:false,RegenHeute:0,RegenGestern:0,WindMax:0};
12
+ node.status( "" );
13
+ if( node.contextStore !== "none" )
14
+ {
15
+ context.get( "storage", node.contextStore, function(err,value)
16
+ {
17
+ if( err )
18
+ {
19
+ node.error( err );
20
+ }
21
+ else
22
+ {
23
+ //console.log( "context read", value );
24
+ if( value !== undefined )
25
+ {
26
+ node.storage = value;
27
+ }
28
+ }
29
+ } );
30
+ }
31
+
32
+ function ampel(value,v1,v2,s1="")
33
+ {
34
+ return value <= v1 ? s1 : ( value <= v2 ? "yellowValue" : "redValue" );
35
+ }
36
+
37
+ function setStorage(topic,value)
38
+ {
39
+ node.storage[topic] = value;
40
+ if( node.contextStore !== "none" )
41
+ {
42
+ context.set( "storage", node.storage, node.contextStore );
43
+ }
44
+ }
45
+
46
+ function genMessage(name,value,style=null)
47
+ {
48
+ if( node.last[name]?.value !== value || node.last[name]?.style !== style )
49
+ {
50
+ node.last[name] = { value:value, style:style };
51
+ let result = { topic: name, payload: value };
52
+ if( style !== null )
53
+ {
54
+ result.ui_update = { class: style };
55
+ }
56
+ return result;
57
+ }
58
+ else
59
+ {
60
+ return null;
61
+ }
62
+ }
63
+
64
+ node.on('input', function(msg,send,done) {
65
+ if( msg.invalid )
66
+ {
67
+ }
68
+ else if( msg.reset || msg.topic==="init" )
69
+ {
70
+ node.last = {};
71
+ }
72
+ else if( msg.newday || msg.topic==="newday" )
73
+ {
74
+ setStorage( "RegenGestern", node.storage.RegenHeute );
75
+ setStorage( "RegenHeute", 0 );
76
+ setStorage( "WindMax", 0 );
77
+ }
78
+ else if( typeof msg.payload !== "object" || msg.payload.temperature === undefined )
79
+ {
80
+ node.error( "invalid payload "+msg.payload );
81
+ }
82
+ else
83
+ {
84
+ const now = Date.now();
85
+
86
+ // Luftdruck https://de.wikipedia.org/wiki/Barometrische_H%C3%B6henformel
87
+ let luftdruck = msg.payload.pressure;
88
+ if( node.refheight != 0 )
89
+ {
90
+ //const E = temperature >= 9.1 ? 18.219 * ( 1.0463 - Math.exp( -0.0666 * temperature ) ) : 5.6402 * ( Math.exp( 0.06 * temperature ) - 0.0916 );
91
+ const p_H2O = ( 6.112 * Math.exp((17.62 * msg.payload.temperature) / ( msg.payload.temperature + 243.12)) * msg.payload.humidity) / 100; // Partialdruck Wasserdampf https://www.schweizer-fn.de/lueftung/feuchte/feuchte.php
92
+ const h = node.refheight; // Ortshöhe
93
+ luftdruck *= Math.exp( 9.80665 / ( 287.05 * ( 273.15 + msg.payload.temperature + 0.12 * p_H2O + 0.0065 * h / 2 ) ) * h );
94
+ }
95
+
96
+ // Regen
97
+ let raining = node.storage.Raining;
98
+ function setRaining(value,timeout)
99
+ {
100
+ raining = value;
101
+ setStorage( "rainingDate", value ? now + timeout*node.timebase : 8640000000000000 );
102
+ if( node.storage.Raining !== value )
103
+ {
104
+ setStorage( "Raining", value );
105
+ }
106
+ }
107
+ if( msg.payload.moisture && ! node.storage.moisture )
108
+ {
109
+ setRaining( true, 15 );
110
+ }
111
+ else if( now >= node.storage.rainingDate )
112
+ {
113
+ setRaining( false, 0 );
114
+ }
115
+ setStorage( "moisture", msg.payload.moisture );
116
+
117
+ // Regenmenge
118
+ if( msg.payload.precipitation > node.storage.Regen )
119
+ {
120
+ setStorage( "RegenHeute", node.storage.RegenHeute + msg.payload.precipitation - node.storage.Regen );
121
+ setRaining( true, 20 );
122
+ }
123
+ else if( msg.payload.precipitation < node.storage.Regen && msg.payload.precipitation <= 10 )
124
+ {
125
+ setStorage( "RegenHeute", node.storage.RegenHeute + msg.payload.precipitation );
126
+ setRaining( true, 20 );
127
+ }
128
+ setStorage( "Regen", msg.payload.precipitation );
129
+
130
+ // Wind
131
+ const wind = msg.payload.wind[1] * 3.6;
132
+ if( wind > node.storage.WindMax )
133
+ {
134
+ setStorage( "WindMax", wind );
135
+ }
136
+
137
+ node.status( Math.round( luftdruck ) );
138
+ send( [
139
+ genMessage( "outside temperature", msg.payload.temperature ),
140
+ genMessage( "dew point", msg.payload.dewpoint ),
141
+ genMessage( "humidity", msg.payload.humidity ),
142
+ genMessage( "raining", raining ),
143
+ genMessage( "rain yesterday", node.storage.RegenGestern ),
144
+ genMessage( "rain today", node.storage.RegenHeute, msg.payload.moisture ? "blueValue" : "" ),
145
+ genMessage( "uv index", msg.payload.uv, ampel( msg.payload.uv, 2, 5, "greenValue" ) ),
146
+ genMessage( "air pressure", luftdruck ),
147
+ genMessage( "wind direction", msg.payload.direction ),
148
+ genMessage( "wind", wind, ampel( wind, 25, 50 ) ),
149
+ genMessage( "wind_max", node.storage.WindMax ),
150
+ genMessage( "illumination", msg.payload.lux )
151
+ ] );
152
+ }
153
+ done();
154
+ });
155
+ }
156
+
157
+ RED.nodes.registerType( "ws90", Ws90Node );
158
+ }