daikin-local-control 0.1.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.
Files changed (115) hide show
  1. package/DESIGN.md +98 -0
  2. package/LICENSE +674 -0
  3. package/README.md +317 -0
  4. package/UNSUPPORTED.md +43 -0
  5. package/dist/authentication.d.ts +24 -0
  6. package/dist/authentication.d.ts.map +1 -0
  7. package/dist/authentication.js +30 -0
  8. package/dist/authentication.js.map +1 -0
  9. package/dist/clients/classic.d.ts +53 -0
  10. package/dist/clients/classic.d.ts.map +1 -0
  11. package/dist/clients/classic.js +142 -0
  12. package/dist/clients/classic.js.map +1 -0
  13. package/dist/clients/client.d.ts +21 -0
  14. package/dist/clients/client.d.ts.map +1 -0
  15. package/dist/clients/client.js +2 -0
  16. package/dist/clients/client.js.map +1 -0
  17. package/dist/clients/dsiot.d.ts +28 -0
  18. package/dist/clients/dsiot.d.ts.map +1 -0
  19. package/dist/clients/dsiot.js +66 -0
  20. package/dist/clients/dsiot.js.map +1 -0
  21. package/dist/codecs/classic/capabilities.d.ts +19 -0
  22. package/dist/codecs/classic/capabilities.d.ts.map +1 -0
  23. package/dist/codecs/classic/capabilities.js +208 -0
  24. package/dist/codecs/classic/capabilities.js.map +1 -0
  25. package/dist/codecs/classic/extendedControl.d.ts +20 -0
  26. package/dist/codecs/classic/extendedControl.d.ts.map +1 -0
  27. package/dist/codecs/classic/extendedControl.js +88 -0
  28. package/dist/codecs/classic/extendedControl.js.map +1 -0
  29. package/dist/codecs/classic/keyValue.d.ts +10 -0
  30. package/dist/codecs/classic/keyValue.d.ts.map +1 -0
  31. package/dist/codecs/classic/keyValue.js +36 -0
  32. package/dist/codecs/classic/keyValue.js.map +1 -0
  33. package/dist/codecs/classic/state.d.ts +18 -0
  34. package/dist/codecs/classic/state.d.ts.map +1 -0
  35. package/dist/codecs/classic/state.js +235 -0
  36. package/dist/codecs/classic/state.js.map +1 -0
  37. package/dist/codecs/credentials.d.ts +8 -0
  38. package/dist/codecs/credentials.d.ts.map +1 -0
  39. package/dist/codecs/credentials.js +14 -0
  40. package/dist/codecs/credentials.js.map +1 -0
  41. package/dist/codecs/device.d.ts +6 -0
  42. package/dist/codecs/device.d.ts.map +1 -0
  43. package/dist/codecs/device.js +35 -0
  44. package/dist/codecs/device.js.map +1 -0
  45. package/dist/codecs/dsiot/capabilities.d.ts +5 -0
  46. package/dist/codecs/dsiot/capabilities.d.ts.map +1 -0
  47. package/dist/codecs/dsiot/capabilities.js +139 -0
  48. package/dist/codecs/dsiot/capabilities.js.map +1 -0
  49. package/dist/codecs/dsiot/multireq.d.ts +37 -0
  50. package/dist/codecs/dsiot/multireq.d.ts.map +1 -0
  51. package/dist/codecs/dsiot/multireq.js +122 -0
  52. package/dist/codecs/dsiot/multireq.js.map +1 -0
  53. package/dist/codecs/dsiot/state.d.ts +92 -0
  54. package/dist/codecs/dsiot/state.d.ts.map +1 -0
  55. package/dist/codecs/dsiot/state.js +461 -0
  56. package/dist/codecs/dsiot/state.js.map +1 -0
  57. package/dist/discovery.d.ts +17 -0
  58. package/dist/discovery.d.ts.map +1 -0
  59. package/dist/discovery.js +67 -0
  60. package/dist/discovery.js.map +1 -0
  61. package/dist/error.d.ts +15 -0
  62. package/dist/error.d.ts.map +1 -0
  63. package/dist/error.js +20 -0
  64. package/dist/error.js.map +1 -0
  65. package/dist/factory.d.ts +26 -0
  66. package/dist/factory.d.ts.map +1 -0
  67. package/dist/factory.js +31 -0
  68. package/dist/factory.js.map +1 -0
  69. package/dist/index.d.ts +22 -0
  70. package/dist/index.d.ts.map +1 -0
  71. package/dist/index.js +21 -0
  72. package/dist/index.js.map +1 -0
  73. package/dist/models/capabilities.d.ts +42 -0
  74. package/dist/models/capabilities.d.ts.map +1 -0
  75. package/dist/models/capabilities.js +2 -0
  76. package/dist/models/capabilities.js.map +1 -0
  77. package/dist/models/device.d.ts +24 -0
  78. package/dist/models/device.d.ts.map +1 -0
  79. package/dist/models/device.js +2 -0
  80. package/dist/models/device.js.map +1 -0
  81. package/dist/models/extendedControl.d.ts +31 -0
  82. package/dist/models/extendedControl.d.ts.map +1 -0
  83. package/dist/models/extendedControl.js +7 -0
  84. package/dist/models/extendedControl.js.map +1 -0
  85. package/dist/models/state.d.ts +56 -0
  86. package/dist/models/state.d.ts.map +1 -0
  87. package/dist/models/state.js +49 -0
  88. package/dist/models/state.js.map +1 -0
  89. package/dist/transport.d.ts +75 -0
  90. package/dist/transport.d.ts.map +1 -0
  91. package/dist/transport.js +118 -0
  92. package/dist/transport.js.map +1 -0
  93. package/package.json +62 -0
  94. package/src/authentication.ts +53 -0
  95. package/src/clients/classic.ts +251 -0
  96. package/src/clients/client.ts +29 -0
  97. package/src/clients/dsiot.ts +116 -0
  98. package/src/codecs/classic/capabilities.ts +272 -0
  99. package/src/codecs/classic/extendedControl.ts +132 -0
  100. package/src/codecs/classic/keyValue.ts +39 -0
  101. package/src/codecs/classic/state.ts +302 -0
  102. package/src/codecs/credentials.ts +19 -0
  103. package/src/codecs/device.ts +41 -0
  104. package/src/codecs/dsiot/capabilities.ts +209 -0
  105. package/src/codecs/dsiot/multireq.ts +162 -0
  106. package/src/codecs/dsiot/state.ts +644 -0
  107. package/src/discovery.ts +85 -0
  108. package/src/error.ts +20 -0
  109. package/src/factory.ts +66 -0
  110. package/src/index.ts +21 -0
  111. package/src/models/capabilities.ts +52 -0
  112. package/src/models/device.ts +25 -0
  113. package/src/models/extendedControl.ts +41 -0
  114. package/src/models/state.ts +110 -0
  115. package/src/transport.ts +191 -0
@@ -0,0 +1,235 @@
1
+ import { takesClassicDirection, takesClassicHumidity } from "./capabilities.js";
2
+ // Maps between `DaikinState` and the classic `control_info` wire fields, and reads
3
+ // `DaikinSensors` from `get_sensor_info`.
4
+ const OPERATING_MODE_CODES = {
5
+ auto: "1",
6
+ dehumidify: "2",
7
+ cool: "3",
8
+ heat: "4",
9
+ fan: "6",
10
+ };
11
+ const OPERATING_MODES_BY_CODE = {
12
+ "0": "auto",
13
+ "1": "auto",
14
+ "7": "auto",
15
+ "2": "dehumidify",
16
+ "3": "cool",
17
+ "4": "heat",
18
+ "6": "fan",
19
+ };
20
+ const FAN_SPEED_CODES = {
21
+ auto: "A",
22
+ silent: "B",
23
+ level1: "3",
24
+ level2: "4",
25
+ level3: "5",
26
+ level4: "6",
27
+ level5: "7",
28
+ };
29
+ const FAN_SPEEDS_BY_CODE = Object.fromEntries(Object.entries(FAN_SPEED_CODES).map(([speed, code]) => [
30
+ code,
31
+ speed,
32
+ ]));
33
+ const SWING_MODE_CODES = {
34
+ off: "0",
35
+ vertical: "1",
36
+ horizontal: "2",
37
+ both: "3",
38
+ };
39
+ const SWING_MODES_BY_CODE = Object.fromEntries(Object.entries(SWING_MODE_CODES).map(([swing, code]) => [
40
+ code,
41
+ swing,
42
+ ]));
43
+ // `f_dir_ud` and `f_dir_lr` carry a digit for stop and each fixed position, and
44
+ // a letter for the rest.
45
+ const LOUVER_STOP = "0";
46
+ const LOUVER_SWING = "S";
47
+ const VERTICAL_POSITION_CODES = {
48
+ stop: LOUVER_STOP,
49
+ position1: "1",
50
+ position2: "2",
51
+ position3: "3",
52
+ position4: "4",
53
+ position5: "5",
54
+ swing: LOUVER_SWING,
55
+ naturalWind: "N",
56
+ auto: "A",
57
+ floorWarming: "F",
58
+ };
59
+ const HORIZONTAL_POSITION_CODES = {
60
+ stop: LOUVER_STOP,
61
+ position1: "1",
62
+ position2: "2",
63
+ position3: "3",
64
+ position4: "4",
65
+ position5: "5",
66
+ swing: LOUVER_SWING,
67
+ auto: "A",
68
+ };
69
+ const VERTICAL_POSITIONS_BY_CODE = Object.fromEntries(Object.entries(VERTICAL_POSITION_CODES).map(([position, code]) => [
70
+ code,
71
+ position,
72
+ ]));
73
+ const HORIZONTAL_POSITIONS_BY_CODE = Object.fromEntries(Object.entries(HORIZONTAL_POSITION_CODES).map(([position, code]) => [
74
+ code,
75
+ position,
76
+ ]));
77
+ const HUMIDITY_SETTING_CODES = {
78
+ off: "0",
79
+ autoLow: "AUTO_L",
80
+ auto: "AUTO",
81
+ autoHigh: "AUTO_H",
82
+ continuous: "CONTINUE",
83
+ };
84
+ const HUMIDITY_SETTINGS_BY_CODE = Object.fromEntries(Object.entries(HUMIDITY_SETTING_CODES).map(([setting, code]) => [
85
+ code,
86
+ setting,
87
+ ]));
88
+ // Fan mode keeps no setpoint memory, and dehumidify runs the fan on auto only.
89
+ const NO_SETPOINT = "--";
90
+ const DEHUMIDIFY_FAN_SPEED = "A";
91
+ // In `ndfd<mode>`, a louver the unit lacks.
92
+ const NO_LOUVER = "-";
93
+ /** Turns a `get_control_info` reply into a `DaikinState`. A `mode` or `f_rate`
94
+ * outside the model reads as `auto`, an `f_dir` outside it as `off`, and an
95
+ * `f_dir_ud` or `f_dir_lr` outside it as `null`. */
96
+ export function parseClassicState(fields) {
97
+ return {
98
+ power: fields.pow === "1",
99
+ mode: OPERATING_MODES_BY_CODE[fields.mode ?? ""] ?? "auto",
100
+ targetTemperatureInC: parseNumeric(fields.stemp),
101
+ targetHumidity: parseTargetHumidity(fields.shum),
102
+ fanSpeed: FAN_SPEEDS_BY_CODE[fields.f_rate ?? ""] ?? "auto",
103
+ swingMode: SWING_MODES_BY_CODE[fields.f_dir ?? ""] ?? "off",
104
+ verticalPosition: VERTICAL_POSITIONS_BY_CODE[fields.f_dir_ud ?? ""] ?? null,
105
+ horizontalPosition: HORIZONTAL_POSITIONS_BY_CODE[fields.f_dir_lr ?? ""] ?? null,
106
+ };
107
+ }
108
+ export function parseClassicSensors(fields) {
109
+ return {
110
+ indoorTemperatureInC: parseNumeric(fields.htemp),
111
+ outdoorTemperatureInC: parseNumeric(fields.otemp),
112
+ indoorHumidityInPercent: parseNumeric(fields.hhum),
113
+ };
114
+ }
115
+ /** Turns `current`, the `get_control_info` reply, and a control into the
116
+ * `set_control_info` query: power and mode, the setpoint, humidity and fan
117
+ * speed for the target mode, and the airflow fields the unit takes. When the
118
+ * mode changes, each comes from the target mode's memory: `dt`, `dh`, `dfr`,
119
+ * `dfd` and, for the louvers, `ndfd`. `capabilityFields`, the field map of
120
+ * `mergeClassicCapabilityFields`, says which fields the unit takes: `shum`
121
+ * unless it is `subtype=qa`, `f_dir_ud` and `f_dir_lr` on a 3D unit
122
+ * (`en_fdir2`), and `f_dir` on a unit that takes a direction. It drops a
123
+ * `targetTemperatureInC` in dehumidify, writes `mode=0` and `mode=7` as
124
+ * `mode=1`, and never echoes `ret`, `adv` or the other modes' memory. */
125
+ export function applyClassicControl(current, control, capabilityFields) {
126
+ const takesDirection = takesClassicDirection(capabilityFields);
127
+ const heldMode = OPERATING_MODES_BY_CODE[current.mode ?? ""];
128
+ // A mode outside the model is sent back as it came.
129
+ const currentMode = heldMode === undefined
130
+ ? (current.mode ?? "")
131
+ : OPERATING_MODE_CODES[heldMode];
132
+ const mode = control.mode === undefined
133
+ ? currentMode
134
+ : OPERATING_MODE_CODES[control.mode];
135
+ const modeChanged = mode !== currentMode;
136
+ const remembered = (field, memoryPrefix) => (modeChanged ? current[`${memoryPrefix}${mode}`] : undefined) ??
137
+ current[field] ??
138
+ "";
139
+ const power = control.power ?? current.pow === "1";
140
+ const next = { pow: power ? "1" : "0", mode };
141
+ const setpointFrozen = mode === OPERATING_MODE_CODES.fan;
142
+ // Only a mode in the model has a `dt` and a `dh` memory.
143
+ const hasMemory = !setpointFrozen && (control.mode !== undefined || heldMode !== undefined);
144
+ next.stemp = setpointFrozen
145
+ ? NO_SETPOINT
146
+ : control.targetTemperatureInC != null &&
147
+ mode !== OPERATING_MODE_CODES.dehumidify
148
+ ? control.targetTemperatureInC.toFixed(1)
149
+ : remembered("stemp", "dt");
150
+ if (hasMemory) {
151
+ next[`dt${mode}`] = next.stemp;
152
+ }
153
+ if (takesClassicHumidity(capabilityFields)) {
154
+ next.shum = setpointFrozen
155
+ ? NO_SETPOINT
156
+ : control.targetHumidity != null
157
+ ? encodeTargetHumidity(control.targetHumidity)
158
+ : remembered("shum", "dh");
159
+ if (hasMemory) {
160
+ next[`dh${mode}`] = next.shum;
161
+ }
162
+ }
163
+ next.f_rate =
164
+ mode === OPERATING_MODE_CODES.dehumidify
165
+ ? DEHUMIDIFY_FAN_SPEED
166
+ : control.fanSpeed === undefined
167
+ ? remembered("f_rate", "dfr")
168
+ : FAN_SPEED_CODES[control.fanSpeed];
169
+ if (capabilityFields.en_fdir2 === "1") {
170
+ // `ndfd<mode>` holds the mode's `f_dir_ud` value, then its `f_dir_lr`
171
+ // value. A value outside the model is sent back as it came.
172
+ const louverMemory = modeChanged ? current[`ndfd${mode}`] : undefined;
173
+ let vertical = rememberedLouver(louverMemory, 0) || current.f_dir_ud || LOUVER_STOP;
174
+ let horizontal = rememberedLouver(louverMemory, 1) || current.f_dir_lr || LOUVER_STOP;
175
+ if (control.swingMode !== undefined) {
176
+ const swingsVertically = control.swingMode === "vertical" || control.swingMode === "both";
177
+ const swingsHorizontally = control.swingMode === "horizontal" || control.swingMode === "both";
178
+ vertical = swingsVertically
179
+ ? LOUVER_SWING
180
+ : vertical === LOUVER_SWING
181
+ ? LOUVER_STOP
182
+ : vertical;
183
+ horizontal = swingsHorizontally
184
+ ? LOUVER_SWING
185
+ : horizontal === LOUVER_SWING
186
+ ? LOUVER_STOP
187
+ : horizontal;
188
+ }
189
+ if (control.verticalPosition != null) {
190
+ vertical = VERTICAL_POSITION_CODES[control.verticalPosition];
191
+ }
192
+ if (control.horizontalPosition != null) {
193
+ horizontal = HORIZONTAL_POSITION_CODES[control.horizontalPosition];
194
+ }
195
+ next.f_dir_ud = vertical;
196
+ next.f_dir_lr = horizontal;
197
+ if (takesDirection) {
198
+ next.f_dir = String((vertical === LOUVER_SWING ? 1 : 0) |
199
+ (horizontal === LOUVER_SWING ? 2 : 0));
200
+ }
201
+ }
202
+ else if (takesDirection) {
203
+ next.f_dir =
204
+ control.swingMode === undefined
205
+ ? remembered("f_dir", "dfd")
206
+ : SWING_MODE_CODES[control.swingMode];
207
+ }
208
+ return next;
209
+ }
210
+ function parseTargetHumidity(shum) {
211
+ const setting = HUMIDITY_SETTINGS_BY_CODE[shum ?? ""];
212
+ if (setting !== undefined) {
213
+ return setting;
214
+ }
215
+ const percent = parseNumeric(shum);
216
+ return percent === null ? null : { percent };
217
+ }
218
+ function encodeTargetHumidity(targetHumidity) {
219
+ return typeof targetHumidity === "string"
220
+ ? HUMIDITY_SETTING_CODES[targetHumidity]
221
+ : String(targetHumidity.percent);
222
+ }
223
+ function rememberedLouver(louverMemory, index) {
224
+ const value = louverMemory?.[index];
225
+ return value === NO_LOUVER ? undefined : value;
226
+ }
227
+ function parseNumeric(value) {
228
+ if (value === undefined || value === "") {
229
+ return null;
230
+ }
231
+ const parsed = Number(value);
232
+ // Modes without a setpoint answer "M", "--" or "-", which are not numbers.
233
+ return Number.isFinite(parsed) ? parsed : null;
234
+ }
235
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../../src/codecs/classic/state.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAEhF,mFAAmF;AACnF,0CAA0C;AAE1C,MAAM,oBAAoB,GAAkC;IAC1D,IAAI,EAAE,GAAG;IACT,UAAU,EAAE,GAAG;IACf,IAAI,EAAE,GAAG;IACT,IAAI,EAAE,GAAG;IACT,GAAG,EAAE,GAAG;CACT,CAAC;AAEF,MAAM,uBAAuB,GAAkC;IAC7D,GAAG,EAAE,MAAM;IACX,GAAG,EAAE,MAAM;IACX,GAAG,EAAE,MAAM;IACX,GAAG,EAAE,YAAY;IACjB,GAAG,EAAE,MAAM;IACX,GAAG,EAAE,MAAM;IACX,GAAG,EAAE,KAAK;CACX,CAAC;AAEF,MAAM,eAAe,GAA6B;IAChD,IAAI,EAAE,GAAG;IACT,MAAM,EAAE,GAAG;IACX,MAAM,EAAE,GAAG;IACX,MAAM,EAAE,GAAG;IACX,MAAM,EAAE,GAAG;IACX,MAAM,EAAE,GAAG;IACX,MAAM,EAAE,GAAG;CACZ,CAAC;AAEF,MAAM,kBAAkB,GAA6B,MAAM,CAAC,WAAW,CACrE,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;IACrD,IAAI;IACJ,KAAiB;CAClB,CAAC,CACH,CAAC;AAEF,MAAM,gBAAgB,GAA8B;IAClD,GAAG,EAAE,GAAG;IACR,QAAQ,EAAE,GAAG;IACb,UAAU,EAAE,GAAG;IACf,IAAI,EAAE,GAAG;CACV,CAAC;AAEF,MAAM,mBAAmB,GAA8B,MAAM,CAAC,WAAW,CACvE,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;IACtD,IAAI;IACJ,KAAkB;CACnB,CAAC,CACH,CAAC;AAEF,gFAAgF;AAChF,yBAAyB;AACzB,MAAM,WAAW,GAAG,GAAG,CAAC;AACxB,MAAM,YAAY,GAAG,GAAG,CAAC;AACzB,MAAM,uBAAuB,GAAqC;IAChE,IAAI,EAAE,WAAW;IACjB,SAAS,EAAE,GAAG;IACd,SAAS,EAAE,GAAG;IACd,SAAS,EAAE,GAAG;IACd,SAAS,EAAE,GAAG;IACd,SAAS,EAAE,GAAG;IACd,KAAK,EAAE,YAAY;IACnB,WAAW,EAAE,GAAG;IAChB,IAAI,EAAE,GAAG;IACT,YAAY,EAAE,GAAG;CAClB,CAAC;AACF,MAAM,yBAAyB,GAAuC;IACpE,IAAI,EAAE,WAAW;IACjB,SAAS,EAAE,GAAG;IACd,SAAS,EAAE,GAAG;IACd,SAAS,EAAE,GAAG;IACd,SAAS,EAAE,GAAG;IACd,SAAS,EAAE,GAAG;IACd,KAAK,EAAE,YAAY;IACnB,IAAI,EAAE,GAAG;CACV,CAAC;AAEF,MAAM,0BAA0B,GAC9B,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;IAChE,IAAI;IACJ,QAA4B;CAC7B,CAAC,CACH,CAAC;AAEJ,MAAM,4BAA4B,GAChC,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;IAClE,IAAI;IACJ,QAA8B;CAC/B,CAAC,CACH,CAAC;AAEJ,MAAM,sBAAsB,GAAoC;IAC9D,GAAG,EAAE,GAAG;IACR,OAAO,EAAE,QAAQ;IACjB,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,QAAQ;IAClB,UAAU,EAAE,UAAU;CACvB,CAAC;AAEF,MAAM,yBAAyB,GAC7B,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;IAC9D,IAAI;IACJ,OAA0B;CAC3B,CAAC,CACH,CAAC;AAEJ,+EAA+E;AAC/E,MAAM,WAAW,GAAG,IAAI,CAAC;AACzB,MAAM,oBAAoB,GAAG,GAAG,CAAC;AACjC,4CAA4C;AAC5C,MAAM,SAAS,GAAG,GAAG,CAAC;AAEtB;;oDAEoD;AACpD,MAAM,UAAU,iBAAiB,CAAC,MAA8B;IAC9D,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,GAAG,KAAK,GAAG;QACzB,IAAI,EAAE,uBAAuB,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,IAAI,MAAM;QAC1D,oBAAoB,EAAE,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC;QAChD,cAAc,EAAE,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC;QAChD,QAAQ,EAAE,kBAAkB,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,IAAI,MAAM;QAC3D,SAAS,EAAE,mBAAmB,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,IAAI,KAAK;QAC3D,gBAAgB,EAAE,0BAA0B,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC,IAAI,IAAI;QAC3E,kBAAkB,EAChB,4BAA4B,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC,IAAI,IAAI;KAC9D,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,MAA8B;IAE9B,OAAO;QACL,oBAAoB,EAAE,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC;QAChD,qBAAqB,EAAE,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC;QACjD,uBAAuB,EAAE,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC;KACnD,CAAC;AACJ,CAAC;AAED;;;;;;;;;yEASyE;AACzE,MAAM,UAAU,mBAAmB,CACjC,OAA+B,EAC/B,OAAsB,EACtB,gBAAwC;IAExC,MAAM,cAAc,GAAG,qBAAqB,CAAC,gBAAgB,CAAC,CAAC;IAC/D,MAAM,QAAQ,GAAG,uBAAuB,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IAC7D,oDAAoD;IACpD,MAAM,WAAW,GACf,QAAQ,KAAK,SAAS;QACpB,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;QACtB,CAAC,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IACrC,MAAM,IAAI,GACR,OAAO,CAAC,IAAI,KAAK,SAAS;QACxB,CAAC,CAAC,WAAW;QACb,CAAC,CAAC,oBAAoB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,WAAW,GAAG,IAAI,KAAK,WAAW,CAAC;IACzC,MAAM,UAAU,GAAG,CAAC,KAAa,EAAE,YAAoB,EAAE,EAAE,CACzD,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,YAAY,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC7D,OAAO,CAAC,KAAK,CAAC;QACd,EAAE,CAAC;IAEL,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,GAAG,KAAK,GAAG,CAAC;IACnD,MAAM,IAAI,GAA2B,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;IAEtE,MAAM,cAAc,GAAG,IAAI,KAAK,oBAAoB,CAAC,GAAG,CAAC;IACzD,yDAAyD;IACzD,MAAM,SAAS,GACb,CAAC,cAAc,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,IAAI,QAAQ,KAAK,SAAS,CAAC,CAAC;IAC5E,IAAI,CAAC,KAAK,GAAG,cAAc;QACzB,CAAC,CAAC,WAAW;QACb,CAAC,CAAC,OAAO,CAAC,oBAAoB,IAAI,IAAI;YAClC,IAAI,KAAK,oBAAoB,CAAC,UAAU;YAC1C,CAAC,CAAC,OAAO,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC,CAAC;YACzC,CAAC,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAChC,IAAI,SAAS,EAAE,CAAC;QACd,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC;IACjC,CAAC;IACD,IAAI,oBAAoB,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAC3C,IAAI,CAAC,IAAI,GAAG,cAAc;YACxB,CAAC,CAAC,WAAW;YACb,CAAC,CAAC,OAAO,CAAC,cAAc,IAAI,IAAI;gBAC9B,CAAC,CAAC,oBAAoB,CAAC,OAAO,CAAC,cAAc,CAAC;gBAC9C,CAAC,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC/B,IAAI,SAAS,EAAE,CAAC;YACd,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC;QAChC,CAAC;IACH,CAAC;IAED,IAAI,CAAC,MAAM;QACT,IAAI,KAAK,oBAAoB,CAAC,UAAU;YACtC,CAAC,CAAC,oBAAoB;YACtB,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS;gBAC9B,CAAC,CAAC,UAAU,CAAC,QAAQ,EAAE,KAAK,CAAC;gBAC7B,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE1C,IAAI,gBAAgB,CAAC,QAAQ,KAAK,GAAG,EAAE,CAAC;QACtC,sEAAsE;QACtE,4DAA4D;QAC5D,MAAM,YAAY,GAAG,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACtE,IAAI,QAAQ,GACV,gBAAgB,CAAC,YAAY,EAAE,CAAC,CAAC,IAAI,OAAO,CAAC,QAAQ,IAAI,WAAW,CAAC;QACvE,IAAI,UAAU,GACZ,gBAAgB,CAAC,YAAY,EAAE,CAAC,CAAC,IAAI,OAAO,CAAC,QAAQ,IAAI,WAAW,CAAC;QACvE,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YACpC,MAAM,gBAAgB,GACpB,OAAO,CAAC,SAAS,KAAK,UAAU,IAAI,OAAO,CAAC,SAAS,KAAK,MAAM,CAAC;YACnE,MAAM,kBAAkB,GACtB,OAAO,CAAC,SAAS,KAAK,YAAY,IAAI,OAAO,CAAC,SAAS,KAAK,MAAM,CAAC;YACrE,QAAQ,GAAG,gBAAgB;gBACzB,CAAC,CAAC,YAAY;gBACd,CAAC,CAAC,QAAQ,KAAK,YAAY;oBACzB,CAAC,CAAC,WAAW;oBACb,CAAC,CAAC,QAAQ,CAAC;YACf,UAAU,GAAG,kBAAkB;gBAC7B,CAAC,CAAC,YAAY;gBACd,CAAC,CAAC,UAAU,KAAK,YAAY;oBAC3B,CAAC,CAAC,WAAW;oBACb,CAAC,CAAC,UAAU,CAAC;QACnB,CAAC;QACD,IAAI,OAAO,CAAC,gBAAgB,IAAI,IAAI,EAAE,CAAC;YACrC,QAAQ,GAAG,uBAAuB,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAC/D,CAAC;QACD,IAAI,OAAO,CAAC,kBAAkB,IAAI,IAAI,EAAE,CAAC;YACvC,UAAU,GAAG,yBAAyB,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;QACrE,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC;QAC3B,IAAI,cAAc,EAAE,CAAC;YACnB,IAAI,CAAC,KAAK,GAAG,MAAM,CACjB,CAAC,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBACjC,CAAC,UAAU,KAAK,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CACxC,CAAC;QACJ,CAAC;IACH,CAAC;SAAM,IAAI,cAAc,EAAE,CAAC;QAC1B,IAAI,CAAC,KAAK;YACR,OAAO,CAAC,SAAS,KAAK,SAAS;gBAC7B,CAAC,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC;gBAC5B,CAAC,CAAC,gBAAgB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,mBAAmB,CAAC,IAAwB;IACnD,MAAM,OAAO,GAAG,yBAAyB,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IACtD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACnC,OAAO,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC;AAC/C,CAAC;AAED,SAAS,oBAAoB,CAAC,cAA8B;IAC1D,OAAO,OAAO,cAAc,KAAK,QAAQ;QACvC,CAAC,CAAC,sBAAsB,CAAC,cAAc,CAAC;QACxC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,gBAAgB,CACvB,YAAgC,EAChC,KAAa;IAEb,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC,KAAK,CAAC,CAAC;IACpC,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;AACjD,CAAC;AAED,SAAS,YAAY,CAAC,KAAyB;IAC7C,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;QACxC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7B,2EAA2E;IAC3E,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACjD,CAAC"}
@@ -0,0 +1,8 @@
1
+ /** The header that carries the terminal uuid on every call. The adapter takes
2
+ * the uuid without its dashes. */
3
+ export declare function encodeTerminalUuid(uuid: string): Record<string, string>;
4
+ /** The query parameter a classic adapter takes the local password as. */
5
+ export declare function encodeClassicLocalPassword(localPassword: string): Record<string, string>;
6
+ /** The header a DSIOT adapter takes the local password as. */
7
+ export declare function encodeDsiotLocalPassword(localPassword: string): Record<string, string>;
8
+ //# sourceMappingURL=credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/codecs/credentials.ts"],"names":[],"mappings":"AAAA;kCACkC;AAClC,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAEvE;AAED,yEAAyE;AACzE,wBAAgB,0BAA0B,CACxC,aAAa,EAAE,MAAM,GACpB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAExB;AAED,8DAA8D;AAC9D,wBAAgB,wBAAwB,CACtC,aAAa,EAAE,MAAM,GACpB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAExB"}
@@ -0,0 +1,14 @@
1
+ /** The header that carries the terminal uuid on every call. The adapter takes
2
+ * the uuid without its dashes. */
3
+ export function encodeTerminalUuid(uuid) {
4
+ return { "X-Daikin-uuid": uuid.replaceAll("-", "") };
5
+ }
6
+ /** The query parameter a classic adapter takes the local password as. */
7
+ export function encodeClassicLocalPassword(localPassword) {
8
+ return { lpw: localPassword };
9
+ }
10
+ /** The header a DSIOT adapter takes the local password as. */
11
+ export function encodeDsiotLocalPassword(localPassword) {
12
+ return { Authorization: `Basic ${localPassword}` };
13
+ }
14
+ //# sourceMappingURL=credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/codecs/credentials.ts"],"names":[],"mappings":"AAAA;kCACkC;AAClC,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,OAAO,EAAE,eAAe,EAAE,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC;AACvD,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,0BAA0B,CACxC,aAAqB;IAErB,OAAO,EAAE,GAAG,EAAE,aAAa,EAAE,CAAC;AAChC,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,wBAAwB,CACtC,aAAqB;IAErB,OAAO,EAAE,aAAa,EAAE,SAAS,aAAa,EAAE,EAAE,CAAC;AACrD,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { DaikinDevice } from "../models/device.js";
2
+ /** Turns a `basic_info` reply into a `DaikinDevice`: `type=GPF` marks a DSIOT
3
+ * adapter, and `api_port`, when present, is the HTTP port and is appended to
4
+ * `host`, the address the reply came from. */
5
+ export declare function parseDevice(host: string, basicInfo: Record<string, string>): DaikinDevice;
6
+ //# sourceMappingURL=device.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../src/codecs/device.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAKxD;;8CAE8C;AAC9C,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,YAAY,CAiBd"}
@@ -0,0 +1,35 @@
1
+ const DSIOT_TYPE = "GPF";
2
+ const MARVELL_ADP_KIND = "3";
3
+ /** Turns a `basic_info` reply into a `DaikinDevice`: `type=GPF` marks a DSIOT
4
+ * adapter, and `api_port`, when present, is the HTTP port and is appended to
5
+ * `host`, the address the reply came from. */
6
+ export function parseDevice(host, basicInfo) {
7
+ const protocol = basicInfo.type === DSIOT_TYPE ? "dsiot" : "classic";
8
+ const secure = basicInfo.en_secure === "1";
9
+ return {
10
+ host: basicInfo.api_port ? `${host}:${basicInfo.api_port}` : host,
11
+ protocol,
12
+ name: decodeName(basicInfo.name),
13
+ // Only classic adapters register terminals.
14
+ requiresRegistration: secure && protocol === "classic",
15
+ // Only a Marvell adapter (adp_kind=3) in secure mode speaks HTTPS; every
16
+ // other adapter, DSIOT included, stays on HTTP on the LAN.
17
+ usesHttps: secure &&
18
+ protocol === "classic" &&
19
+ basicInfo.adp_kind === MARVELL_ADP_KIND,
20
+ requiresLocalPassword: basicInfo.lpw_flag === "1",
21
+ };
22
+ }
23
+ // The name is form-encoded: `+` is a space.
24
+ function decodeName(value) {
25
+ if (value === undefined) {
26
+ return undefined;
27
+ }
28
+ try {
29
+ return decodeURIComponent(value.replaceAll("+", " "));
30
+ }
31
+ catch {
32
+ return value;
33
+ }
34
+ }
35
+ //# sourceMappingURL=device.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device.js","sourceRoot":"","sources":["../../src/codecs/device.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,GAAG,KAAK,CAAC;AACzB,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAE7B;;8CAE8C;AAC9C,MAAM,UAAU,WAAW,CACzB,IAAY,EACZ,SAAiC;IAEjC,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;IACrE,MAAM,MAAM,GAAG,SAAS,CAAC,SAAS,KAAK,GAAG,CAAC;IAC3C,OAAO;QACL,IAAI,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI;QACjE,QAAQ;QACR,IAAI,EAAE,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC;QAChC,4CAA4C;QAC5C,oBAAoB,EAAE,MAAM,IAAI,QAAQ,KAAK,SAAS;QACtD,yEAAyE;QACzE,2DAA2D;QAC3D,SAAS,EACP,MAAM;YACN,QAAQ,KAAK,SAAS;YACtB,SAAS,CAAC,QAAQ,KAAK,gBAAgB;QACzC,qBAAqB,EAAE,SAAS,CAAC,QAAQ,KAAK,GAAG;KAClD,CAAC;AACJ,CAAC;AAED,4CAA4C;AAC5C,SAAS,UAAU,CAAC,KAAyB;IAC3C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,CAAC;QACH,OAAO,kBAAkB,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { DaikinCapabilities } from "../../models/capabilities.js";
2
+ /** Turns the flattened `adp_i` and indoor `dgc_status` trees (with `md`) into
3
+ * `DaikinCapabilities`. Setpoints count half degrees. */
4
+ export declare function parseDsiotCapabilities(values: Record<string, string>): DaikinCapabilities;
5
+ //# sourceMappingURL=capabilities.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../../../src/codecs/dsiot/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAEnB,MAAM,8BAA8B,CAAC;AA+CtC;yDACyD;AACzD,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,kBAAkB,CAkEpB"}
@@ -0,0 +1,139 @@
1
+ import { FAN_SPEEDS, FIXED_LOUVER_POSITIONS, HORIZONTAL_POSITIONS, HUMIDITY_SETTINGS, OPERATING_MODES, SWING_MODES, VERTICAL_POSITIONS, } from "../../models/state.js";
2
+ import { DSIOT_HORIZONTAL_POSITION_VALUES, DSIOT_MODE_PATHS, DSIOT_PATHS, DSIOT_VERTICAL_POSITION_VALUES, decodeDsiotLittleEndian, } from "./state.js";
3
+ const MODE_PATHS = Object.values(DSIOT_MODE_PATHS);
4
+ const ADAPTER_PATHS = {
5
+ region: "adp_i.reg",
6
+ kind: "adp_i.kind",
7
+ energyMonitoring: "adp_i.func.en_ipower",
8
+ demandControl: "adp_i.func.en_demand",
9
+ scheduleTimer: "adp_i.func.en_scdltmr",
10
+ };
11
+ const COOLING_ONLY_MODEL_TYPE = "01";
12
+ const COOLING_ONLY_MODES = [
13
+ "dehumidify",
14
+ "cool",
15
+ "fan",
16
+ ];
17
+ // The fixed positions, 1-14, in a louver leaf's `md.mx`.
18
+ const FIXED_LOUVER_MASK = 0x7ffe;
19
+ const FIXED_POSITIONS = FIXED_LOUVER_POSITIONS;
20
+ /** Turns the flattened `adp_i` and indoor `dgc_status` trees (with `md`) into
21
+ * `DaikinCapabilities`. Setpoints count half degrees. */
22
+ export function parseDsiotCapabilities(values) {
23
+ const modes = values[DSIOT_PATHS.modelType] === COOLING_ONLY_MODEL_TYPE
24
+ ? [...COOLING_ONLY_MODES]
25
+ : [...OPERATING_MODES];
26
+ const offered = (mode, range) => modes.includes(mode) ? range : null;
27
+ // A mode takes a humidity setting when the unit reports the mode's flag.
28
+ const humiditySettings = (mode) => {
29
+ const flag = DSIOT_MODE_PATHS[mode].humidity?.flag;
30
+ return modes.includes(mode) && flag !== undefined && flag in values
31
+ ? [...HUMIDITY_SETTINGS]
32
+ : [];
33
+ };
34
+ const vertical = hasLouver(values, "vertical");
35
+ const horizontal = hasLouver(values, "horizontal");
36
+ const energyMonitoring = values[ADAPTER_PATHS.energyMonitoring] === "1" &&
37
+ values[DSIOT_PATHS.energyMonitoring] === "01";
38
+ return {
39
+ modes,
40
+ fanSpeeds: fanSpeeds(values),
41
+ swingModes: swingModes(vertical, horizontal),
42
+ verticalPositions: vertical
43
+ ? verticalPositions(louverMask(values, "vertical"))
44
+ : [],
45
+ horizontalPositions: horizontal
46
+ ? horizontalPositions(louverMask(values, "horizontal"))
47
+ : [],
48
+ targetTemperatureInC: {
49
+ auto: offered("auto", { min: 18, max: 30, step: 0.5 }),
50
+ cool: offered("cool", range(values, DSIOT_MODE_PATHS.cool.setpoint, 18, 32)),
51
+ heat: offered("heat", range(values, DSIOT_MODE_PATHS.heat.setpoint, 10, 30)),
52
+ dehumidify: null,
53
+ fan: null,
54
+ },
55
+ targetHumidity: {
56
+ auto: humiditySettings("auto"),
57
+ // Dehumidify takes no off.
58
+ dehumidify: humiditySettings("dehumidify").filter((setting) => setting !== "off"),
59
+ cool: humiditySettings("cool"),
60
+ heat: humiditySettings("heat"),
61
+ fan: [],
62
+ },
63
+ // Which leaf reports the special air outlet is not known: see
64
+ // UNSUPPORTED.md.
65
+ specialOutlet: false,
66
+ energyMonitoring,
67
+ demandControl: energyMonitoring &&
68
+ values[ADAPTER_PATHS.kind] === "4" &&
69
+ values[ADAPTER_PATHS.demandControl] === "1",
70
+ scheduleTimer: ["1", "2"].includes(values[ADAPTER_PATHS.scheduleTimer] ?? ""),
71
+ model: values[DSIOT_PATHS.model],
72
+ };
73
+ }
74
+ function hasLouver(values, axis) {
75
+ return MODE_PATHS.some((paths) => paths[axis] in values);
76
+ }
77
+ // Every value the unit takes on an axis in any mode, as `md.mx` bits.
78
+ function louverMask(values, axis) {
79
+ return MODE_PATHS.reduce((mask, paths) => mask | decodeDsiotLittleEndian(values[`${paths[axis]}.md.mx`] ?? ""), 0);
80
+ }
81
+ function takes(mask, value) {
82
+ return value !== undefined && (mask & (1 << value)) !== 0;
83
+ }
84
+ // Japanese units (`jp`) follow other rules: see UNSUPPORTED.md.
85
+ function fanSpeeds(values) {
86
+ const region = values[ADAPTER_PATHS.region];
87
+ if (!region || region === "jp") {
88
+ return [];
89
+ }
90
+ return MODE_PATHS.some(({ fanSpeed }) => fanSpeed in values)
91
+ ? [...FAN_SPEEDS]
92
+ : [];
93
+ }
94
+ function swingModes(vertical, horizontal) {
95
+ if (vertical && horizontal) {
96
+ return [...SWING_MODES];
97
+ }
98
+ if (vertical) {
99
+ return ["off", "vertical"];
100
+ }
101
+ return horizontal ? ["off", "horizontal"] : [];
102
+ }
103
+ // A unit that takes n fixed values offers the first n fixed positions, as
104
+ // `parseDsiotState` names them by rank.
105
+ function verticalPositions(mask) {
106
+ // Without `md.mx` the unit does not say what it takes.
107
+ if (mask === 0) {
108
+ return ["stop", "swing"];
109
+ }
110
+ const fixedCount = bitCount(mask & FIXED_LOUVER_MASK);
111
+ return VERTICAL_POSITIONS.filter((position) => {
112
+ const rank = FIXED_POSITIONS.indexOf(position);
113
+ return rank === -1
114
+ ? takes(mask, DSIOT_VERTICAL_POSITION_VALUES[position])
115
+ : rank < fixedCount;
116
+ });
117
+ }
118
+ // `parseDsiotState` reads a fixed position as `stop`, so stop is always
119
+ // offered: see UNSUPPORTED.md.
120
+ function horizontalPositions(mask) {
121
+ return HORIZONTAL_POSITIONS.filter((position) => position === "stop" ||
122
+ takes(mask, DSIOT_HORIZONTAL_POSITION_VALUES[position]));
123
+ }
124
+ function bitCount(mask) {
125
+ return mask.toString(2).replaceAll("0", "").length;
126
+ }
127
+ // A setpoint's `md.mi` and `md.mx` count half degrees. Without both, the range
128
+ // is `fallbackMin` to `ceiling`, and `ceiling` caps the unit's own maximum.
129
+ function range(values, setpoint, fallbackMin, ceiling) {
130
+ const min = decodeDsiotLittleEndian(values[`${setpoint?.path}.md.mi`] ?? "") / 2;
131
+ const max = decodeDsiotLittleEndian(values[`${setpoint?.path}.md.mx`] ?? "") / 2;
132
+ const reported = Number.isFinite(min) && Number.isFinite(max);
133
+ return {
134
+ min: reported ? min : fallbackMin,
135
+ max: reported ? Math.min(max, ceiling) : ceiling,
136
+ step: 0.5,
137
+ };
138
+ }
139
+ //# sourceMappingURL=capabilities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../../src/codecs/dsiot/capabilities.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ export declare const DSIOT_OPERATIONS: {
2
+ readonly get: 2;
3
+ readonly update: 3;
4
+ readonly delete: 4;
5
+ };
6
+ /** The indoor and the outdoor unit are separate edges on the adapter. */
7
+ export declare const DSIOT_EDGES: {
8
+ readonly indoor: "adr_0100";
9
+ readonly outdoor: "adr_0200";
10
+ };
11
+ /** What a read fetches, as the `to` of a request: whole trees, never single
12
+ * leaves. */
13
+ export declare const DSIOT_TARGETS: {
14
+ readonly adapterInfo: "/dsiot/edge.adp_i?filter=pv";
15
+ readonly indoorStatus: "/dsiot/edge/adr_0100.dgc_status?filter=pv,md";
16
+ readonly outdoorStatus: "/dsiot/edge/adr_0200.dgc_status?filter=pv,md";
17
+ };
18
+ /** One leaf to write: `path` is dotted from its resource, such as
19
+ * `dgc_status.e_1002.e_A002.p_01`, and `value` is the leaf's hex string. */
20
+ export interface DsiotUpdate {
21
+ path: string;
22
+ value: string;
23
+ }
24
+ export declare function buildDsiotMultireqGet(targets: readonly string[]): object;
25
+ /** Builds the body of a multireq write: one `update` request per resource on
26
+ * `edge`, carrying every leaf in a single tree. A `path` that names a resource
27
+ * alone throws an `Error`. */
28
+ export declare function buildDsiotMultireqUpdate(updates: DsiotUpdate[], edge?: string): object;
29
+ /** Flattens a `/dsiot/multireq` reply into dotted paths -> `pv`, plus
30
+ * `<path>.md.mi` / `.md.mx` / `.md.st` where metadata came back.
31
+ *
32
+ * Each of its `responses` carries its own `rsc`; any not starting with 200 is
33
+ * the adapter refusing, and throws a `DaikinError`: status 401 for `rsc` 401
34
+ * or 4001, 503 for 503, 502 for anything else. A body that is not JSON, or has
35
+ * no `responses` array, throws one with status 502. */
36
+ export declare function parseDsiotMultireqReply(body: string): Record<string, string>;
37
+ //# sourceMappingURL=multireq.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multireq.d.ts","sourceRoot":"","sources":["../../../src/codecs/dsiot/multireq.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,gBAAgB;aAC3B,GAAG,EAAE,CAAC;aACN,MAAM,EAAE,CAAC;aACT,MAAM,EAAE,CAAC;CACD,CAAC;AAEX,yEAAyE;AACzE,eAAO,MAAM,WAAW;aACtB,MAAM,EAAE,UAAU;aAClB,OAAO,EAAE,UAAU;CACX,CAAC;AAIX;aACa;AACb,eAAO,MAAM,aAAa;aACxB,WAAW;aACX,YAAY;aACZ,aAAa;CACL,CAAC;AAeX;4EAC4E;AAC5E,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAIxE;AAED;;8BAE8B;AAC9B,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,WAAW,EAAE,EACtB,IAAI,GAAE,MAA2B,GAChC,MAAM,CAqBR;AAWD;;;;;;uDAMuD;AACvD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAoB5E"}