@switchbot/homebridge-switchbot 5.0.0-beta.63 → 5.0.0-beta.65

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.
@@ -1 +1 @@
1
- <!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>default | @switchbot/homebridge-switchbot</title><meta name="description" content="Documentation for @switchbot/homebridge-switchbot"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="../index.html" class="title">@switchbot/homebridge-switchbot</a><div id="tsd-toolbar-links"></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="" aria-current="page">default</a></li></ul><h1>Variable default</h1></div><div class="tsd-signature"><span class="tsd-kind-variable">default</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol">(</span><span class="tsd-kind-parameter">api</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">API</span><span class="tsd-signature-symbol">)</span> <span class="tsd-signature-symbol">=&gt;</span> <span class="tsd-signature-type">void</span></div><div class="tsd-type-declaration"><h4>Type Declaration</h4><ul class="tsd-parameters"><li class="tsd-parameter-signature"><ul class="tsd-signatures"><li class="tsd-signature" id="__type"><span class="tsd-signature-symbol">(</span><span class="tsd-kind-parameter">api</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">API</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">void</span></li><li class="tsd-description"><div class="tsd-parameters"><h4 class="tsd-parameters-title">Parameters</h4><ul class="tsd-parameter-list"><li><span><span class="tsd-kind-parameter">api</span>: <span class="tsd-signature-type">API</span></span></li></ul></div><h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">void</span></h4></li></ul></li></ul></div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/OpenWonderLabs/homebridge-switchbot/blob/0129d2a683e4e9073247a1a3908fc182aba4857f/src/index.ts#L13">index.ts:13</a></li></ul></aside></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div></div><div class="site-menu"><nav class="tsd-navigation"><a href="../modules.html">@switchbot/homebridge-switchbot</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer></footer><div class="overlay"></div></body></html>
1
+ <!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>default | @switchbot/homebridge-switchbot</title><meta name="description" content="Documentation for @switchbot/homebridge-switchbot"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="../index.html" class="title">@switchbot/homebridge-switchbot</a><div id="tsd-toolbar-links"></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="" aria-current="page">default</a></li></ul><h1>Variable default</h1></div><div class="tsd-signature"><span class="tsd-kind-variable">default</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol">(</span><span class="tsd-kind-parameter">api</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">API</span><span class="tsd-signature-symbol">)</span> <span class="tsd-signature-symbol">=&gt;</span> <span class="tsd-signature-type">void</span></div><div class="tsd-type-declaration"><h4>Type Declaration</h4><ul class="tsd-parameters"><li class="tsd-parameter-signature"><ul class="tsd-signatures"><li class="tsd-signature" id="__type"><span class="tsd-signature-symbol">(</span><span class="tsd-kind-parameter">api</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">API</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">void</span></li><li class="tsd-description"><div class="tsd-parameters"><h4 class="tsd-parameters-title">Parameters</h4><ul class="tsd-parameter-list"><li><span><span class="tsd-kind-parameter">api</span>: <span class="tsd-signature-type">API</span></span></li></ul></div><h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">void</span></h4></li></ul></li></ul></div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/OpenWonderLabs/homebridge-switchbot/blob/f7041b5fa47c90b445909ecea8a760a4366b2e4f/src/index.ts#L13">index.ts:13</a></li></ul></aside></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div></div><div class="site-menu"><nav class="tsd-navigation"><a href="../modules.html">@switchbot/homebridge-switchbot</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer></footer><div class="overlay"></div></body></html>
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@switchbot/homebridge-switchbot",
3
3
  "displayName": "SwitchBot",
4
4
  "type": "module",
5
- "version": "5.0.0-beta.63",
5
+ "version": "5.0.0-beta.65",
6
6
  "description": "The SwitchBot plugin allows you to access your SwitchBot device(s) from HomeKit.",
7
7
  "author": "SwitchBot <support@wondertechlabs.com> (https://github.com/SwitchBot)",
8
8
  "contributors": [
@@ -180,32 +180,74 @@ export class RoboticVacuumAccessory extends BaseMatterAccessory {
180
180
  currentMode: 0,
181
181
  },
182
182
  rvcCleanMode: (() => {
183
- if (capabilities.cleanAction === 'vacuum-only') {
184
- return {
185
- supportedModes: [
186
- { label: 'Quiet', mode: 0, modeTags: [{ value: 2 }] },
187
- { label: 'Standard', mode: 1, modeTags: [{ value: 16384 }] },
188
- { label: 'Strong', mode: 2, modeTags: [{ value: 7 }] },
189
- { label: 'MAX', mode: 3, modeTags: [{ value: 8 }] },
190
- ],
191
- currentMode: 1,
192
- }
193
- } else if (capabilities.cleanAction === 'vacuum-or-mop') {
194
- return {
195
- supportedModes: [
196
- { label: 'Vacuum', mode: 0, modeTags: [{ value: 16385 }] },
197
- { label: 'Mop', mode: 1, modeTags: [{ value: 16386 }] },
198
- ],
199
- currentMode: 0,
200
- }
201
- } else {
202
- return {
203
- supportedModes: [
204
- { label: 'Vacuum', mode: 0, modeTags: [{ value: 16385 }] },
205
- { label: 'Vacuum & Mop', mode: 1, modeTags: [{ value: 16385 }, { value: 16386 }] },
206
- ],
207
- currentMode: 0,
208
- }
183
+ switch (model as string) {
184
+ case 'K10':
185
+ return {
186
+ supportedModes: [
187
+ { label: 'Vacuum', mode: 0, modeTags: [{ value: 16385 }] },
188
+ ],
189
+ currentMode: 0,
190
+ }
191
+ case 'Robot Vacuum Cleaner S1':
192
+ case 'Robot Vacuum Cleaner S1 Plus':
193
+ return {
194
+ supportedModes: [
195
+ { label: 'Quiet', mode: 0, modeTags: [{ value: 2 }] },
196
+ { label: 'Standard', mode: 1, modeTags: [{ value: 16384 }] },
197
+ { label: 'Strong', mode: 2, modeTags: [{ value: 7 }] },
198
+ { label: 'MAX', mode: 3, modeTags: [{ value: 8 }] },
199
+ ],
200
+ currentMode: 1,
201
+ }
202
+ case 'Mini Robot Vacuum K10+':
203
+ case 'Mini Robot Vacuum K10+ Pro':
204
+ case 'K10+ Pro Combo':
205
+ return {
206
+ supportedModes: [
207
+ { label: 'Vacuum', mode: 0, modeTags: [{ value: 16385 }] },
208
+ { label: 'Mop', mode: 1, modeTags: [{ value: 16386 }] },
209
+ { label: 'Sweep & Mop', mode: 2, modeTags: [{ value: 16385 }, { value: 16386 }] },
210
+ ],
211
+ currentMode: 0,
212
+ }
213
+ case 'Multitasking Household Robot K20+ Pro':
214
+ return {
215
+ supportedModes: [
216
+ { label: 'Vacuum', mode: 0, modeTags: [{ value: 16385 }] },
217
+ { label: 'Vacuum & Mop', mode: 1, modeTags: [{ value: 16385 }, { value: 16386 }] },
218
+ { label: 'Deep Clean', mode: 2, modeTags: [{ value: 16384 }] },
219
+ ],
220
+ currentMode: 0,
221
+ }
222
+ case 'Floor Cleaning Robot S10':
223
+ case 'Floor Cleaning Robot S20':
224
+ return {
225
+ supportedModes: [
226
+ { label: 'Vacuum', mode: 0, modeTags: [{ value: 16385 }] },
227
+ { label: 'Mop', mode: 1, modeTags: [{ value: 16386 }] },
228
+ ],
229
+ currentMode: 0,
230
+ }
231
+ case 'Robot Vacuum K11+':
232
+ return {
233
+ supportedModes: [
234
+ { label: 'Quiet', mode: 0, modeTags: [{ value: 2 }] },
235
+ { label: 'Standard', mode: 1, modeTags: [{ value: 16384 }] },
236
+ { label: 'Strong', mode: 2, modeTags: [{ value: 7 }] },
237
+ { label: 'MAX', mode: 3, modeTags: [{ value: 8 }] },
238
+ { label: 'Deep Clean', mode: 4, modeTags: [{ value: 16384 }, { value: 16385 }] },
239
+ ],
240
+ currentMode: 1,
241
+ }
242
+ default:
243
+ return {
244
+ supportedModes: [
245
+ { label: 'Vacuum', mode: 0, modeTags: [{ value: 16385 }] },
246
+ { label: 'Vacuum & Mop', mode: 1, modeTags: [{ value: 16385 }, { value: 16386 }] },
247
+ { label: 'Deep Clean', mode: 2, modeTags: [{ value: 16384 }] },
248
+ ],
249
+ currentMode: 0,
250
+ }
209
251
  }
210
252
  })(),
211
253
  rvcOperationalState: {
@@ -213,9 +255,12 @@ export class RoboticVacuumAccessory extends BaseMatterAccessory {
213
255
  { operationalStateId: 0 }, // Stopped
214
256
  { operationalStateId: 1 }, // Running
215
257
  { operationalStateId: 2 }, // Paused
258
+ { operationalStateId: 3 }, // Error
216
259
  { operationalStateId: 64 }, // Seeking Charger
217
260
  { operationalStateId: 65 }, // Charging
218
261
  { operationalStateId: 66 }, // Docked
262
+ { operationalStateId: 67 }, // In Remote Control
263
+ { operationalStateId: 68 }, // In Dust Collecting
219
264
  ],
220
265
  operationalState: 66,
221
266
  },
@@ -225,13 +270,18 @@ export class RoboticVacuumAccessory extends BaseMatterAccessory {
225
270
  stop: async () => this.handleStop(),
226
271
  start: async () => this.handleStart(),
227
272
  goHome: async () => this.handleGoHome(),
273
+ // Always register resume handler, log warning if not supported
274
+ resume: async () => {
275
+ if (capabilities.resume) {
276
+ await this.handleResume()
277
+ } else {
278
+ this.logWarn(`Resume operation is not supported for model: ${this.model}`)
279
+ }
280
+ },
228
281
  }
229
282
  if (capabilities.pause) {
230
283
  opHandlers.pause = async () => this.handlePause()
231
284
  }
232
- if (capabilities.resume) {
233
- opHandlers.resume = async () => this.handleResume()
234
- }
235
285
  return {
236
286
  rvcRunMode: { changeToMode: async (request: MatterRequests.ChangeToMode) => this.handleChangeRunMode(request) },
237
287
  rvcCleanMode: { changeToMode: async (request: MatterRequests.ChangeToMode) => this.handleChangeCleanMode(request) },
@@ -248,58 +298,110 @@ export class RoboticVacuumAccessory extends BaseMatterAccessory {
248
298
  private async handleChangeRunMode(request: MatterRequests.ChangeToMode): Promise<void> {
249
299
  this.logInfo(`ChangeToMode (run) request received: ${JSON.stringify(request)}`)
250
300
  const { newMode } = request
251
- const modeStr = ['Idle', 'Cleaning'][newMode] || `Unknown (mode=${newMode})`
252
- this.logInfo(`changing run mode to: ${modeStr}`)
253
- if (newMode === 1) {
254
- await this.handleStart()
255
- } else if (newMode === 0) {
256
- await this.handleGoHome()
301
+ const modeStr = ['Idle', 'Cleaning', 'Returning to Dock'][newMode] || `Unknown (mode=${newMode})`
302
+ this.logInfo(`Changing run mode to: ${modeStr}`)
303
+
304
+ switch (this.model) {
305
+ case 'Robot Vacuum Cleaner S1':
306
+ case 'Robot Vacuum Cleaner S1 Plus': {
307
+ if (newMode === 1) {
308
+ await this.handleStart()
309
+ } else if (newMode === 0) {
310
+ await this.handleGoHome()
311
+ }
312
+ break
313
+ }
314
+ case 'Mini Robot Vacuum K10+':
315
+ case 'Mini Robot Vacuum K10+ Pro':
316
+ case 'K10+ Pro Combo': {
317
+ if (newMode === 1) {
318
+ await this.handleStart()
319
+ } else if (newMode === 2) {
320
+ await this.handleDock()
321
+ }
322
+ break
323
+ }
324
+ case 'Multitasking Household Robot K20+ Pro': {
325
+ if (newMode === 1) {
326
+ await this.handleStart()
327
+ } else if (newMode === 0) {
328
+ await this.handleGoHome()
329
+ } else if (newMode === 2) {
330
+ await this.handlePause()
331
+ }
332
+ break
333
+ }
334
+ case 'Floor Cleaning Robot S10':
335
+ case 'Floor Cleaning Robot S20': {
336
+ if (newMode === 1) {
337
+ await this.handleStart()
338
+ } else if (newMode === 0) {
339
+ await this.handleGoHome()
340
+ }
341
+ break
342
+ }
343
+ case 'Robot Vacuum K11+': {
344
+ if (newMode === 1) {
345
+ await this.handleStart()
346
+ } else if (newMode === 0) {
347
+ await this.handleGoHome()
348
+ } else if (newMode === 2) {
349
+ await this.handleDock()
350
+ }
351
+ break
352
+ }
353
+ default:
354
+ this.logWarn(`Run mode change not supported for model: ${this.model}`)
257
355
  }
258
356
  }
259
357
 
260
358
  private async handleChangeCleanMode(request: MatterRequests.ChangeToMode): Promise<void> {
261
359
  this.logInfo(`ChangeToMode (clean) request received: ${JSON.stringify(request)}`)
262
360
  const { newMode } = request
263
- if (this.capabilities.cleanAction === 'vacuum-only') {
264
- const mapPow = ['Quiet', 'Standard', 'Strong', 'MAX'] as const
265
- const label = mapPow[newMode] ?? `Unknown (${newMode})`
266
- this.logInfo(`changing suction level to: ${label}`)
267
- if (this.capabilities.suctionKind === 'powLevel-0-3') {
268
- try {
269
- this.logInfo(`[OpenAPI] Sending PowLevel: ${newMode}`)
270
- await this.sendOpenAPICommand('PowLevel', String(newMode))
271
- this.logInfo(`[OpenAPI] PowLevel command sent: ${newMode}`)
272
- } catch (e: any) {
273
- this.logWarn(`OpenAPI PowLevel failed: ${String(e?.message ?? e)}`)
274
- }
275
- } else if (this.capabilities.suctionKind === 'fanLevel-1-4') {
276
- this.currentFanLevel = (Math.min(3, Math.max(0, Number(newMode))) + 1) as 1 | 2 | 3 | 4
277
- try {
278
- this.logInfo(`[OpenAPI] Sending changeParam fanLevel: ${this.currentFanLevel}`)
279
- await this.sendOpenAPICommand('changeParam', JSON.stringify({ fanLevel: this.currentFanLevel }))
280
- this.logInfo(`[OpenAPI] changeParam command sent: fanLevel=${this.currentFanLevel}`)
281
- } catch (e: any) {
282
- this.logWarn(`OpenAPI changeParam(fanLevel) failed: ${String(e?.message ?? e)}`)
283
- }
284
- }
285
- this.updateCleanMode(newMode)
286
- return
287
- }
288
361
 
289
- if (this.capabilities.cleanAction === 'vacuum-or-mop') {
290
- const label = newMode === 0 ? 'Vacuum' : 'Mop'
291
- this.currentCleanAction = newMode === 0 ? 'vacuum' : 'mop'
292
- this.logInfo(`changing clean action to: ${label}`)
293
- this.logInfo(`[OpenAPI] (no command sent for cleanAction change, just updating state)`)
294
- this.updateCleanMode(newMode)
295
- return
362
+ switch (this.model) {
363
+ case 'Robot Vacuum Cleaner S1':
364
+ case 'Robot Vacuum Cleaner S1 Plus': {
365
+ const mapPowS1 = ['Quiet', 'Standard', 'Strong', 'MAX'] as const
366
+ const labelS1 = mapPowS1[newMode] ?? `Unknown (${newMode})`
367
+ this.logInfo(`Changing suction level to: ${labelS1}`)
368
+ await this.sendOpenAPICommand('PowLevel', String(newMode))
369
+ break
370
+ }
371
+ case 'Mini Robot Vacuum K10+':
372
+ case 'Mini Robot Vacuum K10+ Pro':
373
+ case 'K10+ Pro Combo': {
374
+ const mapPowK10 = ['Vacuum', 'Mop', 'Sweep & Mop'] as const
375
+ const labelK10 = mapPowK10[newMode] ?? `Unknown (${newMode})`
376
+ this.logInfo(`Changing cleaning mode to: ${labelK10}`)
377
+ await this.sendOpenAPICommand('CleanMode', String(newMode))
378
+ break
379
+ }
380
+ case 'Multitasking Household Robot K20+ Pro': {
381
+ const mapPowK20 = ['Vacuum', 'Vacuum & Mop', 'Deep Clean'] as const
382
+ const labelK20 = mapPowK20[newMode] ?? `Unknown (${newMode})`
383
+ this.logInfo(`Changing cleaning mode to: ${labelK20}`)
384
+ await this.sendOpenAPICommand('CleanMode', String(newMode))
385
+ break
386
+ }
387
+ case 'Floor Cleaning Robot S10':
388
+ case 'Floor Cleaning Robot S20': {
389
+ const mapPowS10 = ['Vacuum', 'Mop'] as const
390
+ const labelS10 = mapPowS10[newMode] ?? `Unknown (${newMode})`
391
+ this.logInfo(`Changing cleaning mode to: ${labelS10}`)
392
+ await this.sendOpenAPICommand('CleanMode', String(newMode))
393
+ break
394
+ }
395
+ case 'Robot Vacuum K11+': {
396
+ const mapPowK11 = ['Quiet', 'Standard', 'Strong', 'MAX', 'Deep Clean'] as const
397
+ const labelK11 = mapPowK11[newMode] ?? `Unknown (${newMode})`
398
+ this.logInfo(`Changing suction level to: ${labelK11}`)
399
+ await this.sendOpenAPICommand('PowLevel', String(newMode))
400
+ break
401
+ }
402
+ default:
403
+ this.logWarn(`Clean mode change not supported for model: ${this.model}`)
296
404
  }
297
-
298
- const label = newMode === 0 ? 'Vacuum' : 'Vacuum & Mop'
299
- this.currentCleanAction = newMode === 0 ? 'vacuum' : 'vacuum_mop'
300
- this.logInfo(`changing clean action to: ${label}`)
301
- this.logInfo(`[OpenAPI] (no command sent for cleanAction change, just updating state)`)
302
- this.updateCleanMode(newMode)
303
405
  }
304
406
 
305
407
  private async handlePause(): Promise<void> {
@@ -359,7 +461,15 @@ export class RoboticVacuumAccessory extends BaseMatterAccessory {
359
461
 
360
462
  private async handleResume(): Promise<void> {
361
463
  this.logInfo('resume requested.')
362
- await this.handleStart()
464
+ try {
465
+ this.logInfo(`[OpenAPI] Sending resume command`)
466
+ await this.sendOpenAPICommand('resume')
467
+ this.logInfo(`[OpenAPI] resume command sent`)
468
+ } catch (e: any) {
469
+ this.logWarn(`OpenAPI resume failed: ${String(e?.message ?? e)}`)
470
+ }
471
+ this.updateRunMode(1)
472
+ this.updateOperationalState(1)
363
473
  }
364
474
 
365
475
  private async handleGoHome(): Promise<void> {
@@ -397,14 +507,7 @@ export class RoboticVacuumAccessory extends BaseMatterAccessory {
397
507
 
398
508
  public updateCleanMode(mode: number): void {
399
509
  this.updateState('rvcCleanMode', { currentMode: mode })
400
- let label = `Unknown (${mode})`
401
- if (this.capabilities.cleanAction === 'vacuum-only') {
402
- label = ['Quiet', 'Standard', 'Strong', 'MAX'][mode] || label
403
- } else if (this.capabilities.cleanAction === 'vacuum-or-mop') {
404
- label = ['Vacuum', 'Mop'][mode] || label
405
- } else {
406
- label = ['Vacuum', 'Vacuum & Mop'][mode] || label
407
- }
510
+ const label = mode === 0 ? 'Vacuum' : mode === 1 ? 'Mop' : mode === 2 ? 'Vacuum & Mop' : 'Unknown'
408
511
  this.logInfo(`clean mode updated to: ${label}`)
409
512
  }
410
513
 
@@ -431,4 +534,88 @@ export class RoboticVacuumAccessory extends BaseMatterAccessory {
431
534
  ;(this.context as any).batteryChargeLevel = chargeLevel
432
535
  }
433
536
  }
537
+
538
+ private async handleDock(): Promise<void> {
539
+ this.logInfo('Docking the vacuum.')
540
+ try {
541
+ this.logInfo('[OpenAPI] Sending dock command')
542
+ await this.sendOpenAPICommand('dock')
543
+ this.logInfo('[OpenAPI] Dock command sent successfully')
544
+ this.updateRunMode(0) // Set to Idle after docking
545
+ this.updateOperationalState(64) // Seeking Charger state
546
+ } catch (error: any) {
547
+ this.logWarn(`Docking failed: ${String(error?.message ?? error)}`)
548
+ }
549
+ }
550
+
551
+ private async handleServiceArea(): Promise<void> {
552
+ this.logWarn(`Service area functionality is not supported for model: ${this.model}`)
553
+ // Placeholder for potential future support.
554
+ }
555
+
556
+ private async simulateCleaningSequence(): Promise<void> {
557
+ this.logInfo('Starting cleaning sequence simulation.')
558
+ this.updateOperationalState(1) // Set to Running
559
+
560
+ setTimeout(async () => {
561
+ this.logInfo('Cleaning sequence timer expired. Requesting device status update.')
562
+ try {
563
+ const status = await this.requestDeviceStatus()
564
+ if (status && status.operationalState) {
565
+ this.logInfo(`Device status found: ${status.operationalState}`)
566
+ this.updateOperationalState(status.operationalState)
567
+ } else {
568
+ this.logWarn('Device status not found. Setting operational state to Stopped.')
569
+ this.updateOperationalState(0) // Default to Stopped
570
+ }
571
+ } catch (error: any) {
572
+ this.logWarn(`Failed to fetch device status: ${String(error?.message ?? error)}`)
573
+ this.updateOperationalState(0) // Default to Stopped
574
+ }
575
+ }, 5000) // Simulate a 5-second cleaning sequence
576
+ }
577
+
578
+ private async simulateDockingSequence(): Promise<void> {
579
+ this.logInfo('Starting docking sequence simulation.')
580
+ this.updateOperationalState(64) // Set to Seeking Charger
581
+
582
+ setTimeout(async () => {
583
+ this.logInfo('Docking sequence timer expired. Requesting device status update.')
584
+ try {
585
+ const status = await this.requestDeviceStatus()
586
+ if (status && status.operationalState) {
587
+ this.logInfo(`Device status found: ${status.operationalState}`)
588
+ this.updateOperationalState(status.operationalState)
589
+ } else {
590
+ this.logWarn('Device status not found. Setting operational state to Docked.')
591
+ this.updateOperationalState(66) // Default to Docked
592
+ }
593
+ } catch (error: any) {
594
+ this.logWarn(`Failed to fetch device status: ${String(error?.message ?? error)}`)
595
+ this.updateOperationalState(66) // Default to Docked
596
+ }
597
+ }, 5000) // Simulate a 5-second docking sequence
598
+ }
599
+
600
+ private async requestDeviceStatus(): Promise<{ operationalState?: number } | null> {
601
+ this.logInfo('Requesting device status from OpenAPI.')
602
+ try {
603
+ const response = await this.sendOpenAPICommand('getDeviceStatus')
604
+ this.logInfo(`Device status response: ${JSON.stringify(response)}`)
605
+ return response
606
+ } catch (error: any) {
607
+ this.logWarn(`Failed to request device status: ${String(error?.message ?? error)}`)
608
+ return null
609
+ }
610
+ }
611
+
612
+ public async startCleaningSimulation(): Promise<void> {
613
+ this.logInfo('Initiating cleaning simulation.')
614
+ await this.simulateCleaningSequence()
615
+ }
616
+
617
+ public async startDockingSimulation(): Promise<void> {
618
+ this.logInfo('Initiating docking simulation.')
619
+ await this.simulateDockingSequence()
620
+ }
434
621
  }
package/src/settings.ts CHANGED
@@ -88,11 +88,27 @@ export interface options {
88
88
  * When false (default), reset at UTC midnight. Default: false.
89
89
  */
90
90
  dailyApiResetAtLocalMidnight?: boolean
91
- // Matter platform batch refresh options
91
+ /**
92
+ * When true, resets the daily API request counter to zero. This is useful for testing purposes.
93
+ */
94
+ resetDailyApiCounter?: boolean
95
+ /**
96
+ * When set, configures the batch refresh rate (in milliseconds) for Matter devices. Default: 5000 ms.
97
+ */
92
98
  matterBatchRefreshRate?: number
99
+ /**
100
+ * When true, enables batch processing for Matter devices. Default: false.
101
+ */
93
102
  matterBatchConcurrency?: number
103
+ /**
104
+ * When true, enables batch processing for Matter devices. Default: false.
105
+ */
94
106
  matterBatchEnabled?: boolean
107
+ /**
108
+ * When set, adds a random delay (jitter) to batch requests to avoid thundering herd problems.
109
+ */
95
110
  matterBatchJitter?: number
111
+ newFeatureEnabled?: boolean
96
112
  };
97
113
 
98
114
  export type devicesConfig = botConfig | relaySwitch1Config | relaySwitch1PMConfig | meterConfig | meterProConfig | indoorOutdoorSensorConfig | humidifierConfig | curtainConfig | blindTiltConfig | contactConfig | motionConfig | waterDetectorConfig | plugConfig | colorBulbConfig | stripLightConfig | ceilingLightConfig | lockConfig | hubConfig
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=roboticVacuumAccessory.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"roboticVacuumAccessory.test.d.ts","sourceRoot":"","sources":["../../../../src/test/matter/devices-matter/roboticVacuumAccessory.test.ts"],"names":[],"mappings":""}