daikin-local-control 0.2.1 → 0.3.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.
Files changed (92) hide show
  1. package/DESIGN.md +52 -0
  2. package/README.md +39 -2
  3. package/UNSUPPORTED.md +10 -1
  4. package/dist/clients/classic.d.ts +22 -4
  5. package/dist/clients/classic.d.ts.map +1 -1
  6. package/dist/clients/classic.js +55 -8
  7. package/dist/clients/classic.js.map +1 -1
  8. package/dist/clients/client.d.ts +11 -2
  9. package/dist/clients/client.d.ts.map +1 -1
  10. package/dist/clients/dsiot.d.ts +10 -3
  11. package/dist/clients/dsiot.d.ts.map +1 -1
  12. package/dist/clients/dsiot.js +40 -5
  13. package/dist/clients/dsiot.js.map +1 -1
  14. package/dist/clients/setStateCache.d.ts +15 -0
  15. package/dist/clients/setStateCache.d.ts.map +1 -0
  16. package/dist/clients/setStateCache.js +26 -0
  17. package/dist/clients/setStateCache.js.map +1 -0
  18. package/dist/codecs/classic/capabilities.d.ts.map +1 -1
  19. package/dist/codecs/classic/capabilities.js +28 -1
  20. package/dist/codecs/classic/capabilities.js.map +1 -1
  21. package/dist/codecs/classic/extendedControl.d.ts +14 -1
  22. package/dist/codecs/classic/extendedControl.d.ts.map +1 -1
  23. package/dist/codecs/classic/extendedControl.js +39 -4
  24. package/dist/codecs/classic/extendedControl.js.map +1 -1
  25. package/dist/codecs/classic/keyValue.d.ts +3 -0
  26. package/dist/codecs/classic/keyValue.d.ts.map +1 -1
  27. package/dist/codecs/classic/keyValue.js +10 -0
  28. package/dist/codecs/classic/keyValue.js.map +1 -1
  29. package/dist/codecs/classic/state.d.ts +3 -2
  30. package/dist/codecs/classic/state.d.ts.map +1 -1
  31. package/dist/codecs/classic/state.js +14 -1
  32. package/dist/codecs/classic/state.js.map +1 -1
  33. package/dist/codecs/device.d.ts +10 -1
  34. package/dist/codecs/device.d.ts.map +1 -1
  35. package/dist/codecs/device.js +25 -10
  36. package/dist/codecs/device.js.map +1 -1
  37. package/dist/codecs/dsiot/capabilities.d.ts +4 -2
  38. package/dist/codecs/dsiot/capabilities.d.ts.map +1 -1
  39. package/dist/codecs/dsiot/capabilities.js +20 -4
  40. package/dist/codecs/dsiot/capabilities.js.map +1 -1
  41. package/dist/codecs/dsiot/device.d.ts +5 -0
  42. package/dist/codecs/dsiot/device.d.ts.map +1 -0
  43. package/dist/codecs/dsiot/device.js +14 -0
  44. package/dist/codecs/dsiot/device.js.map +1 -0
  45. package/dist/codecs/dsiot/multireq.d.ts +6 -4
  46. package/dist/codecs/dsiot/multireq.d.ts.map +1 -1
  47. package/dist/codecs/dsiot/multireq.js +9 -4
  48. package/dist/codecs/dsiot/multireq.js.map +1 -1
  49. package/dist/codecs/dsiot/state.d.ts +6 -2
  50. package/dist/codecs/dsiot/state.d.ts.map +1 -1
  51. package/dist/codecs/dsiot/state.js +12 -2
  52. package/dist/codecs/dsiot/state.js.map +1 -1
  53. package/dist/factory.d.ts +7 -0
  54. package/dist/factory.d.ts.map +1 -1
  55. package/dist/factory.js +2 -2
  56. package/dist/factory.js.map +1 -1
  57. package/dist/index.d.ts +1 -0
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +1 -0
  60. package/dist/index.js.map +1 -1
  61. package/dist/models/capabilities.d.ts +5 -1
  62. package/dist/models/capabilities.d.ts.map +1 -1
  63. package/dist/models/device.d.ts +12 -1
  64. package/dist/models/device.d.ts.map +1 -1
  65. package/dist/models/extendedControl.d.ts +2 -3
  66. package/dist/models/extendedControl.d.ts.map +1 -1
  67. package/dist/models/extendedControl.js +0 -1
  68. package/dist/models/extendedControl.js.map +1 -1
  69. package/dist/models/state.d.ts +15 -4
  70. package/dist/models/state.d.ts.map +1 -1
  71. package/dist/models/state.js +1 -0
  72. package/dist/models/state.js.map +1 -1
  73. package/package.json +1 -1
  74. package/src/clients/classic.ts +76 -10
  75. package/src/clients/client.ts +13 -1
  76. package/src/clients/dsiot.ts +52 -9
  77. package/src/clients/setStateCache.ts +28 -0
  78. package/src/codecs/classic/capabilities.ts +39 -0
  79. package/src/codecs/classic/extendedControl.ts +56 -5
  80. package/src/codecs/classic/keyValue.ts +10 -0
  81. package/src/codecs/classic/state.ts +30 -12
  82. package/src/codecs/device.ts +35 -10
  83. package/src/codecs/dsiot/capabilities.ts +27 -2
  84. package/src/codecs/dsiot/device.ts +20 -0
  85. package/src/codecs/dsiot/multireq.ts +9 -4
  86. package/src/codecs/dsiot/state.ts +16 -1
  87. package/src/factory.ts +17 -2
  88. package/src/index.ts +1 -0
  89. package/src/models/capabilities.ts +5 -0
  90. package/src/models/device.ts +13 -1
  91. package/src/models/extendedControl.ts +2 -5
  92. package/src/models/state.ts +18 -4
package/DESIGN.md CHANGED
@@ -23,6 +23,36 @@ one that landed changes nothing. `reboot()` passes `{ retry: false }`, as should
23
23
  any caller of `command()`, `multireqGet()` or `multireqUpdate()` whose request
24
24
  is not safe to repeat.
25
25
 
26
+ ## The read before a write
27
+
28
+ `setState` takes only the fields to change, but a write carries more than
29
+ those. So `setState` first reads what the unit holds, and builds the write from
30
+ that reply:
31
+
32
+ | Adapter | A write carries | The reply supplies |
33
+ | --- | --- | --- |
34
+ | Classic | Every control field the unit takes, on each `set_control_info`: `pow`, `mode`, `stemp`, `shum`, `f_rate` and the direction fields. Whether the adapter takes a request without one of them is not known, so none is left out. | Each field the control leaves out. On a mode change, the values the adapter remembers for the target mode: `dt3`, `dh3`, `dfr3` and `dfd3` for cool. |
35
+ | DSIOT | The power, the power transition and the mode on each write, then only the leaves the control changes | The power the unit holds, which decides the transition. The mode, when the control sets none. The `md` of the louver and humidity leaves, which a position and a percentage are encoded from. |
36
+
37
+ With `maxStateAgeForSetStateInMs` set, `setState` skips that read while the
38
+ client's `SetStateCache` holds a reply to `getState` or `getStateAndSensors`
39
+ younger than that. A caller that polls sets it to its poll interval, and a
40
+ write then costs one request where it cost two. No read is answered from the
41
+ cache: `getState` asks the unit every time.
42
+
43
+ The default is 0, because a write built from an old reply undoes a change made
44
+ on the remote control since that reply. Someone switches the unit to heat on
45
+ the remote, the caller sets 23 °C from a reply read before that, and the write
46
+ puts the unit back in cool.
47
+
48
+ Every write through the client clears the cache, `command()` with parameters
49
+ and `multireqUpdate()` included, so the `setState` after a write reads first.
50
+
51
+ Rejected: `setState` taking a whole `DaikinState` from the caller in place of
52
+ the read. A `DaikinState` holds the current mode's values alone: it has neither
53
+ the values a classic adapter remembers for the other modes nor the `md` of a
54
+ DSIOT leaf, so the client would still need the reply.
55
+
26
56
  ## Capabilities
27
57
 
28
58
  `DaikinCapabilities` lists what a unit accepts in the vocabulary of `DaikinState`:
@@ -96,3 +126,25 @@ Rejected: positions as the numbers 0 to 25, typed `number`, with
96
126
  - A caller learned of a mistyped number only when the call ran.
97
127
  - The `Error` was the one failure of `setState` that was not a
98
128
  `DaikinError`.
129
+
130
+ ## Special modes
131
+
132
+ `DaikinState.specialModes` lists the special modes that are on, and `getState`
133
+ reads it on both protocols. `DaikinControl` leaves it out, so `setState` is
134
+ never handed a field it cannot write: UNSUPPORTED.md says what is not known.
135
+
136
+ Rejected: a `getSpecialModes` on `ClassicDaikinClient`, beside `setSpecialMode`.
137
+
138
+ - A classic adapter reports the modes in `adv`, in the `get_control_info` reply
139
+ `getState` already reads, so the method sent a second request for a reply the
140
+ caller had.
141
+ - A DSIOT adapter reports them in its `dgc_status` trees, and a method on
142
+ `ClassicDaikinClient` gave a caller no way to read those.
143
+
144
+ `DaikinCapabilities.specialModes` lists the special modes a unit takes mode by
145
+ mode, as `targetHumidities` does.
146
+
147
+ Rejected: one list for the whole unit.
148
+
149
+ - Econo is not known to be taken in fan mode, so the one list offered it in a
150
+ mode where UNSUPPORTED.md lists it as unknown.
package/README.md CHANGED
@@ -74,7 +74,10 @@ await client.close();
74
74
  ### Discovery
75
75
 
76
76
  `discoverDevices()` resolves with one `DaikinDevice` for each adapter that
77
- answered, and with an empty array when none did.
77
+ answered, and with an empty array when none did. Each carries the adapter's
78
+ `macAddress`, such as `A4:08:EA:CC:91:D4`, and `firmwareVersion`, such as
79
+ `1.2.51`, when the adapter reports them: key a stored device on `macAddress`,
80
+ because `host` changes when the adapter is given a new address.
78
81
 
79
82
  | It | So |
80
83
  | --- | --- |
@@ -92,6 +95,9 @@ const device: DaikinDevice = { host: "192.168.1.50", protocol: "classic" };
92
95
  const client = createDaikinClient(device, { terminalUuid: savedUuid });
93
96
  ```
94
97
 
98
+ A device written by hand has no `macAddress` or `firmwareVersion`: read them
99
+ from the adapter with `await client.getDeviceInfo()`.
100
+
95
101
  Set `protocol` to `dsiot` for a BRP084 and to `classic` for every other
96
102
  adapter. A device without flags is an adapter that requires neither
97
103
  registration nor a child lock code. If yours requires either, set
@@ -113,7 +119,7 @@ again.
113
119
  ```ts
114
120
  import { randomUUID } from "node:crypto";
115
121
 
116
- const savedUuid = loadFromConfiguration() ?? saveToConfiguration(randomUUID());
122
+ const savedUuid = loadFromConfig() ?? saveToConfig(randomUUID());
117
123
  ```
118
124
 
119
125
  **KEY (when `device.requiresRegistration` is `true`).** These
@@ -159,6 +165,7 @@ is not your Wi-Fi or Out-of-Home password. Pass it as `localPassword` to
159
165
  | `swingMode` | `off`, `vertical`, `horizontal` or `both`: `vertical` moves the air up and down, `horizontal` left and right |
160
166
  | `verticalPosition` | `stop`, `position1` to `position5`, `swing`, `naturalWind`, `auto` or `floorWarming`, or `null` where the unit reports none |
161
167
  | `horizontalPosition` | `stop`, `position1` to `position5`, `swing` or `auto`, or `null` where the unit reports none |
168
+ | `specialModes` | Those of `powerful`, `econo` and `streamer` that are on, empty when none is |
162
169
 
163
170
  `getCapabilities()` resolves with a `DaikinCapabilities`, which lists the
164
171
  values this unit takes under the plural of the state field each one limits:
@@ -169,12 +176,17 @@ values this unit takes under the plural of the state field each one limits:
169
176
  | `fanSpeeds`, `swingModes`, `verticalPositions`, `horizontalPositions` | The values the unit takes, empty when it has no such control |
170
177
  | `targetTemperaturesInC` | For each mode, `{ min, max, step }` in °C, or `null` where the mode has no setpoint |
171
178
  | `targetHumidities` | For each mode, the humidity settings it takes, empty where it takes none |
179
+ | `specialModes` | For each mode, the special modes the unit takes, empty where it takes none |
172
180
  | `specialOutlet`, `energyMonitoring`, `demandControl`, `scheduleTimer` | `true` when the unit has the feature |
173
181
  | `model` | The adapter's own code for the unit's model |
174
182
 
175
183
  `getSensors()` resolves with `indoorTemperatureInC`, `outdoorTemperatureInC`
176
184
  and `indoorHumidityInPercent`, each `null` when the unit does not report it.
177
185
 
186
+ Call `getStateAndSensors()` when you want both: it resolves with
187
+ `{ state, sensors }`, and a DSIOT adapter answers it in one request, where
188
+ `getState()` then `getSensors()` sends the same request twice.
189
+
178
190
  ### Changing state
179
191
 
180
192
  Pass `setState()` only the fields to change: a field left out keeps the value
@@ -191,6 +203,24 @@ given, whether or not the unit lists it.
191
203
  | `fanSpeed` | In `dehumidify`, and on a DSIOT adapter in `cool` while a humidity setting is on: the fan runs on `auto` |
192
204
  | `verticalPosition`, `horizontalPosition` | On a classic adapter, when the unit has no 3D airflow. On a DSIOT adapter, a fixed vertical position the unit lacks, and every fixed horizontal position |
193
205
 
206
+ `setState()` takes no `specialModes`: turn one on or off with
207
+ [`setSpecialMode()`](#extended-controls), which only a classic adapter has.
208
+
209
+ Pass `maxStateAgeForSetStateInMs` to `createDaikinClient` when you poll the
210
+ state anyway: `setState()` reads the unit before each write, and with it builds
211
+ the write from a `getState()` or `getStateAndSensors()` reply younger than that
212
+ instead. It changes no read: `getState()` asks the unit every time.
213
+
214
+ ```ts
215
+ const client = createDaikinClient(device, {
216
+ terminalUuid: savedUuid,
217
+ maxStateAgeForSetStateInMs: 30_000, // your poll interval, in milliseconds
218
+ });
219
+ ```
220
+
221
+ The write undoes a change made on the remote control since that reply:
222
+ [DESIGN.md](DESIGN.md#the-read-before-a-write) says how.
223
+
194
224
  ### Extended controls
195
225
 
196
226
  Beyond core climate, `ClassicDaikinClient` exposes the adapter's other `set_*`
@@ -222,6 +252,13 @@ if (client instanceof ClassicDaikinClient) {
222
252
  }
223
253
  ```
224
254
 
255
+ Read a setting back with the matching `get` method:
256
+
257
+ | Method | Resolves with |
258
+ | --- | --- |
259
+ | `getLed()`, `getHolidayMode()`, `getOutOfHomeAccess()` | `true` or `false`, or `null` when the adapter does not report it |
260
+ | `getMetadata()` | `{ name, icon, group }`, without the fields the adapter does not report |
261
+
225
262
  [UNSUPPORTED.md](UNSUPPORTED.md) lists the endpoints without a typed method and
226
263
  what is not known about each.
227
264
 
package/UNSUPPORTED.md CHANGED
@@ -17,7 +17,16 @@ To add one, pin down the request and reply first, then delete its row.
17
17
  | Classic schedule demand mode (`mode=1`) | The full format of the weekly table it needs (`moc`..`suc`, `<day><n>_en`/`_t`/`_p`). | `ClassicDaikinClient.command()` |
18
18
  | Classic special mode `spmode_kind=4` (heat plus) | Which units take it. | `ClassicDaikinClient.command()` |
19
19
  | Timers, weekly programs, schedule timers (`/aircon/get_timer`, `set_timer`, `get_program`, `set_program`, `get_scdltimer_info`, `get_scdltimer_body`, `set_scdltimer_info`, `set_scdltimer_body`) | Their parameters. | `ClassicDaikinClient.command()` |
20
- | Classic setting reads: `/aircon/get_demand_control`, `/aircon/get_price`, `/aircon/get_target`, `/common/get_holiday` | The reply fields. | `ClassicDaikinClient.command()` |
20
+ | Classic setting reads: `/aircon/get_demand_control`, `/aircon/get_price`, `/aircon/get_target`, `/common/get_holiday` | The reply fields. `getHolidayMode` reads `/common/basic_info` instead. | `ClassicDaikinClient.command()` |
21
+ | Classic `method` in `/common/get_remote_method` | Whether the reply carries it. `getOutOfHomeAccess` reads `/common/basic_info` instead. | `ClassicDaikinClient.command()` |
22
+ | Energy history: classic `/aircon/get_week_power`, `get_year_power`, `get_day_power_ex`, `get_week_power_ex`, `get_year_power_ex`, and DSIOT `adr_0100.history` | The unit of each value, and which day or month each position in a list stands for. | `ClassicDaikinClient.command()` |
23
+ | Power draw: classic `mompow` in `/aircon/get_sensor_info`, DSIOT `dgc_status.e_1003.e_A005.p_01` | The unit. | `ClassicDaikinClient.command()`, `DsiotDaikinClient.multireqGet()` |
24
+ | Compressor frequency: classic `cmpfreq` in `/aircon/get_sensor_info`, DSIOT `dgc_status.e_1003.e_2006.p_04` | The unit. | `ClassicDaikinClient.command()`, `DsiotDaikinClient.multireqGet()` |
25
+ | Error code: classic `err` in `/aircon/get_sensor_info` and `/common/basic_info` | Which code on the unit's display each number stands for. | `ClassicDaikinClient.command()` |
26
+ | Reading the settings of a DSIOT adapter: LED, holiday mode, name, icon, group | The value encoding of each `adp_d` leaf. | `DsiotDaikinClient.multireqGet()` |
27
+ | Special modes through `setState`, and on a DSIOT adapter at all | Whether a DSIOT adapter accepts a write to the leaves `getState` reads, and which value turns a mode on. | `ClassicDaikinClient.setSpecialMode()`, `DsiotDaikinClient.multireqUpdate()` |
28
+ | Classic `powerful` and `econo` on a unit whose `cpv` is not 3, or whose `cpv_minor` is `00` or missing | Whether such a unit takes them. `getCapabilities` lists neither for it, whatever its `en_spmode`. | `ClassicDaikinClient.setSpecialMode()` |
29
+ | `econo` in fan mode | Whether a unit takes it. `getCapabilities` lists it in every mode but fan. | `ClassicDaikinClient.setSpecialMode()` |
21
30
  | Classic notifications, clock and account: `/common/get_notify`, `set_notify`, `set_push_notice`, `set_timezone`, `notify_date_time`, `set_account` | Their parameters. | `ClassicDaikinClient.command()` |
22
31
  | Classic network: `/common/get_network_setting`, `set_network_setting`, `start_wifi_scan`, `get_wifi_scan_result`, `start_wifi_connection`, `permit_wifi_connection`, `set_lpw` | Their parameters. | `ClassicDaikinClient.command()` |
23
32
  | Classic firmware update: a POST to `/dkac/system/fwupdate` | The format of the upload. | Not reachable |
@@ -1,6 +1,7 @@
1
1
  import type { DaikinCapabilities } from "../models/capabilities.js";
2
- import type { DemandControl, DeviceMetadata, SpecialMode, TerminalScope } from "../models/extendedControl.js";
3
- import type { DaikinControl, DaikinSensors, DaikinState } from "../models/state.js";
2
+ import type { DaikinDeviceInfo } from "../models/device.js";
3
+ import type { DemandControl, DeviceMetadata, TerminalScope } from "../models/extendedControl.js";
4
+ import type { DaikinControl, DaikinSensors, DaikinState, DaikinStateAndSensors, SpecialMode } from "../models/state.js";
4
5
  import { type DaikinRequestOptions, type DaikinRetryOptions, type DaikinTransport } from "../transport.js";
5
6
  import type { DaikinClient } from "./client.js";
6
7
  /** Classic CGI adapter (BRP069-style). Reads and writes are HTTP GET with query
@@ -9,21 +10,35 @@ export declare class ClassicDaikinClient implements DaikinClient {
9
10
  private readonly transport;
10
11
  private readonly retryOptions?;
11
12
  private capabilityFields;
12
- /** `close` closes `transport`, so give each client a transport of its own. */
13
- constructor(transport: DaikinTransport, retryOptions?: DaikinRetryOptions | undefined);
13
+ private readonly setStateCache;
14
+ /** `close` closes `transport`, so give each client a transport of its own.
15
+ * `maxStateAgeForSetStateInMs` defaults to 0: see
16
+ * `CreateDaikinClientOptions.maxStateAgeForSetStateInMs`. */
17
+ constructor(transport: DaikinTransport, retryOptions?: DaikinRetryOptions | undefined, maxStateAgeForSetStateInMs?: number);
14
18
  close(): Promise<void>;
19
+ getDeviceInfo(): Promise<DaikinDeviceInfo>;
15
20
  getCapabilities(): Promise<DaikinCapabilities>;
16
21
  getState(): Promise<DaikinState>;
17
22
  setState(control: DaikinControl): Promise<void>;
18
23
  getSensors(): Promise<DaikinSensors>;
24
+ getStateAndSensors(): Promise<DaikinStateAndSensors>;
25
+ /** Whether the adapter's status LED is on (`basic_info`): `null` when the
26
+ * adapter does not report it. */
27
+ getLed(): Promise<boolean | null>;
19
28
  /** Adapter status LED on/off (`set_led`). */
20
29
  setLed(on: boolean): Promise<void>;
30
+ /** Whether holiday mode is on (`basic_info`): `null` when the adapter does
31
+ * not report it. */
32
+ getHolidayMode(): Promise<boolean | null>;
21
33
  /** Holiday / away mode (`set_holiday`). */
22
34
  setHolidayMode(enabled: boolean): Promise<void>;
23
35
  /** Demand control — cap the unit's power draw (`set_demand_control`). */
24
36
  setDemandControl(demand: DemandControl): Promise<void>;
25
37
  /** Powerful, econo or streamer (`set_special_mode`). */
26
38
  setSpecialMode(mode: SpecialMode, enabled: boolean): Promise<void>;
39
+ /** Whether the unit can be operated from outside the home network
40
+ * (`basic_info`): `null` when the adapter does not report it. */
41
+ getOutOfHomeAccess(): Promise<boolean | null>;
27
42
  /** Whether the unit can be operated from outside the home network
28
43
  * (`set_remote_method`). */
29
44
  setOutOfHomeAccess(enabled: boolean): Promise<void>;
@@ -32,6 +47,8 @@ export declare class ClassicDaikinClient implements DaikinClient {
32
47
  setEnergyPrice(price: number): Promise<void>;
33
48
  /** Energy target for the "target" feature (`set_target`). */
34
49
  setEnergyTarget(target: number): Promise<void>;
50
+ /** Name / icon / group metadata (`basic_info`). */
51
+ getMetadata(): Promise<DeviceMetadata>;
35
52
  /** Name / icon / group metadata (`set_name` etc.). */
36
53
  setMetadata(metadata: DeviceMetadata): Promise<void>;
37
54
  /** Register this client's uuid with an adapter whose
@@ -48,6 +65,7 @@ export declare class ClassicDaikinClient implements DaikinClient {
48
65
  * timers, schedules, programs, network, credentials and firmware. It throws
49
66
  * a `DaikinError` when the reply's `ret` is not `OK`. */
50
67
  command(path: string, parameters?: Record<string, string>, { retry }?: DaikinRequestOptions): Promise<Record<string, string>>;
68
+ private readControlInfo;
51
69
  private readCapabilityFields;
52
70
  }
53
71
  //# sourceMappingURL=classic.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"classic.d.ts","sourceRoot":"","sources":["../../src/clients/classic.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,KAAK,EACV,aAAa,EACb,cAAc,EACd,WAAW,EACX,aAAa,EACd,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EACV,aAAa,EACb,aAAa,EACb,WAAW,EACZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EAErB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA0BhD;oDACoD;AACpD,qBAAa,mBAAoB,YAAW,YAAY;IAOpD,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;IALhC,OAAO,CAAC,gBAAgB,CAA8C;IAEtE,8EAA8E;IAC9E,YACmB,SAAS,EAAE,eAAe,EAC1B,YAAY,CAAC,EAAE,kBAAkB,YAAA,EAChD;IAEJ,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAErB;IAEK,eAAe,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAEnD;IAEK,QAAQ,IAAI,OAAO,CAAC,WAAW,CAAC,CAErC;IAEK,QAAQ,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAOpD;IAEK,UAAU,IAAI,OAAO,CAAC,aAAa,CAAC,CAIzC;IAKD,6CAA6C;IACvC,MAAM,CAAC,EAAE,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAEvC;IAED,2CAA2C;IACrC,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAKpD;IAED,yEAAyE;IACnE,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAK3D;IAED,wDAAwD;IAClD,cAAc,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAKvE;IAED;gCAC4B;IACtB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAMxD;IAED;gCAC4B;IACtB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKjD;IAED,6DAA6D;IACvD,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKnD;IAED,sDAAsD;IAChD,WAAW,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBzD;IAED;;+EAE2E;IACrE,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKjD;IAED;+BAC2B;IACrB,kBAAkB,CAAC,KAAK,GAAE,aAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAKrE;IAED,qCAAqC;IAC/B,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAE5B;IAED;;;6DAGyD;IACnD,OAAO,CACX,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACnC,EAAE,KAAY,EAAE,GAAE,oBAAyB,GAC1C,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAYjC;IAED,OAAO,CAAC,oBAAoB;CAY7B"}
1
+ {"version":3,"file":"classic.d.ts","sourceRoot":"","sources":["../../src/clients/classic.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,10 @@
1
1
  import { mergeClassicCapabilityFields, parseClassicCapabilities, } from "../codecs/classic/capabilities.js";
2
- import { applyClassicOutOfHomeAccess, encodeClassicDemandControl, encodeClassicEnergyPrice, encodeClassicEnergyTarget, encodeClassicGroup, encodeClassicHolidayMode, encodeClassicIcon, encodeClassicLed, encodeClassicName, encodeClassicSpecialMode, encodeClassicTerminalKey, encodeClassicTerminalScope, } from "../codecs/classic/extendedControl.js";
2
+ import { applyClassicOutOfHomeAccess, encodeClassicDemandControl, encodeClassicEnergyPrice, encodeClassicEnergyTarget, encodeClassicGroup, encodeClassicHolidayMode, encodeClassicIcon, encodeClassicLed, encodeClassicName, encodeClassicSpecialMode, encodeClassicTerminalKey, encodeClassicTerminalScope, parseClassicHolidayMode, parseClassicLed, parseClassicMetadata, parseClassicOutOfHomeAccess, } from "../codecs/classic/extendedControl.js";
3
3
  import { assertClassicOk, parseClassicKeyValue, } from "../codecs/classic/keyValue.js";
4
4
  import { applyClassicControl, parseClassicSensors, parseClassicState, } from "../codecs/classic/state.js";
5
+ import { parseDeviceInfo } from "../codecs/device.js";
5
6
  import { withRetry, } from "../transport.js";
7
+ import { SetStateCache } from "./setStateCache.js";
6
8
  // Classic CGI endpoints (BRP069-style). Reads and writes are both HTTP GET with
7
9
  // query parameters; the reply is `key=value,key=value`.
8
10
  const CLASSIC_ROUTES = {
@@ -34,34 +36,55 @@ export class ClassicDaikinClient {
34
36
  // A unit's capabilities don't change, and `setState` needs them, so they are
35
37
  // read once.
36
38
  capabilityFields;
37
- /** `close` closes `transport`, so give each client a transport of its own. */
38
- constructor(transport, retryOptions) {
39
+ setStateCache;
40
+ /** `close` closes `transport`, so give each client a transport of its own.
41
+ * `maxStateAgeForSetStateInMs` defaults to 0: see
42
+ * `CreateDaikinClientOptions.maxStateAgeForSetStateInMs`. */
43
+ constructor(transport, retryOptions, maxStateAgeForSetStateInMs = 0) {
39
44
  this.transport = transport;
40
45
  this.retryOptions = retryOptions;
46
+ this.setStateCache = new SetStateCache(maxStateAgeForSetStateInMs);
41
47
  }
42
48
  close() {
43
49
  return this.transport.close();
44
50
  }
51
+ async getDeviceInfo() {
52
+ return parseDeviceInfo(await this.command(CLASSIC_ROUTES.basicInfo));
53
+ }
45
54
  async getCapabilities() {
46
55
  return parseClassicCapabilities(await this.readCapabilityFields());
47
56
  }
48
57
  async getState() {
49
- return parseClassicState(await this.command(CLASSIC_ROUTES.getControlInfo));
58
+ return parseClassicState(await this.readControlInfo());
50
59
  }
51
60
  async setState(control) {
52
61
  const capabilityFields = await this.readCapabilityFields();
53
- const current = await this.command(CLASSIC_ROUTES.getControlInfo);
62
+ const current = this.setStateCache.get() ??
63
+ (await this.command(CLASSIC_ROUTES.getControlInfo));
54
64
  await this.command(CLASSIC_ROUTES.setControlInfo, applyClassicControl(current, control, capabilityFields));
55
65
  }
56
66
  async getSensors() {
57
67
  return parseClassicSensors(await this.command(CLASSIC_ROUTES.getSensorInfo));
58
68
  }
69
+ async getStateAndSensors() {
70
+ return { state: await this.getState(), sensors: await this.getSensors() };
71
+ }
59
72
  // --- extended controls ---------------------------------------------------
60
- // Each maps to its own endpoint (not control_info).
73
+ // Each write goes to its own endpoint, not `set_control_info`.
74
+ /** Whether the adapter's status LED is on (`basic_info`): `null` when the
75
+ * adapter does not report it. */
76
+ async getLed() {
77
+ return parseClassicLed(await this.command(CLASSIC_ROUTES.basicInfo));
78
+ }
61
79
  /** Adapter status LED on/off (`set_led`). */
62
80
  async setLed(on) {
63
81
  await this.command(CLASSIC_ROUTES.setLed, encodeClassicLed(on));
64
82
  }
83
+ /** Whether holiday mode is on (`basic_info`): `null` when the adapter does
84
+ * not report it. */
85
+ async getHolidayMode() {
86
+ return parseClassicHolidayMode(await this.command(CLASSIC_ROUTES.basicInfo));
87
+ }
65
88
  /** Holiday / away mode (`set_holiday`). */
66
89
  async setHolidayMode(enabled) {
67
90
  await this.command(CLASSIC_ROUTES.setHoliday, encodeClassicHolidayMode(enabled));
@@ -74,6 +97,11 @@ export class ClassicDaikinClient {
74
97
  async setSpecialMode(mode, enabled) {
75
98
  await this.command(CLASSIC_ROUTES.setSpecialMode, encodeClassicSpecialMode(mode, enabled));
76
99
  }
100
+ /** Whether the unit can be operated from outside the home network
101
+ * (`basic_info`): `null` when the adapter does not report it. */
102
+ async getOutOfHomeAccess() {
103
+ return parseClassicOutOfHomeAccess(await this.command(CLASSIC_ROUTES.basicInfo));
104
+ }
77
105
  /** Whether the unit can be operated from outside the home network
78
106
  * (`set_remote_method`). */
79
107
  async setOutOfHomeAccess(enabled) {
@@ -89,6 +117,10 @@ export class ClassicDaikinClient {
89
117
  async setEnergyTarget(target) {
90
118
  await this.command(CLASSIC_ROUTES.setTarget, encodeClassicEnergyTarget(target));
91
119
  }
120
+ /** Name / icon / group metadata (`basic_info`). */
121
+ async getMetadata() {
122
+ return parseClassicMetadata(await this.command(CLASSIC_ROUTES.basicInfo));
123
+ }
92
124
  /** Name / icon / group metadata (`set_name` etc.). */
93
125
  async setMetadata(metadata) {
94
126
  if (metadata.name !== undefined) {
@@ -126,8 +158,23 @@ export class ClassicDaikinClient {
126
158
  path,
127
159
  ...(parameters ? { query: parameters } : {}),
128
160
  });
129
- const fields = parseClassicKeyValue(await (retry ? withRetry(send, this.retryOptions) : send()));
130
- assertClassicOk(fields);
161
+ try {
162
+ const fields = parseClassicKeyValue(await (retry ? withRetry(send, this.retryOptions) : send()));
163
+ assertClassicOk(fields);
164
+ return fields;
165
+ }
166
+ finally {
167
+ // Every request that changes the unit takes parameters, and any of them
168
+ // may change what `get_control_info` answers, even one that failed: a
169
+ // request that timed out may still have reached the unit.
170
+ if (parameters) {
171
+ this.setStateCache.clear();
172
+ }
173
+ }
174
+ }
175
+ async readControlInfo() {
176
+ const fields = await this.command(CLASSIC_ROUTES.getControlInfo);
177
+ this.setStateCache.set(fields);
131
178
  return fields;
132
179
  }
133
180
  readCapabilityFields() {
@@ -1 +1 @@
1
- {"version":3,"file":"classic.js","sourceRoot":"","sources":["../../src/clients/classic.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"classic.js","sourceRoot":"","sources":["../../src/clients/classic.ts"],"names":[],"mappings":"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"}
@@ -1,20 +1,29 @@
1
1
  import type { DaikinCapabilities } from "../models/capabilities.js";
2
- import type { DaikinControl, DaikinSensors, DaikinState } from "../models/state.js";
2
+ import type { DaikinDeviceInfo } from "../models/device.js";
3
+ import type { DaikinControl, DaikinSensors, DaikinState, DaikinStateAndSensors } from "../models/state.js";
3
4
  /** The controls every adapter offers, whatever its wire protocol or
4
5
  * authentication. `createDaikinClient` picks the implementation, so a caller
5
6
  * needs the concrete class only for what one protocol adds, such as
6
7
  * `ClassicDaikinClient.registerTerminal`. Every method rejects with a
7
8
  * `DaikinError` when its request fails. */
8
9
  export interface DaikinClient {
10
+ /** The adapter's MAC address and firmware version. */
11
+ getDeviceInfo(): Promise<DaikinDeviceInfo>;
9
12
  /** The unit's supported features. */
10
13
  getCapabilities(): Promise<DaikinCapabilities>;
11
14
  /** Current controllable state. */
12
15
  getState(): Promise<DaikinState>;
13
16
  /** Change part of the state. The client reads the current state, overlays the
14
- * control, and writes the whole thing back. */
17
+ * control, and writes the whole thing back. It skips the read when it holds
18
+ * a reply to `getState` or `getStateAndSensors` younger than
19
+ * `CreateDaikinClientOptions.maxStateAgeForSetStateInMs`. */
15
20
  setState(control: DaikinControl): Promise<void>;
16
21
  /** Read-only temperature / humidity readings. */
17
22
  getSensors(): Promise<DaikinSensors>;
23
+ /** What `getState` and `getSensors` resolve with, together. A DSIOT adapter
24
+ * answers both in one request, where calling the two sends the same request
25
+ * twice. A classic adapter takes one request for each. */
26
+ getStateAndSensors(): Promise<DaikinStateAndSensors>;
18
27
  /** Close the connection to the adapter. */
19
28
  close(): Promise<void>;
20
29
  }
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/clients/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,KAAK,EACV,aAAa,EACb,aAAa,EACb,WAAW,EACZ,MAAM,oBAAoB,CAAC;AAE5B;;;;2CAI2C;AAC3C,MAAM,WAAW,YAAY;IAC3B,qCAAqC;IACrC,eAAe,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAE/C,kCAAkC;IAClC,QAAQ,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;IAEjC;mDAC+C;IAC/C,QAAQ,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhD,iDAAiD;IACjD,UAAU,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC;IAErC,2CAA2C;IAC3C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/clients/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EACV,aAAa,EACb,aAAa,EACb,WAAW,EACX,qBAAqB,EACtB,MAAM,oBAAoB,CAAC;AAE5B;;;;2CAI2C;AAC3C,MAAM,WAAW,YAAY;IAC3B,sDAAsD;IACtD,aAAa,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAE3C,qCAAqC;IACrC,eAAe,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAE/C,kCAAkC;IAClC,QAAQ,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;IAEjC;;;iEAG6D;IAC7D,QAAQ,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhD,iDAAiD;IACjD,UAAU,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC;IAErC;;8DAE0D;IAC1D,kBAAkB,IAAI,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAErD,2CAA2C;IAC3C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"}
@@ -1,6 +1,7 @@
1
1
  import { type DsiotUpdate } from "../codecs/dsiot/multireq.js";
2
2
  import type { DaikinCapabilities } from "../models/capabilities.js";
3
- import type { DaikinControl, DaikinSensors, DaikinState } from "../models/state.js";
3
+ import type { DaikinDeviceInfo } from "../models/device.js";
4
+ import type { DaikinControl, DaikinSensors, DaikinState, DaikinStateAndSensors } from "../models/state.js";
4
5
  import { type DaikinRequestOptions, type DaikinRetryOptions, type DaikinTransport } from "../transport.js";
5
6
  import type { DaikinClient } from "./client.js";
6
7
  /** DSIOT adapter (BRP084-style). One endpoint, `/dsiot/multireq`: POST to read
@@ -8,13 +9,18 @@ import type { DaikinClient } from "./client.js";
8
9
  export declare class DsiotDaikinClient implements DaikinClient {
9
10
  private readonly transport;
10
11
  private readonly retryOptions?;
11
- /** `close` closes `transport`, so give each client a transport of its own. */
12
- constructor(transport: DaikinTransport, retryOptions?: DaikinRetryOptions | undefined);
12
+ private readonly setStateCache;
13
+ /** `close` closes `transport`, so give each client a transport of its own.
14
+ * `maxStateAgeForSetStateInMs` defaults to 0: see
15
+ * `CreateDaikinClientOptions.maxStateAgeForSetStateInMs`. */
16
+ constructor(transport: DaikinTransport, retryOptions?: DaikinRetryOptions | undefined, maxStateAgeForSetStateInMs?: number);
13
17
  close(): Promise<void>;
18
+ getDeviceInfo(): Promise<DaikinDeviceInfo>;
14
19
  getCapabilities(): Promise<DaikinCapabilities>;
15
20
  getState(): Promise<DaikinState>;
16
21
  setState(control: DaikinControl): Promise<void>;
17
22
  getSensors(): Promise<DaikinSensors>;
23
+ getStateAndSensors(): Promise<DaikinStateAndSensors>;
18
24
  /** Reboot the adapter (`/config/system/reboot`). */
19
25
  reboot(): Promise<void>;
20
26
  /** Raw multireq read of whole resources (`DSIOT_TARGETS` values or any `to`),
@@ -24,5 +30,6 @@ export declare class DsiotDaikinClient implements DaikinClient {
24
30
  * on the indoor edge. Returns the reply, flattened as `multireqGet` does. */
25
31
  multireqUpdate(updates: DsiotUpdate[], options?: DaikinRequestOptions): Promise<Record<string, string>>;
26
32
  private multireq;
33
+ private readStatus;
27
34
  }
28
35
  //# sourceMappingURL=dsiot.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dsiot.d.ts","sourceRoot":"","sources":["../../src/clients/dsiot.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,WAAW,EAEjB,MAAM,6BAA6B,CAAC;AAMrC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,KAAK,EACV,aAAa,EACb,aAAa,EACb,WAAW,EACZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EAErB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAShD;6DAC6D;AAC7D,qBAAa,iBAAkB,YAAW,YAAY;IAGlD,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;IAHhC,8EAA8E;IAC9E,YACmB,SAAS,EAAE,eAAe,EAC1B,YAAY,CAAC,EAAE,kBAAkB,YAAA,EAChD;IAEJ,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAErB;IAEK,eAAe,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAOnD;IAEK,QAAQ,IAAI,OAAO,CAAC,WAAW,CAAC,CAIrC;IAEK,QAAQ,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAGpD;IAEK,UAAU,IAAI,OAAO,CAAC,aAAa,CAAC,CAOzC;IAID,oDAAoD;IAC9C,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAK5B;IAED;4CACwC;IAClC,WAAW,CACf,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAEjC;IAED;iFAC6E;IACvE,cAAc,CAClB,OAAO,EAAE,WAAW,EAAE,EACtB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAEjC;YAEa,QAAQ;CAWvB"}
1
+ {"version":3,"file":"dsiot.d.ts","sourceRoot":"","sources":["../../src/clients/dsiot.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,WAAW,EAEjB,MAAM,6BAA6B,CAAC;AAMrC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EACV,aAAa,EACb,aAAa,EACb,WAAW,EACX,qBAAqB,EACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EAErB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAUhD;6DAC6D;AAC7D,qBAAa,iBAAkB,YAAW,YAAY;IAOlD,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;IAPhC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAE9C;;iEAE6D;IAC7D,YACmB,SAAS,EAAE,eAAe,EAC1B,YAAY,CAAC,EAAE,kBAAkB,YAAA,EAClD,0BAA0B,SAAI,EAG/B;IAED,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAErB;IAEK,aAAa,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAI/C;IAEK,eAAe,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAQnD;IAEK,QAAQ,IAAI,OAAO,CAAC,WAAW,CAAC,CAErC;IAEK,QAAQ,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAKpD;IAEK,UAAU,IAAI,OAAO,CAAC,aAAa,CAAC,CAOzC;IAEK,kBAAkB,IAAI,OAAO,CAAC,qBAAqB,CAAC,CAMzD;IAID,oDAAoD;IAC9C,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAK5B;IAED;4CACwC;IAClC,WAAW,CACf,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAEjC;IAED;iFAC6E;IACvE,cAAc,CAClB,OAAO,EAAE,WAAW,EAAE,EACtB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAEjC;YAEa,QAAQ;YAoBR,UAAU;CAQzB"}
@@ -1,7 +1,9 @@
1
1
  import { parseDsiotCapabilities } from "../codecs/dsiot/capabilities.js";
2
+ import { parseDsiotDeviceInfo } from "../codecs/dsiot/device.js";
2
3
  import { buildDsiotMultireqGet, buildDsiotMultireqUpdate, DSIOT_TARGETS, parseDsiotMultireqReply, } from "../codecs/dsiot/multireq.js";
3
4
  import { applyDsiotControl, parseDsiotSensors, parseDsiotState, } from "../codecs/dsiot/state.js";
4
5
  import { withRetry, } from "../transport.js";
6
+ import { SetStateCache } from "./setStateCache.js";
5
7
  // DSIOT endpoints (BRP084-style). Climate state is a POST (read) or PUT (write)
6
8
  // of a JSON property tree to `multireq`.
7
9
  const DSIOT_ROUTES = {
@@ -13,25 +15,34 @@ const DSIOT_ROUTES = {
13
15
  export class DsiotDaikinClient {
14
16
  transport;
15
17
  retryOptions;
16
- /** `close` closes `transport`, so give each client a transport of its own. */
17
- constructor(transport, retryOptions) {
18
+ setStateCache;
19
+ /** `close` closes `transport`, so give each client a transport of its own.
20
+ * `maxStateAgeForSetStateInMs` defaults to 0: see
21
+ * `CreateDaikinClientOptions.maxStateAgeForSetStateInMs`. */
22
+ constructor(transport, retryOptions, maxStateAgeForSetStateInMs = 0) {
18
23
  this.transport = transport;
19
24
  this.retryOptions = retryOptions;
25
+ this.setStateCache = new SetStateCache(maxStateAgeForSetStateInMs);
20
26
  }
21
27
  close() {
22
28
  return this.transport.close();
23
29
  }
30
+ async getDeviceInfo() {
31
+ return parseDsiotDeviceInfo(await this.multireqGet([DSIOT_TARGETS.adapterInfo]));
32
+ }
24
33
  async getCapabilities() {
25
34
  return parseDsiotCapabilities(await this.multireqGet([
26
35
  DSIOT_TARGETS.adapterInfo,
27
36
  DSIOT_TARGETS.indoorStatus,
37
+ DSIOT_TARGETS.outdoorStatus,
28
38
  ]));
29
39
  }
30
40
  async getState() {
31
- return parseDsiotState(await this.multireqGet([DSIOT_TARGETS.indoorStatus]));
41
+ return parseDsiotState(await this.readStatus());
32
42
  }
33
43
  async setState(control) {
34
- const values = await this.multireqGet([DSIOT_TARGETS.indoorStatus]);
44
+ const values = this.setStateCache.get() ??
45
+ (await this.multireqGet([DSIOT_TARGETS.indoorStatus]));
35
46
  await this.multireqUpdate(applyDsiotControl(values, control));
36
47
  }
37
48
  async getSensors() {
@@ -40,6 +51,13 @@ export class DsiotDaikinClient {
40
51
  DSIOT_TARGETS.outdoorStatus,
41
52
  ]));
42
53
  }
54
+ async getStateAndSensors() {
55
+ const values = await this.readStatus();
56
+ return {
57
+ state: parseDsiotState(values),
58
+ sensors: parseDsiotSensors(values),
59
+ };
60
+ }
43
61
  // --- extended controls ---------------------------------------------------
44
62
  /** Reboot the adapter (`/config/system/reboot`). */
45
63
  async reboot() {
@@ -60,7 +78,24 @@ export class DsiotDaikinClient {
60
78
  }
61
79
  async multireq(method, jsonBody, { retry = true } = {}) {
62
80
  const send = () => this.transport.send({ method, path: DSIOT_ROUTES.multireq, jsonBody });
63
- return parseDsiotMultireqReply(await (retry ? withRetry(send, this.retryOptions) : send()));
81
+ try {
82
+ return parseDsiotMultireqReply(await (retry ? withRetry(send, this.retryOptions) : send()));
83
+ }
84
+ finally {
85
+ // Even a write that failed: one that timed out may still have reached
86
+ // the unit.
87
+ if (method === "PUT") {
88
+ this.setStateCache.clear();
89
+ }
90
+ }
91
+ }
92
+ async readStatus() {
93
+ const values = await this.multireqGet([
94
+ DSIOT_TARGETS.indoorStatus,
95
+ DSIOT_TARGETS.outdoorStatus,
96
+ ]);
97
+ this.setStateCache.set(values);
98
+ return values;
64
99
  }
65
100
  }
66
101
  //# sourceMappingURL=dsiot.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dsiot.js","sourceRoot":"","sources":["../../src/clients/dsiot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EACL,qBAAqB,EACrB,wBAAwB,EACxB,aAAa,EAEb,uBAAuB,GACxB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,GAChB,MAAM,0BAA0B,CAAC;AAOlC,OAAO,EAIL,SAAS,GACV,MAAM,iBAAiB,CAAC;AAGzB,gFAAgF;AAChF,yCAAyC;AACzC,MAAM,YAAY,GAAG;IACnB,QAAQ,EAAE,iBAAiB;IAC3B,MAAM,EAAE,uBAAuB;CACvB,CAAC;AAEX;6DAC6D;AAC7D,MAAM,OAAO,iBAAiB;IAGT,SAAS;IACT,YAAY;IAH/B,8EAA8E;IAC9E,YACmB,SAA0B,EAC1B,YAAiC;yBADjC,SAAS;4BACT,YAAY;IAC5B,CAAC;IAEJ,KAAK;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,eAAe;QACnB,OAAO,sBAAsB,CAC3B,MAAM,IAAI,CAAC,WAAW,CAAC;YACrB,aAAa,CAAC,WAAW;YACzB,aAAa,CAAC,YAAY;SAC3B,CAAC,CACH,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,OAAO,eAAe,CACpB,MAAM,IAAI,CAAC,WAAW,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CACrD,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,OAAsB;QACnC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC;QACpE,MAAM,IAAI,CAAC,cAAc,CAAC,iBAAiB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAChE,CAAC;IAED,KAAK,CAAC,UAAU;QACd,OAAO,iBAAiB,CACtB,MAAM,IAAI,CAAC,WAAW,CAAC;YACrB,aAAa,CAAC,YAAY;YAC1B,aAAa,CAAC,aAAa;SAC5B,CAAC,CACH,CAAC;IACJ,CAAC;IAED,4EAA4E;IAE5E,oDAAoD;IACpD,KAAK,CAAC,MAAM;QACV,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;YACxB,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,YAAY,CAAC,MAAM;SAC1B,CAAC,CAAC;IACL,CAAC;IAED;4CACwC;IACxC,KAAK,CAAC,WAAW,CACf,OAAiB,EACjB,OAA8B;QAE9B,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC;IACxE,CAAC;IAED;iFAC6E;IAC7E,KAAK,CAAC,cAAc,CAClB,OAAsB,EACtB,OAA8B;QAE9B,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,wBAAwB,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC;IAC1E,CAAC;IAEO,KAAK,CAAC,QAAQ,CACpB,MAAsB,EACtB,QAAiB,EACjB,EAAE,KAAK,GAAG,IAAI,EAAE,GAAyB,EAAE;QAE3C,MAAM,IAAI,GAAG,GAAG,EAAE,CAChB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;QACzE,OAAO,uBAAuB,CAC5B,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAC5D,CAAC;IACJ,CAAC;CACF"}
1
+ {"version":3,"file":"dsiot.js","sourceRoot":"","sources":["../../src/clients/dsiot.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /** Caches the reply a client last read a unit's state from, for `setState`
2
+ * alone. A write carries more than the fields a control changes, so
3
+ * `setState` builds it from what the unit holds: from this reply while it is
4
+ * fresh, and from a read of its own otherwise. No read is answered from the
5
+ * cache: see DESIGN.md#the-read-before-a-write. */
6
+ export declare class SetStateCache {
7
+ private readonly maxAgeInMs;
8
+ private kept;
9
+ /** `get` answers a reply younger than `maxAgeInMs`, so 0 answers none. */
10
+ constructor(maxAgeInMs: number);
11
+ set(reply: Record<string, string>): void;
12
+ get(): Record<string, string> | undefined;
13
+ clear(): void;
14
+ }
15
+ //# sourceMappingURL=setStateCache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setStateCache.d.ts","sourceRoot":"","sources":["../../src/clients/setStateCache.ts"],"names":[],"mappings":"AAAA;;;;mDAImD;AACnD,qBAAa,aAAa;IAMZ,OAAO,CAAC,QAAQ,CAAC,UAAU;IALvC,OAAO,CAAC,IAAI,CAEE;IAEd,0EAA0E;IAC1E,YAA6B,UAAU,EAAE,MAAM,EAAI;IAEnD,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAEvC;IAED,GAAG,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAKxC;IAED,KAAK,IAAI,IAAI,CAEZ;CACF"}