mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 01:21:20 -04:00
102 lines
3.8 KiB
JavaScript
102 lines
3.8 KiB
JavaScript
// Green Mode Service
|
|
// Purpose: Owns the temporary server-wide green visual mode and its tiny light workflow.
|
|
// Scope: Composes existing Home Assistant operations; it does not add policy to that service.
|
|
const EventEmitter = require('events');
|
|
const logger = require('../../globals/logger').child('greenModeService');
|
|
const { sendAlert } = require('../alertService');
|
|
const homeAssistantService = require('../homeAssistantService');
|
|
const { modeEvents } = require('../modeManager');
|
|
|
|
const GREEN_MODE_COLOR = '#00ff00';
|
|
const greenModeEvents = new EventEmitter();
|
|
let enabled = false;
|
|
|
|
function isEnabled() {
|
|
return enabled;
|
|
}
|
|
|
|
async function setEnabled(nextValue, options = {}) {
|
|
const next = Boolean(nextValue);
|
|
if (enabled === next) return enabled;
|
|
|
|
if (next && homeAssistantService.enabled) {
|
|
/*
|
|
Lock first because the existing locked-on transition sets lights white.
|
|
Recoloring RGB lights afterward leaves them green while retaining the
|
|
established room-control lock, idle protection, and laser safety rules.
|
|
*/
|
|
await homeAssistantService.setLightsLockedOn(true, {
|
|
source: String(options?.source || 'greenMode:enable'),
|
|
});
|
|
|
|
const entities = homeAssistantService.getState()?.entities || [];
|
|
/*
|
|
RGB-capable lights become the requested solid green. Every other
|
|
configured room control, including white-only bulbs and switches, is
|
|
explicitly turned off so the physical room has one unambiguous effect.
|
|
These remain generic Home Assistant calls; that service does not know
|
|
that the operations belong to green mode.
|
|
*/
|
|
const results = await Promise.allSettled(
|
|
entities.map((entity) => (
|
|
entity?.supportsColor
|
|
? homeAssistantService.setLightColor(entity.id, GREEN_MODE_COLOR)
|
|
: homeAssistantService.setEntityState(entity.id, 'off', {
|
|
source: 'greenMode:non-rgb-off',
|
|
})
|
|
)),
|
|
);
|
|
const failures = results
|
|
.map((result, index) => ({ result, entityId: entities[index].id }))
|
|
.filter(({ result }) => result.status === 'rejected')
|
|
.map(({ result, entityId }) => ({ entityId, error: result.reason?.message || 'unknown error' }));
|
|
|
|
if (failures.length) {
|
|
logger.warn('Some room controls failed to enter green mode', { failures });
|
|
}
|
|
} else if (!next && homeAssistantService.enabled) {
|
|
// Disabling the visual mode simply releases the lock it created. Bulb
|
|
// colors remain untouched, matching the existing one-shot light behavior.
|
|
await homeAssistantService.setLightsLockedOn(false, {
|
|
source: String(options?.source || 'greenMode:disable'),
|
|
});
|
|
}
|
|
|
|
/*
|
|
Home Assistant is deliberately optional here. When it is not configured,
|
|
skipping the physical-room operations still allows the session theme,
|
|
CardFrame styling, alerts, commands, and timed reward to work normally.
|
|
The integration's generic lock state is also left untouched because there
|
|
are no server-managed room controls to lock.
|
|
*/
|
|
|
|
enabled = next;
|
|
logger.info('Green mode changed', {
|
|
enabled,
|
|
source: options?.source || 'unknown',
|
|
});
|
|
// Emit one shared server alert for every completed transition. Automatic
|
|
// access-mode shutdown uses this same function, so clients also receive the
|
|
// inactive notice when green mode ends without an explicit chat command.
|
|
sendAlert({
|
|
color: GREEN_MODE_COLOR,
|
|
title: 'Green mode',
|
|
message: enabled ? 'Green mode is active.' : 'Green mode is inactive.',
|
|
});
|
|
greenModeEvents.emit('change', enabled);
|
|
return enabled;
|
|
}
|
|
|
|
modeEvents.on('change', () => {
|
|
if (!enabled) return;
|
|
setEnabled(false, { source: 'modeGateReset' }).catch((err) => {
|
|
logger.warn('Failed to disable green mode on access-mode change', err.message);
|
|
});
|
|
});
|
|
|
|
module.exports = {
|
|
isEnabled,
|
|
setEnabled,
|
|
greenModeEvents,
|
|
};
|