UNPKG

matterbridge-roborock-vacuum-plugin

Version:
294 lines 13.7 kB
import { RvcOperationalState, RvcRunMode } from 'matterbridge/matter/clusters'; import { OperationStatusCode } from '../roborockCommunication/enums/operationStatusCode.js'; import { state_to_matter_operational_status, state_to_matter_state } from './function.js'; /** * Resolves the robot's state based on status code and modifier flags. * * Implements a 48-row state resolution matrix with three priority levels: * * 1. **Status Override Rules** (Highest Priority) * - Certain status codes ignore ALL modifier flags * - Examples: Sleeping (2), Idle (3), InError (12), WashingTheMop (23), GoingToWashTheMop (26), etc. * - Sleeping (2): inCleaning=true → Cleaning+Paused; isExploring=true → Mapping+Paused; base → Idle+Paused * * 2. **Cleaning Status Special Overrides** * - When status = 5 (Cleaning), modifiers apply in explicit priority order: * a. isLocating/isExploring (Highest) - Sets UpdatingMaps operational state * b. inWarmup (Second) - Sets CleaningMop operational state * c. inReturning (Third) - Sets SeekingCharger operational state * d. inFreshState (N/A) - Not applicable to Cleaning status * * 3. **Modifier Priority Chain** * - For all other cases, modifiers apply in priority order: * a. inReturning (High) - Sets SeekingCharger operational state (ignored for Paused, ReturnToDock, ReturningDock) * b. isExploring (Medium) - Changes run mode to Mapping (blocked on Charging) * c. inFreshState (Low) - No longer used (redundant with Charging base state) * * @param message StatusChangeMessage containing status code and modifier flags * @returns ResolvedState with runMode and operationalState * * @see misc/state_resolution_matrix.md - Complete 47-row matrix documentation */ export function resolveDeviceState(message) { const status = message.status; // ═══════════════════════════════════════════════════════════════════════════ // Priority 0: Status Override Rules (Highest Priority) // ═══════════════════════════════════════════════════════════════════════════ // These status codes ignore ALL modifier flags and always return fixed states // Sleeping Status Override - Rows 8-10 if (status === OperationStatusCode.Sleeping) { // Row 8: inCleaning=true overrides all other flags → Cleaning + Paused if (message.inCleaning === true) { return { runMode: RvcRunMode.ModeTag.Cleaning, operationalState: RvcOperationalState.OperationalState.Paused, }; } // Row 9: isExploring=true (without inCleaning) → Mapping + Paused if (message.isExploring === true) { return { runMode: RvcRunMode.ModeTag.Mapping, operationalState: RvcOperationalState.OperationalState.Paused, }; } // Row 10: Base → Idle + Paused return { runMode: RvcRunMode.ModeTag.Idle, operationalState: RvcOperationalState.OperationalState.Paused, }; } // Idle Status Override - Row 11 if (status === OperationStatusCode.Idle) { return { runMode: RvcRunMode.ModeTag.Idle, operationalState: RvcOperationalState.OperationalState.Docked, }; } // InError Status Override - Rows 31-33 if (status === OperationStatusCode.InError) { if (message.inCleaning === true) { return { runMode: RvcRunMode.ModeTag.Cleaning, operationalState: RvcOperationalState.OperationalState.Error, }; } if (message.isExploring === true) { return { runMode: RvcRunMode.ModeTag.Mapping, operationalState: RvcOperationalState.OperationalState.Error, }; } return { runMode: RvcRunMode.ModeTag.Idle, operationalState: RvcOperationalState.OperationalState.Error, }; } // EmptyingDustContainer Status Override - Row 44 if (status === OperationStatusCode.EmptyingDustContainer) { return { runMode: RvcRunMode.ModeTag.Cleaning, operationalState: RvcOperationalState.OperationalState.EmptyingDustBin, }; } // WashingTheMop Status Override - Row 45 if (status === OperationStatusCode.WashingTheMop) { return { runMode: RvcRunMode.ModeTag.Cleaning, operationalState: RvcOperationalState.OperationalState.CleaningMop, }; } // GoingToWashTheMop Status Override - Row 46 if (status === OperationStatusCode.GoingToWashTheMop) { return { runMode: RvcRunMode.ModeTag.Cleaning, operationalState: RvcOperationalState.OperationalState.CleaningMop, }; } // Mapping Status Override - Row 47 if (status === OperationStatusCode.Mapping) { return { runMode: RvcRunMode.ModeTag.Mapping, operationalState: RvcOperationalState.OperationalState.Running, }; } // ═══════════════════════════════════════════════════════════════════════════ // Priority 1: Cleaning Status Special Overrides // ═══════════════════════════════════════════════════════════════════════════ // When status = 5 (Cleaning), apply modifiers in explicit priority order if (status === OperationStatusCode.Cleaning || status === OperationStatusCode.ManualMode || status === OperationStatusCode.RoomClean || status === OperationStatusCode.ZoneClean || status === OperationStatusCode.SpotCleaning || status === OperationStatusCode.CleanMopCleaning || status === OperationStatusCode.CleanMopMopping || status === OperationStatusCode.RoomCleanMopCleaning || status === OperationStatusCode.RoomCleanMopMopping || status === OperationStatusCode.ZoneCleanMopCleaning || status === OperationStatusCode.ZoneCleanMopMopping || status === OperationStatusCode.RoomMopping || status === OperationStatusCode.ZoneMopping) { // Priority 1: isLocating/isExploring (Highest) - Rows 14-15 // Map update operations override all other flags during cleaning if (message.isLocating === true || message.isExploring === true) { return { runMode: RvcRunMode.ModeTag.Cleaning, operationalState: RvcOperationalState.OperationalState.UpdatingMaps, }; } // Priority 2: inWarmup (Second) - Row 13 if (message.inWarmup === true) { return { runMode: RvcRunMode.ModeTag.Cleaning, operationalState: RvcOperationalState.OperationalState.CleaningMop, }; } // Priority 3: inReturning (Third) - Rows 16-19 if (message.inReturning === true) { return { runMode: RvcRunMode.ModeTag.Cleaning, operationalState: RvcOperationalState.OperationalState.SeekingCharger, }; } // Priority 4: inFreshState not applicable to Cleaning status // Falls through to base state (Cleaning + Running) - Row 12 } // ═══════════════════════════════════════════════════════════════════════════ // Priority 2: Modifier Priority Chain // ═══════════════════════════════════════════════════════════════════════════ // Apply modifiers in priority order for all other statuses // Get base state from status code let state = getBaseState(message); // Priority 2a: inReturning modifier (High Priority) state = applyInReturningModifier(state, message); // Priority 2b: isExploring modifier (Medium Priority) state = applyIsExploringModifier(state, message); // Priority 2c: inFreshState modifier (Low Priority) state = applyInFreshStateModifier(state, message); return state; } /** * Gets the base state from status code using legacy mapping functions. * Falls back to Idle/Docked if status code is not recognized. * * @param message StatusChangeMessage * @returns ResolvedState with base runMode and operationalState */ function getBaseState(message) { // Special case: Unknown status (0) should return Idle/Docked, not Idle/Error if (message.status === OperationStatusCode.Unknown) { return { runMode: RvcRunMode.ModeTag.Idle, operationalState: RvcOperationalState.OperationalState.Docked, }; } if (message.status === OperationStatusCode.Paused && message.isExploring === true) { return { runMode: RvcRunMode.ModeTag.Mapping, operationalState: RvcOperationalState.OperationalState.Paused, }; } // Special case: Paused status (10) should always return Cleaning/Paused if (message.status === OperationStatusCode.Paused) { return { runMode: RvcRunMode.ModeTag.Cleaning, operationalState: RvcOperationalState.OperationalState.Paused, }; } const runMode = state_to_matter_state(message.status); const operationalState = state_to_matter_operational_status(message.status); if (runMode === undefined || operationalState === undefined) { // Unknown status code - default to Idle/Docked return { runMode: RvcRunMode.ModeTag.Idle, operationalState: RvcOperationalState.OperationalState.Docked, }; } return { runMode, operationalState }; } /** * Applies inReturning modifier (High Priority). * * When inReturning=true, robot is seeking charger regardless of other flags. * Sets runMode to Cleaning and operationalState to SeekingCharger. * * Special Cases: For certain statuses (Paused, ReturnToDock, ReturningDock), * the operational state is fixed by the status itself, so inReturning is ignored entirely. * These statuses only use isExploring to determine run mode (Cleaning vs Mapping). * * Matrix Coverage: Rows 2, 4, 6, 16, 17, 21, 28, 36, 39, 42 * * @param state Current resolved state * @param message StatusChangeMessage * @returns Updated state with inReturning applied */ function applyInReturningModifier(state, message) { if (message.inReturning === true) { // Skip inReturning for statuses with fixed operational states if (message.status === OperationStatusCode.Paused || message.status === OperationStatusCode.ReturnToDock || message.status === OperationStatusCode.ReturningDock) { return state; // Keep current state unchanged } return { runMode: RvcRunMode.ModeTag.Cleaning, operationalState: RvcOperationalState.OperationalState.SeekingCharger, }; } return state; } /** * Applies isExploring modifier (Medium Priority). * * When isExploring=true and inReturning is not true, robot is in mapping mode. * Changes runMode to Mapping while preserving operationalState. * * Note: This modifier is skipped if inReturning was already applied (higher priority). * Note: This modifier is blocked when status is Charging (8) as the vacuum * cannot charge and explore simultaneously. * * Matrix Coverage: Rows 3, 7, 9, 19, 22, 26, 32, 34, 37, 40, 43 * * @param state Current resolved state * @param message StatusChangeMessage * @returns Updated state with isExploring applied */ function applyIsExploringModifier(state, message) { // Block isExploring when status is Charging (8) - invalid state const isCharging = message.status === OperationStatusCode.Charging; if (message.isExploring === true && message.inReturning !== true && !isCharging) { return { ...state, runMode: RvcRunMode.ModeTag.Mapping, }; } return state; } /** * Applies inFreshState modifier (Low Priority). * * When inFreshState=true and status is Charging (8), * robot has just completed cleaning and transitions to Idle/Docked. * * Note: This modifier only applies to status 8 (Charging). * For other statuses, including Cleaning (5), inFreshState has no effect * as the vacuum does not go to fresh state during active cleaning. * * Matrix Coverage: None (inFreshState is redundant and no longer used in matrix) * * @param state Current resolved state * @param message StatusChangeMessage * @returns Updated state with inFreshState applied */ function applyInFreshStateModifier(state, message) { if (message.inFreshState === true && message.status === OperationStatusCode.Charging && message.inReturning !== true) { return { runMode: RvcRunMode.ModeTag.Idle, operationalState: RvcOperationalState.OperationalState.Docked, }; } return state; } //# sourceMappingURL=stateResolver.js.map