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.
|
|
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.
|
|
14
|
+
"xml2js": "0.5.0",
|
|
15
15
|
"dns-sync":"0.2.1"
|
|
16
16
|
},
|
|
17
17
|
"node-red": {
|