node-red-contrib-knx-ultimate 1.4.14 → 1.4.16

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 CHANGED
@@ -6,6 +6,15 @@
6
6
 
7
7
  # CHANGELOG
8
8
 
9
+ <p>
10
+ <b>Version 1.4.16</b> - Mai 2023<br/>
11
+ - FIX: fixed an issue when you have more than one Global Cariable node.<br/>
12
+ </p>
13
+ <p>
14
+ <b>Version 1.4.15</b> - March 2023<br/>
15
+ - FIX: fidex an issue with unicode chars in the ESF imported file.<br/>
16
+ - NEW: Added Datapoint 235.001 Tariff. Please see the sample in the node window, appearing after you select the datapoint.<br/>
17
+ </p>
9
18
  <p>
10
19
  <b>Version 1.4.14</b> - March 2023<br/>
11
20
  - NEW: Added Datapoint 29.xxx. Please see the sample in the node window, appearing after you select the datapoint.<br/>
@@ -0,0 +1,140 @@
1
+ /**
2
+ * KNXEngine - a KNX protocol stack in Javascript
3
+ * (C) 2020 Supergiovane
4
+ */
5
+
6
+ const knxLog = require('./../KnxLog')
7
+
8
+ //
9
+ // DPT235: DPT_Tariff_ActiveEnergy
10
+ //
11
+
12
+ const util = require('util')
13
+
14
+ function hex2bin(hex) {
15
+ return (parseInt(hex, 16).toString(2)).padStart(8, '0')
16
+ }
17
+
18
+ function ldexp(mantissa, exponent) {
19
+ return exponent > 1023 // avoid multiplying by infinity
20
+ ? mantissa * Math.pow(2, 1023) * Math.pow(2, exponent - 1023)
21
+ : exponent < -1074 // avoid multiplying by zero
22
+ ? mantissa * Math.pow(2, -1074) * Math.pow(2, exponent + 1074)
23
+ : mantissa * Math.pow(2, exponent)
24
+ }
25
+
26
+ function frexp(value) {
27
+ try {
28
+ if (value === 0) return [value, 0]
29
+ const data = new DataView(new ArrayBuffer(8))
30
+ data.setFloat64(0, value)
31
+ let bits = (data.getUint32(0) >>> 20) & 0x7FF
32
+ if (bits === 0) {
33
+ data.setFloat64(0, value * Math.pow(2, 64))
34
+ bits = ((data.getUint32(0) >>> 20) & 0x7FF) - 64
35
+ }
36
+ const exponent = bits - 1022; const mantissa = ldexp(value, -exponent)
37
+ return [mantissa, exponent]
38
+ } catch (error) {
39
+
40
+ }
41
+ }
42
+
43
+ function GetHex(_value) {
44
+ try {
45
+ const arr = frexp(_value)
46
+ const mantissa = arr[0]; const exponent = arr[1]
47
+ // find the minimum exponent that will upsize the normalized mantissa (0,5 to 1 range)
48
+ // in order to fit in 11 bits ([-2048, 2047])
49
+ let max_mantissa = 0
50
+ for (e = exponent; e >= -15; e--) {
51
+ max_mantissa = ldexp(100 * mantissa, e)
52
+ if (max_mantissa > -2048 && max_mantissa < 2047) break
53
+ }
54
+ const sign = (mantissa < 0) ? 1 : 0
55
+ const mant = (mantissa < 0) ? ~(max_mantissa ^ 2047) : max_mantissa
56
+ const exp = exponent - e
57
+ return [((sign << 7) + (exp << 3) + (mant >> 8)), (mant % 256)]
58
+ } catch (error) {
59
+
60
+ }
61
+ }
62
+
63
+
64
+ // 08/09/2020 Supergiovane
65
+ // Send to BUS
66
+ exports.formatAPDU = function (value) {
67
+ try {
68
+ const apdu_data = Buffer.alloc(6) // 3 x 2 bytes
69
+
70
+ if (typeof value === 'object' &&
71
+ value.hasOwnProperty('activeElectricalEnergy') &&
72
+ value.hasOwnProperty('tariff') &&
73
+ value.hasOwnProperty('validityTariff') &&
74
+ value.hasOwnProperty('validityEnergy')) {
75
+
76
+ // activeElectricalEnergy
77
+ let nbuff = Buffer.alloc(4)
78
+ nbuff.writeInt32BE(value.activeElectricalEnergy)
79
+ apdu_data[0] = nbuff[0]
80
+ apdu_data[1] = nbuff[1]
81
+ apdu_data[2] = nbuff[2]
82
+ apdu_data[3] = nbuff[3]
83
+
84
+ // tariff
85
+ const tariff = parseInt(value.tariff)
86
+ apdu_data[4] = tariff
87
+
88
+ // Validity
89
+ const validity = parseInt('000000' + (value.validityTariff ? "1" : "0") + (value.validityEnergy ? "1" : "0"), 2)
90
+ apdu_data[5] = validity
91
+ return apdu_data
92
+ } else {
93
+ knxLog.get().error('DPT235: Must supply a payload like, for example: {activeElectricalEnergy:1540, tariff:20, validityTariff:true, validityEnergy:true}')
94
+ }
95
+ } catch (error) {
96
+ knxLog.get().error('DPT235: exports.formatAPDU error ' + error.message)
97
+ }
98
+
99
+ }
100
+
101
+ // RX from BUS
102
+ exports.fromBuffer = function (buf) {
103
+ try {
104
+ // Preparo per l'avvento di Gozer il gozeriano.
105
+ const activeElectricalEnergy = buf.slice(0, 4).readInt32BE() // First 4x8 bits signed integer
106
+ const tariff = parseInt(buf.slice(4, 5)[0]) // next 8 bit unsigned value
107
+ const validity = hex2bin(buf.slice(5, 6)[0].toString(16)) // Next 8 bit, only the latest 2 bits are used.
108
+ const validityTariff = validity.substring(6, 7) === '1'
109
+ const validityEnergy = validity.substring(7, 8) === '1'
110
+ return { activeElectricalEnergy: activeElectricalEnergy, tariff: tariff, validityTariff: validityTariff, validityEnergy: validityEnergy }
111
+ } catch (error) {
112
+ knxLog.get().error('DPT235: exports.fromBuffer error ' + error.message)
113
+ }
114
+ }
115
+
116
+ // DPT basetype info
117
+ exports.basetype = {
118
+ bitlength: 48,
119
+ valuetype: 'basic',
120
+ desc: '6 octect Tariff_ActiveEnergy',
121
+ help:
122
+ `// Set the ActiveElectricalEnergy, Tariff and Validity of Tariff and Validity of Energy
123
+ msg.payload = {
124
+ activeElectricalEnergy:1540,
125
+ tariff:20,
126
+ validityTariff:true,
127
+ validityEnergy:true
128
+ };
129
+ return msg;`,
130
+ helplink: ''
131
+ }
132
+
133
+ // DPT subtypes
134
+ exports.subtypes = {
135
+ "001": {
136
+ desc: 'DPT_Tariff_ActiveEnergy',
137
+ name: 'Tariff of active Energy (Energy+Tariff+Validity)',
138
+ unit: 'Tariff'
139
+ }
140
+ }
@@ -1524,7 +1524,7 @@ return msg;`,
1524
1524
  let element = fileGA[index]
1525
1525
  element = element.replace(/\"/g, '') // Rimuovo evetuali virgolette
1526
1526
  element = element.replace(/\#/g, '') // Rimuovo evetuali #
1527
- element = element.replace(/[^\x00-\x7F]/g, '') // Remove non ascii chars
1527
+ //element = element.replace(/[^\x00-\x7F]/g, '') // Remove non ascii chars
1528
1528
 
1529
1529
  if (element !== '') {
1530
1530
  sFirstGroupName = element.split('\t')[0].split('.')[0] || ''
@@ -78,7 +78,7 @@ module.exports = function (RED) {
78
78
 
79
79
  // exposeAsVariableREADWRITE
80
80
  // #region "WRITE TO BUS"
81
- goTimerGo = () => {
81
+ node.goTimerGo = function () {
82
82
  if (node.timerExposedGAs !== null) clearTimeout(node.timerExposedGAs) // 21/03/2021
83
83
  node.timerExposedGAs = setTimeout(() => {
84
84
  let oContext = node.context().global.get(node.name + '_WRITE') || []
@@ -89,14 +89,14 @@ module.exports = function (RED) {
89
89
  node.setNodeStatus({ fill: 'RED', shape: 'dot', text: 'NO Group Address set', payload: '', GA: '', dpt: '', devicename: '' })
90
90
  RED.log.error('knxUltimateGlobalContext: No group address set in node ' + node.id)
91
91
  oContext = null // 21/03/2022
92
- goTimerGo()
92
+ node.goTimerGo()
93
93
  return
94
94
  }
95
95
  if (!element.hasOwnProperty('payload')) {
96
96
  node.setNodeStatus({ fill: 'RED', shape: 'dot', text: 'NO payload set', payload: '', GA: '', dpt: '', devicename: '' })
97
97
  RED.log.error('knxUltimateGlobalContext: No payload set for address ' + element.address + ' in node ' + node.id)
98
98
  oContext = null // 21/03/2022
99
- goTimerGo()
99
+ node.goTimerGo()
100
100
  return
101
101
  }
102
102
 
@@ -109,7 +109,7 @@ module.exports = function (RED) {
109
109
  node.setNodeStatus({ fill: 'RED', shape: 'dot', text: 'Datapoint not found in CSV for ' + element.address, payload: '', GA: '', dpt: '', devicename: '' })
110
110
  RED.log.error('knxUltimateGlobalContext: Datapoint not found in CSV for address ' + element.address + ' in node ' + node.id)
111
111
  oContext = null // 21/03/2022
112
- goTimerGo()
112
+ node.goTimerGo()
113
113
  return
114
114
  }
115
115
  }
@@ -118,12 +118,12 @@ module.exports = function (RED) {
118
118
  node.server.writeQueueAdd({ grpaddr: element.address, payload: element.payload, dpt: element.dpt || '', outputtype: 'write', nodecallerid: node.id })
119
119
  }
120
120
  oContext = null // 21/03/2022
121
- goTimerGo()
121
+ node.goTimerGo()
122
122
  }, node.writeExecutionInterval)
123
123
  }
124
124
  // 21/02/2021 timer for write to BUS
125
125
  if (node.exposeAsVariable === 'exposeAsVariableREADWRITE') {
126
- goTimerGo()
126
+ node.goTimerGo()
127
127
  node.setNodeStatus({ fill: 'green', shape: 'dot', text: 'Start Writing', payload: '', GA: '', dpt: '', devicename: '' })
128
128
  } else {
129
129
  if (node.timerExposedGAs !== null) clearTimeout(node.timerExposedGAs)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-knx-ultimate",
3
- "version": "1.4.14",
3
+ "version": "1.4.16",
4
4
  "description": "Control your KNX intallation via Node-Red! Single Node KNX IN/OUT with optional ETS group address importer. Easy to use and highly configurable.",
5
5
  "dependencies": {
6
6
  "mkdirp": "1.0.4",
@@ -11,7 +11,7 @@
11
11
  "lodash": "4.17.21",
12
12
  "path": "0.12.7",
13
13
  "crypto-js": "4.1.1",
14
- "xml2js": "0.4.23",
14
+ "xml2js": "0.5.0",
15
15
  "dns-sync":"0.2.1"
16
16
  },
17
17
  "node-red": {