@switchbot/homebridge-switchbot 5.0.0-beta.63 → 5.0.0-beta.64
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/dist/devices-matter/RoboticVacuumAccessory.d.ts +7 -0
- package/dist/devices-matter/RoboticVacuumAccessory.d.ts.map +1 -1
- package/dist/devices-matter/RoboticVacuumAccessory.js +253 -83
- package/dist/devices-matter/RoboticVacuumAccessory.js.map +1 -1
- package/docs/variables/default.html +1 -1
- package/package.json +1 -1
- package/src/devices-matter/RoboticVacuumAccessory.ts +252 -78
- package/dist/test/matter/devices-matter/roboticVacuumAccessory.test.d.ts +0 -2
- package/dist/test/matter/devices-matter/roboticVacuumAccessory.test.d.ts.map +0 -1
- package/dist/test/matter/devices-matter/roboticVacuumAccessory.test.js +0 -366
- package/dist/test/matter/devices-matter/roboticVacuumAccessory.test.js.map +0 -1
- package/src/test/matter/devices-matter/roboticVacuumAccessory.test.ts +0 -453
|
@@ -180,32 +180,74 @@ export class RoboticVacuumAccessory extends BaseMatterAccessory {
|
|
|
180
180
|
currentMode: 0,
|
|
181
181
|
},
|
|
182
182
|
rvcCleanMode: (() => {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
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
|
},
|
|
@@ -248,58 +293,110 @@ export class RoboticVacuumAccessory extends BaseMatterAccessory {
|
|
|
248
293
|
private async handleChangeRunMode(request: MatterRequests.ChangeToMode): Promise<void> {
|
|
249
294
|
this.logInfo(`ChangeToMode (run) request received: ${JSON.stringify(request)}`)
|
|
250
295
|
const { newMode } = request
|
|
251
|
-
const modeStr = ['Idle', 'Cleaning'][newMode] || `Unknown (mode=${newMode})`
|
|
252
|
-
this.logInfo(`
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
296
|
+
const modeStr = ['Idle', 'Cleaning', 'Returning to Dock'][newMode] || `Unknown (mode=${newMode})`
|
|
297
|
+
this.logInfo(`Changing run mode to: ${modeStr}`)
|
|
298
|
+
|
|
299
|
+
switch (this.model) {
|
|
300
|
+
case 'Robot Vacuum Cleaner S1':
|
|
301
|
+
case 'Robot Vacuum Cleaner S1 Plus': {
|
|
302
|
+
if (newMode === 1) {
|
|
303
|
+
await this.handleStart()
|
|
304
|
+
} else if (newMode === 0) {
|
|
305
|
+
await this.handleGoHome()
|
|
306
|
+
}
|
|
307
|
+
break
|
|
308
|
+
}
|
|
309
|
+
case 'Mini Robot Vacuum K10+':
|
|
310
|
+
case 'Mini Robot Vacuum K10+ Pro':
|
|
311
|
+
case 'K10+ Pro Combo': {
|
|
312
|
+
if (newMode === 1) {
|
|
313
|
+
await this.handleStart()
|
|
314
|
+
} else if (newMode === 2) {
|
|
315
|
+
await this.handleDock()
|
|
316
|
+
}
|
|
317
|
+
break
|
|
318
|
+
}
|
|
319
|
+
case 'Multitasking Household Robot K20+ Pro': {
|
|
320
|
+
if (newMode === 1) {
|
|
321
|
+
await this.handleStart()
|
|
322
|
+
} else if (newMode === 0) {
|
|
323
|
+
await this.handleGoHome()
|
|
324
|
+
} else if (newMode === 2) {
|
|
325
|
+
await this.handlePause()
|
|
326
|
+
}
|
|
327
|
+
break
|
|
328
|
+
}
|
|
329
|
+
case 'Floor Cleaning Robot S10':
|
|
330
|
+
case 'Floor Cleaning Robot S20': {
|
|
331
|
+
if (newMode === 1) {
|
|
332
|
+
await this.handleStart()
|
|
333
|
+
} else if (newMode === 0) {
|
|
334
|
+
await this.handleGoHome()
|
|
335
|
+
}
|
|
336
|
+
break
|
|
337
|
+
}
|
|
338
|
+
case 'Robot Vacuum K11+': {
|
|
339
|
+
if (newMode === 1) {
|
|
340
|
+
await this.handleStart()
|
|
341
|
+
} else if (newMode === 0) {
|
|
342
|
+
await this.handleGoHome()
|
|
343
|
+
} else if (newMode === 2) {
|
|
344
|
+
await this.handleDock()
|
|
345
|
+
}
|
|
346
|
+
break
|
|
347
|
+
}
|
|
348
|
+
default:
|
|
349
|
+
this.logWarn(`Run mode change not supported for model: ${this.model}`)
|
|
257
350
|
}
|
|
258
351
|
}
|
|
259
352
|
|
|
260
353
|
private async handleChangeCleanMode(request: MatterRequests.ChangeToMode): Promise<void> {
|
|
261
354
|
this.logInfo(`ChangeToMode (clean) request received: ${JSON.stringify(request)}`)
|
|
262
355
|
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
356
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
357
|
+
switch (this.model) {
|
|
358
|
+
case 'Robot Vacuum Cleaner S1':
|
|
359
|
+
case 'Robot Vacuum Cleaner S1 Plus': {
|
|
360
|
+
const mapPowS1 = ['Quiet', 'Standard', 'Strong', 'MAX'] as const
|
|
361
|
+
const labelS1 = mapPowS1[newMode] ?? `Unknown (${newMode})`
|
|
362
|
+
this.logInfo(`Changing suction level to: ${labelS1}`)
|
|
363
|
+
await this.sendOpenAPICommand('PowLevel', String(newMode))
|
|
364
|
+
break
|
|
365
|
+
}
|
|
366
|
+
case 'Mini Robot Vacuum K10+':
|
|
367
|
+
case 'Mini Robot Vacuum K10+ Pro':
|
|
368
|
+
case 'K10+ Pro Combo': {
|
|
369
|
+
const mapPowK10 = ['Vacuum', 'Mop', 'Sweep & Mop'] as const
|
|
370
|
+
const labelK10 = mapPowK10[newMode] ?? `Unknown (${newMode})`
|
|
371
|
+
this.logInfo(`Changing cleaning mode to: ${labelK10}`)
|
|
372
|
+
await this.sendOpenAPICommand('CleanMode', String(newMode))
|
|
373
|
+
break
|
|
374
|
+
}
|
|
375
|
+
case 'Multitasking Household Robot K20+ Pro': {
|
|
376
|
+
const mapPowK20 = ['Vacuum', 'Vacuum & Mop', 'Deep Clean'] as const
|
|
377
|
+
const labelK20 = mapPowK20[newMode] ?? `Unknown (${newMode})`
|
|
378
|
+
this.logInfo(`Changing cleaning mode to: ${labelK20}`)
|
|
379
|
+
await this.sendOpenAPICommand('CleanMode', String(newMode))
|
|
380
|
+
break
|
|
381
|
+
}
|
|
382
|
+
case 'Floor Cleaning Robot S10':
|
|
383
|
+
case 'Floor Cleaning Robot S20': {
|
|
384
|
+
const mapPowS10 = ['Vacuum', 'Mop'] as const
|
|
385
|
+
const labelS10 = mapPowS10[newMode] ?? `Unknown (${newMode})`
|
|
386
|
+
this.logInfo(`Changing cleaning mode to: ${labelS10}`)
|
|
387
|
+
await this.sendOpenAPICommand('CleanMode', String(newMode))
|
|
388
|
+
break
|
|
389
|
+
}
|
|
390
|
+
case 'Robot Vacuum K11+': {
|
|
391
|
+
const mapPowK11 = ['Quiet', 'Standard', 'Strong', 'MAX', 'Deep Clean'] as const
|
|
392
|
+
const labelK11 = mapPowK11[newMode] ?? `Unknown (${newMode})`
|
|
393
|
+
this.logInfo(`Changing suction level to: ${labelK11}`)
|
|
394
|
+
await this.sendOpenAPICommand('PowLevel', String(newMode))
|
|
395
|
+
break
|
|
396
|
+
}
|
|
397
|
+
default:
|
|
398
|
+
this.logWarn(`Clean mode change not supported for model: ${this.model}`)
|
|
296
399
|
}
|
|
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
400
|
}
|
|
304
401
|
|
|
305
402
|
private async handlePause(): Promise<void> {
|
|
@@ -397,14 +494,7 @@ export class RoboticVacuumAccessory extends BaseMatterAccessory {
|
|
|
397
494
|
|
|
398
495
|
public updateCleanMode(mode: number): void {
|
|
399
496
|
this.updateState('rvcCleanMode', { currentMode: mode })
|
|
400
|
-
|
|
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
|
-
}
|
|
497
|
+
const label = mode === 0 ? 'Vacuum' : mode === 1 ? 'Mop' : mode === 2 ? 'Vacuum & Mop' : 'Unknown'
|
|
408
498
|
this.logInfo(`clean mode updated to: ${label}`)
|
|
409
499
|
}
|
|
410
500
|
|
|
@@ -431,4 +521,88 @@ export class RoboticVacuumAccessory extends BaseMatterAccessory {
|
|
|
431
521
|
;(this.context as any).batteryChargeLevel = chargeLevel
|
|
432
522
|
}
|
|
433
523
|
}
|
|
524
|
+
|
|
525
|
+
private async handleDock(): Promise<void> {
|
|
526
|
+
this.logInfo('Docking the vacuum.')
|
|
527
|
+
try {
|
|
528
|
+
this.logInfo('[OpenAPI] Sending dock command')
|
|
529
|
+
await this.sendOpenAPICommand('dock')
|
|
530
|
+
this.logInfo('[OpenAPI] Dock command sent successfully')
|
|
531
|
+
this.updateRunMode(0) // Set to Idle after docking
|
|
532
|
+
this.updateOperationalState(64) // Seeking Charger state
|
|
533
|
+
} catch (error: any) {
|
|
534
|
+
this.logWarn(`Docking failed: ${String(error?.message ?? error)}`)
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
private async handleServiceArea(): Promise<void> {
|
|
539
|
+
this.logWarn(`Service area functionality is not supported for model: ${this.model}`)
|
|
540
|
+
// Placeholder for potential future support.
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
private async simulateCleaningSequence(): Promise<void> {
|
|
544
|
+
this.logInfo('Starting cleaning sequence simulation.')
|
|
545
|
+
this.updateOperationalState(1) // Set to Running
|
|
546
|
+
|
|
547
|
+
setTimeout(async () => {
|
|
548
|
+
this.logInfo('Cleaning sequence timer expired. Requesting device status update.')
|
|
549
|
+
try {
|
|
550
|
+
const status = await this.requestDeviceStatus()
|
|
551
|
+
if (status && status.operationalState) {
|
|
552
|
+
this.logInfo(`Device status found: ${status.operationalState}`)
|
|
553
|
+
this.updateOperationalState(status.operationalState)
|
|
554
|
+
} else {
|
|
555
|
+
this.logWarn('Device status not found. Setting operational state to Stopped.')
|
|
556
|
+
this.updateOperationalState(0) // Default to Stopped
|
|
557
|
+
}
|
|
558
|
+
} catch (error: any) {
|
|
559
|
+
this.logWarn(`Failed to fetch device status: ${String(error?.message ?? error)}`)
|
|
560
|
+
this.updateOperationalState(0) // Default to Stopped
|
|
561
|
+
}
|
|
562
|
+
}, 5000) // Simulate a 5-second cleaning sequence
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
private async simulateDockingSequence(): Promise<void> {
|
|
566
|
+
this.logInfo('Starting docking sequence simulation.')
|
|
567
|
+
this.updateOperationalState(64) // Set to Seeking Charger
|
|
568
|
+
|
|
569
|
+
setTimeout(async () => {
|
|
570
|
+
this.logInfo('Docking sequence timer expired. Requesting device status update.')
|
|
571
|
+
try {
|
|
572
|
+
const status = await this.requestDeviceStatus()
|
|
573
|
+
if (status && status.operationalState) {
|
|
574
|
+
this.logInfo(`Device status found: ${status.operationalState}`)
|
|
575
|
+
this.updateOperationalState(status.operationalState)
|
|
576
|
+
} else {
|
|
577
|
+
this.logWarn('Device status not found. Setting operational state to Docked.')
|
|
578
|
+
this.updateOperationalState(66) // Default to Docked
|
|
579
|
+
}
|
|
580
|
+
} catch (error: any) {
|
|
581
|
+
this.logWarn(`Failed to fetch device status: ${String(error?.message ?? error)}`)
|
|
582
|
+
this.updateOperationalState(66) // Default to Docked
|
|
583
|
+
}
|
|
584
|
+
}, 5000) // Simulate a 5-second docking sequence
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
private async requestDeviceStatus(): Promise<{ operationalState?: number } | null> {
|
|
588
|
+
this.logInfo('Requesting device status from OpenAPI.')
|
|
589
|
+
try {
|
|
590
|
+
const response = await this.sendOpenAPICommand('getDeviceStatus')
|
|
591
|
+
this.logInfo(`Device status response: ${JSON.stringify(response)}`)
|
|
592
|
+
return response
|
|
593
|
+
} catch (error: any) {
|
|
594
|
+
this.logWarn(`Failed to request device status: ${String(error?.message ?? error)}`)
|
|
595
|
+
return null
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
public async startCleaningSimulation(): Promise<void> {
|
|
600
|
+
this.logInfo('Initiating cleaning simulation.')
|
|
601
|
+
await this.simulateCleaningSequence()
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
public async startDockingSimulation(): Promise<void> {
|
|
605
|
+
this.logInfo('Initiating docking simulation.')
|
|
606
|
+
await this.simulateDockingSequence()
|
|
607
|
+
}
|
|
434
608
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"roboticVacuumAccessory.test.d.ts","sourceRoot":"","sources":["../../../../src/test/matter/devices-matter/roboticVacuumAccessory.test.ts"],"names":[],"mappings":""}
|