@homebridge-plugins/homebridge-ecovacs 7.2.2 → 7.2.4-beta.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
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to homebridge-ecovacs will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## v7.2.4 (Unreleased)
|
|
6
|
+
|
|
7
|
+
### Changes
|
|
8
|
+
|
|
9
|
+
- updated dependencies
|
|
10
|
+
- option to expose as a vacuum robot in homekit
|
|
11
|
+
|
|
12
|
+
## v7.2.3 (2025-07-24)
|
|
13
|
+
|
|
14
|
+
### Other Changes
|
|
15
|
+
|
|
16
|
+
- dependency updates
|
|
17
|
+
|
|
5
18
|
## v7.2.2 (2025-07-18)
|
|
6
19
|
|
|
7
20
|
### Other Changes
|
package/lib/platform.js
CHANGED
|
@@ -13,6 +13,7 @@ const require = createRequire(import.meta.url)
|
|
|
13
13
|
const plugin = require('../package.json')
|
|
14
14
|
|
|
15
15
|
const devicesInHB = new Map()
|
|
16
|
+
const matterDevicesInHB = new Map()
|
|
16
17
|
|
|
17
18
|
export default class {
|
|
18
19
|
constructor(log, config, api) {
|
|
@@ -26,6 +27,9 @@ export default class {
|
|
|
26
27
|
this.log = log
|
|
27
28
|
this.isBeta = plugin.version.includes('beta')
|
|
28
29
|
|
|
30
|
+
// Check if Matter is available and enabled
|
|
31
|
+
this.matterEnabled = api.isMatterAvailable?.() && api.isMatterEnabled?.()
|
|
32
|
+
|
|
29
33
|
// Configuration objects for accessories
|
|
30
34
|
this.deviceConf = {}
|
|
31
35
|
this.ignoredDevices = []
|
|
@@ -374,6 +378,13 @@ export default class {
|
|
|
374
378
|
// Display version of the ecovacs-deebot library in the log
|
|
375
379
|
this.log('%s v%s.', platformLang.ecovacsLibVersion, this.ecovacsAPI.getVersion())
|
|
376
380
|
|
|
381
|
+
// Log Matter availability
|
|
382
|
+
if (this.matterEnabled) {
|
|
383
|
+
this.log('Matter support is enabled - vacuums will be exposed via both HAP and Matter.')
|
|
384
|
+
} else {
|
|
385
|
+
this.log('Matter support is not available - vacuums will be exposed via HAP only.')
|
|
386
|
+
}
|
|
387
|
+
|
|
377
388
|
// Attempt to log in to Ecovacs/Yeedi
|
|
378
389
|
try {
|
|
379
390
|
await this.ecovacsAPI.connect(this.config.username, EcoVacsAPI.md5(this.config.password))
|
|
@@ -440,6 +451,230 @@ export default class {
|
|
|
440
451
|
}
|
|
441
452
|
}
|
|
442
453
|
|
|
454
|
+
createMatterRVCAccessory(device, accessory) {
|
|
455
|
+
// Create a Matter RVC (Robotic Vacuum Cleaner) accessory config
|
|
456
|
+
const serialNumber = device.did
|
|
457
|
+
const displayName = device.nick || device.did
|
|
458
|
+
|
|
459
|
+
// Get device types we need
|
|
460
|
+
const RoboticVacuumCleanerType = this.api.matter.deviceTypes.RoboticVacuumCleaner
|
|
461
|
+
|
|
462
|
+
// Create bound handler functions that preserve the platform context
|
|
463
|
+
const boundHandlers = {
|
|
464
|
+
rvcRunMode: {
|
|
465
|
+
changeToMode: (request) => {
|
|
466
|
+
return this.handleMatterRunModeChange(accessory, request)
|
|
467
|
+
},
|
|
468
|
+
},
|
|
469
|
+
rvcOperationalState: {
|
|
470
|
+
pause: () => {
|
|
471
|
+
return this.handleMatterPause(accessory)
|
|
472
|
+
},
|
|
473
|
+
stop: () => {
|
|
474
|
+
return this.handleMatterStop(accessory)
|
|
475
|
+
},
|
|
476
|
+
start: () => {
|
|
477
|
+
return this.handleMatterStart(accessory)
|
|
478
|
+
},
|
|
479
|
+
resume: () => {
|
|
480
|
+
return this.handleMatterResume(accessory)
|
|
481
|
+
},
|
|
482
|
+
goHome: () => {
|
|
483
|
+
return this.handleMatterGoHome(accessory)
|
|
484
|
+
},
|
|
485
|
+
},
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
return {
|
|
489
|
+
uuid: this.api.matter.uuid.generate(serialNumber),
|
|
490
|
+
displayName,
|
|
491
|
+
deviceType: RoboticVacuumCleanerType,
|
|
492
|
+
serialNumber,
|
|
493
|
+
manufacturer: device.company || 'Ecovacs',
|
|
494
|
+
model: device.deviceModel || 'Deebot',
|
|
495
|
+
firmwareRevision: '1.0.0',
|
|
496
|
+
hardwareRevision: '1.0.0',
|
|
497
|
+
|
|
498
|
+
context: {
|
|
499
|
+
hapAccessoryUUID: accessory.UUID,
|
|
500
|
+
deviceId: device.did,
|
|
501
|
+
},
|
|
502
|
+
|
|
503
|
+
clusters: {
|
|
504
|
+
// Run Mode: Idle or Cleaning
|
|
505
|
+
rvcRunMode: {
|
|
506
|
+
supportedModes: [
|
|
507
|
+
{ label: 'Idle', mode: 0, modeTags: [{ value: 16384 }] }, // RvcRunMode.ModeTag.Idle
|
|
508
|
+
{ label: 'Cleaning', mode: 1, modeTags: [{ value: 16385 }] }, // RvcRunMode.ModeTag.Cleaning
|
|
509
|
+
],
|
|
510
|
+
currentMode: 0, // Start as Idle
|
|
511
|
+
},
|
|
512
|
+
// Clean Mode: Just Vacuum mode
|
|
513
|
+
rvcCleanMode: {
|
|
514
|
+
supportedModes: [
|
|
515
|
+
{ label: 'Vacuum', mode: 0, modeTags: [{ value: 16385 }] }, // RvcCleanMode.ModeTag.Vacuum
|
|
516
|
+
],
|
|
517
|
+
currentMode: 0,
|
|
518
|
+
},
|
|
519
|
+
// Operational State
|
|
520
|
+
rvcOperationalState: {
|
|
521
|
+
operationalStateList: [
|
|
522
|
+
{ operationalStateId: 0, operationalStateLabel: 'Stopped' },
|
|
523
|
+
{ operationalStateId: 1, operationalStateLabel: 'Running' },
|
|
524
|
+
{ operationalStateId: 2, operationalStateLabel: 'Paused' },
|
|
525
|
+
{ operationalStateId: 3, operationalStateLabel: 'Error' },
|
|
526
|
+
{ operationalStateId: 64, operationalStateLabel: 'Seeking Charger' },
|
|
527
|
+
{ operationalStateId: 65, operationalStateLabel: 'Charging' },
|
|
528
|
+
{ operationalStateId: 66, operationalStateLabel: 'Docked' },
|
|
529
|
+
],
|
|
530
|
+
operationalState: 66, // Start docked
|
|
531
|
+
},
|
|
532
|
+
},
|
|
533
|
+
|
|
534
|
+
handlers: boundHandlers,
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
async handleMatterRunModeChange(accessory, request) {
|
|
539
|
+
try {
|
|
540
|
+
const { newMode } = request
|
|
541
|
+
accessory.logDebug(`Matter: ChangeToMode (run) request received: mode=${newMode}`)
|
|
542
|
+
|
|
543
|
+
if (newMode === 1) {
|
|
544
|
+
// Switching to Cleaning mode - start cleaning
|
|
545
|
+
await this.internalCleanUpdate(accessory, true)
|
|
546
|
+
} else if (newMode === 0) {
|
|
547
|
+
// Switching to Idle mode - stop or return to dock
|
|
548
|
+
await this.internalChargeUpdate(accessory, true)
|
|
549
|
+
}
|
|
550
|
+
} catch (err) {
|
|
551
|
+
accessory.logWarn(`Matter: Run mode change failed ${parseError(err)}`)
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
async handleMatterPause(accessory) {
|
|
556
|
+
try {
|
|
557
|
+
accessory.logDebug('Matter: Pause request received')
|
|
558
|
+
// Stop the vacuum
|
|
559
|
+
// TODO work out which devices have a pause and implement properly
|
|
560
|
+
await this.internalCleanUpdate(accessory, false)
|
|
561
|
+
|
|
562
|
+
// Update Matter states immediately
|
|
563
|
+
this.updateMatterRunMode(accessory, 0) // idle
|
|
564
|
+
this.updateMatterOperationalState(accessory, 0) // stopped
|
|
565
|
+
} catch (err) {
|
|
566
|
+
accessory.logWarn(`Matter: Pause failed ${parseError(err)}`)
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
async handleMatterStop(accessory) {
|
|
571
|
+
try {
|
|
572
|
+
accessory.logDebug('Matter: Stop request received')
|
|
573
|
+
await this.internalCleanUpdate(accessory, false)
|
|
574
|
+
|
|
575
|
+
// Update Matter states immediately
|
|
576
|
+
this.updateMatterRunMode(accessory, 0) // idle
|
|
577
|
+
this.updateMatterOperationalState(accessory, 0) // stopped
|
|
578
|
+
} catch (err) {
|
|
579
|
+
accessory.logWarn(`Matter: Stop failed ${parseError(err)}`)
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
async handleMatterStart(accessory) {
|
|
584
|
+
try {
|
|
585
|
+
accessory.logDebug('Matter: Start request received')
|
|
586
|
+
await this.internalCleanUpdate(accessory, true)
|
|
587
|
+
} catch (err) {
|
|
588
|
+
accessory.logWarn(`Matter: Start failed ${parseError(err)}`)
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
async handleMatterResume(accessory) {
|
|
593
|
+
try {
|
|
594
|
+
accessory.logDebug('Matter: Resume request received')
|
|
595
|
+
await this.internalCleanUpdate(accessory, true)
|
|
596
|
+
} catch (err) {
|
|
597
|
+
accessory.logWarn(`Matter: Resume failed ${parseError(err)}`)
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
async handleMatterGoHome(accessory) {
|
|
602
|
+
try {
|
|
603
|
+
accessory.logDebug('Matter: GoHome request received')
|
|
604
|
+
await this.internalChargeUpdate(accessory, true)
|
|
605
|
+
} catch (err) {
|
|
606
|
+
accessory.logWarn(`Matter: GoHome failed ${parseError(err)}`)
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
updateMatterOperationalState(accessory, state) {
|
|
611
|
+
// Update Matter operational state if Matter is enabled and accessory has Matter UUID
|
|
612
|
+
if (!this.matterEnabled || !accessory.matterUUID || !accessory.matterReady) {
|
|
613
|
+
return
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
try {
|
|
617
|
+
this.api.matter.updateAccessoryState(accessory.matterUUID, 'rvcOperationalState', {
|
|
618
|
+
operationalState: state,
|
|
619
|
+
})
|
|
620
|
+
accessory.logDebug(`Matter: Operational state updated to ${state}`)
|
|
621
|
+
} catch (err) {
|
|
622
|
+
accessory.logError(`Matter: Failed to update operational state: ${parseError(err)}`)
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
updateMatterRunMode(accessory, mode) {
|
|
627
|
+
// Update Matter run mode if Matter is enabled and accessory has Matter UUID
|
|
628
|
+
if (!this.matterEnabled || !accessory.matterUUID || !accessory.matterReady) {
|
|
629
|
+
return
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
try {
|
|
633
|
+
this.api.matter.updateAccessoryState(accessory.matterUUID, 'rvcRunMode', {
|
|
634
|
+
currentMode: mode,
|
|
635
|
+
})
|
|
636
|
+
accessory.logDebug(`Matter: Run mode updated to ${mode}`)
|
|
637
|
+
} catch (err) {
|
|
638
|
+
accessory.logError(`Matter: Failed to update run mode: ${parseError(err)}`)
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
updateMatterStateFromHAP(accessory) {
|
|
643
|
+
// Sync current HAP state to Matter when Matter becomes ready
|
|
644
|
+
if (!this.matterEnabled || !accessory.matterUUID || !accessory.matterReady) {
|
|
645
|
+
return
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
try {
|
|
649
|
+
// Sync cleaning state
|
|
650
|
+
const isActive = ['auto', 'clean', 'edge', 'spot', 'spotarea', 'customarea'].includes(
|
|
651
|
+
(accessory.context.cacheClean || '').toLowerCase().replace(/[^a-z]+/g, ''),
|
|
652
|
+
)
|
|
653
|
+
if (isActive) {
|
|
654
|
+
this.updateMatterRunMode(accessory, 1) // Cleaning
|
|
655
|
+
this.updateMatterOperationalState(accessory, 1) // Running
|
|
656
|
+
} else {
|
|
657
|
+
this.updateMatterRunMode(accessory, 0) // Idle
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// Sync charging state
|
|
661
|
+
const chargeStateLower = (accessory.context.cacheCharge || '').toLowerCase()
|
|
662
|
+
if (chargeStateLower === 'charging') {
|
|
663
|
+
this.updateMatterOperationalState(accessory, 65) // charging
|
|
664
|
+
} else if (chargeStateLower === 'returning') {
|
|
665
|
+
this.updateMatterOperationalState(accessory, 64) // seeking charger
|
|
666
|
+
} else if (chargeStateLower === 'idle') {
|
|
667
|
+
this.updateMatterOperationalState(accessory, 66) // docked
|
|
668
|
+
} else if (!isActive) {
|
|
669
|
+
this.updateMatterOperationalState(accessory, 0) // stopped
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
accessory.logDebug('Matter: Initial state synchronized from HAP')
|
|
673
|
+
} catch (err) {
|
|
674
|
+
accessory.logError(`Matter: Failed to sync initial state: ${parseError(err)}`)
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
443
678
|
initialiseDevice(device) {
|
|
444
679
|
try {
|
|
445
680
|
// Generate the Homebridge UUID from the device id
|
|
@@ -789,6 +1024,49 @@ export default class {
|
|
|
789
1024
|
this.api.updatePlatformAccessories([accessory])
|
|
790
1025
|
devicesInHB.set(accessory.UUID, accessory)
|
|
791
1026
|
|
|
1027
|
+
// Register Matter RVC accessory if Matter is enabled
|
|
1028
|
+
if (this.matterEnabled) {
|
|
1029
|
+
try {
|
|
1030
|
+
const matterUUID = this.api.matter.uuid.generate(device.did)
|
|
1031
|
+
|
|
1032
|
+
// Check if this Matter accessory already exists
|
|
1033
|
+
const existingMatterAccessory = matterDevicesInHB.get(matterUUID)
|
|
1034
|
+
|
|
1035
|
+
if (!existingMatterAccessory) {
|
|
1036
|
+
// Create and publish new Matter RVC accessory
|
|
1037
|
+
const matterAccessory = this.createMatterRVCAccessory(device, accessory)
|
|
1038
|
+
|
|
1039
|
+
// Mark Matter accessory as not ready yet
|
|
1040
|
+
accessory.matterReady = false
|
|
1041
|
+
accessory.matterUUID = matterUUID
|
|
1042
|
+
|
|
1043
|
+
// Publish the accessory and listen for the READY event
|
|
1044
|
+
const published = this.api.matter.publishExternalAccessories(plugin.name, [matterAccessory])
|
|
1045
|
+
|
|
1046
|
+
// Listen for when the Matter accessory is ready
|
|
1047
|
+
if (published && published[0] && published[0]._eventEmitter) {
|
|
1048
|
+
published[0]._eventEmitter.on('ready', () => {
|
|
1049
|
+
accessory.matterReady = true
|
|
1050
|
+
accessory.log('Matter RVC accessory is ready.')
|
|
1051
|
+
|
|
1052
|
+
// Update initial state now that it's ready
|
|
1053
|
+
this.updateMatterStateFromHAP(accessory)
|
|
1054
|
+
})
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
matterDevicesInHB.set(matterUUID, matterAccessory)
|
|
1058
|
+
this.log('[%s] Matter RVC accessory published.', accessory.displayName)
|
|
1059
|
+
} else {
|
|
1060
|
+
// Matter accessory already exists, just link it
|
|
1061
|
+
accessory.matterUUID = matterUUID
|
|
1062
|
+
accessory.matterReady = true // Assume existing accessories are ready
|
|
1063
|
+
accessory.logDebug('Matter RVC accessory already registered.')
|
|
1064
|
+
}
|
|
1065
|
+
} catch (err) {
|
|
1066
|
+
accessory.logWarn(`Failed to register Matter RVC accessory: ${parseError(err)}`)
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
|
|
792
1070
|
// Log configuration and device initialisation
|
|
793
1071
|
this.log(
|
|
794
1072
|
'[%s] %s: %s.',
|
|
@@ -912,31 +1190,38 @@ export default class {
|
|
|
912
1190
|
}
|
|
913
1191
|
|
|
914
1192
|
configureAccessory(accessory) {
|
|
915
|
-
|
|
1193
|
+
this.log.debug(`[${accessory.displayName}] loading cached hap accessory.`)
|
|
916
1194
|
devicesInHB.set(accessory.UUID, accessory)
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
throw new this.api.hap.HapStatusError(-70402)
|
|
923
|
-
})
|
|
924
|
-
.updateValue(new this.api.hap.HapStatusError(-70402))
|
|
925
|
-
accessory
|
|
926
|
-
.getService('Go Charge')
|
|
927
|
-
.getCharacteristic(this.api.hap.Characteristic.On)
|
|
928
|
-
.onSet(() => {
|
|
929
|
-
this.log.warn('[%s] %s.', accessory.displayName, platformLang.accNotReady)
|
|
930
|
-
throw new this.api.hap.HapStatusError(-70402)
|
|
931
|
-
})
|
|
932
|
-
.updateValue(new this.api.hap.HapStatusError(-70402))
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
configureMatterAccessory(accessory) {
|
|
1198
|
+
this.log.debug(`[${accessory.displayName}] loading cached matter accessory.`)
|
|
1199
|
+
matterDevicesInHB.set(accessory.uuid, accessory)
|
|
933
1200
|
}
|
|
934
1201
|
|
|
935
1202
|
removeAccessory(accessory) {
|
|
936
1203
|
// Remove an accessory from Homebridge
|
|
937
1204
|
try {
|
|
1205
|
+
// Remove HAP accessory
|
|
938
1206
|
this.api.unregisterPlatformAccessories(plugin.name, plugin.alias, [accessory])
|
|
939
1207
|
devicesInHB.delete(accessory.UUID)
|
|
1208
|
+
|
|
1209
|
+
// Remove corresponding Matter accessory if it exists
|
|
1210
|
+
if (this.matterEnabled && accessory.context.ecoDeviceId) {
|
|
1211
|
+
try {
|
|
1212
|
+
const matterUUID = this.api.matter.uuid.generate(accessory.context.ecoDeviceId)
|
|
1213
|
+
const matterAccessory = matterDevicesInHB.get(matterUUID)
|
|
1214
|
+
|
|
1215
|
+
if (matterAccessory) {
|
|
1216
|
+
this.api.matter.unpublishExternalAccessories([matterAccessory])
|
|
1217
|
+
matterDevicesInHB.delete(matterUUID)
|
|
1218
|
+
this.log.debug('[%s] Matter RVC accessory removed.', accessory.displayName)
|
|
1219
|
+
}
|
|
1220
|
+
} catch (matterErr) {
|
|
1221
|
+
this.log.warn('[%s] Failed to remove Matter accessory: %s', accessory.displayName, parseError(matterErr))
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
|
|
940
1225
|
this.log('[%s] %s.', accessory.displayName, platformLang.devRemove)
|
|
941
1226
|
} catch (err) {
|
|
942
1227
|
// Catch any errors during remove
|
|
@@ -964,7 +1249,7 @@ export default class {
|
|
|
964
1249
|
const order = value ? `Clean${accessory.context.commandSuffix}` : 'Stop'
|
|
965
1250
|
|
|
966
1251
|
// Log the update
|
|
967
|
-
accessory.log(`${platformLang.curCleaning} [${value ? platformLang.cleaning : platformLang.stop}
|
|
1252
|
+
accessory.log(`${platformLang.curCleaning} [${value ? platformLang.cleaning : platformLang.stop}]`)
|
|
968
1253
|
|
|
969
1254
|
// Send the command
|
|
970
1255
|
accessory.logDebug(`${platformLang.sendCmd} [${order}]`)
|
|
@@ -1255,15 +1540,25 @@ export default class {
|
|
|
1255
1540
|
|
|
1256
1541
|
// Check if the new cleaning state is different from the cached state
|
|
1257
1542
|
if (accessory.context.cacheClean !== newVal) {
|
|
1258
|
-
|
|
1543
|
+
const isActive = ['auto', 'clean', 'edge', 'spot', 'spotarea', 'customarea'].includes(
|
|
1544
|
+
newVal.toLowerCase().replace(/[^a-z]+/g, ''),
|
|
1545
|
+
)
|
|
1546
|
+
|
|
1547
|
+
// State is different so update HAP service
|
|
1259
1548
|
accessory
|
|
1260
1549
|
.getService('Clean')
|
|
1261
|
-
.updateCharacteristic(
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
)
|
|
1550
|
+
.updateCharacteristic(this.hapChar.On, isActive)
|
|
1551
|
+
|
|
1552
|
+
// Update Matter states
|
|
1553
|
+
if (isActive) {
|
|
1554
|
+
// Vacuum is cleaning
|
|
1555
|
+
this.updateMatterRunMode(accessory, 1) // Cleaning mode
|
|
1556
|
+
this.updateMatterOperationalState(accessory, 1) // Running state
|
|
1557
|
+
} else {
|
|
1558
|
+
// Vacuum is not cleaning - could be idle or stopped
|
|
1559
|
+
this.updateMatterRunMode(accessory, 0) // Idle mode
|
|
1560
|
+
this.updateMatterOperationalState(accessory, 0) // Stopped state
|
|
1561
|
+
}
|
|
1267
1562
|
|
|
1268
1563
|
// Log the change
|
|
1269
1564
|
accessory.log(`${platformLang.curCleaning} [${newVal}]`)
|
|
@@ -1356,7 +1651,7 @@ export default class {
|
|
|
1356
1651
|
|
|
1357
1652
|
// Check if the new charging state is different from the cached state
|
|
1358
1653
|
if (accessory.context.cacheCharge !== newVal) {
|
|
1359
|
-
// State is different so update service
|
|
1654
|
+
// State is different so update HAP service
|
|
1360
1655
|
accessory
|
|
1361
1656
|
.getService('Go Charge')
|
|
1362
1657
|
.updateCharacteristic(this.hapChar.On, newVal === 'returning')
|
|
@@ -1365,6 +1660,19 @@ export default class {
|
|
|
1365
1660
|
.getService(this.hapServ.Battery)
|
|
1366
1661
|
.updateCharacteristic(this.hapChar.ChargingState, chargeState)
|
|
1367
1662
|
|
|
1663
|
+
// Update Matter operational state based on charge state
|
|
1664
|
+
const chargeStateLower = newVal.toLowerCase()
|
|
1665
|
+
if (chargeStateLower === 'charging') {
|
|
1666
|
+
this.updateMatterRunMode(accessory, 0) // Idle mode
|
|
1667
|
+
this.updateMatterOperationalState(accessory, 65) // Charging
|
|
1668
|
+
} else if (chargeStateLower === 'returning') {
|
|
1669
|
+
this.updateMatterRunMode(accessory, 0) // Idle mode
|
|
1670
|
+
this.updateMatterOperationalState(accessory, 64) // Seeking Charger
|
|
1671
|
+
} else if (chargeStateLower === 'idle') {
|
|
1672
|
+
this.updateMatterRunMode(accessory, 0) // Idle mode
|
|
1673
|
+
this.updateMatterOperationalState(accessory, 66) // Docked
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1368
1676
|
// Log the change
|
|
1369
1677
|
accessory.log(`${platformLang.curCharging} [${newVal}]`)
|
|
1370
1678
|
}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"displayName": "Homebridge Ecovacs",
|
|
4
4
|
"alias": "Deebot",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"version": "7.2.
|
|
6
|
+
"version": "7.2.4-beta.0",
|
|
7
7
|
"description": "Homebridge plugin to integrate Ecovacs Deebot devices into HomeKit.",
|
|
8
8
|
"author": {
|
|
9
9
|
"name": "bwp91",
|
|
@@ -63,15 +63,15 @@
|
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
65
|
"@homebridge/plugin-ui-utils": "^2.1.0",
|
|
66
|
-
"ecovacs-deebot": "^0.9.6-beta.
|
|
67
|
-
"patch-package": "^8.0.
|
|
66
|
+
"ecovacs-deebot": "^0.9.6-beta.12",
|
|
67
|
+
"patch-package": "^8.0.1"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
|
-
"@antfu/eslint-config": "^
|
|
70
|
+
"@antfu/eslint-config": "^6.1.0"
|
|
71
71
|
},
|
|
72
72
|
"overrides": {
|
|
73
|
-
"
|
|
74
|
-
"
|
|
73
|
+
"request": {
|
|
74
|
+
"form-data": "^2.5.4"
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
diff --git a/node_modules/ecovacs-deebot/library/tools.js b/node_modules/ecovacs-deebot/library/tools.js
|
|
2
|
-
index d484ba1..
|
|
2
|
+
index d484ba1..eb8e866 100644
|
|
3
3
|
--- a/node_modules/ecovacs-deebot/library/tools.js
|
|
4
4
|
+++ b/node_modules/ecovacs-deebot/library/tools.js
|
|
5
5
|
@@ -369,11 +369,13 @@ function envLogRaw(message) {
|