mysa-js-sdk 2.1.2 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,54 @@
1
1
  # mysa-js-sdk
2
2
 
3
+ ## 3.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#211](https://github.com/bourquep/mysa2mqtt/pull/211) [`5dc3270`](https://github.com/bourquep/mysa2mqtt/commit/5dc32709beee8fa7caf487f422c0ed97ebc7c4a2) Thanks [@bourquep](https://github.com/bourquep)! - Support Mysa in-floor heating thermostats (INF-V1-0) ([#94](https://github.com/bourquep/mysa2mqtt/issues/94)).
8
+
9
+ - Parse the in-floor-specific status fields — floor-probe temperature (`flrSnsrTemp`), binary heating-relay state (`heatStat`), tracked sensor (`trackedSnsr`) and line voltage (`lineVtg`) — which share the V2 status message type (`msg: 40`). `heatStat` maps onto the emitted `dutyCycle`, and the floor-probe reading is surfaced as a new `Status.floorTemperature`.
10
+ - Send the correct control command `type` (3) for in-floor thermostats so setpoint and mode changes take effect instead of being silently ignored.
11
+
12
+ - [#212](https://github.com/bourquep/mysa2mqtt/pull/212) [`a1000a7`](https://github.com/bourquep/mysa2mqtt/commit/a1000a7475c4487931edddab678ace6558a1d0e7) Thanks [@bourquep](https://github.com/bourquep)! - Add a `mysa2mqtt-capture` tool (and the underlying `MysaApiClient.startRawTopicCapture()` SDK method) to record the raw AWS IoT Device Shadow traffic of unsupported thermostats, most notably the central-HVAC ST-V1.
13
+
14
+ Unlike the real-time path, `startRawTopicCapture()` subscribes to arbitrary MQTT topic filters and relays every message verbatim (full topic + decoded payload) with no parsing, re-subscribing across reconnects. The `mysa2mqtt-capture` command uses it to dump a device's REST metadata and passively record every shadow message to a file, providing the raw material needed to implement support for a new device family. Run `npm run capture -w mysa2mqtt -- --help` for usage.
15
+
16
+ ### Patch Changes
17
+
18
+ - [#205](https://github.com/bourquep/mysa2mqtt/pull/205) [`b5bf8f9`](https://github.com/bourquep/mysa2mqtt/commit/b5bf8f922c90a2342466e9ea1ba7e398ff0cd5d6) Thanks [@bourquep](https://github.com/bourquep)! - Fix fan-speed `fn` mapping for AC-V1-X (CodeNum=1117) devices ([#179](https://github.com/bourquep/mysa2mqtt/issues/179)).
19
+
20
+ - Derive the send-side `fn` values from the device's reported `SupportedCaps.fanSpeeds` (positionally mapped to the canonical `[auto, low, medium, high, max]` order) instead of a hardcoded universal map. Devices that don't report `fanSpeeds` keep the previous behaviour.
21
+ - Recognise the CodeNum=1117 canonical receive values (`fn` 2/4/6 → low/medium/high) so the current fan speed is surfaced instead of coming back `undefined`.
22
+ - Add the `fanSpeeds` field to the `SupportedCaps` type so consumers no longer need to cast to access it.
23
+ - Throw a new `UnsupportedFanSpeedError` when a requested fan speed is not supported by the target device (e.g. `max` on a device that only exposes auto/low/medium/high), instead of silently publishing a no-op command.
24
+
25
+ - [#202](https://github.com/bourquep/mysa2mqtt/pull/202) [`49d3017`](https://github.com/bourquep/mysa2mqtt/commit/49d3017fd301c1b79560d1a6403927a7c15de3be) Thanks [@bourquep](https://github.com/bourquep)! - Harden the MQTT connection against `AWS_ERROR_MQTT_UNEXPECTED_HANGUP` interrupt storms ([#178](https://github.com/bourquep/mysa2mqtt/issues/178)).
26
+
27
+ - Switch to clean MQTT sessions so the broker no longer redelivers a backlog of queued QoS1 messages on reconnect (the source of the ~1000x message bursts and exponential Home Assistant database growth) and so forced resets no longer leave orphaned broker sessions.
28
+ - Make the forced connection reset repeatable with exponential backoff instead of one-shot, so a persistent storm keeps recovering (fresh client id + fresh credentials) rather than giving up.
29
+ - Tag each connection with a generation and ignore events from discarded connections, and ensure the reset never rejects — preventing the in-flight publish crash (`AWS_ERROR_MQTT_CONNECTION_DESTROYED`) that terminated the process.
30
+ - Add interrupt dwell-time and session diagnostics to help pin down the server-side hangup trigger.
31
+
32
+ ## 3.0.0
33
+
34
+ ### Major Changes
35
+
36
+ - [#199](https://github.com/bourquep/mysa2mqtt/pull/199) [`b384d79`](https://github.com/bourquep/mysa2mqtt/commit/b384d7950d757bc85af7580eaa26435190b47364) Thanks [@bourquep](https://github.com/bourquep)! - The client now takes Mysa account credentials instead of a session object, and re-authenticates on its own when its refresh token expires or is revoked, so long-running processes no longer die after about a month. `new MysaApiClient(session, options)` becomes `new MysaApiClient({ username, password }, options)`, `login()` no longer takes arguments and is optional (the client authenticates on demand), and the `MysaSession` type, the `session` and `isAuthenticated` properties, and the `sessionChanged` event are gone — there is no longer any session state to persist.
37
+
38
+ ### Patch Changes
39
+
40
+ - [#201](https://github.com/bourquep/mysa2mqtt/pull/201) [`10ee91c`](https://github.com/bourquep/mysa2mqtt/commit/10ee91c1981b77ef1e9f76abd3d24ba6d9a19d77) Thanks [@bourquep](https://github.com/bourquep)! - A Mysa login rejected for a bad password now reports that a `$` in it is expanded by shells and by Docker Compose (in both `environment:` entries and default-format `env_file:` files, where it must be written `$$`, but not in an `env_file:` declared with `format: raw`), and that an unquoted `#` truncates a `.env` value, instead of surfacing a bare `Incorrect username or password.` stack trace. An unrecognized account gets username-specific guidance instead, since none of the password escaping rules apply to it. Transport and Cognito service failures keep propagating without that guidance, since `UnauthenticatedError` now carries the underlying failure as its `cause`. Debug logging also reports the length of the password that was actually received -- never the password or the account it belongs to -- so a mangled value can be spotted at a glance.
41
+
42
+ - [#190](https://github.com/bourquep/mysa2mqtt/pull/190) [`7169263`](https://github.com/bourquep/mysa2mqtt/commit/7169263fcb4b2aeb51c7eae4c112972c3e2fdb08) Thanks [@vavallee](https://github.com/vavallee)! - Payload parse failures no longer write to console.error, which bypassed the configurable SDK logger and could leak payload contents. The error is rethrown with the original failure attached as cause and logged by the message handler through the SDK logger.
43
+
44
+ - [#191](https://github.com/bourquep/mysa2mqtt/pull/191) [`527ef25`](https://github.com/bourquep/mysa2mqtt/commit/527ef25886aad766a2fd71fc92002d8de126b364) Thanks [@vavallee](https://github.com/vavallee)! - setDeviceState now throws a descriptive UnknownDeviceError when the device id does not match any device on the account, instead of failing with a raw TypeError on an undefined dereference.
45
+
46
+ - [#200](https://github.com/bourquep/mysa2mqtt/pull/200) [`61dc2a2`](https://github.com/bourquep/mysa2mqtt/commit/61dc2a2b395397e9e5245098bfd31b49b501fd7d) Thanks [@bourquep](https://github.com/bourquep)! - V2 thermostats can now report power. These devices have no current sensor and only report the duty cycle of their heating relay, which is why their **Current power** sensor has always been unavailable. Set the new `--heater-watts` option (`M2M_HEATER_WATTS`) to the rated wattage of the heaters each thermostat controls — for example `M2M_HEATER_WATTS="Kitchen=1500,<device-id>=750"`, matching devices by name or id — and power is estimated as `duty cycle × rated wattage`. V1 thermostats measure their own current and continue to work with no configuration.
47
+
48
+ The power sensor is now only created for devices that can actually report a value. If you have AC devices, or V2 thermostats for which you have not configured a wattage, their **Current power** entity is removed from Home Assistant on startup; it only ever showed as unavailable.
49
+
50
+ `mqtt2ha` gains a `Discoverable.removeConfig()` method, which clears an entity's retained discovery topic so Home Assistant drops the entity. This is what makes the removal above take effect: because `writeConfig()` retains its payload, an entity published by an earlier run persists until its topic is explicitly cleared.
51
+
3
52
  ## 2.1.2
4
53
 
5
54
  ### Patch Changes
package/README.md CHANGED
@@ -66,17 +66,20 @@ The Mysa SDK provides a simple interface to interact with Mysa smart thermostats
66
66
  ```typescript
67
67
  import { MysaApiClient } from 'mysa-js-sdk';
68
68
 
69
- const client = new MysaApiClient();
70
-
71
- // Login with email and password
72
- await client.login('your-email@example.com', 'your-password');
69
+ // The client holds your credentials and authenticates on demand
70
+ const client = new MysaApiClient({
71
+ username: 'your-email@example.com',
72
+ password: 'your-password'
73
+ });
73
74
 
74
- // Check if authenticated
75
- if (client.isAuthenticated) {
76
- console.log('Successfully authenticated!');
77
- }
75
+ // Optional: log in eagerly to fail fast on invalid credentials
76
+ await client.login();
78
77
  ```
79
78
 
79
+ The client manages its session on its own: it refreshes the session when it needs to, and logs back in automatically
80
+ when the refresh token has itself expired or been revoked. There is nothing to persist, and no need to re-create the
81
+ client after a long run.
82
+
80
83
  ### Retrieving Thermostat Data
81
84
 
82
85
  Once authenticated, you can access your thermostat data:
@@ -139,10 +142,9 @@ The SDK provides specific error types to handle API errors:
139
142
  ```typescript
140
143
  import { MysaApiClient, MysaApiError, UnauthenticatedError } from 'mysa-js-sdk';
141
144
 
142
- const client = new MysaApiClient();
145
+ const client = new MysaApiClient({ username: 'user@example.com', password: 'password' });
143
146
 
144
147
  try {
145
- await client.login('user@example.com', 'password');
146
148
  const devices = await client.getDevices();
147
149
  } catch (error) {
148
150
  if (error instanceof UnauthenticatedError) {
@@ -170,31 +172,13 @@ const logger = pino({
170
172
  });
171
173
 
172
174
  // Configure client with options
173
- const client = new MysaApiClient(undefined, {
174
- logger: logger,
175
- fetcher: fetch // Custom fetch implementation if needed
176
- });
177
-
178
- // Or restore from a saved session
179
- const savedSession = {
180
- username: 'user@example.com',
181
- idToken: 'eyJ...',
182
- accessToken: 'eyJ...',
183
- refreshToken: 'abc123...'
184
- };
185
-
186
- const clientWithSession = new MysaApiClient(savedSession, { logger });
187
-
188
- // Listen for session changes to persist them
189
- client.emitter.on('sessionChanged', (newSession) => {
190
- if (newSession) {
191
- // Save session to storage (file, database, etc.)
192
- localStorage.setItem('mysaSession', JSON.stringify(newSession));
193
- } else {
194
- // Session expired or logged out
195
- localStorage.removeItem('mysaSession');
175
+ const client = new MysaApiClient(
176
+ { username: 'user@example.com', password: 'password' },
177
+ {
178
+ logger: logger,
179
+ fetcher: fetch // Custom fetch implementation if needed
196
180
  }
197
- });
181
+ );
198
182
  ```
199
183
 
200
184
  ### Reference documentation