mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-15 17:12:59 -04:00
light lock rs command
This commit is contained in:
@@ -9,6 +9,7 @@ const { getActiveDrivers } = require('../turnService');
|
|||||||
const { getNickname } = require('../nicknameService');
|
const { getNickname } = require('../nicknameService');
|
||||||
const { getGlobalObjective, setGlobalObjective, clearGlobalObjective } = require('../globalObjectiveService');
|
const { getGlobalObjective, setGlobalObjective, clearGlobalObjective } = require('../globalObjectiveService');
|
||||||
const { getAdminReason, setAdminReason, clearAdminReason } = require('../adminReasonService');
|
const { getAdminReason, setAdminReason, clearAdminReason } = require('../adminReasonService');
|
||||||
|
const homeAssistantService = require('../homeAssistantService');
|
||||||
const {
|
const {
|
||||||
listVerifiedUsers,
|
listVerifiedUsers,
|
||||||
removeVerifiedUser,
|
removeVerifiedUser,
|
||||||
@@ -162,6 +163,11 @@ async function runChatTextCommand({ text, socket, sendSystemMessage }) {
|
|||||||
getAdminReason,
|
getAdminReason,
|
||||||
setAdminReason,
|
setAdminReason,
|
||||||
clearAdminReason,
|
clearAdminReason,
|
||||||
|
// Web chat builds its own command-router instance for the sending socket.
|
||||||
|
// Supplying the same Home Assistant service used by Discord keeps `rs
|
||||||
|
// lights lock/unlock` from becoming transport-specific, and it preserves
|
||||||
|
// the existing session update path for all connected browsers.
|
||||||
|
homeAssistantService,
|
||||||
getGuildConfig: () => null,
|
getGuildConfig: () => null,
|
||||||
setGuildConfig: () => null,
|
setGuildConfig: () => null,
|
||||||
removeGuildConfig: () => null,
|
removeGuildConfig: () => null,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ function formatHelp() {
|
|||||||
'`rs bridge here <global|private>` — set chat bridge to this channel',
|
'`rs bridge here <global|private>` — set chat bridge to this channel',
|
||||||
'`rs bridge mode <global|private>` — change chat bridge mode',
|
'`rs bridge mode <global|private>` — change chat bridge mode',
|
||||||
'`rs bridge off` — disable chat bridge for this server',
|
'`rs bridge off` — disable chat bridge for this server',
|
||||||
|
'`rs lights <status|lock|unlock>` — show or change room light lock state',
|
||||||
'`rs lock <rover>` — lock a rover; rover names can be fuzzy',
|
'`rs lock <rover>` — lock a rover; rover names can be fuzzy',
|
||||||
'`rs unlock <rover>` — unlock a rover; rover names can be fuzzy',
|
'`rs unlock <rover>` — unlock a rover; rover names can be fuzzy',
|
||||||
'`rs mode <open|turns|admin|lockdown>` — change server mode',
|
'`rs mode <open|turns|admin|lockdown>` — change server mode',
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ const { createVerifyCommand } = require('./verify');
|
|||||||
const { createDeterCommand } = require('./deter');
|
const { createDeterCommand } = require('./deter');
|
||||||
const { createBridgeCommand } = require('./bridge');
|
const { createBridgeCommand } = require('./bridge');
|
||||||
const { createTimeStatusCommand } = require('./timeStatus');
|
const { createTimeStatusCommand } = require('./timeStatus');
|
||||||
|
const { createLightsCommand } = require('./lights');
|
||||||
|
|
||||||
function createCommandHandlers(deps) {
|
function createCommandHandlers(deps) {
|
||||||
const {
|
const {
|
||||||
@@ -33,6 +34,7 @@ function createCommandHandlers(deps) {
|
|||||||
const handleDeterCommand = createDeterCommand(deps);
|
const handleDeterCommand = createDeterCommand(deps);
|
||||||
const handleBridgeCommand = createBridgeCommand(deps);
|
const handleBridgeCommand = createBridgeCommand(deps);
|
||||||
const handleTimeStatusCommand = createTimeStatusCommand(deps);
|
const handleTimeStatusCommand = createTimeStatusCommand(deps);
|
||||||
|
const handleLightsCommand = createLightsCommand(deps);
|
||||||
|
|
||||||
async function handleCommand(message) {
|
async function handleCommand(message) {
|
||||||
if (message.author.bot) return;
|
if (message.author.bot) return;
|
||||||
@@ -52,7 +54,11 @@ function createCommandHandlers(deps) {
|
|||||||
const isAdmin = isAdminUser(message.author.id);
|
const isAdmin = isAdminUser(message.author.id);
|
||||||
const isLockdownAdmin = isLockdownAdminUser(message.author.id);
|
const isLockdownAdmin = isLockdownAdminUser(message.author.id);
|
||||||
const mode = getMode();
|
const mode = getMode();
|
||||||
const moderationActions = new Set(['lock', 'unlock', 'mode', 'goal', 'reason', 'verify', 'deter']);
|
// Actions in this set can change operational safety or access policy, so
|
||||||
|
// lockdown mode narrows them from normal admins to lockdown admins. Room
|
||||||
|
// light locking belongs here because it can force the physical room lights
|
||||||
|
// on and disables ordinary Home Assistant room controls for everyone else.
|
||||||
|
const moderationActions = new Set(['lock', 'unlock', 'mode', 'goal', 'reason', 'verify', 'deter', 'lights']);
|
||||||
|
|
||||||
if (!isAdmin && action !== '' && action !== 'status' && action !== 'help' && action !== 'replay' && action !== 'bridge' && action !== 'goal' && action !== 'reason' && action !== 'verify' && action !== 'deter') {
|
if (!isAdmin && action !== '' && action !== 'status' && action !== 'help' && action !== 'replay' && action !== 'bridge' && action !== 'goal' && action !== 'reason' && action !== 'verify' && action !== 'deter') {
|
||||||
await message.reply({ content: 'Only admins can run that command.', allowedMentions: { parse: [], repliedUser: false } });
|
await message.reply({ content: 'Only admins can run that command.', allowedMentions: { parse: [], repliedUser: false } });
|
||||||
@@ -74,6 +80,8 @@ function createCommandHandlers(deps) {
|
|||||||
return handleReplayCommand(message, tokens.join(' '));
|
return handleReplayCommand(message, tokens.join(' '));
|
||||||
case 'bridge':
|
case 'bridge':
|
||||||
return handleBridgeCommand(message, tokens);
|
return handleBridgeCommand(message, tokens);
|
||||||
|
case 'lights':
|
||||||
|
return handleLightsCommand(message, tokens);
|
||||||
case 'lock':
|
case 'lock':
|
||||||
return handleLockCommand(message, rest, true);
|
return handleLockCommand(message, rest, true);
|
||||||
case 'unlock':
|
case 'unlock':
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
// Discord Lights Command
|
||||||
|
// Purpose: Handles admin room-light lock policy commands from Discord and web chat.
|
||||||
|
// Scope: Delegates all actual Home Assistant policy behavior to homeAssistantService.
|
||||||
|
function describeLightPolicy(lightPolicy = {}) {
|
||||||
|
// The HA service exposes both the newer explicit lockState and the older
|
||||||
|
// lockedOn boolean. Prefer lockState because it can distinguish locked-on
|
||||||
|
// from locked-off, but keep lockedOn as a defensive fallback for any caller
|
||||||
|
// that passes an older or partial policy object.
|
||||||
|
const lockState = lightPolicy?.lockState || (lightPolicy?.lockedOn ? 'on' : null);
|
||||||
|
if (lockState === 'on') return 'Room lights are locked on.';
|
||||||
|
if (lockState === 'off') return 'Room lights are locked off.';
|
||||||
|
return 'Room lights are unlocked.';
|
||||||
|
}
|
||||||
|
|
||||||
|
function createLightsCommand({ homeAssistantService, sanitizeMentions }) {
|
||||||
|
return async function handleLightsCommand(message, tokens = []) {
|
||||||
|
// Defaulting to status makes `rs lights` safe to type while still exposing
|
||||||
|
// the explicit mutating forms as `rs lights lock` and `rs lights unlock`.
|
||||||
|
const action = String(tokens.shift() || 'status').trim().toLowerCase();
|
||||||
|
|
||||||
|
if (!homeAssistantService) {
|
||||||
|
await message.reply({
|
||||||
|
content: 'Room light controls are unavailable.',
|
||||||
|
allowedMentions: { parse: [], repliedUser: false },
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === 'status') {
|
||||||
|
await message.reply({
|
||||||
|
content: describeLightPolicy(homeAssistantService.getLightPolicyState?.() || {}),
|
||||||
|
allowedMentions: { parse: [], repliedUser: false },
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action !== 'lock' && action !== 'unlock') {
|
||||||
|
await message.reply({
|
||||||
|
content: 'Invalid lights command. Use `rs lights lock`, `rs lights unlock`, or `rs lights status`.',
|
||||||
|
allowedMentions: { parse: [], repliedUser: false },
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const locked = action === 'lock';
|
||||||
|
// The bot command intentionally calls the shared policy setter instead of
|
||||||
|
// issuing direct Home Assistant entity commands. That keeps all secondary
|
||||||
|
// behavior centralized: web UI controls become disabled through the
|
||||||
|
// session lightPolicy update, lock-on still forces configured lights to
|
||||||
|
// white where possible, and commandService sees the same update event that
|
||||||
|
// forces rover lasers off while the room is locked on.
|
||||||
|
await homeAssistantService.setLightsLockedOn(locked, {
|
||||||
|
source: `bot-command:lights:${action}`,
|
||||||
|
forceApply: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
await message.reply({
|
||||||
|
content: sanitizeMentions(locked ? 'Room lights locked on.' : 'Room lights unlocked.'),
|
||||||
|
allowedMentions: { parse: [], repliedUser: false },
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
await message.reply({
|
||||||
|
content: sanitizeMentions(`Failed to update room lights: ${err.message}`),
|
||||||
|
allowedMentions: { parse: [], repliedUser: false },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { createLightsCommand };
|
||||||
@@ -19,6 +19,7 @@ const { getActiveDrivers } = require('../turnService');
|
|||||||
const { getNickname } = require('../nicknameService');
|
const { getNickname } = require('../nicknameService');
|
||||||
const { getGlobalObjective, setGlobalObjective, clearGlobalObjective } = require('../globalObjectiveService');
|
const { getGlobalObjective, setGlobalObjective, clearGlobalObjective } = require('../globalObjectiveService');
|
||||||
const { getAdminReason, setAdminReason, clearAdminReason } = require('../adminReasonService');
|
const { getAdminReason, setAdminReason, clearAdminReason } = require('../adminReasonService');
|
||||||
|
const homeAssistantService = require('../homeAssistantService');
|
||||||
const {
|
const {
|
||||||
getGuildConfig,
|
getGuildConfig,
|
||||||
listGuildConfigs,
|
listGuildConfigs,
|
||||||
@@ -136,6 +137,11 @@ const commands = createCommandHandlers({
|
|||||||
getAdminReason,
|
getAdminReason,
|
||||||
setAdminReason,
|
setAdminReason,
|
||||||
clearAdminReason,
|
clearAdminReason,
|
||||||
|
// Room-light lock commands must use the same Home Assistant service instance
|
||||||
|
// as sockets, HA button triggers, and idle/darkness policies. Passing the
|
||||||
|
// service into the shared command router keeps Discord and mirrored web-chat
|
||||||
|
// command behavior aligned without duplicating Home Assistant calls here.
|
||||||
|
homeAssistantService,
|
||||||
getGuildConfig,
|
getGuildConfig,
|
||||||
setGuildConfig,
|
setGuildConfig,
|
||||||
removeGuildConfig,
|
removeGuildConfig,
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
2. pagewide system for "why was i removed from a rover", instead of the link to spectator page thing
|
2. pagewide system for "why was i removed from a rover", instead of the link to spectator page thing
|
||||||
3. admin command for kicking people off of rovers. just a kick, nothing persistent
|
3. admin command for kicking people off of rovers. just a kick, nothing persistent
|
||||||
4. kick people off rover after 3 consecurtive bump-off attempts
|
4. kick people off rover after 3 consecurtive bump-off attempts
|
||||||
5. add rs admin command for controlling light lock
|
5. make signaling more clear for idle skips and idle skip kicks
|
||||||
6. make signaling more clear for idle skips and idle skip kicks
|
6. add a kick command that disconnects sockets with a message
|
||||||
7. fix this:
|
7. fix this:
|
||||||
`Jun 18 15:14:18 roombaserver.local node[216731]: /home/daniel/MultiRoombaRover/server/src/services/roverManager/socketHandlers.js:92
|
`Jun 18 15:14:18 roombaserver.local node[216731]: /home/daniel/MultiRoombaRover/server/src/services/roverManager/socketHandlers.js:92
|
||||||
Jun 18 15:14:18 roombaserver.local node[216731]: cb({ error: err.message });
|
Jun 18 15:14:18 roombaserver.local node[216731]: cb({ error: err.message });
|
||||||
|
|||||||
Reference in New Issue
Block a user