hm-simulator 1.4.0 → 1.5.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/CHANGELOG.md CHANGED
@@ -3,6 +3,28 @@
3
3
  All notable changes of hm-simulator. The release workflow takes each version's section from here for the
4
4
  GitHub release notes.
5
5
 
6
+ ## 1.5.0 — 2026-10-30
7
+
8
+ - `getParamsetId(address, paramset)`, which answered the unknown-method fault: hmipserver's id
9
+ built from the device type, channel index and key (`hmipw-drbl4_2_link`), and on rfd and
10
+ BidCos-Wired the id the device file gives the paramset (`cc_tc_ch_wsr_link`), from the new
11
+ `data/paramset-ids.json` (261 BidCos device types, generated by `tools/paramset-ids.js` from
12
+ OpenCCU-Base's device files), with rfd's `-3 Unknown paramset` and its reading of any other key
13
+ as a peer address - all measured on 3.89.11. The option `paramsetIds` answers first.
14
+ - The fixture `data/fixtures/hmip-wired.json`: an HmIPW-DRBL4 blind actuator, HmIPW-DRI32 and
15
+ HmIPW-DRI16 input modules and an HmIPW-WRC6 wall button with their real descriptions (MASTER,
16
+ VALUES, LINK, SERVICE), and five links to the actuator whose LINK paramsets hold what the CCU's
17
+ WebUI writes for the shutter profile chosen (one of them as the WebUI of firmware 3.87 wrote it,
18
+ with the long press's `LONG_PROFILE_ACTION_TYPE` 5 the current WebUI no longer writes).
19
+ - The option `paramsets` (and the fixture property of that name for `--devices`): the stored
20
+ values MASTER, VALUES, SERVICE and link paramsets start with, on top of the defaults.
21
+ - The interface option `stickyWriteEvents` (default `true`, as before): with `false`, a client's
22
+ `setValue` or `putParamset(VALUES)` on a sticky datapoint (`FLAGS & 16`, the acknowledgement of
23
+ `STICKY_UNREACH`) changes the value and sends no event. A registered client on rfd 3.89.11 got
24
+ none when another client acknowledged the message, so a client that waits for the event shows
25
+ the device as "was unreachable" until its next read; a consumer's test can now ask for that
26
+ (found through occulited's service messages).
27
+
6
28
  ## 1.4.0 — 2026-10-03
7
29
 
8
30
  - `setInstallModeWithWhitelist(on, time, [{ADDRESS, KEY_MODE, KEY}])` on hmipserver, which answered
@@ -11,7 +33,7 @@ GitHub release notes.
11
33
  puts an HmIP device in reach of the next install mode: it joins, or - with a whitelist `LOCAL` key
12
34
  that is not its own - is declined, nothing joins and the device stays in reach; `getInclusions`
13
35
  answers every request with its result (`paired`, `declined`, `ignored`), `getInstallWhitelist` the
14
- open install mode's list. The simulator's model, not a measurement (Homematic Manager task 88).
36
+ open install mode's list. The simulator's model, not a measurement.
15
37
 
16
38
  ## 1.3.2
17
39
 
@@ -20,12 +42,11 @@ GitHub release notes.
20
42
  as both interface processes do on 3.89.11; it answered `''`. A paramset the channel does not list
21
43
  answers the new table entry `unknownParamsetDescription` (`-3 Unknown Paramset` / `-3 Unknown
22
44
  paramset`, measured); a paramset the channel has but the description set lacks still answers `''`
23
- (B-5, found through node-red-contrib-ccu's handling of the fault on a real CCU).
45
+ (found through node-red-contrib-ccu's handling of the fault on a real CCU).
24
46
  - `getLinkPeers` of a device address faults on `rfd` with the `notSupported` entry (`-1 Failure`
25
47
  under rfd's table, as rfd 3.89.11 answers; `-1 Generic error` under the default one), where it
26
48
  answered the peers of all channels; on hmipserver and the other interfaces it answers the channels'
27
- lists one after the other, a peer linked with two of the channels twice, as hmipserver 3.89.11 does
28
- (B-4).
49
+ lists one after the other, a peer linked with two of the channels twice, as hmipserver 3.89.11 does.
29
50
 
30
51
  ## 1.3.1
31
52
 
@@ -33,14 +54,14 @@ paramset`, measured); a paramset the channel has but the description set lacks s
33
54
  `rfd` - a relay's own button on the relay, a dimmer's channel on its virtual channels - as rfd
34
55
  3.89.11 does although such a link works; filtered by an address the link carries its stored flags,
35
56
  0, as rfd answers there too. A test that shows a client how it handles rfd's flag can now make the
36
- link with `addLink` instead of seeding it (B-3, found through Homematic Manager's links list).
57
+ link with `addLink` instead of seeding it (found through Homematic Manager's links list).
37
58
  - `replaceDevice` answers `true`, as the specification's `bool` says, where it answered `''` (a
38
59
  client that takes the answer as the success saw a replacement that did happen as failed).
39
60
  - rfd's `listReplaceableDevices` names only the devices of the same type that are unreachable
40
61
  (`setReachable(iface, address, false)`); a device that still answers is not replaced.
41
62
  - The declarations gain `clients` (the registered logic layers per interface, read-only, `Client`),
42
63
  `dispatch` with its `DispatchContext` (the servers' entry, which a test may wrap to record calls),
43
- and `replaceDevice`'s `true` (B-2, found through Homematic Manager's tests on 1.3.0).
64
+ and `replaceDevice`'s `true` (found through Homematic Manager's tests on 1.3.0).
44
65
 
45
66
  ## 1.3.0
46
67
 
@@ -123,7 +144,7 @@ paramset`, measured); a paramset the channel has but the description set lacks s
123
144
  the members in `TEAM_CHANNELS`; `setTeam(channel, team)` moves it and deletes a team nobody is
124
145
  left in, `setTeam(channel, '')` puts it back into a team of its own, created like the one it
125
146
  left (`newDevices`, `deleteDevices`, `updateDevice` to the logic layers). The shape is rfd's
126
- as Homematic Manager task 58 read it from a CCU3; when rfd deletes and creates the team devices
147
+ as Homematic Manager read it from a CCU3; when rfd deletes and creates the team devices
127
148
  is the simulator's model, not a measurement.
128
149
 
129
150
  ## 1.0.0
package/README.md CHANGED
@@ -126,7 +126,7 @@ that starts with the bytes `Bin` is BIN-RPC, anything else XML-RPC over HTTP.
126
126
  | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
127
127
  | session | `init` (register and de-register a logic layer), `ping`, `system.listMethods`, `system.methodHelp`, `system.multicall` |
128
128
  | devices | `listDevices`, `getDeviceDescription`, `deleteDevice`, `replaceDevice`, `listReplaceableDevices`, `setInstallMode`, `setInstallModeWithWhitelist` (hmipserver), `getInstallMode`, `addDevice` (BidCos only), `getKeyMismatchDevice` (rfd, hmipserver) |
129
- | paramsets | `getParamsetDescription`, `getParamset`, `putParamset`, `getValue`, `setValue`, `determineParameter`, `reportValueUsage` |
129
+ | paramsets | `getParamsetDescription`, `getParamsetId`, `getParamset`, `putParamset`, `getValue`, `setValue`, `determineParameter`, `reportValueUsage` |
130
130
  | links | `getLinks`, `getLinkPeers`, `getLinkInfo`, `setLinkInfo`, `addLink`, `removeLink`, `activateLinkParamset` |
131
131
  | interface | `rssiInfo`, `listBidcosInterfaces`, `setBidcosInterface`, `getServiceMessages`, `setTempKey` (BidCos only), `changeKey` (rfd, hmipserver), `logLevel`, `getVersion`, `setInterfaceClock` (rfd, hmipserver), `getLGWStatus` (only when configured) |
132
132
  | metadata | `getMetadata`, `setMetadata` (rfd, hs485d, hmipserver), `getAllMetadata` (BidCos only) |
@@ -196,6 +196,8 @@ UTF-8. BIN-RPC strings go out as ISO-8859-1, as rfd sends them.
196
196
  | `newDevices` | `{}` | devices that appear when the install mode is switched on, `{<iface>: {devices, delay}}` |
197
197
  | `defaultRssi` | `-65` | what `rssiInfo` answers where a device has no RSSI datapoint |
198
198
  | `metadata` | `{}` | what `getMetadata` answers before any `setMetadata`, `{<iface>: {<address>: {<key>: value}}}` |
199
+ | `paramsets` | `{}` | stored values to start with, `{<iface>: {<address>: {<MASTER\|VALUES\|SERVICE\|peer>: {}}}}` |
200
+ | `paramsetIds` | `{}` | what `getParamsetId` answers first, `{<iface>: {<address>: {<paramset>: id}}}` |
199
201
  | `config.listenAddress` | all interfaces | `'127.0.0.1'` in tests |
200
202
  | `config.binrpcListenPort` | – | rfd |
201
203
  | `config.xmlrpcListenPort` | – | hmipserver |
@@ -226,6 +228,7 @@ UTF-8. BIN-RPC strings go out as ISO-8859-1, as rfd sends them.
226
228
  | `pingDelay` | `0` | milliseconds between `ping` and its `PONG` |
227
229
  | `startDelay` | `0` | milliseconds after `whenReady()` until the port accepts connections: a process that starts late (`sim.ports` knows the port from the start) |
228
230
  | `unreachWrites` | `'accept'` | what `setValue`/`putParamset` to an unreachable device answer: `'accept'`, or `'fault'` (`notReachable`). The simulator's model, not a measurement |
231
+ | `stickyWriteEvents` | `true` | `false`: a client's `setValue`/`putParamset` on a sticky datapoint (`FLAGS & 16`, the acknowledgement of `STICKY_UNREACH`) sends no event, see [Device and radio health](#device-and-radio-health) |
229
232
  | `firmwareUpdateDelay` | `0` | milliseconds per step of a firmware update |
230
233
  | `getServiceMessagesFault` | `false` | answer `getServiceMessages` with the unknown-method fault (`Invalid XML-RPC message`), as VirtualDevices, CUxD and hmipserver were seen to on 3.89.x |
231
234
  | `version` | `'2.6.0'` for `rfd` and `wired`, `'3.89.11.20260919'` for `hmip` | what `getVersion` answers; the rest has no `getVersion` |
@@ -319,6 +322,13 @@ sim.regaSim.scripts; // every script the ReGa mock received
319
322
  with `setServiceMessage`. `STICKY_UNREACH` stays after the device is back until a client writes
320
323
  it `false`, as rfd does. A write to an unreachable device is accepted unless `unreachWrites` is
321
324
  `'fault'`.
325
+ - That acknowledgement is answered with the channel's events, like every other write. On rfd
326
+ 3.89.11 a registered client got **no** event when another client wrote `STICKY_UNREACH` `false`
327
+ (observed once, from the receiving client's log; a second measurement is pending): the
328
+ interface option `stickyWriteEvents: false` models that - a client's write to a datapoint with
329
+ the sticky flag (`FLAGS & 16`) changes the value and sends nothing, so only a read finds it
330
+ acknowledged. Use it to test that a client does not wait for an event that never comes. The
331
+ default stays `true` until the measurement is repeated.
322
332
  - The radio module is the HmIP device whose address is the last 14 characters of the interface's
323
333
  address in `listBidcosInterfaces` (its SGTIN), or a device of a radio module's type
324
334
  (`RPI-RF-MOD`, `HmIP-RFUSB`); without one only `listBidcosInterfaces` changes.
@@ -420,6 +430,7 @@ HMIP-PS, HMIP-SWDO, HMIP-WTH, HmIP-SMI and a radio module). Without `paramsetDes
420
430
  | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
421
431
  | `data/fixtures/lab-2026-09.json` | real devices of four test systems with the descriptions of their exact firmware, links and radio modules - the recommended one |
422
432
  | `data/fixtures/devices.json` | generated from node-red-contrib-ccu's `paramsets.json`: real descriptions, synthesised channel indexes - HmIP-PDT, HmIPW-DRS8, HmIPW-DRI16, HmIPW-DRAP, HM-LC-Sw1-Pl, HM-CC-RT-DN |
433
+ | `data/fixtures/hmip-wired.json` | an HmIP-Wired distribution board: HmIPW-DRBL4, HmIPW-DRI32, HmIPW-DRI16, HmIPW-WRC6, links to the DRBL4 with the LINK paramsets the WebUI writes |
423
434
  | `data/fixtures/lab-devices.json` | a real `listDevices` of two CCUs on firmware 3.89.8 (2026-09-05), no descriptions of its own - pass the ones of `devices.json` or the bundled set alongside |
424
435
 
425
436
  **`data/fixtures/lab-2026-09.json`**: four test systems (openccu-lite, the interface processes of
@@ -443,6 +454,30 @@ Real hardware's oddities stay: the CCU's own `HmIP-RCV-50` sends a trailing **em
443
454
  `CHILDREN`, for instance. The file is also a device file for the command line (`--devices`; add
444
455
  `--wired-port 0` or a port for BidCos-Wired).
445
456
 
457
+ **`data/fixtures/hmip-wired.json`**: a wired blind actuator HmIPW-DRBL4 (firmware 1.6.0, four
458
+ channels run as shutters), the input modules HmIPW-DRI32 (1.2.2) and HmIPW-DRI16 (1.4.6, as in
459
+ `lab-2026-09.json`) with their inputs in key mode, and the wall button HmIPW-WRC6 (1.0.8). The
460
+ descriptions of the DRBL4, DRI32 and WRC6 are hmipserver's answers as
461
+ [pydevccu](https://github.com/danielperna84/pydevccu) (MIT) recorded them. Five links go to the
462
+ DRBL4, and their `paramsets` hold what the CCU's WebUI writes for the profile chosen - the presets
463
+ of its easymode file (`SHUTTER_VIRTUAL_RECEIVER/MULTI_MODE_INPUT_TRANSMITTER_1.tcl` and
464
+ `…/KEY_TRANSCEIVER.tcl`, the first value where it lists several) on the description's defaults. The
465
+ WebUI is eQ-3's current source, except for one link made the way the WebUI of firmware 3.87 made it:
466
+ its shutter profiles still wrote `LONG_PROFILE_ACTION_TYPE` 5 for the long press, where the current
467
+ one writes 1 (changed in June 2026), so a CCU keeps links of both kinds.
468
+
469
+ | Sender | Receiver | Profile |
470
+ | ---------- | ----------- | ------------------------------------------- |
471
+ | DRI32 `:1` | DRBL4 `:2` | 3, "open / closed & up / down" |
472
+ | DRI32 `:2` | DRBL4 `:3` | 3, "open / closed & up / down" (WebUI 3.87) |
473
+ | DRI16 `:1` | DRBL4 `:6` | 1, "open / up" |
474
+ | WRC6 `:1` | DRBL4 `:10` | 3, "open / closed & up / down" |
475
+ | WRC6 `:2` | DRBL4 `:14` | 4, "move to position" |
476
+
477
+ Pass the four properties (`devices`, `paramsetDescriptions`, `links`, `paramsets`) to the
478
+ constructor, or the file to `--devices`. `tools/fixture-hmip-wired.js` builds it from a pydevccu
479
+ package and an OpenCCU-Base checkout.
480
+
446
481
  **How descriptions are found.** A description is looked up by
447
482
  `<interface>/<type>/<firmware>/<version>/<channel type>/<paramset>`, and a device reports the
448
483
  firmware it runs - which a description set often does not have. Such a device uses the description
@@ -492,7 +527,7 @@ a run of the generator, or, better, by dumping a CCU that has one.
492
527
  ## Interface behaviour, measured
493
528
 
494
529
  Where the simulator imitates an interface process, this says whether the shape was measured on a
495
- CCU or is the simulator's model. The measurements were made for Homematic Manager (tasks 6 and 58)
530
+ CCU or is the simulator's model. The measurements were made for Homematic Manager
496
531
  on CCUs with firmware 3.89.8 and 3.89.x.
497
532
 
498
533
  ### Direct links
@@ -543,6 +578,29 @@ What a `putParamset MASTER` does, per interface (`interfaces.<iface>.configPendi
543
578
  The two models are the explanations that competed before the measurement (Homematic Manager issue
544
579
  #98); they stay for applications that want to test against them.
545
580
 
581
+ ### Paramset ids
582
+
583
+ `getParamsetId(address, paramset)` is the CCU's own name of a paramset; its WebUI picks the form of a
584
+ channel or a link side by it (`easymodes/<id>.tcl`). Measured 2026-10-30 on firmware 3.89.11:
585
+
586
+ - **hmipserver builds it** from the device type, the channel index and the key, lower case and
587
+ joined by `_`: `hmipw-drbl4_2_link`, `hmipw-dri16_1_master`, `hmipw-dri16_master` for a device
588
+ address. It does that for any key - `VALUES`, `SERVICE`, a peer address
589
+ (`hmipw-dri16_1_00000000000102:1`), a name the channel does not have, `null` without one - and
590
+ for a channel without a LINK paramset as well. The simulator does the same on `hmip`, `virtual`
591
+ and `cuxd` (VirtualDevices and CUxD not measured).
592
+ - **rfd and hs485d answer the `id` of the `<paramset>` in the device file** (`firmware/rftypes`,
593
+ `firmware/hs485types`): `cc_tc_dev_master` for a device address (MASTER only), `maint_ch_master`,
594
+ `cc_tc_ch_wsr_link`, `hmw_input_ch_values` for a channel. Another key on a channel is taken as a
595
+ peer address and answers the LINK id; a paramset the address does not have - LINK or VALUES of a
596
+ device, LINK of a maintenance channel, any other key there - is `-3 Unknown paramset`. The
597
+ simulator answers from `data/paramset-ids.json` (261 device types, by type and the device file's
598
+ version, which is the description's `VERSION`; built by `tools/paramset-ids.js` from
599
+ OpenCCU-Base), the `unknownParamsetDescription` entry of the fault table for a paramset the
600
+ address does not list, and `''` for a type the files do not describe.
601
+ - An unknown address is `unknownInstance` on all of them. `paramsetIds` in the constructor options
602
+ answers before the rules above.
603
+
546
604
  ### Fault codes
547
605
 
548
606
  The default table is **hmipserver's**, because that is the one an application has to survive
@@ -729,8 +787,8 @@ Usage: hm-simulator [options]
729
787
  as one line to stdout with "-" (the log then goes to stderr)
730
788
  --config <file> constructor options as a .json or .js file; the flags override it
731
789
  --devices <file> a device file: {devices: {rfd, hmip, ...}, paramsetDescriptions, links,
732
- bidcosInterfaces}, such as data/fixtures/lab-2026-09.json; default:
733
- the bundled rfd and hmip lists
790
+ bidcosInterfaces, paramsets}, such as data/fixtures/lab-2026-09.json;
791
+ default: the bundled rfd and hmip lists
734
792
  --tls serve the XML-RPC servers over TLS with a generated certificate
735
793
  --tls-cert-out <file> write that certificate (PEM) to the file
736
794
  --auth <user:password> HTTP basic auth for the XML-RPC servers and ReGa