@thingwala/node-red-contrib-geyserwala-connect 0.0.4 → 0.0.6

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 ADDED
@@ -0,0 +1,30 @@
1
+ # Change Log - Geyserwala Connect - Node-RED Plugin
2
+
3
+ ## [0.0.6] - 2024-01-06
4
+
5
+ Fix import flows from older versions
6
+
7
+ ## [0.0.5] - 2023-12-20
8
+
9
+ Allow for custom signals
10
+
11
+ ### Added
12
+ - Custom node.
13
+
14
+ ## [0.0.4] - 2023-12-05
15
+
16
+ Migrate to persistent latch signals, with programmable hold time
17
+
18
+ ### Added
19
+ - `external-disable` signal, accepts integer of number or seconds to latch, or true (defaults to 24 hours). Zero/false will clear.
20
+
21
+ ### Changed
22
+ - naming to geyserwala-connect-...
23
+ - `external-demand` signal: accepts integer of number of seconds to latch, or true (defaults to 24 hours). Zero/false will clear.
24
+
25
+ ### Removed
26
+ - `lowpower-enable`: replaced by `external-disable`.
27
+
28
+ ## [0.0.3] - 2023-09-01
29
+
30
+ Initial development
@@ -0,0 +1,220 @@
1
+ [
2
+ {
3
+ "id": "ca3352fdbb2d931a",
4
+ "type": "tab",
5
+ "label": "Geyserwala - BMS SoC",
6
+ "disabled": false,
7
+ "info": "",
8
+ "env": []
9
+ },
10
+ {
11
+ "id": "29a73b429a4838ca",
12
+ "type": "victron-input-battery",
13
+ "z": "ca3352fdbb2d931a",
14
+ "service": "com.victronenergy.battery/512",
15
+ "path": "/Soc",
16
+ "serviceObj": {
17
+ "service": "com.victronenergy.battery/512",
18
+ "name": "SS4143 BMS-EX"
19
+ },
20
+ "pathObj": {
21
+ "path": "/Soc",
22
+ "type": "float",
23
+ "name": "State of charge (%)"
24
+ },
25
+ "name": "",
26
+ "onlyChanges": false,
27
+ "x": 190,
28
+ "y": 160,
29
+ "wires": [
30
+ [
31
+ "0399d69c01f87a48"
32
+ ]
33
+ ]
34
+ },
35
+ {
36
+ "id": "3d2a53f1b12d9675",
37
+ "type": "geyserwala-connect-external-disable",
38
+ "z": "ca3352fdbb2d931a",
39
+ "name": "External Disable",
40
+ "geyserwalaApi": "20dd980fafe6ca2e",
41
+ "x": 580,
42
+ "y": 240,
43
+ "wires": [
44
+ []
45
+ ]
46
+ },
47
+ {
48
+ "id": "562e3bc5f100a612",
49
+ "type": "switch",
50
+ "z": "ca3352fdbb2d931a",
51
+ "name": "90%",
52
+ "property": "payload",
53
+ "propertyType": "msg",
54
+ "rules": [
55
+ {
56
+ "t": "gte",
57
+ "v": "90",
58
+ "vt": "str"
59
+ },
60
+ {
61
+ "t": "lt",
62
+ "v": "90",
63
+ "vt": "str"
64
+ }
65
+ ],
66
+ "checkall": "true",
67
+ "repair": false,
68
+ "outputs": 2,
69
+ "x": 270,
70
+ "y": 240,
71
+ "wires": [
72
+ [
73
+ "d5a7a12a701ab13c"
74
+ ],
75
+ [
76
+ "d31b6ddda17ef2fc"
77
+ ]
78
+ ]
79
+ },
80
+ {
81
+ "id": "d31b6ddda17ef2fc",
82
+ "type": "change",
83
+ "z": "ca3352fdbb2d931a",
84
+ "name": "true",
85
+ "rules": [
86
+ {
87
+ "t": "set",
88
+ "p": "payload",
89
+ "pt": "msg",
90
+ "to": "true",
91
+ "tot": "bool"
92
+ }
93
+ ],
94
+ "action": "",
95
+ "property": "",
96
+ "from": "",
97
+ "to": "",
98
+ "reg": false,
99
+ "x": 410,
100
+ "y": 260,
101
+ "wires": [
102
+ [
103
+ "3d2a53f1b12d9675"
104
+ ]
105
+ ]
106
+ },
107
+ {
108
+ "id": "d5a7a12a701ab13c",
109
+ "type": "change",
110
+ "z": "ca3352fdbb2d931a",
111
+ "name": "false",
112
+ "rules": [
113
+ {
114
+ "t": "set",
115
+ "p": "payload",
116
+ "pt": "msg",
117
+ "to": "false",
118
+ "tot": "bool"
119
+ }
120
+ ],
121
+ "action": "",
122
+ "property": "",
123
+ "from": "",
124
+ "to": "",
125
+ "reg": false,
126
+ "x": 410,
127
+ "y": 220,
128
+ "wires": [
129
+ [
130
+ "3d2a53f1b12d9675"
131
+ ]
132
+ ]
133
+ },
134
+ {
135
+ "id": "0399d69c01f87a48",
136
+ "type": "rbe",
137
+ "z": "ca3352fdbb2d931a",
138
+ "name": "",
139
+ "func": "rbe",
140
+ "gap": "",
141
+ "start": "",
142
+ "inout": "out",
143
+ "septopics": true,
144
+ "property": "payload",
145
+ "topi": "topic",
146
+ "x": 150,
147
+ "y": 240,
148
+ "wires": [
149
+ [
150
+ "562e3bc5f100a612"
151
+ ]
152
+ ]
153
+ },
154
+ {
155
+ "id": "f1e662c9433dcab2",
156
+ "type": "inject",
157
+ "z": "ca3352fdbb2d931a",
158
+ "name": "true",
159
+ "props": [
160
+ {
161
+ "p": "payload"
162
+ }
163
+ ],
164
+ "repeat": "",
165
+ "crontab": "",
166
+ "once": false,
167
+ "onceDelay": 0.1,
168
+ "topic": "",
169
+ "payload": "true",
170
+ "payloadType": "bool",
171
+ "x": 410,
172
+ "y": 320,
173
+ "wires": [
174
+ [
175
+ "3d2a53f1b12d9675"
176
+ ]
177
+ ]
178
+ },
179
+ {
180
+ "id": "e9867b4f5d12423a",
181
+ "type": "inject",
182
+ "z": "ca3352fdbb2d931a",
183
+ "name": "false",
184
+ "props": [
185
+ {
186
+ "p": "payload"
187
+ }
188
+ ],
189
+ "repeat": "",
190
+ "crontab": "",
191
+ "once": false,
192
+ "onceDelay": 0.1,
193
+ "topic": "",
194
+ "payload": "false",
195
+ "payloadType": "bool",
196
+ "x": 410,
197
+ "y": 360,
198
+ "wires": [
199
+ [
200
+ "3d2a53f1b12d9675"
201
+ ]
202
+ ]
203
+ },
204
+ {
205
+ "id": "20dd980fafe6ca2e",
206
+ "type": "geyserwala-connect-api",
207
+ "name": "Geyserwala",
208
+ "api": "REST",
209
+ "mqttBroker": "",
210
+ "mqttTopicTemplate": "geyserwala/%prefix%/%mac%",
211
+ "mqttTopicMac": "",
212
+ "mqttTopicIp": "",
213
+ "mqttTopicHostname": "",
214
+ "restHost": "10.0.0.51",
215
+ "restPort": "80",
216
+ "restUser": "admin",
217
+ "restPassword": "",
218
+ "restPollInterval": "10"
219
+ }
220
+ ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thingwala/node-red-contrib-geyserwala-connect",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "Node-RED nodes for the Geyserwala Connect",
5
5
  "author": "Thingwala",
6
6
  "license": "MIT",
@@ -27,7 +27,7 @@ class GeyserwalaConnectorMqtt {
27
27
  try {
28
28
  this.subscriptions[topic](payload)
29
29
  } catch (error) {
30
- this.RED.log.error(`{Geyserwala Connect} Handling subscription: ${error.message}`);
30
+ this.RED.log.error(`{Geyserwala Connect} Handling messsage: ${error.message}`);
31
31
  }
32
32
  });
33
33
 
@@ -7,7 +7,7 @@
7
7
 
8
8
  api: { value: "MQTT", requred: true },
9
9
 
10
- mqttBroker: { type: "mqtt-broker" },
10
+ mqttBroker: { type: "mqtt-broker", required: false },
11
11
  mqttPubQos: { value: 0 },
12
12
  mqttRetain: { value: false },
13
13
  mqttTopicTemplate: { value: "geyserwala/%prefix%/%mac%" },
@@ -1,30 +1,32 @@
1
1
 
2
2
  module.exports = function (RED) {
3
- function Node(config) {
4
- RED.nodes.createNode(this, config);
3
+ class Node {
4
+ constructor (config) {
5
+ RED.nodes.createNode(this, config);
5
6
 
6
- if (config.api == 'MQTT') {
7
- const GeyserwalaConnectorMqtt = require('./geyserwala-api-mqtt');
7
+ if (config.api == 'MQTT') {
8
+ const GeyserwalaConnectorMqtt = require('./geyserwala-api-mqtt');
8
9
 
9
- this.api = new GeyserwalaConnectorMqtt(RED,
10
- RED.nodes.getNode(config.mqttBroker),
11
- config.mqttPubQos,
12
- config.mqttRetain,
13
- config.mqttTopicTemplate,
14
- config.mqttTopicMac,
15
- config.mqttTopicIP,
16
- config.mqttTopicHostname
17
- );
18
- } else if (config.api == "REST") {
19
- const GeyserwalaConnectorRest = require('./geyserwala-api-rest');
10
+ this.api = new GeyserwalaConnectorMqtt(RED,
11
+ RED.nodes.getNode(config.mqttBroker),
12
+ config.mqttPubQos,
13
+ config.mqttRetain,
14
+ config.mqttTopicTemplate,
15
+ config.mqttTopicMac,
16
+ config.mqttTopicIP,
17
+ config.mqttTopicHostname
18
+ );
19
+ } else if (config.api == "REST") {
20
+ const GeyserwalaConnectorRest = require('./geyserwala-api-rest');
20
21
 
21
- this.api = new GeyserwalaConnectorRest(RED,
22
- config.restHost,
23
- config.restPort,
24
- config.restUser,
25
- config.restPassword,
26
- config.restPollInterval,
27
- )
22
+ this.api = new GeyserwalaConnectorRest(RED,
23
+ config.restHost,
24
+ config.restPort,
25
+ config.restUser,
26
+ config.restPassword,
27
+ config.restPollInterval,
28
+ )
29
+ }
28
30
  }
29
31
  }
30
32
  RED.nodes.registerType("geyserwala-connect-api", Node);
@@ -12,50 +12,129 @@
12
12
  </div>
13
13
  </script>
14
14
 
15
+ <script type="text/template" id="node-input-value-template">
16
+ <fieldset id="node-input-value">
17
+ <legend>Value</legend>
18
+ <div class="form-row">
19
+ <label for="node-input-valueType"><i class="fa fa-cube"></i> Type</label>
20
+ <select id="node-input-valueType" style="width:25%;">
21
+ <option value="">Undefined</option>
22
+ <option value="Boolean">Boolean</option>
23
+ <option value="Number">Number</option>
24
+ <option value="String">String</option>
25
+ </select>
26
+ </div>
27
+ <div class="form-row">
28
+ <label for="node-input-valueKey"><i class="fa fa-hashtag"></i> Key</label>
29
+ <input type="text" id="node-input-valueKey" placeholder="Key">
30
+ </div>
31
+ </fieldset>
32
+ </script>
33
+
15
34
  <script type="text/javascript">
16
- function addInputDialog(valueKey, nodeLabel) {
35
+ function addInputDialog(node) {
17
36
  var nodeInput = $("#node-input-template").clone().html();
18
37
 
19
- var scriptTag = $("<script>").attr("type", "text/x-red").attr("data-template-name", `geyserwala-connect-${valueKey}`).append(nodeInput);
20
- scriptTag.find('#title').text(`Geyserwala Connect : ${nodeLabel}`);
38
+ if (node.type === null) {
39
+ var nodeInputValue = $("#node-input-value-template").clone().html();
40
+ console.log(typeof nodeInput)
41
+ nodeInput += nodeInputValue
42
+ }
43
+
44
+ var scriptTag = $("<script>").attr("type", "text/x-red").attr("data-template-name", `geyserwala-connect-${node.key}`).append(nodeInput);
45
+ scriptTag.find('#title').text(`Geyserwala Connect : ${node.name}`);
21
46
  $('body').append(scriptTag.prop('outerHTML'));
22
47
  }
23
48
 
24
- function registerType(valueKey, nodeLabel, icon, input) {
25
- addInputDialog(valueKey, nodeLabel)
49
+ function _registerNode(node) {
50
+ addInputDialog(node)
26
51
 
27
- RED.nodes.registerType(`geyserwala-connect-${valueKey}`, {
52
+ RED.nodes.registerType(`geyserwala-connect-${node.key}`, {
28
53
  category: 'Geyserwala Connect',
29
- paletteLabel: nodeLabel,
54
+ paletteLabel: node.name,
30
55
  defaults: {
31
- name: { value: nodeLabel },
56
+ name: { value: node.name },
32
57
  geyserwalaApi: { type: "geyserwala-connect-api", required: true },
58
+ valueKey: { value: undefined },
59
+ valueType: { value: undefined },
33
60
  },
34
- inputs: input ? 1 : 0,
61
+ inputs: node.input ? 1 : 0,
35
62
  outputs: 1,
36
63
  color: "#00A9E0",
37
- icon: icon,
64
+ icon: node.icon,
38
65
  label: function () {
39
66
  return this.name;
40
67
  }
41
68
  });
42
69
  }
43
70
 
71
+ function registerNode(key, name, type, icon, input) {
72
+ _registerNode({key: key, name: name, type: type, icon: icon, input: input})
73
+ }
74
+
44
75
  // Icons: https://fontawesome.com/v4/icons/
45
- registerType('status', "Status", "font-awesome/fa-envelope-o", false);
46
- registerType('mode', "Mode", "font-awesome/fa-info", true);
76
+ registerNode("status", "Status", String, "font-awesome/fa-envelope-o", false)
77
+ registerNode("mode", "Mode", String, "font-awesome/fa-sliders", true)
78
+ registerNode("tank-temp", "Tank Temp", Number, "font-awesome/fa-thermometer-half", false)
79
+ registerNode("element-demand", "Element Demand", Boolean, "font-awesome/fa-fire", false)
80
+ registerNode("external-setpoint", "External Setpoint", Number, "inject.png", true)
81
+ registerNode("external-demand", "External Demand", Number, "serial.png", true)
82
+ registerNode("external-disable", "External Disable", Number, "font-awesome/fa-stop-circle-o", true)
83
+ registerNode("setpoint", "Setpoint", Number, "inject.png", true)
84
+ registerNode("boost-demand", "Boost Demand", Boolean, "font-awesome/fa-power-off", true)
85
+ registerNode("collector-temp", "Collector Temp", Number, "font-awesome/fa-thermometer-half", false)
86
+ registerNode("pump-status", "Pump Status", Boolean, "font-awesome/fa-recycle", false)
87
+ registerNode("custom-io", "Custom", null, "font-awesome/fa-cogs", true)
88
+ </script>
89
+
90
+ <script type="text/x-red" data-help-name="geyserwala-connect-status">
91
+ <p></p>
92
+ </script>
93
+
94
+ <script type="text/x-red" data-help-name="geyserwala-connect-mode">
95
+ <p></p>
96
+ </script>
97
+
98
+ <script type="text/x-red" data-help-name="geyserwala-connect-tank-temp">
99
+ <p></p>
100
+ </script>
101
+
102
+ <script type="text/x-red" data-help-name="geyserwala-connect-element-demand">
103
+ <p></p>
104
+ </script>
47
105
 
48
- registerType('tank-temp', "Tank Temp", "font-awesome/fa-thermometer-half", false);
49
- registerType('element-demand', "Element Demand", "font-awesome/fa-fire", false);
106
+ <script type="text/x-red" data-help-name="geyserwala-connect-element-demand">
107
+ <p></p>
108
+ </script>
50
109
 
51
- registerType('external-setpoint', "External Setpoint", "inject.png", true);
52
- registerType('external-demand', "External Demand", "serial.png", true);
53
- registerType('external-disable', "External Disable", "font-awesome/fa-stop-circle-o", true);
110
+ <script type="text/x-red" data-help-name="geyserwala-connect-external-setpoint">
111
+ <p></p>
112
+ </script>
54
113
 
55
- registerType('setpoint', "Setpoint", "inject.png", true);
56
- registerType('boost-demand', "Boost Demand", "font-awesome/fa-power-off", true);
114
+ <script type="text/x-red" data-help-name="geyserwala-connect-external-demand">
115
+ <p></p>
116
+ </script>
57
117
 
58
- registerType('collector-temp', "Collector Temp", "font-awesome/fa-thermometer-half", false);
59
- registerType('pump-status', "Pump Status", "font-awesome/fa-recycle", false);
118
+ <script type="text/x-red" data-help-name="geyserwala-connect-external-disable">
119
+ <p></p>
120
+ </script>
121
+
122
+ <script type="text/x-red" data-help-name="geyserwala-connect-setpoint">
123
+ <p></p>
124
+ </script>
125
+
126
+ <script type="text/x-red" data-help-name="geyserwala-connect-boost-demand">
127
+ <p></p>
128
+ </script>
129
+
130
+ <script type="text/x-red" data-help-name="geyserwala-connect-collector-temp">
131
+ <p></p>
132
+ </script>
133
+
134
+ <script type="text/x-red" data-help-name="geyserwala-connect-pump-status">
135
+ <p></p>
136
+ </script>
60
137
 
138
+ <script type="text/x-red" data-help-name="geyserwala-connect-custom-io">
139
+ <p></p>
61
140
  </script>
@@ -1,62 +1,75 @@
1
1
  module.exports = function (RED) {
2
- function createNode (valueKey, type, input) {
3
- function Node(config) {
4
- RED.nodes.createNode(this, config);
5
-
6
- var geyserwalaApi = RED.nodes.getNode(config.geyserwalaApi)
7
- if (!geyserwalaApi) {
8
- this.error('Connector not configured')
9
- return
10
- }
11
- this.api = geyserwalaApi.api;
12
- if (!geyserwalaApi.api) {
13
- this.error('Invalid Connector')
14
- return
15
- }
2
+ function _registerNode (node) {
3
+ class Node {
4
+ constructor (config) {
5
+ RED.nodes.createNode(this, config);
16
6
 
17
- this.api.registerNode(this)
18
-
19
- this.api.subscribe(valueKey, type, (payload) => {
20
- try {
21
- this.send({ topic: valueKey, payload: payload })
22
- } catch (error) {
23
- RED.log.error(`{Geyserwala Connect} Outputing: ${error.message}`);
7
+ var geyserwalaApi = RED.nodes.getNode(config.geyserwalaApi)
8
+ if (!geyserwalaApi) {
9
+ this.error('Configured connector invalid')
10
+ return
11
+ }
12
+ this.api = geyserwalaApi.api;
13
+ if (!geyserwalaApi.api) {
14
+ this.error('Connector not defined')
15
+ return
24
16
  }
25
- });
26
- this.on('close', () => {
27
- this.api.unsubscribe(valueKey);
28
- this.api.unregister(this);
29
- });
30
17
 
31
- if (input) {
18
+ this.api.registerNode(this)
19
+
20
+ const valueKey = node.type ? node.key : config.valueKey
21
+ const valueType = node.type ? node.type : {
22
+ "": String,
23
+ "Boolean": Boolean,
24
+ "Number": Number,
25
+ "String": String,
26
+ }[config.valueType]
27
+
28
+ this.api.subscribe(valueKey, valueType, (payload) => {
29
+ try {
30
+ this.send({ topic: valueKey, payload: payload })
31
+ } catch (error) {
32
+ this.error(`Receiving "${valueKey}": ${error.message}`);
33
+ }
34
+ });
35
+
36
+ this.on('close', () => {
37
+ this.api.unsubscribe(node.valueKey);
38
+ this.api.unregister(this);
39
+ });
40
+
32
41
  this.on('input', function (message) {
33
42
  try {
34
43
  this.api.send(valueKey, message.payload)
35
44
  } catch (error) {
36
- RED.log.error(`{Geyserwala Connect} Sending: ${error.message}`);
45
+ this.error(`Sending "${valueKey}": ${error.message}`);
37
46
  }
38
47
  })
48
+
49
+ this.on('close', function () {
50
+ this.api.unregister(this);
51
+ });
39
52
  }
40
- this.on('close', function () {
41
- this.api.unregister(this);
42
- });
43
53
  }
44
54
 
45
- RED.nodes.registerType(`geyserwala-connect-${valueKey}`, Node);
55
+ RED.nodes.registerType(`geyserwala-connect-${node.key}`, Node);
46
56
  }
47
57
 
48
- createNode('tank-temp', Number, false);
49
- createNode('element-demand', Boolean, false);
50
-
51
- createNode('external-setpoint', Number, true);
52
- createNode('external-demand', Number, true);
53
- createNode('external-disable', Number, true);
54
-
55
- createNode('status', String, false);
56
- createNode('mode', String, true);
57
- createNode('setpoint', Number, true);
58
- createNode('boost-demand', Boolean, true);
58
+ function registerNode(key, name, type, icon, input) {
59
+ _registerNode({key: key, name: name, type: type, icon: icon, input: input})
60
+ }
59
61
 
60
- createNode('collector-temp', Number, false);
61
- createNode('pump-status', Boolean, false);
62
+ // Icons: https://fontawesome.com/v4/icons/
63
+ registerNode("status", "Status", String, "font-awesome/fa-envelope-o", false)
64
+ registerNode("mode", "Mode", String, "font-awesome/fa-sliders", true)
65
+ registerNode("tank-temp", "Tank Temp", Number, "font-awesome/fa-thermometer-half", false)
66
+ registerNode("element-demand", "Element Demand", Boolean, "font-awesome/fa-fire", false)
67
+ registerNode("external-setpoint", "External Setpoint", Number, "inject.png", true)
68
+ registerNode("external-demand", "External Demand", Number, "serial.png", true)
69
+ registerNode("external-disable", "External Disable", Number, "font-awesome/fa-stop-circle-o", true)
70
+ registerNode("setpoint", "Setpoint", Number, "inject.png", true)
71
+ registerNode("boost-demand", "Boost Demand", Boolean, "font-awesome/fa-power-off", true)
72
+ registerNode("collector-temp", "Collector Temp", Number, "font-awesome/fa-thermometer-half", false)
73
+ registerNode("pump-status", "Pump Status", Boolean, "font-awesome/fa-recycle", false)
74
+ registerNode("custom-io", "Custom", null, "font-awesome/fa-cogs", true)
62
75
  }
package/CHANGELOG DELETED
@@ -1,19 +0,0 @@
1
- # Change Log - Geyserwala Connect Node-RED plugin
2
-
3
- ## [0.0.4] - 2023-12-05
4
-
5
- Migrate to persistent latch signals, with programable hold time
6
-
7
- ### Added
8
- - element-disable signal, accepts integer of number or seconds to latch, or true (defaults to 24 hours). Zero/false will clear.
9
-
10
- ### Changed
11
- - naming to geyserwala-connect-...
12
- - element-enable signal: accepts integer of number of seconds to latch, or true (defaults to 24 hours). Zero/false will clear.
13
-
14
- ### Removed
15
- - lowpower-enable: replaced by element-disable.
16
-
17
- ## [0.0.3] - 2023-09-01
18
-
19
- Initial development