mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 01:21:20 -04:00
smol changess
This commit is contained in:
@@ -6,7 +6,7 @@ Always pay attention to the chat.
|
|||||||
|
|
||||||
Output contract:
|
Output contract:
|
||||||
- Output must be either SKIP if you want to stay silent, or a message if you want to speak.
|
- Output must be either SKIP if you want to stay silent, or a message if you want to speak.
|
||||||
- Allow 10 skips before speaking again, unless someone is talking to you.
|
- Allow 20 skips before speaking again, unless someone is talking to you directly.
|
||||||
- If you choose to speak, send only one line.
|
- If you choose to speak, send only one line.
|
||||||
- Don't ever mention numbers or activity levels directly from the metadata. They are for internal use only.
|
- Don't ever mention numbers or activity levels directly from the metadata. They are for internal use only.
|
||||||
- Don't repeat the same or similar message over and over.
|
- Don't repeat the same or similar message over and over.
|
||||||
|
|||||||
@@ -92,6 +92,19 @@ let presenceInterval = null;
|
|||||||
let presenceShowGoal = false;
|
let presenceShowGoal = false;
|
||||||
const VERIFY_APPROVE_EMOJI = '✅';
|
const VERIFY_APPROVE_EMOJI = '✅';
|
||||||
const VERIFY_DENY_EMOJI = '❌';
|
const VERIFY_DENY_EMOJI = '❌';
|
||||||
|
const ADMIN_ALERT_EVENT_TYPES = new Set([
|
||||||
|
'rover.online',
|
||||||
|
'rover.offline',
|
||||||
|
'rover.dockGuard',
|
||||||
|
'battery.warn',
|
||||||
|
'battery.urgent',
|
||||||
|
'battery.docked',
|
||||||
|
'battery.undocked',
|
||||||
|
'battery.charging.start',
|
||||||
|
'battery.charging.stop',
|
||||||
|
'battery.locked',
|
||||||
|
'battery.unlocked',
|
||||||
|
]);
|
||||||
function sanitizeMentions(text) {
|
function sanitizeMentions(text) {
|
||||||
if (!text) return '';
|
if (!text) return '';
|
||||||
return String(text)
|
return String(text)
|
||||||
@@ -169,7 +182,6 @@ function isCharging(sensors) {
|
|||||||
|
|
||||||
function buildRoverStatusSnapshot(record) {
|
function buildRoverStatusSnapshot(record) {
|
||||||
if (!record) return null;
|
if (!record) return null;
|
||||||
if (!roverManager.canReplayRoverId(record.id)) return null;
|
|
||||||
const sensors = record.lastSensor?.decoded || record.lastSensor?.sensors || null;
|
const sensors = record.lastSensor?.decoded || record.lastSensor?.sensors || null;
|
||||||
const docked = Boolean(sensors?.chargingSources?.homeBase);
|
const docked = Boolean(sensors?.chargingSources?.homeBase);
|
||||||
const charging = isCharging(sensors);
|
const charging = isCharging(sensors);
|
||||||
@@ -1208,10 +1220,11 @@ async function handleTimeStatusCommand(message) {
|
|||||||
|
|
||||||
function buildBatteryStatusEmbed(color, records = null) {
|
function buildBatteryStatusEmbed(color, records = null) {
|
||||||
const embed = buildEmbed({ title: 'Rover Battery Status', color: color || 0x2196f3 });
|
const embed = buildEmbed({ title: 'Rover Battery Status', color: color || 0x2196f3 });
|
||||||
const baseRecords = (records || Array.from(rovers.values())).filter((entry) =>
|
const sourceRecords = records || Array.from(rovers.values());
|
||||||
roverManager.canReplayRoverId(entry?.id),
|
const baseRecords = records
|
||||||
);
|
? sourceRecords
|
||||||
const snapshots = baseRecords.map(buildRoverStatusSnapshot).filter(Boolean);
|
: sourceRecords.filter((entry) => roverManager.canReplayRoverId(entry?.id));
|
||||||
|
const snapshots = baseRecords.map((entry) => buildRoverStatusSnapshot(entry)).filter(Boolean);
|
||||||
if (snapshots.length === 0) {
|
if (snapshots.length === 0) {
|
||||||
embed.setDescription('No rovers online.');
|
embed.setDescription('No rovers online.');
|
||||||
return embed;
|
return embed;
|
||||||
@@ -1286,9 +1299,6 @@ function buildAccessModeEmbed(mode, color) {
|
|||||||
|
|
||||||
function buildBatteryCaption(type, payload) {
|
function buildBatteryCaption(type, payload) {
|
||||||
const roverId = payload?.roverId || 'unknown';
|
const roverId = payload?.roverId || 'unknown';
|
||||||
if (!roverManager.canReplayRoverId(roverId)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const record = rovers.get(roverId) || findRoverRecord(roverId);
|
const record = rovers.get(roverId) || findRoverRecord(roverId);
|
||||||
const snapshot = buildRoverStatusSnapshot(record);
|
const snapshot = buildRoverStatusSnapshot(record);
|
||||||
const base = snapshot?.name || roverId;
|
const base = snapshot?.name || roverId;
|
||||||
@@ -1323,6 +1333,12 @@ function buildBatteryCaption(type, payload) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getEventRoverRecord(payload) {
|
||||||
|
const roverId = String(payload?.roverId || '').trim();
|
||||||
|
if (!roverId) return null;
|
||||||
|
return rovers.get(roverId) || findRoverRecord(roverId) || null;
|
||||||
|
}
|
||||||
|
|
||||||
async function announce({
|
async function announce({
|
||||||
channelId,
|
channelId,
|
||||||
content,
|
content,
|
||||||
@@ -1379,7 +1395,7 @@ function handleBusEvent(event) {
|
|||||||
const channels = discordConfig.channels || {};
|
const channels = discordConfig.channels || {};
|
||||||
const roles = discordConfig.roles || {};
|
const roles = discordConfig.roles || {};
|
||||||
const roverId = payload?.roverId || null;
|
const roverId = payload?.roverId || null;
|
||||||
if (roverId && !roverManager.canReplayRoverId(roverId)) {
|
if (roverId && !roverManager.canReplayRoverId(roverId) && !ADMIN_ALERT_EVENT_TYPES.has(type)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@@ -1474,7 +1490,7 @@ function handleBusEvent(event) {
|
|||||||
content: buildBatteryCaption(type, payload),
|
content: buildBatteryCaption(type, payload),
|
||||||
title: 'Battery Status',
|
title: 'Battery Status',
|
||||||
description: null,
|
description: null,
|
||||||
embeds: [buildBatteryStatusEmbed(0xf0b651)],
|
embeds: [buildBatteryStatusEmbed(0xf0b651, [getEventRoverRecord(payload)].filter(Boolean))],
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'battery.urgent':
|
case 'battery.urgent':
|
||||||
@@ -1486,7 +1502,7 @@ function handleBusEvent(event) {
|
|||||||
content: buildBatteryCaption(type, payload),
|
content: buildBatteryCaption(type, payload),
|
||||||
title: 'Battery Status',
|
title: 'Battery Status',
|
||||||
description: null,
|
description: null,
|
||||||
embeds: [buildBatteryStatusEmbed(0xe53935)],
|
embeds: [buildBatteryStatusEmbed(0xe53935, [getEventRoverRecord(payload)].filter(Boolean))],
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'battery.docked':
|
case 'battery.docked':
|
||||||
@@ -1497,7 +1513,7 @@ function handleBusEvent(event) {
|
|||||||
content: buildBatteryCaption(type, payload),
|
content: buildBatteryCaption(type, payload),
|
||||||
title: 'Battery Status',
|
title: 'Battery Status',
|
||||||
description: null,
|
description: null,
|
||||||
embeds: [buildBatteryStatusEmbed(0x2196f3)],
|
embeds: [buildBatteryStatusEmbed(0x2196f3, [getEventRoverRecord(payload)].filter(Boolean))],
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'battery.undocked':
|
case 'battery.undocked':
|
||||||
@@ -1508,7 +1524,7 @@ function handleBusEvent(event) {
|
|||||||
content: buildBatteryCaption(type, payload),
|
content: buildBatteryCaption(type, payload),
|
||||||
title: 'Battery Status',
|
title: 'Battery Status',
|
||||||
description: null,
|
description: null,
|
||||||
embeds: [buildBatteryStatusEmbed(0x2196f3)],
|
embeds: [buildBatteryStatusEmbed(0x2196f3, [getEventRoverRecord(payload)].filter(Boolean))],
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'battery.charging.start':
|
case 'battery.charging.start':
|
||||||
@@ -1519,7 +1535,7 @@ function handleBusEvent(event) {
|
|||||||
content: buildBatteryCaption(type, payload),
|
content: buildBatteryCaption(type, payload),
|
||||||
title: 'Battery Status',
|
title: 'Battery Status',
|
||||||
description: null,
|
description: null,
|
||||||
embeds: [buildBatteryStatusEmbed(0x2196f3)],
|
embeds: [buildBatteryStatusEmbed(0x2196f3, [getEventRoverRecord(payload)].filter(Boolean))],
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'battery.charging.stop':
|
case 'battery.charging.stop':
|
||||||
@@ -1530,7 +1546,7 @@ function handleBusEvent(event) {
|
|||||||
content: buildBatteryCaption(type, payload),
|
content: buildBatteryCaption(type, payload),
|
||||||
title: 'Battery Status',
|
title: 'Battery Status',
|
||||||
description: null,
|
description: null,
|
||||||
embeds: [buildBatteryStatusEmbed(0xf0b651)],
|
embeds: [buildBatteryStatusEmbed(0xf0b651, [getEventRoverRecord(payload)].filter(Boolean))],
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'battery.locked':
|
case 'battery.locked':
|
||||||
@@ -1541,7 +1557,7 @@ function handleBusEvent(event) {
|
|||||||
content: buildBatteryCaption(type, payload),
|
content: buildBatteryCaption(type, payload),
|
||||||
title: 'Battery Status',
|
title: 'Battery Status',
|
||||||
description: null,
|
description: null,
|
||||||
embeds: [buildBatteryStatusEmbed(0xf0b651)],
|
embeds: [buildBatteryStatusEmbed(0xf0b651, [getEventRoverRecord(payload)].filter(Boolean))],
|
||||||
});
|
});
|
||||||
schedulePresenceRotation();
|
schedulePresenceRotation();
|
||||||
break;
|
break;
|
||||||
@@ -1553,7 +1569,7 @@ function handleBusEvent(event) {
|
|||||||
content: buildBatteryCaption(type, payload),
|
content: buildBatteryCaption(type, payload),
|
||||||
title: 'Battery Status',
|
title: 'Battery Status',
|
||||||
description: null,
|
description: null,
|
||||||
embeds: [buildBatteryStatusEmbed(0x4caf50)],
|
embeds: [buildBatteryStatusEmbed(0x4caf50, [getEventRoverRecord(payload)].filter(Boolean))],
|
||||||
});
|
});
|
||||||
schedulePresenceRotation();
|
schedulePresenceRotation();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ const logger = require('../globals/logger').child('homeAssistantService');
|
|||||||
const { loadConfig } = require('../helpers/configLoader');
|
const { loadConfig } = require('../helpers/configLoader');
|
||||||
const { getMode, MODES, modeEvents } = require('./modeManager');
|
const { getMode, MODES, modeEvents } = require('./modeManager');
|
||||||
const { isAdmin, isLockdownAdmin } = require('./roleService');
|
const { isAdmin, isLockdownAdmin } = require('./roleService');
|
||||||
|
const roverManager = require('./roverManager');
|
||||||
|
const { issueCommand } = require('./commandService');
|
||||||
const { publishEvent } = require('./eventBus');
|
const { publishEvent } = require('./eventBus');
|
||||||
const { getActiveDrivers, turnEvents } = require('./turnService');
|
const { getActiveDrivers, turnEvents } = require('./turnService');
|
||||||
|
|
||||||
@@ -192,6 +194,30 @@ function getControllableEntityIds() {
|
|||||||
return Array.from(entityConfig.values()).map((meta) => String(meta.id));
|
return Array.from(entityConfig.values()).map((meta) => String(meta.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function turnOffAllRoverNightVision() {
|
||||||
|
const records = Array.from(roverManager.rovers.values());
|
||||||
|
let attempted = 0;
|
||||||
|
let failed = 0;
|
||||||
|
records.forEach((record) => {
|
||||||
|
if (!record?.ws) return;
|
||||||
|
if (!record?.meta?.nightVision?.enabled) return;
|
||||||
|
attempted += 1;
|
||||||
|
try {
|
||||||
|
issueCommand(record.id, {
|
||||||
|
type: 'nightVision',
|
||||||
|
nightVision: { action: 'off' },
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
failed += 1;
|
||||||
|
logger.warn('Failed to auto turn off rover night vision after idle', {
|
||||||
|
roverId: record.id,
|
||||||
|
error: err.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { attempted, failed };
|
||||||
|
}
|
||||||
|
|
||||||
function getActiveDriverCount() {
|
function getActiveDriverCount() {
|
||||||
const active = getActiveDrivers();
|
const active = getActiveDrivers();
|
||||||
if (!active || typeof active !== 'object') return 0;
|
if (!active || typeof active !== 'object') return 0;
|
||||||
@@ -225,8 +251,11 @@ function scheduleLightsIdleOffTimer() {
|
|||||||
lightsIdleOffDeadline = null;
|
lightsIdleOffDeadline = null;
|
||||||
try {
|
try {
|
||||||
await setAllControllableEntitiesState('off');
|
await setAllControllableEntitiesState('off');
|
||||||
|
const nightVisionResult = turnOffAllRoverNightVision();
|
||||||
logger.info('Auto-turned off room lights due to no active drivers', {
|
logger.info('Auto-turned off room lights due to no active drivers', {
|
||||||
idleMs: LIGHT_IDLE_OFF_MS,
|
idleMs: LIGHT_IDLE_OFF_MS,
|
||||||
|
nightVisionRovers: nightVisionResult.attempted,
|
||||||
|
nightVisionFailures: nightVisionResult.failed,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.warn('Failed auto light-off after idle', err.message);
|
logger.warn('Failed auto light-off after idle', err.message);
|
||||||
|
|||||||
Reference in New Issue
Block a user