mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-19 02:50:46 -04:00
uiuiui
This commit is contained in:
@@ -66,6 +66,7 @@ const CONTROL_ACTION_NAMES = [
|
||||
'sendSong',
|
||||
'startHorn',
|
||||
'stopHorn',
|
||||
'setPeripheralControl',
|
||||
'setMicPttActive',
|
||||
];
|
||||
|
||||
@@ -724,6 +725,29 @@ export function ControlSystemProvider({ children }) {
|
||||
dispatch({ type: 'control/set-mic-ptt', payload: Boolean(active) });
|
||||
}, []);
|
||||
|
||||
const setPeripheralControl = useCallback(
|
||||
(peripheralId, controlId, value) => {
|
||||
const sent = pipeline.sendPeripheralControl(peripheralId, controlId, value);
|
||||
if (sent) {
|
||||
// The generic protocol is currently command-only. Recording the value
|
||||
// here lets every renderer instance share the browser's latest intent
|
||||
// without pretending that it is device-reported telemetry.
|
||||
dispatch({
|
||||
type: 'control/set-peripheral-value',
|
||||
payload: {
|
||||
roverId: pipeline.roverId,
|
||||
peripheralId,
|
||||
controlId,
|
||||
value,
|
||||
},
|
||||
});
|
||||
recordControlIntent();
|
||||
}
|
||||
return sent;
|
||||
},
|
||||
[pipeline, recordControlIntent],
|
||||
);
|
||||
|
||||
const actionImplementations = useMemo(
|
||||
() => ({
|
||||
setMode,
|
||||
@@ -751,6 +775,7 @@ export function ControlSystemProvider({ children }) {
|
||||
sendSong,
|
||||
startHorn,
|
||||
stopHorn,
|
||||
setPeripheralControl,
|
||||
setMicPttActive,
|
||||
}),
|
||||
[
|
||||
@@ -779,6 +804,7 @@ export function ControlSystemProvider({ children }) {
|
||||
sendSong,
|
||||
startHorn,
|
||||
stopHorn,
|
||||
setPeripheralControl,
|
||||
setMicPttActive,
|
||||
],
|
||||
);
|
||||
|
||||
@@ -44,6 +44,11 @@ export function useCommandPipeline(options = {}) {
|
||||
return rosterEntry.horn;
|
||||
}, [rosterEntry]);
|
||||
|
||||
const peripherals = useMemo(
|
||||
() => (Array.isArray(rosterEntry?.peripherals) ? rosterEntry.peripherals : []),
|
||||
[rosterEntry],
|
||||
);
|
||||
|
||||
const headlightState = useMemo(() => rosterEntry?.headlight?.state ?? null, [rosterEntry]);
|
||||
const laserState = useMemo(() => rosterEntry?.laser?.state ?? null, [rosterEntry]);
|
||||
const emitCommand = useCallback(
|
||||
@@ -208,6 +213,22 @@ export function useCommandPipeline(options = {}) {
|
||||
[emitCommand, roverId],
|
||||
);
|
||||
|
||||
const sendPeripheralControl = useCallback(
|
||||
(peripheralId, controlId, value) => {
|
||||
if (!roverId || !peripheralId || !controlId) return null;
|
||||
const peripheral = { id: peripheralId, control: controlId, value };
|
||||
// Peripheral commands deliberately use the same command envelope as all
|
||||
// other rover actuation. This keeps turn authorization, acknowledgements,
|
||||
// and rover WebSocket routing in the server's existing command boundary.
|
||||
emitCommand({
|
||||
type: 'peripheral',
|
||||
data: { peripheral },
|
||||
});
|
||||
return peripheral;
|
||||
},
|
||||
[emitCommand, roverId],
|
||||
);
|
||||
|
||||
const sendSong = useCallback(
|
||||
(notes = [], options = {}) => {
|
||||
if (!roverId) return null;
|
||||
@@ -244,6 +265,7 @@ export function useCommandPipeline(options = {}) {
|
||||
laser,
|
||||
laserState,
|
||||
horn,
|
||||
peripherals,
|
||||
emitCommand,
|
||||
enableSensorStream,
|
||||
sendDriveDirect,
|
||||
@@ -253,6 +275,7 @@ export function useCommandPipeline(options = {}) {
|
||||
sendHeadlight,
|
||||
sendLaser,
|
||||
sendHorn,
|
||||
sendPeripheralControl,
|
||||
sendSong,
|
||||
runMacroSteps,
|
||||
}),
|
||||
@@ -265,6 +288,7 @@ export function useCommandPipeline(options = {}) {
|
||||
laser,
|
||||
laserState,
|
||||
horn,
|
||||
peripherals,
|
||||
emitCommand,
|
||||
enableSensorStream,
|
||||
sendDriveDirect,
|
||||
@@ -274,6 +298,8 @@ export function useCommandPipeline(options = {}) {
|
||||
sendHeadlight,
|
||||
sendLaser,
|
||||
sendHorn,
|
||||
sendPeripheralControl,
|
||||
sendSong,
|
||||
runMacroSteps,
|
||||
],
|
||||
);
|
||||
|
||||
@@ -69,6 +69,10 @@ export const initialControlState = {
|
||||
macros: DEFAULT_MACROS,
|
||||
keymap: DEFAULT_KEYMAP,
|
||||
inputs: {},
|
||||
// Generic accessory controls do not currently report state back from roverd.
|
||||
// Keep the last browser-issued value per rover/device/control so closing a
|
||||
// drawer or changing responsive layouts does not make the UI lie about it.
|
||||
peripheralValues: {},
|
||||
};
|
||||
|
||||
export function controlReducer(state, action) {
|
||||
@@ -226,6 +230,27 @@ export function controlReducer(state, action) {
|
||||
active: Boolean(action.payload),
|
||||
},
|
||||
};
|
||||
case 'control/set-peripheral-value': {
|
||||
const roverId = String(action.payload?.roverId || '');
|
||||
const peripheralId = String(action.payload?.peripheralId || '');
|
||||
const controlId = String(action.payload?.controlId || '');
|
||||
if (!roverId || !peripheralId || !controlId) return state;
|
||||
const roverValues = state.peripheralValues?.[roverId] || {};
|
||||
const peripheralValues = roverValues[peripheralId] || {};
|
||||
return {
|
||||
...state,
|
||||
peripheralValues: {
|
||||
...(state.peripheralValues || {}),
|
||||
[roverId]: {
|
||||
...roverValues,
|
||||
[peripheralId]: {
|
||||
...peripheralValues,
|
||||
[controlId]: action.payload.value,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user