@rhizomatics/signalk-einklabel-plugin 1.3.0-beta15 → 1.3.0-beta16

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.
@@ -247,7 +247,24 @@ function bleApiBackend(bleApi, pluginId) {
247
247
  }
248
248
  throw new Error(`connecting to device timed out after ${timeoutMs}ms`);
249
249
  }
250
- return withSessionWatchdog(conn, GATT_SESSION_WATCHDOG_MS, async () => {
250
+ // Disconnecting alone doesn't always drop the server's claim - it only clears that itself once it
251
+ // sees the link close, which a half-dead link may never report - so every disconnect releases the
252
+ // claim explicitly too, leaving the device free for the next paint (or another plugin).
253
+ const released = {
254
+ read: conn.read.bind(conn),
255
+ write: conn.write.bind(conn),
256
+ startNotifications: conn.startNotifications.bind(conn),
257
+ stopNotifications: conn.stopNotifications.bind(conn),
258
+ discoverServices: conn.discoverServices.bind(conn),
259
+ onDisconnect: conn.onDisconnect.bind(conn),
260
+ get connected() {
261
+ return conn.connected;
262
+ },
263
+ async disconnect() {
264
+ await Promise.allSettled([conn.disconnect(), bleApi.releaseGATTDevice(address, pluginId)]);
265
+ },
266
+ };
267
+ return withSessionWatchdog(released, GATT_SESSION_WATCHDOG_MS, async () => {
251
268
  // Belt-and-suspenders, matching the timeout-cleanup above: `releaseGATTDevice` is the
252
269
  // authoritative claim release, `disconnect()` a secondary teardown of this specific handle -
253
270
  // do both regardless of which (if either) itself hangs or rejects.
@@ -56,7 +56,7 @@ class ZhsunycoDriver {
56
56
  const conn = await backend.connectGatt(config.address, config.connectTimeoutMs ?? DEFAULT_PAINT_CONNECT_TIMEOUT_MS);
57
57
  log("connected");
58
58
  try {
59
- const info = (0, protocol_1.decodeAdvertisedInfo)(await conn.read(protocol_1.WOLINK_SERVICE_UUID, protocol_1.WOLINK_CHARACTERISTIC_UUIDS.config));
59
+ const info = (0, protocol_1.decodeAdvertisedInfo)(await readConfig(conn, log));
60
60
  if (!info) {
61
61
  throw new Error("zhsunyco device did not return valid config data");
62
62
  }
@@ -125,6 +125,22 @@ class ZhsunycoDriver {
125
125
  }
126
126
  }
127
127
  exports.ZhsunycoDriver = ZhsunycoDriver;
128
+ /**
129
+ * The first read of a paint. If the label's service isn't there at all (seen as node-ble's "Service not
130
+ * available" behind the BLE Manager), logs which services the connection does report - the difference
131
+ * between BlueZ not having discovered the label's services yet and it seeing a different set entirely.
132
+ */
133
+ async function readConfig(conn, log) {
134
+ try {
135
+ return await conn.read(protocol_1.WOLINK_SERVICE_UUID, protocol_1.WOLINK_CHARACTERISTIC_UUIDS.config);
136
+ }
137
+ catch (err) {
138
+ const services = await conn.discoverServices().catch((discoverErr) => `could not list them: ${discoverErr.message}`);
139
+ const listed = Array.isArray(services) ? services.map((service) => service.uuid).join(", ") || "none" : services;
140
+ log(`reading the label's config failed (${err.message}) - services visible on this connection: ${listed}`);
141
+ throw err;
142
+ }
143
+ }
128
144
  /**
129
145
  * Battery level needs a connection regardless, so reuse it to also fill in the PID/hwVersion
130
146
  * when the advertisement didn't carry decodable manufacturer data - a scan matched purely by name
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rhizomatics/signalk-einklabel-plugin",
3
- "version": "1.3.0-beta15",
3
+ "version": "1.3.0-beta16",
4
4
  "description": "Display SignalK data on eInk Electronic Shelf Labels, includes working examples for tide clock and watch schedule.",
5
5
  "keywords": [
6
6
  "ble",