node-red-contrib-remote 1.3.0 → 1.4.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/README.md CHANGED
@@ -26,7 +26,7 @@ There is a help page describing how the the nodes work together and how to conne
26
26
 
27
27
  [Help in English](https://www.remote-red.com/en/help/)
28
28
 
29
- [Hilfe in deutsch](https://www.remote-red.com/de/hilfe/)
29
+ [Hilfe in Deutsch](https://www.remote-red.com/de/hilfe/)
30
30
 
31
31
 
32
32
  ## Contact
@@ -36,6 +36,21 @@ You will find more information on [www.remote-red-com](https://www.remote-red.co
36
36
 
37
37
  ## Version History
38
38
 
39
+ Version 1.4.0
40
+ - In addition to the QR code, a link is now generated to add an instance in the app.
41
+ - Sending notifications and questions is prevented if msg.playload.send === false.
42
+ - Error catched if a notification or question does not contain a title and body.
43
+
44
+ Version 1.3.3:
45
+ - Improved compatibility for Windows.
46
+
47
+ Version 1.3.2:
48
+ - Changed the method to get the installed node version. Thanks hardillb!
49
+
50
+ Version 1.3.1:
51
+ - Added timeout handling to the heartbeat function.
52
+ - Catches errors when evaluating the title, body or sound of an notification.
53
+
39
54
  Version 1.3.0:
40
55
  - A heartbeat function is added to the remote access node. This will automatically reconnect if the connection is interrupted, e.g. due to an unstable internet connection.
41
56
 
@@ -46,6 +46,11 @@
46
46
  "apphelp": {
47
47
  "title": "App Hilfe",
48
48
  "para1": "Lade die Remote-RED App aus dem Apple AppStore oder Google PlayStore herunter. Verwende in der App die Funktion “Node-RED Instanz hinzufügen” um diesen QR-Code zu scannen."
49
+ },
50
+ "applink": {
51
+ "title": "Alternative: Per Link hinzufügen",
52
+ "para1": "Öffne diesen Link auf Deinem iOS oder Android Gerät, nachdem Du die Remote-RED App installiert hast:",
53
+ "link": "Link zum hinzufügen"
49
54
  }
50
55
  }
51
56
  }
@@ -34,7 +34,7 @@
34
34
  "title": "Hilfe",
35
35
  "para1": "Über diese Node kannst Du eine Push Notification an die Geräte versenden, die mit der gewählten Config-Node verbunden sind. Wähle hierzu eine Config-Node, die Du auch z.B. bereits in einer Access-Node verwendest. Du kannst in mehreren Notification-Nodes die selbe Config-Node verwenden.",
36
36
  "para2": "Konfiguriere den Titel und den Text der Benachrichtigung. Die Vorgabewerte gehen davon aus, das im Payload der eingehenden Nachricht die Strings “title” und “body” enthalten sind. Du kannst aber auch feste Texte eingeben oder Flow- bzw. Global-Variablen verwenden.",
37
- "para3": "Immer sobald eine Message bei der Notification-Node ankommt, wird eine Notification an Deine Geräte versendet."
37
+ "para3": "Immer sobald eine Message bei der Notification-Node ankommt, wird eine Notification an Deine Geräte versendet. Es wird kein Versand durchgeführt, wenn msg.payload.send den Boolean-Wert 'false' enthält."
38
38
  }
39
39
  }
40
40
  }
@@ -38,7 +38,7 @@
38
38
  "para2": "Wichtig ist, das die Confg-Node auf Deinen lokalen Node-RED Rechner verweist und eine Access-Node damit aktiv ist. Die Basis URL ist dabei irrelevant.",
39
39
  "para3": "Konfiguriere den Titel und den Text der Benachrichtigung. Die Vorgabewerte gehen davon aus, das im Payload der eingehenden Nachricht die Strings “title” und “body” enthalten sind. Du kannst aber auch feste Texte eingeben oder Flow- bzw. Global-Variablen verwenden.",
40
40
  "para4": "Du kannst bis zu drei Antworten vorgeben. Der Text der Antworten kannst Du direkt als String eingeben oder aus der eingehenden Nachricht übernehmen. Ist der Text leer, wird die Antwort nicht angezeigt. Über den Wert kannst Du angeben, was die Node per msg.payload ausgibt, wenn Du diese Antwort wählst.",
41
- "para5": "Immer sobald eine Message bei der Question-Node ankommt, wird eine Notification an Deine Geräte versendet."
41
+ "para5": "Immer sobald eine Message bei der Question-Node ankommt, wird eine Notification an Deine Geräte versendet. Es wird kein Versand durchgeführt, wenn msg.payload.send den Boolean-Wert 'false' enthält."
42
42
  }
43
43
  }
44
44
  }
@@ -46,6 +46,11 @@
46
46
  "apphelp": {
47
47
  "title": "App Help",
48
48
  "para1": "Download the Remote-RED app from the Apple AppStore or Google PlayStore. Use the function “Add Node-RED Instance” in the app to scan this QR Code."
49
+ },
50
+ "applink": {
51
+ "title": "Alternative: Add via link",
52
+ "para1": "Open this link on your iOS or Android device after installing the Remote-RED app:",
53
+ "link": "Link to add"
49
54
  }
50
55
  }
51
56
  }
@@ -34,7 +34,7 @@
34
34
  "title": "Help",
35
35
  "para1": "With this node you can send a push notification to the devices connected to the selected config node. Select a config node that you already use in an access node. You can use the same config node in several notification nodes.",
36
36
  "para2": "Configure the title and the text of the notification. The default values assume that the payload of the incoming message contains the strings “title” and “body”. You can also enter fixed texts or use flow or global variables.",
37
- "para3": "Whenever a message arrives at the notification node, a notification is sent to your devices."
37
+ "para3": "Whenever a message arrives at the notification node, a notification is sent to your devices. No send is performed if msg.payload.send contains the boolean value 'false'."
38
38
  }
39
39
  }
40
40
  }
@@ -38,7 +38,7 @@
38
38
  "para2": "It is important that the confg node points to your local Node-RED computer and that an access node is active with it. The base URL is irrelevant.",
39
39
  "para3": "Configure the title and the text of the notification. The default values assume that the payload of the incoming message contains the strings “title” and “body”. You can also enter fixed texts or use flow or global variables.",
40
40
  "para4": "You can specify up to three answers. The text of the answers can be entered directly as an string or taken from the incoming message. If the text is empty, the answer is not displayed. You can use the value to specify what the node outputs in msg.payload when you select this answer.",
41
- "para5": "Whenever a message arrives at the question node, a notification is sent to your devices."
41
+ "para5": "Whenever a message arrives at the question node, a notification is sent to your devices. No send is performed if msg.payload.send contains the boolean value 'false'."
42
42
  }
43
43
  }
44
44
  }
@@ -10,6 +10,8 @@
10
10
  inputs: 0,
11
11
  outputs: 1,
12
12
  outputLabels: ["action output"],
13
+ // outputs: 2,
14
+ // outputLabels: ["action output", "geofence output"],
13
15
  icon: "font-awesome/fa-mobile",
14
16
  label: function() {
15
17
  return this.name || "remote access";
@@ -2,6 +2,8 @@ module.exports = function(RED) {
2
2
  const commons = require('./remote-commons');
3
3
  const child_process = require('child_process');
4
4
  const os = require("os");
5
+ let sshprocess = undefined
6
+ let statustext = ''
5
7
 
6
8
  function startSSH(node, server, port) {
7
9
  try {
@@ -21,10 +23,10 @@ module.exports = function(RED) {
21
23
  if ( node.verbose ) {
22
24
  sshparameters.push('-v');
23
25
  }
24
- const sshprocess = child_process.spawn("ssh", sshparameters);
26
+ sshprocess = child_process.spawn("ssh", sshparameters);
25
27
 
26
28
  // Set serving.. if not working, the process will exit or close
27
- node.status({fill:"green",shape:"dot",text:"remote-access.status.serving"});
29
+ setStatus(node, {fill:"green",shape:"dot",text:"remote-access.status.serving"});
28
30
  node.serving = true
29
31
 
30
32
  // Attach to process events
@@ -37,13 +39,17 @@ module.exports = function(RED) {
37
39
  });
38
40
 
39
41
  sshprocess.on('close', (code, signal) => {
40
- node.status({fill:"red",shape:"dot",text:"remote-access.status.stopped"});
42
+ if ( statustext !== "remote-access.status.heartbeaterror" ) {
43
+ setStatus(node, {fill:"red",shape:"dot",text:"remote-access.status.stopped"});
44
+ }
41
45
  node.serving = false
42
46
  node.log("ssh process stopped (close: " + code + " / " + signal + ")");
43
47
  });
44
48
 
45
49
  sshprocess.on('exit', (code, signal) => {
46
- node.status({fill:"red",shape:"dot",text:"remote-access.status.stopped"});
50
+ if ( statustext !== "remote-access.status.heartbeaterror" ) {
51
+ setStatus(node, {fill:"red",shape:"dot",text:"remote-access.status.stopped"});
52
+ }
47
53
  node.serving = false
48
54
  node.log("ssh process stopped (exit: " + code + " / " + signal + ")");
49
55
  });
@@ -53,7 +59,7 @@ module.exports = function(RED) {
53
59
  });
54
60
 
55
61
  node.on('close', function() {
56
- node.status({fill:"red",shape:"dot",text:"remote-access.status.stopping"});
62
+ setStatus(node, {fill:"red",shape:"dot",text:"remote-access.status.stopping"});
57
63
  node.log("stopping ssh process");
58
64
  sshprocess.kill();
59
65
  });
@@ -74,6 +80,14 @@ module.exports = function(RED) {
74
80
  }
75
81
  }
76
82
 
83
+ function setStatus(node, options) {
84
+ // Set the status, remember text
85
+ if ( options !== undefined && options.text !== undefined ) {
86
+ statustext = options.text
87
+ }
88
+ node.status(options);
89
+ }
90
+
77
91
  function requestInstanceSlot(node) {
78
92
  // Call API to retrive server and port.
79
93
  const axiosInstance = commons.createAxiosInstance();
@@ -95,7 +109,7 @@ module.exports = function(RED) {
95
109
  if ( error.response && error.response.data && error.response.data.message ) {
96
110
  node.error(`${error.response.data.message}`);
97
111
  }
98
- node.status({fill:"red",shape:"dot",text:"remote-access.status.commerror"});
112
+ setStatus(node, {fill:"red",shape:"dot",text:"remote-access.status.commerror"});
99
113
  return;
100
114
  });
101
115
  }
@@ -139,6 +153,8 @@ module.exports = function(RED) {
139
153
  'instancehash': node.confignode.instancehash,
140
154
  'instanceauth': node.confignode.instanceauth,
141
155
  'version': commons.getNodeVersion()
156
+ }, {
157
+ 'timeout': 60*1000
142
158
  })
143
159
  .then(response => {
144
160
  // Remember the status
@@ -150,17 +166,18 @@ module.exports = function(RED) {
150
166
  // If the communication is not ok...
151
167
  if ( node.lastHeartbeatStatus === 'NOTFOUND' ) {
152
168
  // The local endpoint responed a 404...
153
- node.status({fill:"yellow",shape:"dot",text:"remote-access.status.heartbeaterrornotfound"});
169
+ setStatus(node, {fill:"yellow",shape:"dot",text:"remote-access.status.heartbeaterrornotfound"});
154
170
  node.log(`Heartbeat detected no valid endpoint, got a 404 response. Please check the base URL in the connection settings.`);
155
171
  } else if ( node.lastHeartbeatStatus !== 'OK' ) {
156
172
  if ( node.initialHeartbeatStatus === 'OK' ) {
157
173
  // If the status before was ok > Restart communication
158
- node.status({fill:"red",shape:"dot",text:"remote-access.status.heartbeaterror"});
174
+ setStatus(node, {fill:"red",shape:"dot",text:"remote-access.status.heartbeaterror"});
175
+ sshprocess.kill();
159
176
  node.serving = false
160
177
  node.log(`Heartbeat error. Reconnecting soon.`);
161
178
  } else {
162
179
  // If the status before had also an error > Just change the label.
163
- node.status({fill:"yellow",shape:"dot",text:"remote-access.status.heartbeaterroractive"});
180
+ setStatus(node, {fill:"yellow",shape:"dot",text:"remote-access.status.heartbeaterroractive"});
164
181
  node.log(`Heartbeat detected no valid endpoint. Please check your connection settings (Base URL, Serving Port and Protocol).`);
165
182
  }
166
183
  }
@@ -183,7 +200,7 @@ module.exports = function(RED) {
183
200
  node.errorcounter = 0;
184
201
 
185
202
  // Status
186
- node.status({fill:"orange",shape:"dot",text:"remote-access.status.starting"});
203
+ setStatus(node, {fill:"orange",shape:"dot",text:"remote-access.status.starting"});
187
204
 
188
205
  // Retrieve the config node
189
206
  node.confignode = RED.nodes.getNode(config.confignode);
@@ -191,17 +208,17 @@ module.exports = function(RED) {
191
208
  node.log("Server: " + node.confignode.server + " InstanceHash: " + node.confignode.instancehash );
192
209
  } else {
193
210
  node.log("No configuration found.");
194
- node.status({fill:"red",shape:"dot",text:"remote-access.status.noconfig"});
211
+ setStatus(node, {fill:"red",shape:"dot",text:"remote-access.status.noconfig"});
195
212
  return;
196
213
  }
197
214
  if ( node.confignode.instancehash === undefined || node.confignode.instancehash === '' ) {
198
215
  node.log("Configuration incomplete.");
199
- node.status({fill:"red",shape:"dot",text:"remote-access.status.incompleteconfig"});
216
+ setStatus(node, {fill:"red",shape:"dot",text:"remote-access.status.incompleteconfig"});
200
217
  return;
201
218
  }
202
219
  if ( node.confignode.instancehash !== undefined && node.confignode.instanceauth === undefined ) {
203
220
  node.log("Configuration has no instanceauth. Maybe restored backup!");
204
- node.status({fill:"red",shape:"dot",text:"remote-access.status.backupconfig"});
221
+ setStatus(node, {fill:"red",shape:"dot",text:"remote-access.status.backupconfig"});
205
222
  return;
206
223
  }
207
224
 
@@ -214,8 +231,8 @@ module.exports = function(RED) {
214
231
  tryConnect(node);
215
232
 
216
233
  // Post URL for action
217
- const postUrl = `/contrib-remote/action/${node.confignode.instancehash}`;
218
- RED.httpNode.post(postUrl, function(req,res) {
234
+ const postUrlAction = `/contrib-remote/action/${node.confignode.instancehash}`;
235
+ RED.httpNode.post(postUrlAction, function(req,res) {
219
236
  // Output action as new message
220
237
  node.log(`Action '${req.body.action}' received value '${req.body.value}'`);
221
238
  const msg = {
@@ -225,7 +242,28 @@ module.exports = function(RED) {
225
242
  "value": req.body.value
226
243
  }
227
244
  }
228
- node.send(msg);
245
+ node.send([msg, null]);
246
+
247
+ // Send OK to app
248
+ const responseData = {
249
+ 'status': 'OK'
250
+ };
251
+ res.json(responseData);
252
+ });
253
+
254
+ // Post URL for geofence
255
+ const postUrlGeofence = `/contrib-remote/geofence/${node.confignode.instancehash}`;
256
+ RED.httpNode.post(postUrlGeofence, function(req,res) {
257
+ // Output action as new message
258
+ node.log(`Geofence '${req.body.name}' received enter value '${req.body.enter}'`);
259
+ const msg = {
260
+ "_msgid": RED.util.generateId(),
261
+ "payload": {
262
+ "name": req.body.name,
263
+ "enter": req.body.enter
264
+ }
265
+ }
266
+ node.send([null, msg]);
229
267
 
230
268
  // Send OK to app
231
269
  const responseData = {
@@ -254,7 +292,20 @@ module.exports = function(RED) {
254
292
 
255
293
  // Remove old routes, without a new deploy would break it..
256
294
  RED.httpNode._router.stack.forEach(function(route,i,routes) {
257
- if (route.route && (route.route.path === postUrl || route.route.path === getUrl)) {
295
+ if (route.route && route.route.path === postUrlAction) {
296
+ node.log(` -> Remove Route '${route.route.path}'`);
297
+ routes.splice(i,1);
298
+ }
299
+ });
300
+ RED.httpNode._router.stack.forEach(function(route,i,routes) {
301
+ if (route.route && route.route.path === postUrlGeofence) {
302
+ node.log(` -> Remove Route '${route.route.path}'`);
303
+ routes.splice(i,1);
304
+ }
305
+ });
306
+ RED.httpNode._router.stack.forEach(function(route,i,routes) {
307
+ if (route.route && route.route.path === getUrl) {
308
+ node.log(` -> Remove Route '${route.route.path}'`);
258
309
  routes.splice(i,1);
259
310
  }
260
311
  });
@@ -2,11 +2,13 @@ const https = require('https')
2
2
  const axios = require('axios')
3
3
  const fs = require('fs');
4
4
  const crypto = require('crypto');
5
+ const path = require('path');
5
6
 
6
7
  module.exports = {
7
8
  createAxiosInstance: function() {
9
+ var filepath = path.join(__dirname, 'resources', 'ca.cer');
8
10
  const httpsAgent = new https.Agent({
9
- ca: fs.readFileSync(__dirname + '/resources/ca.cer'),
11
+ ca: fs.readFileSync(filepath),
10
12
  checkServerIdentity: function(host, cert) {
11
13
  const pubkeyPinned = 'YHGEo54+LKxdpCuSAFt+Zwx/RVSHER96vM/Rh0/zcQ4=';
12
14
  const pubkeyServer = crypto.createHash('sha256').update(cert.pubkey).digest('base64');
@@ -19,7 +21,20 @@ module.exports = {
19
21
  },
20
22
 
21
23
  getNodeVersion: function() {
22
- var pjson = require(__dirname.replace('/nodes', '') + '/package.json');
24
+ var filepath = path.join(__dirname, '..', 'package.json');
25
+ var pjson = require(filepath);
23
26
  return pjson.version;
27
+ },
28
+
29
+ evaluateValue: function(RED, value, type, node, msg) {
30
+ // Evaluates the value
31
+ let evalValue = ''
32
+ try {
33
+ evalValue = RED.util.evaluateNodeProperty(value, type, node, msg);
34
+ } catch (e) {
35
+ node.error(`Error evaluating value: ${e}`)
36
+ }
37
+ return evalValue;
24
38
  }
39
+
25
40
  }
@@ -130,6 +130,7 @@
130
130
  if ( data.error == undefined ) {
131
131
  // Show QR Code
132
132
  document.getElementById('registerRemoteAppQRCode').src = data.qrcode;
133
+ document.getElementById('appLink').setAttribute('href', data.link);
133
134
  document.getElementById('registerRemoteAppQRCodeContainer').style.removeProperty('visibility');
134
135
  document.getElementById('registerRemoteAppQRCodeContainer').style.removeProperty('height');
135
136
  document.getElementById('registerRemoteAppButtonText').innerHTML = document.getElementById('registerRemoteAppButton_next_text').innerHTML;
@@ -243,6 +244,11 @@
243
244
  <label data-i18n="remote-config.apphelp.title" style="font-weight: bold;"></label>
244
245
  <label data-i18n="remote-config.apphelp.para1"></label>
245
246
  </div>
247
+ <div style="max-width: 460px; border-width: 1px; border-style: dashed; border-color: #666; padding: 10px; margin-top: 6px; margin-bottom: 20px;">
248
+ <label data-i18n="remote-config.applink.title" style="font-weight: bold;"></label>
249
+ <label data-i18n="remote-config.applink.para1"></label>
250
+ <a id="appLink" href="" target="_blank"><i><label data-i18n="remote-config.applink.link" style="display: inline; color: #AD1626;"></label></i></a>
251
+ </div>
246
252
  </div>
247
253
 
248
254
  <div id="remoteInstanceInputs" style="max-height: 0px;">
@@ -82,9 +82,11 @@ module.exports = function(RED) {
82
82
  const qrCodeString = JSON.stringify(qrCodeData);
83
83
  const qrCodeStringBuffer = Buffer.from(qrCodeString);
84
84
  const qrCodeStringBase64 = qrCodeStringBuffer.toString('base64');
85
+ const link = 'remotered://add?data=' + qrCodeStringBase64;
85
86
  QRCode.toDataURL(qrCodeStringBase64, function (err, url) {
86
87
  const responseData = {
87
- 'qrcode': url
88
+ 'qrcode': url,
89
+ 'link': link
88
90
  }
89
91
  res.json(responseData);
90
92
  });
@@ -18,11 +18,17 @@ module.exports = function(RED) {
18
18
  // Act on incomming messages
19
19
  node.on('input', function(msg) {
20
20
  if (node.confignode != undefined) {
21
+ if (msg.payload.send === false) {
22
+ node.log(`Notification not send (msg.payload.send = false).`)
23
+ return;
24
+ }
21
25
  node.limiter.removeTokens(1, function(err, remainingRequests) {
22
26
  if (remainingRequests >= 0) {
23
- const title = RED.util.evaluateNodeProperty(config.notificationTitle, config.notificationTitleType, node, msg);
24
- const body = RED.util.evaluateNodeProperty(config.notificationBody, config.notificationBodyType, node, msg);
25
- const notificationEmpty = ((title == undefined || title == '') && (body == undefined || body == ''));
27
+ let title = commons.evaluateValue(RED, config.notificationTitle, config.notificationTitleType, node, msg);
28
+ let body = commons.evaluateValue(RED, config.notificationBody, config.notificationBodyType, node, msg);
29
+ if (title == undefined) title = '';
30
+ if (body == undefined) body = '';
31
+ const notificationEmpty = (title == '' && body == '');
26
32
  if (!notificationEmpty) {
27
33
  // Title and/or body are filled
28
34
 
@@ -34,7 +40,7 @@ module.exports = function(RED) {
34
40
  // Sound configured or computed?
35
41
  let sound = config.notificationSound
36
42
  if (sound === 'computed') {
37
- sound = RED.util.evaluateNodeProperty(config.notificationSoundComputed, config.notificationSoundComputedType, node, msg);
43
+ sound = commons.evaluateValue(RED, config.notificationSoundComputed, config.notificationSoundComputedType, node, msg);
38
44
  }
39
45
 
40
46
  // Call API to send notification
@@ -18,11 +18,17 @@ module.exports = function(RED) {
18
18
  // Act on incomming messages
19
19
  node.on('input', function(msg) {
20
20
  if (node.confignode != undefined) {
21
+ if (msg.payload.send === false) {
22
+ node.log(`Question not send (msg.payload.send = false).`)
23
+ return;
24
+ }
21
25
  node.limiter.removeTokens(1, function(err, remainingRequests) {
22
26
  if (remainingRequests >= 0) {
23
- const title = RED.util.evaluateNodeProperty(config.questionTitle, config.questionTitleType, node, msg);
24
- const body = RED.util.evaluateNodeProperty(config.questionBody, config.questionBodyType, node, msg);
25
- const notificationEmpty = ((title == undefined || title == '') && (body == undefined || body == ''));
27
+ let title = commons.evaluateValue(RED, config.questionTitle, config.questionTitleType, node, msg);
28
+ let body = commons.evaluateValue(RED, config.questionBody, config.questionBodyType, node, msg);
29
+ if (title == undefined) title = '';
30
+ if (body == undefined) body = '';
31
+ const notificationEmpty = (title == '' && body == '');
26
32
  if (!notificationEmpty) {
27
33
  // Title and/or body are filled, generate question data
28
34
  let questionData = {
@@ -31,16 +37,16 @@ module.exports = function(RED) {
31
37
  "questiontype" : 1,
32
38
  "answers": [
33
39
  {
34
- "text": RED.util.evaluateNodeProperty(config.questionAnswerOne, config.questionAnswerOneType, node, msg),
35
- "value": RED.util.evaluateNodeProperty(config.questionAnswerOneValue, config.questionAnswerOneValueType, node, msg)
40
+ "text": commons.evaluateValue(RED, config.questionAnswerOne, config.questionAnswerOneType, node, msg),
41
+ "value": commons.evaluateValue(RED, config.questionAnswerOneValue, config.questionAnswerOneValueType, node, msg)
36
42
  },
37
43
  {
38
- "text": RED.util.evaluateNodeProperty(config.questionAnswerTwo, config.questionAnswerTwoType, node, msg),
39
- "value": RED.util.evaluateNodeProperty(config.questionAnswerTwoValue, config.questionAnswerTwoValueType, node, msg)
44
+ "text": commons.evaluateValue(RED, config.questionAnswerTwo, config.questionAnswerTwoType, node, msg),
45
+ "value": commons.evaluateValue(RED, config.questionAnswerTwoValue, config.questionAnswerTwoValueType, node, msg)
40
46
  },
41
47
  {
42
- "text": RED.util.evaluateNodeProperty(config.questionAnswerThree, config.questionAnswerThreeType, node, msg),
43
- "value": RED.util.evaluateNodeProperty(config.questionAnswerThreeValue, config.questionAnswerThreeValueType, node, msg)
48
+ "text": commons.evaluateValue(RED, config.questionAnswerThree, config.questionAnswerThreeType, node, msg),
49
+ "value": commons.evaluateValue(RED, config.questionAnswerThreeValue, config.questionAnswerThreeValueType, node, msg)
44
50
  }
45
51
  ]
46
52
  };
@@ -53,7 +59,7 @@ module.exports = function(RED) {
53
59
  // Sound configured or computed?
54
60
  let sound = config.questionSound
55
61
  if (sound === 'computed') {
56
- sound = RED.util.evaluateNodeProperty(config.questionSoundComputed, config.questionSoundComputedType, node, msg);
62
+ sound = commons.evaluateValue(RED, config.questionSoundComputed, config.questionSoundComputedType, node, msg);
57
63
  }
58
64
 
59
65
  // Call API to send notification
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-remote",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Remote services for Node-RED including remote access, push notifications and questions through push notifications.",
5
5
  "author": "Thorsten Heilmann",
6
6
  "license": "GPL-3.0",
@@ -16,6 +16,7 @@
16
16
  "axios": "^0.21.0",
17
17
  "internal-ip": "^6.1.0",
18
18
  "limiter": "^1.1.5",
19
+ "path": "^0.12.7",
19
20
  "qrcode": "^1.4.4"
20
21
  },
21
22
  "main": "remote-config.js",