Compare commits
63
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc78ab80cb | ||
|
|
af21d05e6a | ||
|
|
aa54f94e94 | ||
|
|
e00b0d2c3e | ||
|
|
b338d71874 | ||
|
|
fb650216d2 | ||
|
|
da823197d5 | ||
|
|
fe5f109c89 | ||
|
|
1d86a42fb6 | ||
|
|
fb8eee4b8d | ||
|
|
24cd1d857f | ||
|
|
b7c4e1939d | ||
|
|
7d0a683c4b | ||
|
|
fde51a95c8 | ||
|
|
d88f45f81f | ||
|
|
8e0005d447 | ||
|
|
2bfa75810f | ||
|
|
b86130ec0d | ||
|
|
ad9305e1fd | ||
|
|
191d022270 | ||
|
|
2d3a69852f | ||
|
|
d145bf547e | ||
|
|
ed90b253f7 | ||
|
|
4e78c6c912 | ||
|
|
1efebc4a27 | ||
|
|
ea7d799cfc | ||
|
|
54ac5678ad | ||
|
|
19ebbb77ac | ||
|
|
4bb2a73f6c | ||
|
|
972562b1d6 | ||
|
|
2a68a2da8f | ||
|
|
2d7b71ef5d | ||
|
|
0398bd0242 | ||
|
|
74e83d7cf5 | ||
|
|
25a1d3515d | ||
|
|
81d4b162e9 | ||
|
|
a790f15db9 | ||
|
|
50d7373f02 | ||
|
|
f1cd0c6216 | ||
|
|
eb7724a756 | ||
|
|
df88eded18 | ||
|
|
503a6b493e | ||
|
|
4a7bb2abfd | ||
|
|
12a42eb0a6 | ||
|
|
d3981d7276 | ||
|
|
89e702275e | ||
|
|
4a1239fa27 | ||
|
|
bd22c39b4a | ||
|
|
96edca9f66 | ||
|
|
2d198e0a44 | ||
|
|
9107e1372a | ||
|
|
8268eff39b | ||
|
|
63910ab5be | ||
|
|
91fdd7eb1e | ||
|
|
8aa86a91ff | ||
|
|
6f125ff0ab | ||
|
|
256c032b7c | ||
|
|
46a794d323 | ||
|
|
a18b10bf50 | ||
|
|
405a1f3c2f | ||
|
|
3e09a00000 | ||
|
|
b4ee86a88c | ||
|
|
1eeb3f8190 |
No files matched your search
@@ -5,15 +5,37 @@ import React from "react";
|
||||
import { useBuffer1 } from "./useBuffer1";
|
||||
import { ControlCard } from "@/control/ControlCard";
|
||||
import { SelectionGroup } from "@/control/SelectionGroup";
|
||||
import { EditValue } from "@/control/EditValue";
|
||||
import { TimeSeriesValueNumeric } from "@/control/TimeSeriesValue";
|
||||
import { roundToDecimals } from "@/lib/decimal";
|
||||
import { Label } from "@/control/Label";
|
||||
import { TouchButton } from "@/components/touch/TouchButton";
|
||||
import { StatusBadge } from "@/control/StatusBadge";
|
||||
|
||||
export function Buffer1ControlPage() {
|
||||
const { state, setBufferMode } = useBuffer1();
|
||||
const {
|
||||
state,
|
||||
defaultState,
|
||||
setBufferMode,
|
||||
setCurrentInputSpeed,
|
||||
pullerSpeed,
|
||||
setPullerRegulationMode,
|
||||
setPullerTargetSpeed,
|
||||
liftPosition,
|
||||
gotoLiftHome,
|
||||
isLoading,
|
||||
isDisabled,
|
||||
} = useBuffer1();
|
||||
|
||||
const current_input_speed =
|
||||
state?.current_input_speed_state.current_input_speed ?? 0.0;
|
||||
const default_speed = 0.0;
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<ControlGrid>
|
||||
<ControlCard className="bg-red" title="Mode">
|
||||
<SelectionGroup<"Standby" | "FillingBuffer" | "EmptyingBuffer">
|
||||
<SelectionGroup<"Standby" | "Hold" | "Filling" | "Emptying">
|
||||
value={state?.mode_state.mode}
|
||||
orientation="vertical"
|
||||
className="grid h-full grid-cols-2 gap-2"
|
||||
@@ -24,13 +46,19 @@ export function Buffer1ControlPage() {
|
||||
isActiveClassName: "bg-green-600",
|
||||
className: "h-full",
|
||||
},
|
||||
FillingBuffer: {
|
||||
children: "FillingBuffer",
|
||||
Hold: {
|
||||
children: "Hold",
|
||||
icon: "lu:Pause",
|
||||
isActiveClassName: "bg-green-600",
|
||||
className: "h-full",
|
||||
},
|
||||
Filling: {
|
||||
children: "Filling",
|
||||
icon: "lu:Flame",
|
||||
isActiveClassName: "bg-green-600",
|
||||
className: "h-full",
|
||||
},
|
||||
EmptyingBuffer: {
|
||||
Emptying: {
|
||||
children: "EmptyingBuffer",
|
||||
icon: "lu:ArrowBigLeftDash",
|
||||
isActiveClassName: "bg-green-600",
|
||||
@@ -40,6 +68,83 @@ export function Buffer1ControlPage() {
|
||||
onChange={setBufferMode}
|
||||
/>
|
||||
</ControlCard>
|
||||
<ControlCard title="Set Current Input Speed - (For Debugging)">
|
||||
<EditValue
|
||||
title="Input Speed"
|
||||
unit="m/min"
|
||||
value={current_input_speed}
|
||||
defaultValue={default_speed}
|
||||
min={0.0}
|
||||
max={60.0}
|
||||
step={0.1}
|
||||
renderValue={(value) => roundToDecimals(value, 1)}
|
||||
onChange={setCurrentInputSpeed}
|
||||
/>
|
||||
</ControlCard>
|
||||
|
||||
<ControlCard className="bg-red" height={2} title="Lift">
|
||||
<TimeSeriesValueNumeric
|
||||
label="Position"
|
||||
unit="mm"
|
||||
timeseries={liftPosition}
|
||||
renderValue={(value) => roundToDecimals(value, 1)}
|
||||
/>
|
||||
<Label label="Home">
|
||||
<TouchButton
|
||||
variant="outline"
|
||||
icon="lu:House"
|
||||
onClick={() => gotoLiftHome()}
|
||||
disabled={isDisabled}
|
||||
isLoading={isLoading || state?.lift_state?.is_going_home}
|
||||
>
|
||||
Go to Home
|
||||
</TouchButton>
|
||||
{state?.lift_state?.is_homed !== true ? (
|
||||
<StatusBadge variant={"error"}>{"Not Homed"}</StatusBadge>
|
||||
) : null}
|
||||
</Label>
|
||||
</ControlCard>
|
||||
|
||||
<ControlCard className="bg-red" title="Puller">
|
||||
<TimeSeriesValueNumeric
|
||||
label="Speed"
|
||||
unit="m/min"
|
||||
timeseries={pullerSpeed}
|
||||
renderValue={(value) => roundToDecimals(value, 1)}
|
||||
/>
|
||||
<Label label="Regulation">
|
||||
<SelectionGroup
|
||||
value={state?.puller_state?.regulation}
|
||||
options={{
|
||||
Speed: {
|
||||
children: "Speed",
|
||||
icon: "lu:Gauge",
|
||||
},
|
||||
Diameter: {
|
||||
children: "Diameter",
|
||||
icon: "lu:Sun",
|
||||
disabled: true,
|
||||
},
|
||||
}}
|
||||
onChange={setPullerRegulationMode}
|
||||
disabled={isDisabled}
|
||||
loading={isLoading}
|
||||
/>
|
||||
</Label>
|
||||
<Label label="Target Speed">
|
||||
<EditValue
|
||||
value={state?.puller_state?.target_speed}
|
||||
unit="m/min"
|
||||
title="Target Speed"
|
||||
defaultValue={defaultState?.puller_state?.target_speed}
|
||||
min={0}
|
||||
max={75}
|
||||
step={0.1}
|
||||
renderValue={(value) => roundToDecimals(value, 1)}
|
||||
onChange={setPullerTargetSpeed}
|
||||
/>
|
||||
</Label>
|
||||
</ControlCard>
|
||||
</ControlGrid>
|
||||
</Page>
|
||||
);
|
||||
|
||||
@@ -16,23 +16,55 @@ import {
|
||||
ThrottledStoreUpdater,
|
||||
} from "../../../client/socketioStore";
|
||||
import { MachineIdentificationUnique } from "@/machines/types";
|
||||
import {
|
||||
createTimeSeries,
|
||||
TimeSeries,
|
||||
TimeSeriesValue,
|
||||
} from "@/lib/timeseries";
|
||||
|
||||
// ========== Event Schema Definitions ==========
|
||||
|
||||
/**
|
||||
* Machine operation mode enum
|
||||
*/
|
||||
export const modeSchema = z.enum([
|
||||
"Standby",
|
||||
"FillingBuffer",
|
||||
"EmptyingBuffer",
|
||||
]);
|
||||
export const modeSchema = z.enum(["Standby", "Hold", "Filling", "Emptying"]);
|
||||
export type Mode = z.infer<typeof modeSchema>;
|
||||
|
||||
/**
|
||||
* Consolidated live values event schema (30FPS data)
|
||||
*/
|
||||
export const liveValuesEventDataSchema = z.object({});
|
||||
export const liveValuesEventDataSchema = z.object({
|
||||
lift_position: z.number().nullable(),
|
||||
puller_speed: z.number(),
|
||||
});
|
||||
|
||||
/**
|
||||
* Puller regulation type enum
|
||||
*/
|
||||
export const pullerRegulationSchema = z.enum(["Speed", "Diameter"]);
|
||||
export type PullerRegulation = z.infer<typeof pullerRegulationSchema>;
|
||||
|
||||
/**
|
||||
* Puller state event schmema
|
||||
*/
|
||||
export const pullerStateSchema = z.object({
|
||||
regulation: pullerRegulationSchema,
|
||||
target_speed: z.number(),
|
||||
target_diameter: z.number(),
|
||||
forward: z.boolean(),
|
||||
});
|
||||
|
||||
/**
|
||||
* Lift state schema
|
||||
*/
|
||||
export const liftStateSchema = z.object({
|
||||
is_going_up: z.boolean(),
|
||||
is_going_down: z.boolean(),
|
||||
is_homed: z.boolean(),
|
||||
is_going_home: z.boolean(),
|
||||
is_buffering: z.boolean(),
|
||||
step_size: z.number(),
|
||||
});
|
||||
|
||||
/**
|
||||
* Mode state event schema
|
||||
@@ -41,6 +73,10 @@ export const modeStateSchema = z.object({
|
||||
mode: modeSchema,
|
||||
});
|
||||
|
||||
export const currentInputSpeedSchema = z.object({
|
||||
current_input_speed: z.number(),
|
||||
});
|
||||
|
||||
/**
|
||||
* Connected machine state scheme
|
||||
*/
|
||||
@@ -65,7 +101,10 @@ export const connectedMachineStateSchema = z.object({
|
||||
|
||||
export const stateEventDataSchema = z.object({
|
||||
mode_state: modeStateSchema,
|
||||
lift_state: liftStateSchema,
|
||||
puller_state: pullerStateSchema,
|
||||
connected_machine_state: connectedMachineStateSchema,
|
||||
current_input_speed_state: currentInputSpeedSchema,
|
||||
});
|
||||
|
||||
// ========== Event Schemas with Wrappers ==========
|
||||
@@ -80,8 +119,24 @@ export type StateEvent = z.infer<typeof stateEventSchema>;
|
||||
export type Buffer1NamespaceStore = {
|
||||
// State events (latest only)
|
||||
state: StateEvent | null;
|
||||
defaultState: StateEvent | null;
|
||||
|
||||
// Time series data for live values
|
||||
liftPosition: TimeSeries;
|
||||
pullerSpeed: TimeSeries;
|
||||
};
|
||||
|
||||
// Constants for time durations
|
||||
const TWENTY_MILLISECOND = 20;
|
||||
const ONE_SECOND = 1000;
|
||||
const FIVE_SECOND = 5 * ONE_SECOND;
|
||||
const ONE_HOUR = 60 * 60 * ONE_SECOND;
|
||||
|
||||
const { initialTimeSeries: pullerSpeed, insert: addPullerSpeed } =
|
||||
createTimeSeries(TWENTY_MILLISECOND, ONE_SECOND, FIVE_SECOND, ONE_HOUR);
|
||||
const { initialTimeSeries: liftPosition, insert: addLiftPosition } =
|
||||
createTimeSeries(TWENTY_MILLISECOND, ONE_SECOND, FIVE_SECOND, ONE_HOUR);
|
||||
|
||||
/**
|
||||
* Creates a message handler for Buffer1 namespace events with validation and appropriate caching strategies
|
||||
* @param store The store to update when messages are received
|
||||
@@ -110,12 +165,41 @@ export function buffer1MessageHandler(
|
||||
...state,
|
||||
state: stateEvent,
|
||||
}));
|
||||
console.log(stateEvent);
|
||||
} else if (eventName === "LiveValuesEvent") {
|
||||
// Parse and validate the live values event
|
||||
const liveValuesEvent = liveValuesEventSchema.parse(event);
|
||||
const timestamp = event.ts;
|
||||
updateStore((state) => ({
|
||||
...state,
|
||||
}));
|
||||
|
||||
// Extract values and add to time series
|
||||
const { lift_position, puller_speed } = liveValuesEvent.data;
|
||||
|
||||
const timestamp = liveValuesEvent.ts;
|
||||
updateStore((state) => {
|
||||
const newState = { ...state };
|
||||
// Add lift position if not null
|
||||
if (lift_position !== null) {
|
||||
const timeseriesValue: TimeSeriesValue = {
|
||||
value: lift_position,
|
||||
timestamp,
|
||||
};
|
||||
newState.liftPosition = addLiftPosition(
|
||||
state.liftPosition,
|
||||
timeseriesValue,
|
||||
);
|
||||
}
|
||||
|
||||
// Add puller speed
|
||||
const pullerSpeedValue: TimeSeriesValue = {
|
||||
value: puller_speed,
|
||||
timestamp,
|
||||
};
|
||||
newState.pullerSpeed = addPullerSpeed(
|
||||
state.pullerSpeed,
|
||||
pullerSpeedValue,
|
||||
);
|
||||
|
||||
return newState;
|
||||
});
|
||||
} else {
|
||||
handleUnhandledEventError(eventName);
|
||||
}
|
||||
@@ -134,7 +218,13 @@ export const createBuffer1NamespaceStore =
|
||||
(): StoreApi<Buffer1NamespaceStore> =>
|
||||
create<Buffer1NamespaceStore>(() => {
|
||||
return {
|
||||
// State event from server
|
||||
state: null,
|
||||
defaultState: null,
|
||||
|
||||
// Time series data for live values
|
||||
liftPosition,
|
||||
pullerSpeed,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -8,7 +8,13 @@ import {
|
||||