homematic-manager 3.0.0-beta.25 → 3.0.0-beta.27

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.
@@ -99,8 +99,8 @@ export class Backend {
99
99
  * swallows packets takes 30 s); a store that has not started by then never will.
100
100
  */
101
101
  #metaStarting;
102
- /** Task 36: ReGa's first report per `<interface>|<address>|<datapoint>`, from its pending alarms. */
103
- #regaFirstSeen = new Map();
102
+ /** Task 36, B-74: ReGa's pending alarms per `<interface>|<address>|<datapoint>` - the CCU's own list. */
103
+ #regaAlarms = new Map();
104
104
  /** Task 64: `getParamsetId` answers by `<interface>|<address>`; emptied on every connect. */
105
105
  #paramsetIds = new Map();
106
106
  #serviceMessageTimer;
@@ -392,6 +392,14 @@ export class Backend {
392
392
  return this.#setInstallMode(p[0], p[1], p[2]);
393
393
  case 'devices.installMode.get':
394
394
  return Number(await this.#read(p[0], 'getInstallMode', []));
395
+ case 'devices.installMode.keyMismatch': {
396
+ // rfd answers the serial as a string; anything else means "none"
397
+ const serial = await this.#read(p[0], 'getKeyMismatchDevice', [true]);
398
+ return typeof serial === 'string' ? serial : '';
399
+ }
400
+ case 'devices.installMode.tempKey':
401
+ await this.#write(p[0], 'setTempKey', [p[1]]);
402
+ return null;
395
403
  case 'devices.replaceable':
396
404
  return asDescriptions(await this.#read(p[0], 'listReplaceableDevices', [p[1]]));
397
405
  case 'names.get':
@@ -665,7 +673,7 @@ export class Backend {
665
673
  });
666
674
  // B-54: the names are waited for only so long; the store starts after them either way,
667
675
  // so its names still land over ReGa's as before (task 27, D-40)
668
- this.#regaFirstSeen.clear();
676
+ this.#regaAlarms.clear();
669
677
  const names = this.#rega.refreshNames().then((changed) => {
670
678
  if (changed && this.#manager === manager) {
671
679
  this.#caches.saveNames();
@@ -1085,7 +1093,8 @@ export class Backend {
1085
1093
  */
1086
1094
  #stickyUnreachMessages() {
1087
1095
  const states = this.#manager?.states() ?? [];
1088
- return this.#caches.listServiceMessages().filter((message) => {
1096
+ // B-74: with the messages only ReGa lists - the WebUI's "war gestört" the interface forgot
1097
+ return this.#serviceMessages().filter((message) => {
1089
1098
  if (message.datapoint !== 'STICKY_UNREACH' || message.value === false) {
1090
1099
  return false;
1091
1100
  }
@@ -1102,9 +1111,7 @@ export class Backend {
1102
1111
  */
1103
1112
  async #acknowledgeExisting(messages) {
1104
1113
  for (const message of messages) {
1105
- const listed = this.#caches
1106
- .listServiceMessages(message.interfaceName)
1107
- .some((entry) => entry.address === message.address && entry.datapoint === message.datapoint);
1114
+ const listed = this.#serviceMessages(message.interfaceName).some((entry) => entry.address === message.address && entry.datapoint === message.datapoint);
1108
1115
  if (!listed || this.#stopped) {
1109
1116
  continue;
1110
1117
  }
@@ -1432,20 +1439,56 @@ export class Backend {
1432
1439
  return matrix;
1433
1440
  }
1434
1441
  #serviceMessages(interfaceName) {
1435
- return this.#withRegaTimes(this.#caches.listServiceMessages(interfaceName));
1442
+ return this.#withRegaAlarms(this.#caches.listServiceMessages(interfaceName), interfaceName);
1436
1443
  }
1437
1444
  /**
1438
1445
  * Task 36: where ReGa knows a message, its first report (the WebUI's *Erste Meldung*) replaces
1439
1446
  * the time this application first saw it, and says so.
1447
+ *
1448
+ * B-74 (#150): and a pending alarm whose datapoint the interface process does not list becomes
1449
+ * a row of its own, as the WebUI shows it - value and first report from ReGa, marked as listed
1450
+ * by the CCU only. rfd forgets a `STICKY_UNREACH` at a restart while ReGa keeps the alarm until
1451
+ * it is receipted, so the WebUI had nine messages this list lacked. Only the connection's own
1452
+ * interfaces and the datapoints that are service messages here: an alarm on a system variable
1453
+ * or a CUxD datapoint stays the WebUI's.
1440
1454
  */
1441
- #withRegaTimes(messages) {
1442
- if (this.#regaFirstSeen.size === 0) {
1455
+ #withRegaAlarms(messages, interfaceName) {
1456
+ if (this.#regaAlarms.size === 0) {
1443
1457
  return messages;
1444
1458
  }
1445
- return messages.map((message) => {
1446
- const first = this.#regaFirstSeen.get(`${message.interfaceName}|${message.address}|${message.datapoint}`);
1447
- return first === undefined ? message : { ...message, since: first, sinceSource: 'rega' };
1459
+ const listed = new Set();
1460
+ const result = messages.map((message) => {
1461
+ const key = `${message.interfaceName}|${message.address}|${message.datapoint}`;
1462
+ listed.add(key);
1463
+ const alarm = this.#regaAlarms.get(key);
1464
+ return alarm === undefined ? message : { ...message, since: alarm.first, sinceSource: 'rega' };
1448
1465
  });
1466
+ const known = new Set(this.#manager?.names() ?? []);
1467
+ for (const [key, alarm] of this.#regaAlarms) {
1468
+ if (listed.has(key) ||
1469
+ !known.has(alarm.interfaceName) ||
1470
+ (interfaceName !== undefined && alarm.interfaceName !== interfaceName) ||
1471
+ !countsAsServiceMessage(alarm.datapoint, alarm.value)) {
1472
+ continue;
1473
+ }
1474
+ result.push({
1475
+ interfaceName: alarm.interfaceName,
1476
+ address: alarm.address,
1477
+ datapoint: alarm.datapoint,
1478
+ value: alarm.value,
1479
+ since: alarm.first,
1480
+ sinceSource: 'rega',
1481
+ source: 'rega',
1482
+ });
1483
+ }
1484
+ return result;
1485
+ }
1486
+ /** B-74: is this message one only ReGa lists - a pending alarm without the interface's datapoint? */
1487
+ #isRegaOnly(interfaceName, address, datapoint) {
1488
+ return (this.#regaAlarms.has(`${interfaceName}|${address}|${datapoint}`) &&
1489
+ !this.#caches
1490
+ .listServiceMessages(interfaceName)
1491
+ .some((message) => message.address === address && message.datapoint === datapoint));
1449
1492
  }
1450
1493
  /**
1451
1494
  * Task 36: reads ReGa's pending service messages (one short script, read-only) and keeps their
@@ -1457,8 +1500,8 @@ export class Backend {
1457
1500
  async #refreshRegaAlarms() {
1458
1501
  const rega = this.#rega;
1459
1502
  if (!rega?.state.enabled) {
1460
- if (this.#regaFirstSeen.size > 0) {
1461
- this.#regaFirstSeen.clear();
1503
+ if (this.#regaAlarms.size > 0) {
1504
+ this.#regaAlarms.clear();
1462
1505
  this.events.emit('serviceMessages.changed', this.#serviceMessages());
1463
1506
  }
1464
1507
  return;
@@ -1467,12 +1510,15 @@ export class Backend {
1467
1510
  if (alarms === undefined || this.#rega !== rega) {
1468
1511
  return;
1469
1512
  }
1470
- const next = new Map(alarms.map((alarm) => [`${alarm.interfaceName}|${alarm.address}|${alarm.datapoint}`, alarm.first]));
1471
- const changed = next.size !== this.#regaFirstSeen.size ||
1472
- [...next].some(([key, first]) => this.#regaFirstSeen.get(key) !== first);
1473
- this.#regaFirstSeen.clear();
1474
- for (const [key, first] of next) {
1475
- this.#regaFirstSeen.set(key, first);
1513
+ const next = new Map(alarms.map((alarm) => [`${alarm.interfaceName}|${alarm.address}|${alarm.datapoint}`, alarm]));
1514
+ const changed = next.size !== this.#regaAlarms.size ||
1515
+ [...next].some(([key, alarm]) => {
1516
+ const before = this.#regaAlarms.get(key);
1517
+ return before === undefined || before.first !== alarm.first || before.value !== alarm.value;
1518
+ });
1519
+ this.#regaAlarms.clear();
1520
+ for (const [key, alarm] of next) {
1521
+ this.#regaAlarms.set(key, alarm);
1476
1522
  }
1477
1523
  if (changed) {
1478
1524
  this.events.emit('serviceMessages.changed', this.#serviceMessages());
@@ -1705,21 +1751,44 @@ export class Backend {
1705
1751
  if (!isAcknowledgeable(datapoint)) {
1706
1752
  throw validationError(`${datapoint} cannot be acknowledged`);
1707
1753
  }
1708
- const description = await this.#describe(interfaceName, address, 'VALUES');
1709
- const parameter = description[datapoint];
1710
- const value = parameter?.TYPE === 'ACTION';
1711
- await this.#writer.setValue(interfaceName, address, datapoint, value);
1754
+ // B-74: a message only ReGa lists has no flag left to clear on the interface; the write is
1755
+ // still sent (rfd takes a `false` for a flag it does not hold), but its failure - a device
1756
+ // the interface no longer knows, say - must not keep the alarm standing in the WebUI
1757
+ const regaOnly = this.#isRegaOnly(interfaceName, address, datapoint);
1758
+ try {
1759
+ const description = await this.#describe(interfaceName, address, 'VALUES');
1760
+ const parameter = description[datapoint];
1761
+ const value = parameter?.TYPE === 'ACTION';
1762
+ await this.#writer.setValue(interfaceName, address, datapoint, value);
1763
+ }
1764
+ catch (error) {
1765
+ if (!regaOnly) {
1766
+ throw error;
1767
+ }
1768
+ this.#notice('info', `${address}: ${datapoint} is listed by the CCU only; the interface did not take the write (${errorMessage(error)}), the alarm is receipted in ReGa`, interfaceName);
1769
+ }
1712
1770
  if (this.#caches.serviceMessages.clear(interfaceName, address, datapoint)) {
1713
1771
  this.events.emit('serviceMessages.changed', this.#serviceMessages());
1714
1772
  }
1715
1773
  // Issue #94: the datapoint write above is the acknowledgement that matters, and it happened
1716
1774
  // whether ReGa exists or not. This clears the CCU's own alarm on top, so the WebUI stops
1717
1775
  // showing a message the user has already dealt with here. D-2: silent when ReGa is off.
1718
- void this.#rega?.acknowledgeAlarm(interfaceName, address, datapoint).then(async (receipted) => {
1776
+ // B-74: for a message only ReGa lists the receipt *is* the acknowledgement, so it is waited
1777
+ // for, and the row goes with the list that follows it.
1778
+ const receipt = (this.#rega?.acknowledgeAlarm(interfaceName, address, datapoint) ?? Promise.resolve(false)).then(async (receipted) => {
1719
1779
  if (receipted) {
1720
1780
  await this.#refreshRegaAlarms();
1721
1781
  }
1782
+ else if (regaOnly) {
1783
+ this.#notice('warn', `${address}: ${datapoint} is listed by the CCU only, and ReGa did not receipt it`, interfaceName);
1784
+ }
1722
1785
  });
1786
+ if (regaOnly) {
1787
+ await receipt;
1788
+ }
1789
+ else {
1790
+ void receipt;
1791
+ }
1723
1792
  return null;
1724
1793
  }
1725
1794
  #recentEvents(interfaceName, limit) {
@@ -1915,6 +1984,8 @@ export const API_METHOD_NAMES = [
1915
1984
  'devices.installFirmware',
1916
1985
  'devices.installMode.set',
1917
1986
  'devices.installMode.get',
1987
+ 'devices.installMode.keyMismatch',
1988
+ 'devices.installMode.tempKey',
1918
1989
  'devices.replaceable',
1919
1990
  'names.get',
1920
1991
  'names.set',
@@ -20,6 +20,7 @@
20
20
  * the interface process, or is a convenience; a system without ReGa loses nothing but the CCU-side
21
21
  * bookkeeping.
22
22
  */
23
+ import type { ParamsetValue } from '@homematic-manager/core';
23
24
  /** Escapes a string for the ReGa string literal it is written into. */
24
25
  export declare function escapeRegaString(value: string): string;
25
26
  /** One entry of a rename: the ReGa object id and the name it should carry. */
@@ -72,24 +73,35 @@ export declare function parseConfirmedDevices(output: string): ConfirmedDevice[]
72
73
  */
73
74
  export declare function acknowledgeAlarmScript(interfaceName: string, address: string, datapoint: string): string | undefined;
74
75
  /**
75
- * Task 36: the CCU's pending service messages with their times, as the WebUI's service-message page
76
- * reads them: every `OT_ALARMDP` of `ID_SERVICES` that is `asOncoming`, one line per alarm with the
77
- * trigger datapoint's name, `AlOccurrenceTime()` (the WebUI's *Erste Meldung*) and `Timestamp()`
76
+ * Task 36, B-74: the CCU's pending service messages with their times and values, as the WebUI's
77
+ * service-message page lists them: every `OT_ALARMDP` of `ID_SERVICES` that is `Used()`,
78
+ * `Enabled()` and `asOncoming` (`serviceMessages.htm` of OpenCCU 3.89.8), one line per alarm with
79
+ * the trigger datapoint's name, `AlOccurrenceTime()` (the WebUI's *Erste Meldung*), `Timestamp()`
78
80
  * (*Letzte Meldung*), both as Unix seconds (`ToInteger()`, checked against `date +%s` on the lab's
79
- * OpenCCU). Read-only.
81
+ * OpenCCU), and the trigger's `Value()` - ReGa's own last value of the datapoint, which is what
82
+ * the WebUI shows for the message (`true`/`false`, an ENUM as its index). Read-only.
83
+ *
84
+ * B-74 (#150): an alarm stays oncoming until it is receipted, whatever the interface process
85
+ * reports meanwhile - rfd forgets a `STICKY_UNREACH` at a restart, ReGa does not - so the
86
+ * WebUI lists messages `getServiceMessages` does not. The value is what such a message is shown
87
+ * with.
80
88
  */
81
- export declare const REGA_ALARMS_SCRIPT = "string sId;\nforeach (sId, dom.GetObject(ID_SERVICES).EnumIDs()) {\n object oAlarm = dom.GetObject(sId);\n if (oAlarm) {\n if (oAlarm.IsTypeOf(OT_ALARMDP) && (oAlarm.AlState() == asOncoming)) {\n object oTrigger = dom.GetObject(oAlarm.AlTriggerDP());\n if (oTrigger) {\n Write(oTrigger.Name() # \"\\t\" # oAlarm.AlOccurrenceTime().ToInteger() # \"\\t\" # oAlarm.Timestamp().ToInteger() # \"\\n\");\n }\n }\n }\n}\n";
82
- /** One pending ReGa service message: whose datapoint, first and last reported (epoch ms). */
89
+ export declare const REGA_ALARMS_SCRIPT = "string sId;\nforeach (sId, dom.GetObject(ID_SERVICES).EnumIDs()) {\n object oAlarm = dom.GetObject(sId);\n if (oAlarm) {\n if (oAlarm.IsTypeOf(OT_ALARMDP) && (oAlarm.Used() == true) && (oAlarm.Enabled() == true) && (oAlarm.AlState() == asOncoming)) {\n object oTrigger = dom.GetObject(oAlarm.AlTriggerDP());\n if (oTrigger) {\n Write(oTrigger.Name() # \"\\t\" # oAlarm.AlOccurrenceTime().ToInteger() # \"\\t\" # oAlarm.Timestamp().ToInteger() # \"\\t\" # oTrigger.Value() # \"\\n\");\n }\n }\n }\n}\n";
90
+ /** One pending ReGa service message: whose datapoint, its value, first and last reported (epoch ms). */
83
91
  export interface RegaAlarm {
84
92
  readonly interfaceName: string;
85
93
  readonly address: string;
86
94
  readonly datapoint: string;
95
+ /** ReGa's last value of the trigger datapoint; `true` when the line carries none (older script). */
96
+ readonly value: ParamsetValue;
87
97
  readonly first: number;
88
98
  readonly last: number;
89
99
  }
90
100
  /**
91
101
  * Reads what {@link REGA_ALARMS_SCRIPT} wrote. A line whose name is not `<interface>.<channel>.<datapoint>`
92
- * (a system alarm, a CUxD name with more dots) or whose time is no positive number is skipped.
102
+ * (a system alarm, a CUxD name with more dots) or whose time is no positive number is skipped. The
103
+ * value column is ReGa's text of the value: `true`/`false`, a number as it prints it (an ENUM by
104
+ * its index), anything else stays a string; a line without it means `true`.
93
105
  */
94
106
  export declare function parseRegaAlarms(output: string): RegaAlarm[];
95
107
  /**
@@ -124,20 +124,27 @@ Write(iDone);
124
124
  `;
125
125
  }
126
126
  /**
127
- * Task 36: the CCU's pending service messages with their times, as the WebUI's service-message page
128
- * reads them: every `OT_ALARMDP` of `ID_SERVICES` that is `asOncoming`, one line per alarm with the
129
- * trigger datapoint's name, `AlOccurrenceTime()` (the WebUI's *Erste Meldung*) and `Timestamp()`
127
+ * Task 36, B-74: the CCU's pending service messages with their times and values, as the WebUI's
128
+ * service-message page lists them: every `OT_ALARMDP` of `ID_SERVICES` that is `Used()`,
129
+ * `Enabled()` and `asOncoming` (`serviceMessages.htm` of OpenCCU 3.89.8), one line per alarm with
130
+ * the trigger datapoint's name, `AlOccurrenceTime()` (the WebUI's *Erste Meldung*), `Timestamp()`
130
131
  * (*Letzte Meldung*), both as Unix seconds (`ToInteger()`, checked against `date +%s` on the lab's
131
- * OpenCCU). Read-only.
132
+ * OpenCCU), and the trigger's `Value()` - ReGa's own last value of the datapoint, which is what
133
+ * the WebUI shows for the message (`true`/`false`, an ENUM as its index). Read-only.
134
+ *
135
+ * B-74 (#150): an alarm stays oncoming until it is receipted, whatever the interface process
136
+ * reports meanwhile - rfd forgets a `STICKY_UNREACH` at a restart, ReGa does not - so the
137
+ * WebUI lists messages `getServiceMessages` does not. The value is what such a message is shown
138
+ * with.
132
139
  */
133
140
  export const REGA_ALARMS_SCRIPT = `string sId;
134
141
  foreach (sId, dom.GetObject(ID_SERVICES).EnumIDs()) {
135
142
  object oAlarm = dom.GetObject(sId);
136
143
  if (oAlarm) {
137
- if (oAlarm.IsTypeOf(OT_ALARMDP) && (oAlarm.AlState() == asOncoming)) {
144
+ if (oAlarm.IsTypeOf(OT_ALARMDP) && (oAlarm.Used() == true) && (oAlarm.Enabled() == true) && (oAlarm.AlState() == asOncoming)) {
138
145
  object oTrigger = dom.GetObject(oAlarm.AlTriggerDP());
139
146
  if (oTrigger) {
140
- Write(oTrigger.Name() # "\\t" # oAlarm.AlOccurrenceTime().ToInteger() # "\\t" # oAlarm.Timestamp().ToInteger() # "\\n");
147
+ Write(oTrigger.Name() # "\\t" # oAlarm.AlOccurrenceTime().ToInteger() # "\\t" # oAlarm.Timestamp().ToInteger() # "\\t" # oTrigger.Value() # "\\n");
141
148
  }
142
149
  }
143
150
  }
@@ -145,12 +152,14 @@ foreach (sId, dom.GetObject(ID_SERVICES).EnumIDs()) {
145
152
  `;
146
153
  /**
147
154
  * Reads what {@link REGA_ALARMS_SCRIPT} wrote. A line whose name is not `<interface>.<channel>.<datapoint>`
148
- * (a system alarm, a CUxD name with more dots) or whose time is no positive number is skipped.
155
+ * (a system alarm, a CUxD name with more dots) or whose time is no positive number is skipped. The
156
+ * value column is ReGa's text of the value: `true`/`false`, a number as it prints it (an ENUM by
157
+ * its index), anything else stays a string; a line without it means `true`.
149
158
  */
150
159
  export function parseRegaAlarms(output) {
151
160
  const alarms = [];
152
161
  for (const line of output.split('\n')) {
153
- const [name, first, last] = line.split('\t');
162
+ const [name, first, last, value] = line.split('\t');
154
163
  const match = /^([^.\s]+)\.([^.\s]+)\.([^.\s]+)$/u.exec(name?.trim() ?? '');
155
164
  const firstSeconds = Number(first);
156
165
  const lastSeconds = Number(last);
@@ -161,12 +170,25 @@ export function parseRegaAlarms(output) {
161
170
  interfaceName: match[1] ?? '',
162
171
  address: match[2] ?? '',
163
172
  datapoint: match[3] ?? '',
173
+ value: parseRegaValue(value),
164
174
  first: firstSeconds * 1000,
165
175
  last: Number.isFinite(lastSeconds) && lastSeconds > 0 ? lastSeconds * 1000 : firstSeconds * 1000,
166
176
  });
167
177
  }
168
178
  return alarms;
169
179
  }
180
+ /** ReGa's text of a datapoint value, as `Write(oDP.Value())` prints it. */
181
+ function parseRegaValue(text) {
182
+ const trimmed = text?.trim() ?? '';
183
+ if (trimmed === '' || trimmed === 'true') {
184
+ return true;
185
+ }
186
+ if (trimmed === 'false') {
187
+ return false;
188
+ }
189
+ const number = Number(trimmed);
190
+ return Number.isFinite(number) ? number : trimmed;
191
+ }
170
192
  /**
171
193
  * Is this safe to put inside a ReGa string literal *unescaped*?
172
194
  *
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homematic-manager/backend",
3
- "version": "3.0.0-beta.25",
3
+ "version": "3.0.0-beta.27",
4
4
  "type": "module",
5
5
  "description": "Homematic Manager backend: XML-RPC/BIN-RPC clients and callback servers, caches, optional ReGa",
6
6
  "license": "AGPL-3.0-or-later",
@@ -589,6 +589,13 @@ export interface ServiceMessage {
589
589
  * WebUI's *Erste Meldung*); absent when it is when this application first saw it.
590
590
  */
591
591
  sinceSource?: 'rega';
592
+ /**
593
+ * B-74 (#150): `rega` when only the CCU's ReGa lists this message - its alarm is pending while
594
+ * the interface process no longer reports the datapoint (rfd forgets a `STICKY_UNREACH` at a
595
+ * restart, ReGa keeps the alarm until it is receipted). The WebUI shows such a message; so does
596
+ * this list. Absent when the interface reports it.
597
+ */
598
+ source?: 'rega';
592
599
  }
593
600
  export interface EventRecord {
594
601
  /** Milliseconds since epoch. */
@@ -741,7 +748,10 @@ export interface InstallModeOptions {
741
748
  * seconds)` with exactly two arguments, `hmipKey` ignored.
742
749
  */
743
750
  hmipKeyMode?: 'KEY' | 'SGTIN' | 'ANY';
744
- /** BidCos: temporary key for `setTempKey`. */
751
+ /**
752
+ * BidCos: temporary key for `setTempKey` - the security key (passphrase) of the system the
753
+ * device was paired to, sent before the install mode or `addDevice`.
754
+ */
745
755
  tempKey?: string;
746
756
  /** Restrict to a device address (BidCos `setInstallMode` with address). */
747
757
  address?: string;
@@ -892,6 +902,25 @@ export interface ApiMethods {
892
902
  params: [interfaceName: string];
893
903
  result: number;
894
904
  };
905
+ /**
906
+ * Task 76: the serial of the last BidCos device rfd refused to pair because it holds a security
907
+ * key this system does not have (`getKeyMismatchDevice(true)`: read once, then cleared in the
908
+ * interface process), or `''` when there is none. rfd reports it to nobody, so a client polls
909
+ * it while its install mode is open, as the CCU WebUI does every five seconds.
910
+ */
911
+ 'devices.installMode.keyMismatch': {
912
+ params: [interfaceName: string];
913
+ result: string;
914
+ };
915
+ /**
916
+ * Task 76: `setTempKey(passphrase)` on its own - the security key of the system a device was
917
+ * paired to, which rfd uses for the pairings that follow; `''` clears it, so a mistyped key does
918
+ * not linger for the next pairing. `devices.installMode.set` sends it too when `tempKey` is set.
919
+ */
920
+ 'devices.installMode.tempKey': {
921
+ params: [interfaceName: string, key: string];
922
+ result: null;
923
+ };
895
924
  'devices.replaceable': {
896
925
  params: [interfaceName: string, address: string];
897
926
  result: DeviceDescription[];
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homematic-manager/core",
3
- "version": "3.0.0-beta.25",
3
+ "version": "3.0.0-beta.27",
4
4
  "type": "module",
5
5
  "description": "Pure domain logic of the Homematic Manager: no I/O, no DOM",
6
6
  "license": "AGPL-3.0-or-later",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "homematic-manager",
3
- "version": "3.0.0-beta.25",
3
+ "version": "3.0.0-beta.27",
4
4
  "type": "module",
5
5
  "description": "Configure and administer Homematic and HomematicIP devices - devices and channels, direct links, paramsets, RSSI, service messages, events and an RPC console - from a local HTTP/WebSocket server that also serves the web UI",
6
6
  "keywords": [
@@ -67,8 +67,8 @@
67
67
  "hm-simulator": "^1.0.0"
68
68
  },
69
69
  "dependencies": {
70
- "@homematic-manager/backend": "3.0.0-beta.25",
71
- "@homematic-manager/core": "3.0.0-beta.25",
70
+ "@homematic-manager/backend": "3.0.0-beta.27",
71
+ "@homematic-manager/core": "3.0.0-beta.27",
72
72
  "binrpc": "^4.2.0",
73
73
  "homematic-rega": "^2.0.0",
74
74
  "homematic-xmlrpc": "^2.0.0",