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,31 @@
1
+ import { ClassicLocalPasswordAuthentication, DsiotLocalPasswordAuthentication, } from "./authentication.js";
2
+ import { ClassicDaikinClient } from "./clients/classic.js";
3
+ import { DsiotDaikinClient } from "./clients/dsiot.js";
4
+ import { DaikinTransport, } from "./transport.js";
5
+ /** Builds the client for a device: a `DsiotDaikinClient` when
6
+ * `device.protocol` is `dsiot`, a `ClassicDaikinClient` otherwise. The client
7
+ * sends over HTTPS when `device.usesHttps` is set, and sends the local
8
+ * password when `options.localPassword` is given. Call `close` on the client
9
+ * when done with the unit. */
10
+ export function createDaikinClient(device, options) {
11
+ const transport = new DaikinTransport({
12
+ host: device.host,
13
+ usesHttps: device.usesHttps,
14
+ terminalUuid: options.terminalUuid,
15
+ authentication: localPasswordAuthentication(device, options.localPassword),
16
+ timeoutInMs: options.timeoutInMs,
17
+ tls: options.tls,
18
+ });
19
+ return device.protocol === "dsiot"
20
+ ? new DsiotDaikinClient(transport, options.retry)
21
+ : new ClassicDaikinClient(transport, options.retry);
22
+ }
23
+ function localPasswordAuthentication(device, localPassword) {
24
+ if (localPassword === undefined) {
25
+ return undefined;
26
+ }
27
+ return device.protocol === "dsiot"
28
+ ? new DsiotLocalPasswordAuthentication(localPassword)
29
+ : new ClassicLocalPasswordAuthentication(localPassword);
30
+ }
31
+ //# sourceMappingURL=factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.js","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kCAAkC,EAElC,gCAAgC,GACjC,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,EAGL,eAAe,GAChB,MAAM,gBAAgB,CAAC;AAmBxB;;;;8BAI8B;AAC9B,MAAM,UAAU,kBAAkB,CAChC,MAAoB,EACpB,OAAkC;IAElC,MAAM,SAAS,GAAG,IAAI,eAAe,CAAC;QACpC,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,cAAc,EAAE,2BAA2B,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC;QAC1E,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,GAAG,EAAE,OAAO,CAAC,GAAG;KACjB,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC,QAAQ,KAAK,OAAO;QAChC,CAAC,CAAC,IAAI,iBAAiB,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC;QACjD,CAAC,CAAC,IAAI,mBAAmB,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,2BAA2B,CAClC,MAAoB,EACpB,aAAiC;IAEjC,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,MAAM,CAAC,QAAQ,KAAK,OAAO;QAChC,CAAC,CAAC,IAAI,gCAAgC,CAAC,aAAa,CAAC;QACrD,CAAC,CAAC,IAAI,kCAAkC,CAAC,aAAa,CAAC,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,22 @@
1
+ export type { DaikinAuthentication } from "./authentication.js";
2
+ export * from "./clients/classic.js";
3
+ export * from "./clients/client.js";
4
+ export * from "./clients/dsiot.js";
5
+ export * from "./codecs/classic/capabilities.js";
6
+ export * from "./codecs/classic/extendedControl.js";
7
+ export * from "./codecs/classic/keyValue.js";
8
+ export * from "./codecs/classic/state.js";
9
+ export * from "./codecs/credentials.js";
10
+ export * from "./codecs/device.js";
11
+ export * from "./codecs/dsiot/capabilities.js";
12
+ export * from "./codecs/dsiot/multireq.js";
13
+ export * from "./codecs/dsiot/state.js";
14
+ export * from "./discovery.js";
15
+ export * from "./error.js";
16
+ export * from "./factory.js";
17
+ export * from "./models/capabilities.js";
18
+ export * from "./models/device.js";
19
+ export * from "./models/extendedControl.js";
20
+ export * from "./models/state.js";
21
+ export * from "./transport.js";
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAChE,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kCAAkC,CAAC;AACjD,cAAc,qCAAqC,CAAC;AACpD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC;AACnC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,21 @@
1
+ export * from "./clients/classic.js";
2
+ export * from "./clients/client.js";
3
+ export * from "./clients/dsiot.js";
4
+ export * from "./codecs/classic/capabilities.js";
5
+ export * from "./codecs/classic/extendedControl.js";
6
+ export * from "./codecs/classic/keyValue.js";
7
+ export * from "./codecs/classic/state.js";
8
+ export * from "./codecs/credentials.js";
9
+ export * from "./codecs/device.js";
10
+ export * from "./codecs/dsiot/capabilities.js";
11
+ export * from "./codecs/dsiot/multireq.js";
12
+ export * from "./codecs/dsiot/state.js";
13
+ export * from "./discovery.js";
14
+ export * from "./error.js";
15
+ export * from "./factory.js";
16
+ export * from "./models/capabilities.js";
17
+ export * from "./models/device.js";
18
+ export * from "./models/extendedControl.js";
19
+ export * from "./models/state.js";
20
+ export * from "./transport.js";
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kCAAkC,CAAC;AACjD,cAAc,qCAAqC,CAAC;AACpD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC;AACnC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,42 @@
1
+ import type { FanSpeed, HorizontalPosition, OperatingMode, SwingMode, TargetHumidity, VerticalPosition } from "./state.js";
2
+ /** In °C. */
3
+ export interface TemperatureRange {
4
+ min: number;
5
+ max: number;
6
+ step: number;
7
+ }
8
+ /** What a specific unit accepts. Each control field is named for the
9
+ * `DaikinState` field it limits and lists values in that field's own
10
+ * vocabulary, so a caller can offer `capabilities.fanSpeeds` and send any of
11
+ * them back as `fanSpeed`. */
12
+ export interface DaikinCapabilities {
13
+ /** Operating modes the unit offers. */
14
+ modes: readonly OperatingMode[];
15
+ /** Fan speeds the unit accepts; empty when the fan is not controllable.
16
+ * Dehumidify runs the fan on `auto` only, and so does cool on a DSIOT
17
+ * adapter while a humidity setting is on. */
18
+ fanSpeeds: readonly FanSpeed[];
19
+ /** Swing settings the unit accepts; empty when airflow is not controllable. */
20
+ swingModes: readonly SwingMode[];
21
+ /** Vertical louver positions the unit accepts; empty unless it is a 3D
22
+ * unit. */
23
+ verticalPositions: readonly VerticalPosition[];
24
+ /** Horizontal louver positions the unit accepts; empty unless it is a 3D
25
+ * unit. */
26
+ horizontalPositions: readonly HorizontalPosition[];
27
+ /** Setpoint range per mode; `null` where the mode has no setpoint or the unit
28
+ * does not offer the mode. */
29
+ targetTemperatureInC: Readonly<Record<OperatingMode, TemperatureRange | null>>;
30
+ /** Humidity settings per mode; empty where the mode has none or the unit does
31
+ * not offer it. A percentage is listed for no unit: see UNSUPPORTED.md. */
32
+ targetHumidity: Readonly<Record<OperatingMode, readonly TargetHumidity[]>>;
33
+ /** Whether the unit has the special air outlet, which heat can swing
34
+ * through. That swing is not modelled: see UNSUPPORTED.md. */
35
+ specialOutlet: boolean;
36
+ energyMonitoring: boolean;
37
+ demandControl: boolean;
38
+ scheduleTimer: boolean;
39
+ /** The adapter's own code for the unit's model: see UNSUPPORTED.md. */
40
+ model?: string;
41
+ }
42
+ //# sourceMappingURL=capabilities.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../../src/models/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,kBAAkB,EAClB,aAAa,EACb,SAAS,EACT,cAAc,EACd,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAEpB,aAAa;AACb,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;8BAG8B;AAC9B,MAAM,WAAW,kBAAkB;IACjC,uCAAuC;IACvC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAC;IAChC;;iDAE6C;IAC7C,SAAS,EAAE,SAAS,QAAQ,EAAE,CAAC;IAC/B,+EAA+E;IAC/E,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IACjC;eACW;IACX,iBAAiB,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC/C;eACW;IACX,mBAAmB,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACnD;kCAC8B;IAC9B,oBAAoB,EAAE,QAAQ,CAC5B,MAAM,CAAC,aAAa,EAAE,gBAAgB,GAAG,IAAI,CAAC,CAC/C,CAAC;IACF;+EAC2E;IAC3E,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,aAAa,EAAE,SAAS,cAAc,EAAE,CAAC,CAAC,CAAC;IAC3E;kEAC8D;IAC9D,aAAa,EAAE,OAAO,CAAC;IACvB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=capabilities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../src/models/capabilities.ts"],"names":[],"mappings":""}
@@ -0,0 +1,24 @@
1
+ export declare const DAIKIN_PROTOCOLS: readonly ["classic", "dsiot"];
2
+ /** The wire protocol an adapter speaks, and the only difference between
3
+ * adapters that takes a separate `DaikinClient` implementation: `classic` for
4
+ * a CGI adapter such as the BRP069 or BRP072, `dsiot` for a BRP084. */
5
+ export type DaikinProtocol = (typeof DAIKIN_PROTOCOLS)[number];
6
+ /** An adapter on the LAN, as `discoverDevices` finds it or as a caller writes
7
+ * it by hand, carrying what `createDaikinClient` needs to reach it. A flag left
8
+ * out means `false`, so a device written by hand needs only `host` and
9
+ * `protocol`. */
10
+ export interface DaikinDevice {
11
+ /** Address, with `:port` when the adapter announces one. */
12
+ host: string;
13
+ protocol: DaikinProtocol;
14
+ name?: string;
15
+ /** The adapter answers a terminal uuid only once it is registered with the
16
+ * KEY on the adapter's label (`registerTerminal`). Classic only. */
17
+ requiresRegistration?: boolean;
18
+ /** The adapter speaks HTTPS. An adapter can require registration and still
19
+ * speak plain HTTP. */
20
+ usesHttps?: boolean;
21
+ /** The adapter requires the local password: the child lock code. */
22
+ requiresLocalPassword?: boolean;
23
+ }
24
+ //# sourceMappingURL=device.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../src/models/device.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,YAAI,SAAS,EAAE,OAAO,CAAU,CAAC;AAE9D;;uEAEuE;AACvE,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/D;;;iBAGiB;AACjB,MAAM,WAAW,YAAY;IAC3B,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;wEACoE;IACpE,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B;2BACuB;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,oEAAoE;IACpE,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC"}
@@ -0,0 +1,2 @@
1
+ export const DAIKIN_PROTOCOLS = ["classic", "dsiot"];
2
+ //# sourceMappingURL=device.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device.js","sourceRoot":"","sources":["../../src/models/device.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,SAAS,EAAE,OAAO,CAAU,CAAC"}
@@ -0,0 +1,31 @@
1
+ export declare const TERMINAL_SCOPES: readonly ["self", "others", "all"];
2
+ /** Which registered terminals to unregister: this uuid, every other uuid, or
3
+ * all of them. */
4
+ export type TerminalScope = (typeof TERMINAL_SCOPES)[number];
5
+ /** The adapter's third mode, schedule, is not offered: see UNSUPPORTED.md. */
6
+ export declare const DEMAND_MODES: readonly ["manual", "auto"];
7
+ /** Who picks the cap: `manual` holds the unit to `maxPowerInPercent`, and `auto`
8
+ * lets the unit choose, which it does in cool and heat only. */
9
+ export type DemandMode = (typeof DEMAND_MODES)[number];
10
+ export interface DemandControl {
11
+ enabled: boolean;
12
+ /** The unit caps its power draw at this percent. A unit accepts 40, 50 and
13
+ * 70 in `manual` and 85 in `auto`; what else it accepts is not known. */
14
+ maxPowerInPercent: number;
15
+ mode: DemandMode;
16
+ }
17
+ export declare const SPECIAL_MODES: readonly ["powerful", "econo", "streamer"];
18
+ export type SpecialMode = (typeof SPECIAL_MODES)[number];
19
+ export interface DeviceGroup {
20
+ name: string;
21
+ /** Whether the unit is in the group. */
22
+ enabled: boolean;
23
+ }
24
+ /** A field left out is not written. */
25
+ export interface DeviceMetadata {
26
+ name?: string;
27
+ /** The adapter's own code for the icon: see UNSUPPORTED.md. */
28
+ icon?: string;
29
+ group?: DeviceGroup;
30
+ }
31
+ //# sourceMappingURL=extendedControl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extendedControl.d.ts","sourceRoot":"","sources":["../../src/models/extendedControl.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,eAAe,YAAI,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAU,CAAC;AAElE;kBACkB;AAClB,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D,8EAA8E;AAC9E,eAAO,MAAM,YAAY,YAAI,QAAQ,EAAE,MAAM,CAAU,CAAC;AAExD;gEACgE;AAChE,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB;6EACyE;IACzE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,eAAO,MAAM,aAAa,YAAI,UAAU,EAAE,OAAO,EAAE,UAAU,CAAU,CAAC;AAExE,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,uCAAuC;AACvC,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB"}
@@ -0,0 +1,7 @@
1
+ // Inputs to the controls outside `DaikinState`, which only a classic adapter
2
+ // takes.
3
+ export const TERMINAL_SCOPES = ["self", "others", "all"];
4
+ /** The adapter's third mode, schedule, is not offered: see UNSUPPORTED.md. */
5
+ export const DEMAND_MODES = ["manual", "auto"];
6
+ export const SPECIAL_MODES = ["powerful", "econo", "streamer"];
7
+ //# sourceMappingURL=extendedControl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extendedControl.js","sourceRoot":"","sources":["../../src/models/extendedControl.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,SAAS;AAET,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAU,CAAC;AAMlE,8EAA8E;AAC9E,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAU,CAAC;AAcxD,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,UAAU,EAAE,OAAO,EAAE,UAAU,CAAU,CAAC"}
@@ -0,0 +1,56 @@
1
+ export declare const OPERATING_MODES: readonly ["auto", "dehumidify", "cool", "heat", "fan"];
2
+ export type OperatingMode = (typeof OPERATING_MODES)[number];
3
+ export declare const FAN_SPEEDS: readonly ["auto", "silent", "level1", "level2", "level3", "level4", "level5"];
4
+ export type FanSpeed = (typeof FAN_SPEEDS)[number];
5
+ export declare const SWING_MODES: readonly ["off", "vertical", "horizontal", "both"];
6
+ /** The axes the louvers swing on: `vertical` moves the air up and down, and
7
+ * `horizontal` moves it left and right. A 3D unit, one with 3D airflow, also
8
+ * reports each axis on its own, as `DaikinState.verticalPosition` and
9
+ * `DaikinState.horizontalPosition`. */
10
+ export type SwingMode = (typeof SWING_MODES)[number];
11
+ /** The positions a louver holds still at, on either axis. */
12
+ export declare const FIXED_LOUVER_POSITIONS: readonly ["position1", "position2", "position3", "position4", "position5"];
13
+ export declare const VERTICAL_POSITIONS: readonly ["stop", "position1", "position2", "position3", "position4", "position5", "swing", "naturalWind", "auto", "floorWarming"];
14
+ /** On a DSIOT adapter, `position1` to `position5` are the first five fixed
15
+ * positions the unit takes, in the adapter's order. */
16
+ export type VerticalPosition = (typeof VERTICAL_POSITIONS)[number];
17
+ export declare const HORIZONTAL_POSITIONS: readonly ["stop", "position1", "position2", "position3", "position4", "position5", "swing", "auto"];
18
+ /** A DSIOT adapter reports a fixed position as `stop`: see UNSUPPORTED.md. */
19
+ export type HorizontalPosition = (typeof HORIZONTAL_POSITIONS)[number];
20
+ export declare const HUMIDITY_SETTINGS: readonly ["off", "autoLow", "auto", "autoHigh", "continuous"];
21
+ /** The humidity settings that name no percentage. */
22
+ export type HumiditySetting = (typeof HUMIDITY_SETTINGS)[number];
23
+ /** A `HumiditySetting` or a percentage.
24
+ * `DaikinCapabilities.targetHumidity` lists which of them a unit takes. */
25
+ export type TargetHumidity = HumiditySetting | {
26
+ percent: number;
27
+ };
28
+ export interface DaikinState {
29
+ power: boolean;
30
+ mode: OperatingMode;
31
+ /** `null` in modes without a setpoint (fan, sometimes dehumidify). */
32
+ targetTemperatureInC: number | null;
33
+ /** `null` when the unit has no humidity setting. */
34
+ targetHumidity: TargetHumidity | null;
35
+ fanSpeed: FanSpeed;
36
+ swingMode: SwingMode;
37
+ /** On a 3D unit. `null` where the unit reports none, or one outside
38
+ * `VerticalPosition`. */
39
+ verticalPosition: VerticalPosition | null;
40
+ /** On a 3D unit. `null` where the unit reports none, or one outside
41
+ * `HorizontalPosition`. */
42
+ horizontalPosition: HorizontalPosition | null;
43
+ }
44
+ /** A partial `DaikinState`, as `DaikinClient.setState` takes it: set only the
45
+ * fields to change. The client reads the current state, overlays the control,
46
+ * and writes the whole state back. It drops a field the unit does not take in
47
+ * the target mode, such as a louver position outside
48
+ * `DaikinCapabilities.verticalPositions`. */
49
+ export type DaikinControl = Partial<DaikinState>;
50
+ /** A reading is `null` when the unit does not report it. */
51
+ export interface DaikinSensors {
52
+ indoorTemperatureInC: number | null;
53
+ outdoorTemperatureInC: number | null;
54
+ indoorHumidityInPercent: number | null;
55
+ }
56
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/models/state.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,eAAe,YAC1B,MAAM,EACN,YAAY,EACZ,MAAM,EACN,MAAM,EACN,KAAK,CACG,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D,eAAO,MAAM,UAAU,YACrB,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,QAAQ,CACA,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnD,eAAO,MAAM,WAAW,YAAI,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,CAAU,CAAC;AAE9E;;;uCAGuC;AACvC,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAErD,6DAA6D;AAC7D,eAAO,MAAM,sBAAsB,YACjC,WAAW,EACX,WAAW,EACX,WAAW,EACX,WAAW,EACX,WAAW,CACH,CAAC;AAEX,eAAO,MAAM,kBAAkB,oIAOrB,CAAC;AAEX;uDACuD;AACvD,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnE,eAAO,MAAM,oBAAoB,qGAKvB,CAAC;AAEX,8EAA8E;AAC9E,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvE,eAAO,MAAM,iBAAiB,YAC5B,KAAK,EACL,SAAS,EACT,MAAM,EACN,UAAU,EACV,YAAY,CACJ,CAAC;AAEX,qDAAqD;AACrD,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjE;2EAC2E;AAC3E,MAAM,MAAM,cAAc,GAAG,eAAe,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,aAAa,CAAC;IACpB,sEAAsE;IACtE,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,oDAAoD;IACpD,cAAc,EAAE,cAAc,GAAG,IAAI,CAAC;IACtC,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,EAAE,SAAS,CAAC;IACrB;6BACyB;IACzB,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC1C;+BAC2B;IAC3B,kBAAkB,EAAE,kBAAkB,GAAG,IAAI,CAAC;CAC/C;AAED;;;;6CAI6C;AAC7C,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;AAEjD,4DAA4D;AAC5D,MAAM,WAAW,aAAa;IAC5B,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,uBAAuB,EAAE,MAAM,GAAG,IAAI,CAAC;CACxC"}
@@ -0,0 +1,49 @@
1
+ // The unit's controllable state, in the package's own terms. The
2
+ // codecs map it to and from each protocol's wire encoding.
3
+ export const OPERATING_MODES = [
4
+ "auto",
5
+ "dehumidify",
6
+ "cool",
7
+ "heat",
8
+ "fan",
9
+ ];
10
+ export const FAN_SPEEDS = [
11
+ "auto",
12
+ "silent",
13
+ "level1",
14
+ "level2",
15
+ "level3",
16
+ "level4",
17
+ "level5",
18
+ ];
19
+ export const SWING_MODES = ["off", "vertical", "horizontal", "both"];
20
+ /** The positions a louver holds still at, on either axis. */
21
+ export const FIXED_LOUVER_POSITIONS = [
22
+ "position1",
23
+ "position2",
24
+ "position3",
25
+ "position4",
26
+ "position5",
27
+ ];
28
+ export const VERTICAL_POSITIONS = [
29
+ "stop",
30
+ ...FIXED_LOUVER_POSITIONS,
31
+ "swing",
32
+ "naturalWind",
33
+ "auto",
34
+ "floorWarming",
35
+ ];
36
+ export const HORIZONTAL_POSITIONS = [
37
+ "stop",
38
+ ...FIXED_LOUVER_POSITIONS,
39
+ "swing",
40
+ "auto",
41
+ ];
42
+ export const HUMIDITY_SETTINGS = [
43
+ "off",
44
+ "autoLow",
45
+ "auto",
46
+ "autoHigh",
47
+ "continuous",
48
+ ];
49
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/models/state.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,2DAA2D;AAE3D,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,MAAM;IACN,YAAY;IACZ,MAAM;IACN,MAAM;IACN,KAAK;CACG,CAAC;AAIX,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,MAAM;IACN,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;CACA,CAAC;AAIX,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,CAAU,CAAC;AAQ9E,6DAA6D;AAC7D,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,WAAW;IACX,WAAW;IACX,WAAW;IACX,WAAW;IACX,WAAW;CACH,CAAC;AAEX,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,MAAM;IACN,GAAG,sBAAsB;IACzB,OAAO;IACP,aAAa;IACb,MAAM;IACN,cAAc;CACN,CAAC;AAMX,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,MAAM;IACN,GAAG,sBAAsB;IACzB,OAAO;IACP,MAAM;CACE,CAAC;AAKX,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,KAAK;IACL,SAAS;IACT,MAAM;IACN,UAAU;IACV,YAAY;CACJ,CAAC"}
@@ -0,0 +1,75 @@
1
+ import type { DaikinAuthentication } from "./authentication.js";
2
+ export interface DaikinRequestOptions {
3
+ /** Retry a refused or dropped connection. Defaults to true. Pass false for a
4
+ * request that is not safe to repeat. */
5
+ retry?: boolean;
6
+ }
7
+ export interface DaikinRetryOptions {
8
+ /** How long, in milliseconds, to wait before each retry, so its length is
9
+ * how many times a request is retried. Defaults to 0, 50, 100, 200 and 400:
10
+ * see DESIGN.md#retries. Pass an empty array to never retry. */
11
+ delaysInMs?: number[];
12
+ }
13
+ /** Runs `operation` again each time it throws a `DaikinConnectionError`, once
14
+ * for each of `delaysInMs`, and throws any other error at once: see
15
+ * DESIGN.md#retries. */
16
+ export declare function withRetry<ResultT>(operation: () => Promise<ResultT>, { delaysInMs }?: DaikinRetryOptions): Promise<ResultT>;
17
+ export interface DaikinRequest {
18
+ method: "GET" | "POST" | "PUT";
19
+ /** From the leading `/`, without a query string. */
20
+ path: string;
21
+ /** Unencoded: `send` percent-encodes each key and value. */
22
+ query?: Record<string, string>;
23
+ /** JSON body for DSIOT writes. Classic uses `query` only. */
24
+ jsonBody?: unknown;
25
+ }
26
+ export interface DaikinTransportOptions {
27
+ /** With `:port` when the adapter announces one. */
28
+ host: string;
29
+ /** HTTPS (a Marvell adapter in secure mode). */
30
+ usesHttps?: boolean;
31
+ /** The terminal uuid, sent as `X-Daikin-uuid` on every call. */
32
+ terminalUuid: string;
33
+ authentication?: DaikinAuthentication;
34
+ /** How long, in milliseconds, to wait for each of the connection, the
35
+ * reply's headers and the reply's body before `send` throws a
36
+ * `DaikinError` with status 504. Defaults to 10000. */
37
+ timeoutInMs?: number;
38
+ /** HTTPS adapters only. */
39
+ tls?: DaikinTlsOptions;
40
+ }
41
+ /** An HTTPS adapter presents a certificate chaining to Daikin's own CA, which
42
+ * this package cannot ship. So by default the certificate is not verified at
43
+ * all; supplying the CA turns chain verification on. */
44
+ export interface DaikinTlsOptions {
45
+ /** Daikin's CA certificate (PEM). The chain is then verified against it, but
46
+ * not the hostname: the adapter's certificate doesn't name its LAN address. */
47
+ ca?: string | Buffer;
48
+ }
49
+ /** The HTTP connection to one adapter. It builds each URL from `host` and
50
+ * `usesHttps`, attaches the uuid header and whatever the
51
+ * `DaikinAuthentication` contributes, and returns the reply's body as text for
52
+ * a codec to parse.
53
+ *
54
+ * It holds one undici connection per adapter, so requests queue rather than
55
+ * run in parallel: these small embedded servers are best talked to one request
56
+ * at a time. */
57
+ export declare class DaikinTransport {
58
+ private readonly options;
59
+ private readonly origin;
60
+ private readonly client;
61
+ /** Call `close` when done with the adapter. */
62
+ constructor(options: DaikinTransportOptions);
63
+ /** Sends one request and returns the reply's body as text. It never retries:
64
+ * wrap the call in `withRetry` for that.
65
+ *
66
+ * It throws a `DaikinConnectionError` when the adapter refuses, resets or
67
+ * closes the connection, and a `DaikinError` with status 504 when the
68
+ * request fails to complete any other way, such as a timeout or a TLS
69
+ * error. A reply whose status is not 2xx makes it throw a `DaikinError`
70
+ * with that status. */
71
+ send(request: DaikinRequest): Promise<string>;
72
+ /** Close the connection to the adapter. */
73
+ close(): Promise<void>;
74
+ }
75
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAIhE,MAAM,WAAW,oBAAoB;IACnC;6CACyC;IACzC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC;;oEAEgE;IAChE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAID;;wBAEwB;AACxB,wBAAsB,SAAS,CAAC,OAAO,EACrC,SAAS,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EACjC,EAAE,UAAuC,EAAE,GAAE,kBAAuB,GACnE,OAAO,CAAC,OAAO,CAAC,CAYlB;AAoBD,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC;IAC/B,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,sBAAsB;IACrC,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gEAAgE;IAChE,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,oBAAoB,CAAC;IACtC;;2DAEuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2BAA2B;IAC3B,GAAG,CAAC,EAAE,gBAAgB,CAAC;CACxB;AAED;;wDAEwD;AACxD,MAAM,WAAW,gBAAgB;IAC/B;mFAC+E;IAC/E,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACtB;AAED;;;;;;;gBAOgB;AAChB,qBAAa,eAAe;IAKd,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAEhC,+CAA+C;IAC/C,YAA6B,OAAO,EAAE,sBAAsB,EAU3D;IAED;;;;;;;2BAOuB;IACjB,IAAI,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAoDlD;IAED,2CAA2C;IACrC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAE3B;CACF"}
@@ -0,0 +1,118 @@
1
+ import { Client } from "undici";
2
+ import { encodeTerminalUuid } from "./codecs/credentials.js";
3
+ import { DaikinConnectionError, DaikinError } from "./error.js";
4
+ const DEFAULT_RETRY_DELAYS_IN_MS = [0, 50, 100, 200, 400];
5
+ /** Runs `operation` again each time it throws a `DaikinConnectionError`, once
6
+ * for each of `delaysInMs`, and throws any other error at once: see
7
+ * DESIGN.md#retries. */
8
+ export async function withRetry(operation, { delaysInMs = DEFAULT_RETRY_DELAYS_IN_MS } = {}) {
9
+ for (const delayInMs of delaysInMs) {
10
+ try {
11
+ return await operation();
12
+ }
13
+ catch (error) {
14
+ if (!(error instanceof DaikinConnectionError)) {
15
+ throw error;
16
+ }
17
+ }
18
+ await sleep(delayInMs);
19
+ }
20
+ return operation();
21
+ }
22
+ function sleep(delayInMs) {
23
+ return new Promise((resolve) => setTimeout(resolve, delayInMs));
24
+ }
25
+ const JSON_CONTENT_HEADERS = {
26
+ "Content-Type": "application/json",
27
+ };
28
+ const DEFAULT_TIMEOUT_IN_MS = 10_000;
29
+ // The codes for a refused, reset or closed connection. Every other failure,
30
+ // such as a timeout or a TLS error, is not one.
31
+ const CONNECTION_FAILURE_CODES = new Set([
32
+ "ECONNREFUSED",
33
+ "ECONNRESET",
34
+ "UND_ERR_SOCKET",
35
+ ]);
36
+ /** The HTTP connection to one adapter. It builds each URL from `host` and
37
+ * `usesHttps`, attaches the uuid header and whatever the
38
+ * `DaikinAuthentication` contributes, and returns the reply's body as text for
39
+ * a codec to parse.
40
+ *
41
+ * It holds one undici connection per adapter, so requests queue rather than
42
+ * run in parallel: these small embedded servers are best talked to one request
43
+ * at a time. */
44
+ export class DaikinTransport {
45
+ options;
46
+ origin;
47
+ client;
48
+ /** Call `close` when done with the adapter. */
49
+ constructor(options) {
50
+ this.options = options;
51
+ const scheme = options.usesHttps ? "https" : "http";
52
+ this.origin = `${scheme}://${options.host.replace(/\/+$/, "")}`;
53
+ const timeoutInMs = options.timeoutInMs ?? DEFAULT_TIMEOUT_IN_MS;
54
+ this.client = new Client(this.origin, {
55
+ connect: { timeout: timeoutInMs, ...tlsConnectOptions(options.tls) },
56
+ headersTimeout: timeoutInMs,
57
+ bodyTimeout: timeoutInMs,
58
+ });
59
+ }
60
+ /** Sends one request and returns the reply's body as text. It never retries:
61
+ * wrap the call in `withRetry` for that.
62
+ *
63
+ * It throws a `DaikinConnectionError` when the adapter refuses, resets or
64
+ * closes the connection, and a `DaikinError` with status 504 when the
65
+ * request fails to complete any other way, such as a timeout or a TLS
66
+ * error. A reply whose status is not 2xx makes it throw a `DaikinError`
67
+ * with that status. */
68
+ async send(request) {
69
+ const authenticationQuery = (await this.options.authentication?.query()) ?? {};
70
+ // Not URLSearchParams: it writes a space as `+`, and the adapter expects
71
+ // `%20` (e.g. `method=home%20only`).
72
+ const query = Object.entries({ ...request.query, ...authenticationQuery })
73
+ .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
74
+ .join("&");
75
+ const headers = {
76
+ ...encodeTerminalUuid(this.options.terminalUuid),
77
+ ...((await this.options.authentication?.headers()) ?? {}),
78
+ ...(request.jsonBody !== undefined ? JSON_CONTENT_HEADERS : {}),
79
+ };
80
+ let statusCode;
81
+ let text;
82
+ try {
83
+ const response = await this.client.request({
84
+ method: request.method,
85
+ path: query ? `${request.path}?${query}` : request.path,
86
+ headers,
87
+ ...(request.jsonBody !== undefined
88
+ ? { body: JSON.stringify(request.jsonBody) }
89
+ : {}),
90
+ });
91
+ statusCode = response.statusCode;
92
+ text = await response.body.text();
93
+ }
94
+ catch (error) {
95
+ const message = `Daikin request to ${request.path} did not complete: ${String(error)}`;
96
+ if (CONNECTION_FAILURE_CODES.has(error.code ?? "")) {
97
+ throw new DaikinConnectionError(message);
98
+ }
99
+ throw new DaikinError(message, 504);
100
+ }
101
+ if (statusCode < 200 || statusCode >= 300) {
102
+ // The classic protocol signals logical failures in the body with HTTP 200,
103
+ // so an HTTP error here is a transport-level one.
104
+ throw new DaikinError(`Daikin request to ${request.path} failed`, statusCode);
105
+ }
106
+ return text;
107
+ }
108
+ /** Close the connection to the adapter. */
109
+ async close() {
110
+ await this.client.close();
111
+ }
112
+ }
113
+ function tlsConnectOptions(tls) {
114
+ return tls?.ca === undefined
115
+ ? { rejectUnauthorized: false }
116
+ : { ca: tls.ca, checkServerIdentity: () => undefined };
117
+ }
118
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "daikin-local-control",
3
+ "version": "0.1.1",
4
+ "description": "Unofficial local-network (LAN) control client for Daikin air-conditioner Wi-Fi adapters (classic CGI and DSIOT)",
5
+ "keywords": [
6
+ "daikin",
7
+ "daikin-mobile-controller",
8
+ "air-conditioner",
9
+ "aircon",
10
+ "local-control",
11
+ "lan",
12
+ "wifi-adapter",
13
+ "brp072a42",
14
+ "brp072c42",
15
+ "brp084",
16
+ "dsiot",
17
+ "home-automation",
18
+ "thailand",
19
+ "singapore",
20
+ "hong-kong",
21
+ "taiwan",
22
+ "philippines",
23
+ "australia",
24
+ "new-zealand"
25
+ ],
26
+ "license": "GPL-3.0-or-later",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "git+https://github.com/cheziyi/daikin-local-control.git"
30
+ },
31
+ "type": "module",
32
+ "files": [
33
+ "dist",
34
+ "src",
35
+ "!src/**/__tests__",
36
+ "DESIGN.md",
37
+ "UNSUPPORTED.md"
38
+ ],
39
+ "exports": "./dist/index.js",
40
+ "devDependencies": {
41
+ "@biomejs/biome": "2.5.15",
42
+ "@tsconfig/node22": "^22.0.6",
43
+ "@types/node": "^22.20.5",
44
+ "@vitest/coverage-v8": "5.0.3",
45
+ "lefthook": "^2.2.1",
46
+ "typescript": "^7.0.2",
47
+ "vitest": "^5.0.3"
48
+ },
49
+ "engines": {
50
+ "node": ">=22.19.0"
51
+ },
52
+ "dependencies": {
53
+ "undici": "^8.11.2"
54
+ },
55
+ "scripts": {
56
+ "build": "tsc -p tsconfig.build.json",
57
+ "typecheck": "tsc",
58
+ "test": "pnpm typecheck && vitest run",
59
+ "check": "biome check",
60
+ "fix": "biome check --write"
61
+ }
62
+ }