@homebridge-plugins/homebridge-sharkiq 2.0.0-beta.12 → 2.0.0-beta.13
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/constants.d.ts.map +1 -1
- package/dist/constants.js.map +1 -1
- package/dist/devices/BaseMatterAccessory.d.ts +63 -0
- package/dist/devices/BaseMatterAccessory.d.ts.map +1 -0
- package/dist/devices/BaseMatterAccessory.js +100 -0
- package/dist/devices/BaseMatterAccessory.js.map +1 -0
- package/dist/devices/RoboticVacuumAccessory.d.ts +53 -28
- package/dist/devices/RoboticVacuumAccessory.d.ts.map +1 -1
- package/dist/devices/RoboticVacuumAccessory.js +316 -308
- package/dist/devices/RoboticVacuumAccessory.js.map +1 -1
- package/dist/devices/index.d.ts +9 -0
- package/dist/devices/index.d.ts.map +1 -0
- package/dist/devices/index.js +8 -0
- package/dist/devices/index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/platform.d.ts +32 -32
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +91 -312
- package/dist/platform.js.map +1 -1
- package/docs/variables/default.html +2 -1
- package/package.json +1 -1
- package/dist/errorHandling.d.ts +0 -19
- package/dist/errorHandling.d.ts.map +0 -1
- package/dist/errorHandling.js +0 -27
- package/dist/errorHandling.js.map +0 -1
- package/dist/platformAccessory.d.ts +0 -48
- package/dist/platformAccessory.d.ts.map +0 -1
- package/dist/platformAccessory.js +0 -560
- package/dist/platformAccessory.js.map +0 -1
|
@@ -1,86 +1,125 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
pollIntervalId = null;
|
|
12
|
-
dockedDelay = 0;
|
|
13
|
-
dockedUpdateInterval = TIMEOUTS.DEFAULT_DOCKED_UPDATE_INTERVAL;
|
|
14
|
-
constructor(api, log, device) {
|
|
15
|
-
this.api = api;
|
|
16
|
-
this.log = log;
|
|
17
|
-
this.device = device;
|
|
18
|
-
}
|
|
19
|
-
// Simple retry helper with exponential backoff
|
|
20
|
-
async retry(fn, attempts = 3, initialDelay = 500) {
|
|
21
|
-
let lastError;
|
|
22
|
-
let delay = initialDelay;
|
|
23
|
-
for (let i = 0; i < attempts; i++) {
|
|
24
|
-
try {
|
|
25
|
-
return await fn();
|
|
26
|
-
}
|
|
27
|
-
catch (e) {
|
|
28
|
-
lastError = e;
|
|
29
|
-
this.log.debug(`Retry ${i + 1}/${attempts} failed:`, e);
|
|
30
|
-
if (i < attempts - 1) {
|
|
31
|
-
await new Promise(res => setTimeout(res, delay));
|
|
32
|
-
delay *= 2;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
throw lastError;
|
|
37
|
-
}
|
|
38
|
-
toAccessory() {
|
|
39
|
-
const serialNumber = this.device._dsn && this.device._dsn.toString ? this.device._dsn.toString() : String(this.device._dsn);
|
|
40
|
-
const uuid = this.api.matter.uuid.generate(serialNumber);
|
|
41
|
-
const deviceType = this.api.matter.deviceTypes.RoboticVacuumCleaner;
|
|
42
|
-
const acc = {
|
|
43
|
-
uuid,
|
|
44
|
-
displayName: this.device._name || `Robot Vacuum ${serialNumber}`,
|
|
45
|
-
deviceType,
|
|
1
|
+
/* global NodeJS */
|
|
2
|
+
import { BaseMatterAccessory } from './BaseMatterAccessory.js';
|
|
3
|
+
export class RoboticVacuumAccessory extends BaseMatterAccessory {
|
|
4
|
+
activeTimers = [];
|
|
5
|
+
constructor(api, log) {
|
|
6
|
+
const serialNumber = 'VACUUM-001';
|
|
7
|
+
super(api, log, {
|
|
8
|
+
uuid: api.matter.uuid.generate(serialNumber),
|
|
9
|
+
displayName: 'Robot Vacuum',
|
|
10
|
+
deviceType: api.matter.deviceTypes.RoboticVacuumCleaner,
|
|
46
11
|
serialNumber,
|
|
47
|
-
manufacturer: '
|
|
48
|
-
model:
|
|
49
|
-
firmwareRevision:
|
|
12
|
+
manufacturer: 'Homebridge Matter',
|
|
13
|
+
model: 'HB-MATTER-VACUUM-ROBOTIC',
|
|
14
|
+
firmwareRevision: '2.0.0',
|
|
50
15
|
hardwareRevision: '1.0.0',
|
|
51
16
|
clusters: {
|
|
17
|
+
// Run Mode: Controls what the vacuum is doing (Idle, Cleaning, Mapping)
|
|
52
18
|
rvcRunMode: {
|
|
53
19
|
supportedModes: [
|
|
54
|
-
{ label: 'Idle', mode: 0 },
|
|
55
|
-
{ label: 'Cleaning', mode: 1 },
|
|
56
|
-
{ label: 'Mapping', mode: 2 },
|
|
20
|
+
{ label: 'Idle', mode: 0, modeTags: [{ value: 16384 }] }, // RvcRunMode.ModeTag.Idle
|
|
21
|
+
{ label: 'Cleaning', mode: 1, modeTags: [{ value: 16385 }] }, // RvcRunMode.ModeTag.Cleaning
|
|
22
|
+
{ label: 'Mapping', mode: 2, modeTags: [{ value: 16386 }] }, // RvcRunMode.ModeTag.Mapping
|
|
57
23
|
],
|
|
58
24
|
currentMode: 0,
|
|
59
25
|
},
|
|
26
|
+
// Clean Mode: Controls HOW the vacuum cleans
|
|
27
|
+
// You can combine semantic tags (0-9) with functional tags (16384-16386)
|
|
28
|
+
// Available semantic tags: Auto, Quick, Quiet, LowNoise, LowEnergy, Vacation, Min, Max, Night, Day
|
|
29
|
+
// Available functional tags: DeepClean, Vacuum, Mop
|
|
60
30
|
rvcCleanMode: {
|
|
61
31
|
supportedModes: [
|
|
62
|
-
|
|
63
|
-
{ label: '
|
|
64
|
-
{ label: '
|
|
32
|
+
// Basic functional modes
|
|
33
|
+
{ label: 'Vacuum', mode: 0, modeTags: [{ value: 16385 }] }, // Vacuum
|
|
34
|
+
{ label: 'Mop', mode: 1, modeTags: [{ value: 16386 }] }, // Mop
|
|
35
|
+
{ label: 'Vacuum & Mop', mode: 2, modeTags: [{ value: 16385 }, { value: 16386 }] }, // Both
|
|
36
|
+
// Deep clean modes
|
|
37
|
+
{ label: 'Deep Clean', mode: 3, modeTags: [{ value: 16384 }] }, // DeepClean
|
|
38
|
+
{ label: 'Deep Vacuum', mode: 4, modeTags: [{ value: 16384 }, { value: 16385 }] }, // DeepClean + Vacuum
|
|
39
|
+
{ label: 'Deep Mop', mode: 5, modeTags: [{ value: 16384 }, { value: 16386 }] }, // DeepClean + Mop
|
|
40
|
+
// Intensity modes
|
|
41
|
+
{ label: 'Quick Clean', mode: 6, modeTags: [{ value: 1 }, { value: 16385 }] }, // Quick + Vacuum
|
|
42
|
+
{ label: 'Max Clean', mode: 7, modeTags: [{ value: 7 }, { value: 16385 }] }, // Max + Vacuum
|
|
43
|
+
{ label: 'Min Clean', mode: 8, modeTags: [{ value: 6 }, { value: 16385 }] }, // Min + Vacuum
|
|
44
|
+
// Quiet modes
|
|
45
|
+
{ label: 'Quiet Vacuum', mode: 9, modeTags: [{ value: 2 }, { value: 16385 }] }, // Quiet + Vacuum
|
|
46
|
+
{ label: 'Quiet Mop', mode: 10, modeTags: [{ value: 2 }, { value: 16386 }] }, // Quiet + Mop
|
|
47
|
+
{ label: 'Night Mode', mode: 11, modeTags: [{ value: 8 }, { value: 16385 }] }, // Night + Vacuum
|
|
48
|
+
// Energy efficient
|
|
49
|
+
{ label: 'Eco Vacuum', mode: 12, modeTags: [{ value: 4 }, { value: 16385 }] }, // LowEnergy + Vacuum
|
|
50
|
+
{ label: 'Eco Mop', mode: 13, modeTags: [{ value: 4 }, { value: 16386 }] }, // LowEnergy + Mop
|
|
51
|
+
// Auto mode
|
|
52
|
+
{ label: 'Auto', mode: 14, modeTags: [{ value: 0 }, { value: 16385 }] }, // Auto + Vacuum
|
|
65
53
|
],
|
|
66
|
-
currentMode: 0,
|
|
54
|
+
currentMode: 0, // start with basic Vacuum
|
|
67
55
|
},
|
|
56
|
+
// Operational State: Current state (Stopped, Running, Paused, Error, etc.)
|
|
68
57
|
rvcOperationalState: {
|
|
69
58
|
operationalStateList: [
|
|
70
|
-
{ operationalStateId: 0,
|
|
71
|
-
{ operationalStateId: 1,
|
|
72
|
-
{ operationalStateId: 2,
|
|
73
|
-
{ operationalStateId:
|
|
74
|
-
{ operationalStateId:
|
|
75
|
-
{ operationalStateId:
|
|
59
|
+
{ operationalStateId: 0 }, // stopped (standard label from Matter spec)
|
|
60
|
+
{ operationalStateId: 1 }, // running
|
|
61
|
+
{ operationalStateId: 2 }, // paused
|
|
62
|
+
{ operationalStateId: 3 }, // error
|
|
63
|
+
{ operationalStateId: 64 }, // seeking charger
|
|
64
|
+
{ operationalStateId: 65 }, // charging
|
|
65
|
+
{ operationalStateId: 66 }, // docked
|
|
76
66
|
],
|
|
77
|
-
operationalState:
|
|
67
|
+
operationalState: 66, // start docked
|
|
78
68
|
},
|
|
69
|
+
// Service Area: Room/zone selection for targeted cleaning
|
|
79
70
|
serviceArea: {
|
|
80
|
-
supportedMaps: [],
|
|
81
|
-
supportedAreas: [
|
|
82
|
-
|
|
83
|
-
|
|
71
|
+
supportedMaps: [], // empty array - we don't use map features
|
|
72
|
+
supportedAreas: [
|
|
73
|
+
{
|
|
74
|
+
areaId: 0,
|
|
75
|
+
mapId: null, // required: must be null when supportedMaps is empty
|
|
76
|
+
areaInfo: {
|
|
77
|
+
locationInfo: {
|
|
78
|
+
locationName: 'Living Room',
|
|
79
|
+
floorNumber: 0,
|
|
80
|
+
areaType: 7, // AreaNamespaceTag.LivingRoom
|
|
81
|
+
},
|
|
82
|
+
landmarkInfo: null,
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
areaId: 1,
|
|
87
|
+
mapId: null,
|
|
88
|
+
areaInfo: {
|
|
89
|
+
locationInfo: {
|
|
90
|
+
locationName: 'Kitchen',
|
|
91
|
+
floorNumber: 0,
|
|
92
|
+
areaType: 10, // AreaNamespaceTag.Kitchen
|
|
93
|
+
},
|
|
94
|
+
landmarkInfo: null,
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
areaId: 2,
|
|
99
|
+
mapId: null,
|
|
100
|
+
areaInfo: {
|
|
101
|
+
locationInfo: {
|
|
102
|
+
locationName: 'Bedroom',
|
|
103
|
+
floorNumber: 0,
|
|
104
|
+
areaType: 2, // AreaNamespaceTag.Bedroom
|
|
105
|
+
},
|
|
106
|
+
landmarkInfo: null,
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
areaId: 3,
|
|
111
|
+
mapId: null,
|
|
112
|
+
areaInfo: {
|
|
113
|
+
locationInfo: {
|
|
114
|
+
locationName: 'Bathroom',
|
|
115
|
+
floorNumber: 0,
|
|
116
|
+
areaType: 6, // AreaNamespaceTag.Bathroom
|
|
117
|
+
},
|
|
118
|
+
landmarkInfo: null,
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
selectedAreas: [0, 1, 2, 3], // all areas selected by default
|
|
84
123
|
},
|
|
85
124
|
},
|
|
86
125
|
handlers: {
|
|
@@ -91,9 +130,9 @@ export class RoboticVacuumAccessory {
|
|
|
91
130
|
changeToMode: async (request) => this.handleChangeCleanMode(request),
|
|
92
131
|
},
|
|
93
132
|
rvcOperationalState: {
|
|
94
|
-
start: async () => this.handleStart(),
|
|
95
|
-
stop: async () => this.handleStop(),
|
|
96
133
|
pause: async () => this.handlePause(),
|
|
134
|
+
stop: async () => this.handleStop(),
|
|
135
|
+
start: async () => this.handleStart(),
|
|
97
136
|
resume: async () => this.handleResume(),
|
|
98
137
|
goHome: async () => this.handleGoHome(),
|
|
99
138
|
},
|
|
@@ -102,266 +141,235 @@ export class RoboticVacuumAccessory {
|
|
|
102
141
|
skipArea: async (request) => this.handleSkipArea(request),
|
|
103
142
|
},
|
|
104
143
|
},
|
|
105
|
-
};
|
|
106
|
-
|
|
144
|
+
});
|
|
145
|
+
this.logInfo('initialized and ready.');
|
|
107
146
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
147
|
+
async handleChangeRunMode(request) {
|
|
148
|
+
this.logInfo(`ChangeToMode (run) request received: ${JSON.stringify(request)}`);
|
|
149
|
+
const { newMode } = request;
|
|
150
|
+
const modeStr = ['Idle', 'Cleaning', 'Mapping'][newMode] || `Unknown (mode=${newMode})`;
|
|
151
|
+
this.logInfo(`changing run mode to: ${modeStr}`);
|
|
152
|
+
// TODO: await myVacuumAPI.setRunMode(newMode)
|
|
153
|
+
// Clear any existing timers
|
|
154
|
+
this.clearTimers();
|
|
155
|
+
if (newMode === 1) {
|
|
156
|
+
// Switching to Cleaning mode - start the vacuum
|
|
157
|
+
this.updateOperationalState(1); // Running
|
|
158
|
+
// Simulate cleaning completion after 15 seconds
|
|
159
|
+
const completionTimer = setTimeout(() => {
|
|
160
|
+
this.logInfo('cleaning completed, returning to dock.');
|
|
161
|
+
this.updateRunMode(0); // Set to Idle - cleaning session ending
|
|
162
|
+
this.returnToDock();
|
|
163
|
+
}, 15000);
|
|
164
|
+
this.activeTimers.push(completionTimer);
|
|
165
|
+
}
|
|
166
|
+
else if (newMode === 0) {
|
|
167
|
+
// Switching to Idle mode - return to dock
|
|
168
|
+
this.returnToDock();
|
|
169
|
+
}
|
|
170
|
+
else if (newMode === 2) {
|
|
171
|
+
// Switching to Mapping mode - start mapping
|
|
172
|
+
this.updateOperationalState(1); // Running
|
|
173
|
+
// Simulate mapping completion after 20 seconds
|
|
174
|
+
const completionTimer = setTimeout(() => {
|
|
175
|
+
this.logInfo('mapping completed, returning to dock.');
|
|
176
|
+
this.returnToDock();
|
|
177
|
+
}, 20000);
|
|
178
|
+
this.activeTimers.push(completionTimer);
|
|
135
179
|
}
|
|
136
180
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
181
|
+
async handleChangeCleanMode(request) {
|
|
182
|
+
this.logInfo(`ChangeToMode (clean) request received: ${JSON.stringify(request)}`);
|
|
183
|
+
const { newMode } = request;
|
|
184
|
+
const modes = [
|
|
185
|
+
'Vacuum',
|
|
186
|
+
'Mop',
|
|
187
|
+
'Vacuum & Mop',
|
|
188
|
+
'Deep Clean',
|
|
189
|
+
'Deep Vacuum',
|
|
190
|
+
'Deep Mop',
|
|
191
|
+
'Quick Clean',
|
|
192
|
+
'Max Clean',
|
|
193
|
+
'Min Clean',
|
|
194
|
+
'Quiet Vacuum',
|
|
195
|
+
'Quiet Mop',
|
|
196
|
+
'Night Mode',
|
|
197
|
+
'Eco Vacuum',
|
|
198
|
+
'Eco Mop',
|
|
199
|
+
'Auto',
|
|
200
|
+
];
|
|
201
|
+
const modeStr = modes[newMode] || `Unknown (mode=${newMode})`;
|
|
202
|
+
this.logInfo(`changing clean mode to: ${modeStr}`);
|
|
203
|
+
// TODO: await myVacuumAPI.setCleanMode(newMode)
|
|
154
204
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
const interval = this.dockedUpdateInterval || TIMEOUTS.DEFAULT_DOCKED_UPDATE_INTERVAL;
|
|
161
|
-
this.pollIntervalId = setInterval(async () => {
|
|
162
|
-
try {
|
|
163
|
-
const maybeDelay = await this.retry(() => this.device.update([Properties.DOCKED_STATUS, Properties.OPERATING_MODE, Properties.POWER_MODE]));
|
|
164
|
-
if (typeof maybeDelay === 'number') {
|
|
165
|
-
this.dockedDelay = maybeDelay;
|
|
166
|
-
}
|
|
167
|
-
await this.updateOperationalState();
|
|
168
|
-
await this.updateRunMode();
|
|
169
|
-
await this.updateCleanMode();
|
|
170
|
-
await this.updateSelectedAreas();
|
|
171
|
-
await this.updateProgress();
|
|
172
|
-
}
|
|
173
|
-
catch (e) {
|
|
174
|
-
this.log.debug('Polling update error', e);
|
|
175
|
-
}
|
|
176
|
-
}, interval + this.dockedDelay);
|
|
205
|
+
async handlePause() {
|
|
206
|
+
this.logInfo('pausing.');
|
|
207
|
+
// TODO: await myVacuumAPI.pause()
|
|
208
|
+
this.clearTimers(); // Clear cleaning completion timer
|
|
209
|
+
this.updateOperationalState(2); // Paused
|
|
177
210
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
211
|
+
async handleStop() {
|
|
212
|
+
this.logInfo('stopping.');
|
|
213
|
+
// TODO: await myVacuumAPI.stop()
|
|
214
|
+
this.clearTimers();
|
|
215
|
+
this.updateRunMode(0); // Reset to Idle
|
|
216
|
+
this.updateOperationalState(0); // Stopped
|
|
184
217
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
catch (e) {
|
|
202
|
-
this.log.debug('setClusterValue error', e);
|
|
203
|
-
}
|
|
218
|
+
async handleStart() {
|
|
219
|
+
this.logInfo('starting (via start command).');
|
|
220
|
+
// TODO: await myVacuumAPI.start()
|
|
221
|
+
// Clear any existing timers
|
|
222
|
+
this.clearTimers();
|
|
223
|
+
this.updateRunMode(1); // Set to Cleaning mode - this will trigger the run mode handler logic
|
|
224
|
+
this.updateOperationalState(1); // Running
|
|
225
|
+
// Simulate cleaning completion after 15 seconds
|
|
226
|
+
const completionTimer = setTimeout(() => {
|
|
227
|
+
this.logInfo('cleaning completed, returning to dock.');
|
|
228
|
+
this.updateRunMode(0); // Set to Idle - cleaning session ending
|
|
229
|
+
this.returnToDock();
|
|
230
|
+
}, 15000);
|
|
231
|
+
this.activeTimers.push(completionTimer);
|
|
204
232
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
// Docked status overrides when docked
|
|
220
|
-
const docked = this.device.docked_status && this.device.docked_status() === 1;
|
|
221
|
-
if (docked) {
|
|
222
|
-
opState = 66;
|
|
223
|
-
}
|
|
224
|
-
this.setClusterValue('rvcOperationalState', 'operationalState', opState);
|
|
225
|
-
}
|
|
226
|
-
catch (e) {
|
|
227
|
-
this.log.debug('updateOperationalState error', e);
|
|
228
|
-
}
|
|
233
|
+
async handleResume() {
|
|
234
|
+
this.logInfo('resuming.');
|
|
235
|
+
// TODO: await myVacuumAPI.resume()
|
|
236
|
+
// Clear any existing timers
|
|
237
|
+
this.clearTimers();
|
|
238
|
+
this.updateRunMode(1); // Set to Cleaning mode
|
|
239
|
+
this.updateOperationalState(1); // Running
|
|
240
|
+
// Simulate cleaning completion after 10 seconds (shorter since resuming)
|
|
241
|
+
const completionTimer = setTimeout(() => {
|
|
242
|
+
this.logInfo('cleaning completed, returning to dock.');
|
|
243
|
+
this.updateRunMode(0); // Set to Idle - cleaning session ending
|
|
244
|
+
this.returnToDock();
|
|
245
|
+
}, 10000);
|
|
246
|
+
this.activeTimers.push(completionTimer);
|
|
229
247
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
this.log.debug('updateRunMode error', e);
|
|
243
|
-
}
|
|
248
|
+
async handleGoHome() {
|
|
249
|
+
this.logInfo('goHome command received.');
|
|
250
|
+
// TODO: await myVacuumAPI.goHome()
|
|
251
|
+
// Clear any existing timers
|
|
252
|
+
this.clearTimers();
|
|
253
|
+
// Defer state updates to ensure handler completes first
|
|
254
|
+
setImmediate(() => {
|
|
255
|
+
// Set to Idle mode since we're ending the cleaning session
|
|
256
|
+
this.updateRunMode(0);
|
|
257
|
+
// Initiate return to dock sequence
|
|
258
|
+
this.returnToDock();
|
|
259
|
+
});
|
|
244
260
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
let cleanMode = 0;
|
|
252
|
-
if (power === PowerModes.MAX) {
|
|
253
|
-
cleanMode = 0;
|
|
254
|
-
}
|
|
255
|
-
this.setClusterValue('rvcCleanMode', 'currentMode', cleanMode);
|
|
256
|
-
}
|
|
257
|
-
catch (e) {
|
|
258
|
-
this.log.debug('updateCleanMode error', e);
|
|
259
|
-
}
|
|
261
|
+
async handleSelectAreas(request) {
|
|
262
|
+
this.logInfo(`SelectAreas request received: ${JSON.stringify(request)}`);
|
|
263
|
+
const { newAreas } = request;
|
|
264
|
+
const areaNames = newAreas.map((id) => ['Living Room', 'Kitchen', 'Bedroom', 'Bathroom'][id] || `Area ${id}`);
|
|
265
|
+
this.logInfo(`selecting areas: ${areaNames.join(', ')}`);
|
|
266
|
+
// TODO: await myVacuumAPI.selectAreas(newAreas)
|
|
260
267
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
this.setClusterValue('serviceArea', 'supportedMaps', maps);
|
|
268
|
-
this.setClusterValue('serviceArea', 'supportedAreas', areas);
|
|
269
|
-
// No selectedAreas by default
|
|
270
|
-
}
|
|
271
|
-
catch (e) {
|
|
272
|
-
this.log.debug('updateSelectedAreas error', e);
|
|
273
|
-
}
|
|
268
|
+
async handleSkipArea(request) {
|
|
269
|
+
this.logInfo(`SkipArea request received: ${JSON.stringify(request)}`);
|
|
270
|
+
const { skippedArea } = request;
|
|
271
|
+
const areaName = ['Living Room', 'Kitchen', 'Bedroom', 'Bathroom'][skippedArea] || `Area ${skippedArea}`;
|
|
272
|
+
this.logInfo(`skipping area: ${areaName}`);
|
|
273
|
+
// TODO: await myVacuumAPI.skipArea(skippedArea)
|
|
274
274
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
}
|
|
282
|
-
catch (e) {
|
|
283
|
-
this.log.debug('updateProgress error', e);
|
|
284
|
-
}
|
|
275
|
+
/**
|
|
276
|
+
* Helper method to clear all active timers
|
|
277
|
+
*/
|
|
278
|
+
clearTimers() {
|
|
279
|
+
this.activeTimers.forEach(timer => clearTimeout(timer));
|
|
280
|
+
this.activeTimers = [];
|
|
285
281
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
282
|
+
/**
|
|
283
|
+
* Helper method to initiate return to dock sequence
|
|
284
|
+
* Can be called synchronously from other handlers
|
|
285
|
+
*/
|
|
286
|
+
returnToDock() {
|
|
287
|
+
this.logInfo('initiating return to dock sequence.');
|
|
288
|
+
// Defer ALL state updates to ensure handler completes first
|
|
289
|
+
setImmediate(() => {
|
|
290
|
+
// Start seeking charger directly (skip intermediate Stopped state)
|
|
291
|
+
this.updateOperationalState(64); // Seeking Charger
|
|
292
|
+
// After 5 seconds, start charging
|
|
293
|
+
const chargingTimer = setTimeout(() => {
|
|
294
|
+
this.logInfo('reached dock, now charging.');
|
|
295
|
+
this.updateOperationalState(65); // Charging
|
|
296
|
+
// After 3 more seconds, fully docked
|
|
297
|
+
const dockedTimer = setTimeout(() => {
|
|
298
|
+
this.logInfo('fully charged and docked.');
|
|
299
|
+
this.updateOperationalState(66); // Docked
|
|
300
|
+
}, 3000);
|
|
301
|
+
this.activeTimers.push(dockedTimer);
|
|
302
|
+
}, 5000);
|
|
303
|
+
this.activeTimers.push(chargingTimer);
|
|
304
|
+
});
|
|
295
305
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
306
|
+
/**
|
|
307
|
+
* Update Methods - Use these to update the vacuum state from your API/device
|
|
308
|
+
*
|
|
309
|
+
* Since this is a platform accessory, state updates work immediately after registration.
|
|
310
|
+
*/
|
|
311
|
+
updateOperationalState(state) {
|
|
312
|
+
this.updateState('rvcOperationalState', { operationalState: state });
|
|
313
|
+
const states = [
|
|
314
|
+
'Stopped',
|
|
315
|
+
'Running',
|
|
316
|
+
'Paused',
|
|
317
|
+
'Error',
|
|
318
|
+
null,
|
|
319
|
+
null,
|
|
320
|
+
null,
|
|
321
|
+
null,
|
|
322
|
+
...Array.from({ length: 56 }).fill(null),
|
|
323
|
+
'Seeking Charger',
|
|
324
|
+
'Charging',
|
|
325
|
+
'Docked',
|
|
326
|
+
];
|
|
327
|
+
this.logInfo(`operational state updated to: ${states[state] || `Unknown (${state})`}`);
|
|
304
328
|
}
|
|
305
|
-
|
|
306
|
-
this.
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}
|
|
310
|
-
catch (e) {
|
|
311
|
-
this.log.debug('handlePause error', e);
|
|
312
|
-
}
|
|
329
|
+
updateRunMode(mode) {
|
|
330
|
+
this.updateState('rvcRunMode', { currentMode: mode });
|
|
331
|
+
const modes = ['Idle', 'Cleaning', 'Mapping'];
|
|
332
|
+
this.logInfo(`run mode updated to: ${modes[mode] || `Unknown (${mode})`}`);
|
|
313
333
|
}
|
|
314
|
-
|
|
315
|
-
this.
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
334
|
+
updateCleanMode(mode) {
|
|
335
|
+
this.updateState('rvcCleanMode', { currentMode: mode });
|
|
336
|
+
const modes = [
|
|
337
|
+
'Vacuum',
|
|
338
|
+
'Mop',
|
|
339
|
+
'Vacuum & Mop',
|
|
340
|
+
'Deep Clean',
|
|
341
|
+
'Deep Vacuum',
|
|
342
|
+
'Deep Mop',
|
|
343
|
+
'Quick Clean',
|
|
344
|
+
'Max Clean',
|
|
345
|
+
'Min Clean',
|
|
346
|
+
'Quiet Vacuum',
|
|
347
|
+
'Quiet Mop',
|
|
348
|
+
'Night Mode',
|
|
349
|
+
'Eco Vacuum',
|
|
350
|
+
'Eco Mop',
|
|
351
|
+
'Auto',
|
|
352
|
+
];
|
|
353
|
+
this.logInfo(`clean mode updated to: ${modes[mode] || `Unknown (${mode})`}`);
|
|
322
354
|
}
|
|
323
|
-
|
|
324
|
-
this.
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
}
|
|
328
|
-
catch (e) {
|
|
329
|
-
this.log.debug('handleGoHome error', e);
|
|
330
|
-
}
|
|
355
|
+
updateSelectedAreas(areaIds) {
|
|
356
|
+
this.updateState('serviceArea', { selectedAreas: areaIds });
|
|
357
|
+
const areaNames = areaIds.map(id => ['Living Room', 'Kitchen', 'Bedroom', 'Bathroom'][id] || `Area ${id}`);
|
|
358
|
+
this.logInfo(`selected areas updated to: ${areaNames.join(', ') || 'All Areas'}`);
|
|
331
359
|
}
|
|
332
|
-
|
|
333
|
-
this.
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
await this.retry(() => this.device.clean_rooms([]));
|
|
338
|
-
}
|
|
339
|
-
else if (newMode === 0) {
|
|
340
|
-
await this.retry(() => this.device.cancel_clean());
|
|
341
|
-
}
|
|
360
|
+
updateCurrentArea(areaId) {
|
|
361
|
+
this.updateState('serviceArea', { currentArea: areaId });
|
|
362
|
+
if (areaId !== null) {
|
|
363
|
+
const areaName = ['Living Room', 'Kitchen', 'Bedroom', 'Bathroom'][areaId] || `Area ${areaId}`;
|
|
364
|
+
this.logInfo(`current area updated to: ${areaName}`);
|
|
342
365
|
}
|
|
343
|
-
|
|
344
|
-
this.
|
|
366
|
+
else {
|
|
367
|
+
this.logInfo('current area cleared');
|
|
345
368
|
}
|
|
346
369
|
}
|
|
347
|
-
|
|
348
|
-
this.
|
|
349
|
-
|
|
350
|
-
}
|
|
351
|
-
async handleSelectAreas(request) {
|
|
352
|
-
this.log.info('Matter -> Select Areas', request);
|
|
353
|
-
const areas = request?.newAreas;
|
|
354
|
-
if (Array.isArray(areas) && areas.length > 0) {
|
|
355
|
-
try {
|
|
356
|
-
await this.retry(() => this.device.clean_rooms(areas));
|
|
357
|
-
}
|
|
358
|
-
catch (e) {
|
|
359
|
-
this.log.debug('handleSelectAreas error', e);
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
async handleSkipArea(request) {
|
|
364
|
-
this.log.info('Matter -> Skip Area', request);
|
|
370
|
+
updateProgress(progress) {
|
|
371
|
+
this.updateState('serviceArea', { progress });
|
|
372
|
+
this.logInfo(`progress updated: ${progress.length} areas`);
|
|
365
373
|
}
|
|
366
374
|
}
|
|
367
375
|
//# sourceMappingURL=RoboticVacuumAccessory.js.map
|