node-red-contrib-ccu 4.7.0 → 4.7.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/CHANGELOG.md +22 -0
- package/nodes/lib/lite.js +60 -6
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,28 @@ Notable changes to node-red-contrib-ccu. Format follows
|
|
|
5
5
|
user-visible symptom and the cause, not the commit list (the release notes
|
|
6
6
|
append commits automatically).
|
|
7
7
|
|
|
8
|
+
## 4.7.1 (2026-10-28)
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **On openccu-lite every write of a decimal value failed** - a dimmer's or a
|
|
13
|
+
blind's `LEVEL`, a thermostat's set point, an `ON_TIME`, through _value_,
|
|
14
|
+
_set value_, _rpc_ and the other nodes alike. A `FLOAT` datapoint is sent as
|
|
15
|
+
a typed double, which over XML-RPC is homematic-xmlrpc's
|
|
16
|
+
`{explicitDouble: n}`; the lite-rpc connection of 4.7.0 passed that object
|
|
17
|
+
on as it was, so the interface process got a struct where a number belongs
|
|
18
|
+
and refused it (`Failure` from rfd and hs485d,
|
|
19
|
+
`-5 Invalid parameter or value` from hmipserver). The lite-rpc connection
|
|
20
|
+
now sends lite-rpc's own typed double, `{double: n}` (or the plain number
|
|
21
|
+
on a system that does not announce it) - in `setValue`, in a paramset of
|
|
22
|
+
`putParamset` and in a multicall. The direct connection to a CCU is unchanged. Until this version
|
|
23
|
+
the workaround was _CCU_ in the connection node's _openccu-lite interfaces_.
|
|
24
|
+
- **Errors of the lite-rpc connection said less than they should:** a fault
|
|
25
|
+
of the interface process was logged as `fault -1 undefined` and reached the
|
|
26
|
+
flow as `OccuLiteError: Failure`, and a token without the needed rights did
|
|
27
|
+
not say which right it lacks. The fault now carries its code and text, and a
|
|
28
|
+
refused call names the missing scope.
|
|
29
|
+
|
|
8
30
|
## 4.7.0 (2026-10-27)
|
|
9
31
|
|
|
10
32
|
### Added
|
package/nodes/lib/lite.js
CHANGED
|
@@ -80,7 +80,26 @@ function readAddonToken(file = module.exports.ADDON_TOKEN_FILE) {
|
|
|
80
80
|
* @returns {boolean}
|
|
81
81
|
*/
|
|
82
82
|
function isFault(error) {
|
|
83
|
-
return
|
|
83
|
+
return kindOf(error) === 'rpc-fault' && error.faultCode !== undefined;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The client's error kind: occulite-client's OccuLiteError carries it as `code` (rpc-fault,
|
|
88
|
+
* forbidden, timeout ...); `kind` is ours, on an error translated before. A Node system error's
|
|
89
|
+
* `code` (ECONNREFUSED ...) is not a kind.
|
|
90
|
+
* @param {*} error
|
|
91
|
+
* @returns {string|undefined}
|
|
92
|
+
*/
|
|
93
|
+
function kindOf(error) {
|
|
94
|
+
if (!error) {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (error.kind) {
|
|
99
|
+
return error.kind;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return error.name === 'OccuLiteError' && typeof error.code === 'string' ? error.code : undefined;
|
|
84
103
|
}
|
|
85
104
|
|
|
86
105
|
/**
|
|
@@ -97,7 +116,8 @@ function translateError(error) {
|
|
|
97
116
|
return fault;
|
|
98
117
|
}
|
|
99
118
|
|
|
100
|
-
|
|
119
|
+
const kind = kindOf(error);
|
|
120
|
+
if (kind === 'forbidden') {
|
|
101
121
|
const refused = new Error(
|
|
102
122
|
'the openccu-lite token may not call this method' + (error.scope ? ' (needs ' + error.scope + ')' : ''),
|
|
103
123
|
);
|
|
@@ -106,15 +126,47 @@ function translateError(error) {
|
|
|
106
126
|
return refused;
|
|
107
127
|
}
|
|
108
128
|
|
|
109
|
-
if (
|
|
110
|
-
const translated = new Error(error.message ||
|
|
111
|
-
translated.kind =
|
|
129
|
+
if (kind) {
|
|
130
|
+
const translated = new Error(error.message || kind);
|
|
131
|
+
translated.kind = kind;
|
|
112
132
|
return translated;
|
|
113
133
|
}
|
|
114
134
|
|
|
115
135
|
return error instanceof Error ? error : new Error(String(error));
|
|
116
136
|
}
|
|
117
137
|
|
|
138
|
+
/**
|
|
139
|
+
* B-41: cast.js marks a FLOAT as homematic-xmlrpc's `{explicitDouble: n}` (the XML-RPC client's
|
|
140
|
+
* `<double>`). lite-rpc's JSON path does not know that marker and would hand the process a struct
|
|
141
|
+
* where a double belongs - hs485d and hmipserver refuse it. Its own marker is `{double: n}`
|
|
142
|
+
* (capability `json_double`); a system without it gets the plain number. Walks the whole
|
|
143
|
+
* parameter list: the top level, structs and paramsets, a multicall's calls.
|
|
144
|
+
* @param {*} value
|
|
145
|
+
* @param {boolean} jsonDouble whether the system announces `json_double`
|
|
146
|
+
* @returns {*} the value for lite-rpc
|
|
147
|
+
*/
|
|
148
|
+
function liteValue(value, jsonDouble) {
|
|
149
|
+
if (Array.isArray(value)) {
|
|
150
|
+
return value.map((item) => liteValue(item, jsonDouble));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (value && typeof value === 'object' && Object.getPrototypeOf(value) === Object.prototype) {
|
|
154
|
+
const keys = Object.keys(value);
|
|
155
|
+
if (keys.length === 1 && keys[0] === 'explicitDouble') {
|
|
156
|
+
const number = Number(value.explicitDouble);
|
|
157
|
+
return jsonDouble ? {double: number} : number;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const out = {};
|
|
161
|
+
keys.forEach((key) => {
|
|
162
|
+
out[key] = liteValue(value[key], jsonDouble);
|
|
163
|
+
});
|
|
164
|
+
return out;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return value;
|
|
168
|
+
}
|
|
169
|
+
|
|
118
170
|
const RPC_TIERS = ['rpc:operate', 'rpc:configure', 'rpc:admin'];
|
|
119
171
|
|
|
120
172
|
/**
|
|
@@ -263,7 +315,8 @@ class LiteConnection {
|
|
|
263
315
|
return Promise.reject(new Error('lite-rpc client not started'));
|
|
264
316
|
}
|
|
265
317
|
|
|
266
|
-
|
|
318
|
+
const jsonDouble = Boolean(this.box.capabilities && this.box.capabilities.json_double);
|
|
319
|
+
return this.box.call(iface, method, liteValue(parameters || [], jsonDouble)).then(
|
|
267
320
|
(result) => (result === null || result === undefined ? '' : result),
|
|
268
321
|
(error) => {
|
|
269
322
|
throw translateError(error);
|
|
@@ -302,6 +355,7 @@ module.exports = {
|
|
|
302
355
|
ADDON_TOKEN_FILE,
|
|
303
356
|
CALLBACK_METHODS,
|
|
304
357
|
readAddonToken,
|
|
358
|
+
liteValue,
|
|
305
359
|
tierAwareTransport,
|
|
306
360
|
translateError,
|
|
307
361
|
isFault,
|