mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 01:21:20 -04:00
home assistant white light buttons
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
You are The Overseer of the rovers. You are able to see their actions and the chatting of the people using them. You are not able to control them.
|
||||
|
||||
Your purpose is to provide entertainment and break the silence.
|
||||
You are The Overseer of the rovers. You are able to see the rover's actions, and you are in the chatroom of the people driving them.
|
||||
You are not able to control the people or the rovers.
|
||||
|
||||
Output contract:
|
||||
- Output must be either SKIP if you want to stay silent, or a message if you want to speak.
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -11,8 +11,8 @@
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
<meta name="apple-mobile-web-app-title" content="Multi Roomba Rover" />
|
||||
<title>Multi Roomba Rover</title>
|
||||
<script type="module" crossorigin src="/assets/index-Cxe8USDb.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BquPV0pG.css">
|
||||
<script type="module" crossorigin src="/assets/index-BrQIm3tI.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-gFnxuq00.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -24,6 +24,7 @@ const triggerConfig = []; // [{ runtimeKey, entityId, action, stateEquals, paylo
|
||||
const triggerRuntime = new Map(); // triggerId -> { lastFiredAt, lastState, lastChanged, lastUpdated }
|
||||
const HA_BUTTON_EVENT_TYPE = 'ha.button.action';
|
||||
const LIGHT_IDLE_OFF_MS = 2 * 60 * 1000;
|
||||
const DEFAULT_WHITE_KELVIN = 4000;
|
||||
|
||||
let connection = null;
|
||||
let unsubscribeEntities = null;
|
||||
@@ -463,6 +464,31 @@ async function setLightColor(entityId, rgbColor) {
|
||||
logger.info('Issued Home Assistant color command', { entityId, rgbColor: normalized });
|
||||
}
|
||||
|
||||
async function setLightWhite(entityId, kelvin = DEFAULT_WHITE_KELVIN) {
|
||||
if (!enabled) {
|
||||
throw new Error('Home Assistant not configured');
|
||||
}
|
||||
const meta = entityConfig.get(entityId);
|
||||
if (!meta || meta.type !== 'light') {
|
||||
throw new Error('Home Assistant light required');
|
||||
}
|
||||
if (!connection) {
|
||||
throw new Error('Home Assistant not connected');
|
||||
}
|
||||
const nextKelvin = Number(kelvin);
|
||||
const normalizedKelvin = Number.isFinite(nextKelvin)
|
||||
? Math.max(2000, Math.min(6500, Math.round(nextKelvin)))
|
||||
: DEFAULT_WHITE_KELVIN;
|
||||
await callService(connection, 'light', 'turn_on', {
|
||||
entity_id: entityId,
|
||||
color_temp_kelvin: normalizedKelvin,
|
||||
});
|
||||
logger.info('Issued Home Assistant white command', {
|
||||
entityId,
|
||||
colorTempKelvin: normalizedKelvin,
|
||||
});
|
||||
}
|
||||
|
||||
function isLightControlLocked() {
|
||||
return lightsLockState != null;
|
||||
}
|
||||
@@ -611,6 +637,27 @@ io.on('connection', (socket) => {
|
||||
cb({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('homeAssistant:lightWhite', async ({ entityId } = {}, cb = () => {}) => {
|
||||
const mode = getMode();
|
||||
if (
|
||||
(mode === 'admin' && isAdmin(socket) !== true) ||
|
||||
(mode === 'lockdown' && isLockdownAdmin(socket) !== true)
|
||||
) {
|
||||
return cb({ error: 'Insufficient permissions to control Home Assistant' });
|
||||
}
|
||||
if (isLightControlLocked()) {
|
||||
return cb({ error: 'Room controls are locked' });
|
||||
}
|
||||
|
||||
try {
|
||||
if (!entityId) throw new Error('entityId required');
|
||||
await setLightWhite(entityId, haConfig?.whiteKelvin);
|
||||
cb({ success: true });
|
||||
} catch (err) {
|
||||
cb({ error: err.message });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
@@ -620,6 +667,7 @@ module.exports = {
|
||||
toggleEntity,
|
||||
setEntityState,
|
||||
setLightColor,
|
||||
setLightWhite,
|
||||
setLightsLockedOn,
|
||||
toggleLightsLockedOn,
|
||||
homeAssistantEvents: events,
|
||||
|
||||
@@ -84,7 +84,7 @@ function getEntityHue(entity) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
function EntityRow({ entity, connected, controlsLocked, onToggle, onSetColor }) {
|
||||
function EntityRow({ entity, connected, controlsLocked, onToggle, onSetColor, onSetWhite }) {
|
||||
const unavailable = entity.state === 'unavailable' || !entity.available;
|
||||
const isOn = entity.state === 'on';
|
||||
const supportsColor = entity.type === 'light' && entity.supportsColor;
|
||||
@@ -125,6 +125,12 @@ function EntityRow({ entity, connected, controlsLocked, onToggle, onSetColor })
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
const handleSetWhite = (event) => {
|
||||
stopPropagation(event);
|
||||
if (disableColor || !onSetWhite) return;
|
||||
onSetWhite(entity.id);
|
||||
};
|
||||
|
||||
const displayRgb = supportsColor ? hueToRgb(hueRef.current) : [255, 255, 255];
|
||||
const displayColor = `rgb(${displayRgb.join(',')})`;
|
||||
|
||||
@@ -191,10 +197,35 @@ function EntityRow({ entity, connected, controlsLocked, onToggle, onSetColor })
|
||||
)}
|
||||
</div>
|
||||
{supportsColor && (
|
||||
<span
|
||||
className="pointer-events-none absolute right-1 top-1 h-2.5 w-2.5 rounded-full border border-white/60"
|
||||
style={{ backgroundColor: displayColor }}
|
||||
/>
|
||||
<div className="absolute right-1 top-1 flex items-center gap-0.5">
|
||||
<span
|
||||
role="button"
|
||||
tabIndex={disableColor ? -1 : 0}
|
||||
onClick={handleSetWhite}
|
||||
onPointerDown={stopPropagation}
|
||||
onKeyDown={(event) => {
|
||||
if (disableColor) return;
|
||||
if (event.key === 'Enter' || event.key === ' ') {
|
||||
event.preventDefault();
|
||||
handleSetWhite(event);
|
||||
}
|
||||
}}
|
||||
title="Set white color temperature"
|
||||
aria-label={`Set ${entity.name || entity.id} to white`}
|
||||
aria-disabled={disableColor}
|
||||
className={`inline-flex items-center justify-center rounded border border-slate-200 bg-white px-1 py-0.5 text-xs font-semibold leading-none text-slate-900 ${
|
||||
disableColor
|
||||
? 'cursor-not-allowed opacity-60'
|
||||
: 'cursor-pointer hover:bg-slate-100'
|
||||
}`}
|
||||
>
|
||||
white
|
||||
</span>
|
||||
<span
|
||||
className="pointer-events-none h-2.5 w-2.5 rounded-full border border-white/60"
|
||||
style={{ backgroundColor: displayColor }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{!supportsColor && (
|
||||
<div className="self-center text-xs font-semibold text-white/90">
|
||||
@@ -209,7 +240,8 @@ export default function HomeAssistantControls() {
|
||||
const {
|
||||
state: { keymap },
|
||||
} = useControlSystem();
|
||||
const { session, homeAssistantToggle, homeAssistantSetLightColor } = useSession();
|
||||
const { session, homeAssistantToggle, homeAssistantSetLightColor, homeAssistantSetLightWhite } =
|
||||
useSession();
|
||||
const ha = session?.homeAssistant;
|
||||
const entities = useMemo(() => ha?.entities || [], [ha?.entities]);
|
||||
const lightPolicy = ha?.lightPolicy || null;
|
||||
@@ -274,6 +306,7 @@ export default function HomeAssistantControls() {
|
||||
controlsLocked={controlsLocked}
|
||||
onToggle={homeAssistantToggle}
|
||||
onSetColor={homeAssistantSetLightColor}
|
||||
onSetWhite={homeAssistantSetLightWhite}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -19,6 +19,7 @@ const SessionContext = createContext({
|
||||
homeAssistantToggle: async () => {},
|
||||
homeAssistantSetState: async () => {},
|
||||
homeAssistantSetLightColor: async () => {},
|
||||
homeAssistantSetLightWhite: async () => {},
|
||||
setNickname: async () => {},
|
||||
requestVerification: async () => {},
|
||||
requestPrivateRoverAccess: async () => {},
|
||||
@@ -141,6 +142,8 @@ export function SessionProvider({ children }) {
|
||||
emitWithAck('homeAssistant:setState', { entityId, state }),
|
||||
homeAssistantSetLightColor: (entityId, rgbColor) =>
|
||||
emitWithAck('homeAssistant:lightColor', { entityId, rgbColor }),
|
||||
homeAssistantSetLightWhite: (entityId) =>
|
||||
emitWithAck('homeAssistant:lightWhite', { entityId }),
|
||||
setNickname: (nickname) => emitWithAck('nickname:set', { nickname }),
|
||||
requestVerification: () => emitWithAck('verification:request'),
|
||||
requestPrivateRoverAccess: (roverId) =>
|
||||
|
||||
Reference in New Issue
Block a user