Add Gluetex Heaters page and integrate simulated temperature and power data

This commit is contained in:
Christian committed 2025-11-15 16:30:53 +01:00
1 parent caf4ae47a0
commit 7d230defea
8 files changed
+387 -48

No files matched your search

+5 -4
View File
@@ -96,7 +96,7 @@ export function RatioInput({
const handleNumpadClick = (digit: string) => {
if (activeField === null) return;
let newValue = inputValue + digit;
const newValue = inputValue + digit;
setInputValue(newValue);
};
@@ -216,7 +216,8 @@ export function RatioInput({
value: number;
}) => {
const isActive = activeField === field;
const displayValue = isActive && inputValue !== "" ? inputValue : value.toFixed(1);
const displayValue =
isActive && inputValue !== "" ? inputValue : value.toFixed(1);
return (
<div className="flex flex-col items-center gap-3">
@@ -312,7 +313,7 @@ export function RatioInput({
<div className="flex gap-2">
<TouchButton
variant="outline"
className="flex-1 h-10"
className="h-10 flex-1"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
@@ -322,7 +323,7 @@ export function RatioInput({
C
</TouchButton>
<TouchButton
className="flex-1 h-10 bg-green-600 text-white hover:bg-green-700"
className="h-10 flex-1 bg-green-600 text-white hover:bg-green-700"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
@@ -110,8 +110,7 @@ export function buffer1MessageHandler(
state: stateEvent,
}));
} else if (eventName === "LiveValuesEvent") {
const liveValuesEvent = liveValuesEventSchema.parse(event);
const timestamp = event.ts;
liveValuesEventSchema.parse(event);
updateStore((state) => ({
...state,
}));
@@ -10,7 +10,11 @@ import { Label } from "@/control/Label";
import { TouchButton } from "@/components/touch/TouchButton";
import { StatusBadge } from "@/control/StatusBadge";
import { useGluetex } from "./useGluetex";
import { StepperMode, HeatingMode, getGearRatioMultiplier } from "./gluetexNamespace";
import {
StepperMode,
HeatingMode,
getGearRatioMultiplier,
} from "./gluetexNamespace";
import { roundToDecimals, roundDegreesToDecimals } from "@/lib/decimal";
import { TensionArm } from "../TensionArm";
import { RatioInput } from "@/components/ratio/RatioInput";
@@ -44,8 +48,6 @@ export function GluetexAddonsPage() {
const gearRatioMultiplier = getGearRatioMultiplier(
state?.puller_state?.gear_ratio,
);
const maxMotorSpeed = 75; // Maximum motor speed in m/min
const maxTargetSpeed = maxMotorSpeed / gearRatioMultiplier;
return (
<Page>
@@ -154,35 +156,59 @@ export function GluetexAddonsPage() {
renderValue={(value) => roundToDecimals(value, 1)}
/>
</div>
<TemperatureBar
min={0}
max={150}
minLimit={state?.quality_control_state?.temperature1.min_temperature ?? 0}
maxLimit={state?.quality_control_state?.temperature1.max_temperature ?? 150}
minLimit={
state?.quality_control_state?.temperature1.min_temperature ??
0
}
maxLimit={
state?.quality_control_state?.temperature1.max_temperature ??
150
}
current={temperature1.current?.value ?? 0}
/>
<div className="flex flex-row flex-wrap gap-4">
<Label label="Min Temperature">
<EditValue
value={state?.quality_control_state?.temperature1.min_temperature}
value={
state?.quality_control_state?.temperature1.min_temperature
}
unit="C"
title="Min Temperature 1"
defaultValue={defaultState?.quality_control_state?.temperature1.min_temperature}
defaultValue={
defaultState?.quality_control_state?.temperature1
.min_temperature
}
min={0}
max={Math.min(149, (state?.quality_control_state?.temperature1.max_temperature ?? 150) - 1)}
max={Math.min(
149,
(state?.quality_control_state?.temperature1
.max_temperature ?? 150) - 1,
)}
renderValue={(value) => roundToDecimals(value, 1)}
onChange={setTemperature1Min}
/>
</Label>
<Label label="Max Temperature">
<EditValue
value={state?.quality_control_state?.temperature1.max_temperature}
value={
state?.quality_control_state?.temperature1.max_temperature
}
unit="C"
title="Max Temperature 1"
defaultValue={defaultState?.quality_control_state?.temperature1.max_temperature}
min={Math.max(1, (state?.quality_control_state?.temperature1.min_temperature ?? 0) + 1)}
defaultValue={
defaultState?.quality_control_state?.temperature1
.max_temperature
}
min={Math.max(
1,
(state?.quality_control_state?.temperature1
.min_temperature ?? 0) + 1,
)}
max={150}
renderValue={(value) => roundToDecimals(value, 1)}
onChange={setTemperature1Max}
@@ -201,35 +227,59 @@ export function GluetexAddonsPage() {
renderValue={(value) => roundToDecimals(value, 1)}
/>
</div>
<TemperatureBar
min={0}
max={200}
minLimit={state?.quality_control_state?.temperature2.min_temperature ?? 0}
maxLimit={state?.quality_control_state?.temperature2.max_temperature ?? 200}
minLimit={
state?.quality_control_state?.temperature2.min_temperature ??
0
}
maxLimit={
state?.quality_control_state?.temperature2.max_temperature ??
200
}
current={temperature2.current?.value ?? 0}
/>
<div className="flex flex-row flex-wrap gap-4">
<Label label="Min Temperature">
<EditValue
value={state?.quality_control_state?.temperature2.min_temperature}
value={
state?.quality_control_state?.temperature2.min_temperature
}
unit="C"
title="Min Temperature 2"
defaultValue={defaultState?.quality_control_state?.temperature2.min_temperature}
defaultValue={
defaultState?.quality_control_state?.temperature2
.min_temperature
}
min={0}
max={Math.min(199, (state?.quality_control_state?.temperature2.max_temperature ?? 200) - 1)}
max={Math.min(
199,
(state?.quality_control_state?.temperature2
.max_temperature ?? 200) - 1,
)}
renderValue={(value) => roundToDecimals(value, 1)}
onChange={setTemperature2Min}
/>
</Label>
<Label label="Max Temperature">
<EditValue
value={state?.quality_control_state?.temperature2.max_temperature}
value={
state?.quality_control_state?.temperature2.max_temperature
}
unit="C"
title="Max Temperature 2"
defaultValue={defaultState?.quality_control_state?.temperature2.max_temperature}
min={Math.max(1, (state?.quality_control_state?.temperature2.min_temperature ?? 0) + 1)}
defaultValue={
defaultState?.quality_control_state?.temperature2
.max_temperature
}
min={Math.max(
1,
(state?.quality_control_state?.temperature2
.min_temperature ?? 0) + 1,
)}
max={200}
renderValue={(value) => roundToDecimals(value, 1)}
onChange={setTemperature2Max}
@@ -45,7 +45,6 @@ export function GluetexControlPage() {
setMode,
pullerSpeed,
spoolProgress,
setPullerRegulationMode,
setPullerTargetSpeed,
traversePosition,
resetSpoolProgress,
@@ -0,0 +1,279 @@
import { Page } from "@/components/Page";
import React, { useMemo } from "react";
import { ControlGrid } from "@/control/ControlGrid";
import { HeatingZone } from "@/machines/extruder/HeatingZone";
import { useGluetex } from "./useGluetex";
import { createTimeSeries } from "@/lib/timeseries";
const TWENTY_MILLISECOND = 20;
const ONE_SECOND = 1000;
const FIVE_SECOND = 5 * ONE_SECOND;
const ONE_HOUR = 60 * 60 * ONE_SECOND;
export function GluetexHeatersPage() {
// Create mock timeseries with simulated data for each heater
const heater1Temp = useMemo(() => {
const { initialTimeSeries, insert } = createTimeSeries(
TWENTY_MILLISECOND,
ONE_SECOND,
FIVE_SECOND,
ONE_HOUR,
);
let series = initialTimeSeries;
const now = Date.now();
for (let i = 0; i < 50; i++) {
const timestamp = now - (50 - i) * 100;
const value = 150 + Math.sin(i / 5) * 2;
series = insert(series, { value, timestamp });
}
return series;
}, []);
const heater1Power = useMemo(() => {
const { initialTimeSeries, insert } = createTimeSeries(
TWENTY_MILLISECOND,
ONE_SECOND,
FIVE_SECOND,
ONE_HOUR,
);
let series = initialTimeSeries;
const now = Date.now();
for (let i = 0; i < 50; i++) {
const timestamp = now - (50 - i) * 100;
const value = 500 + Math.random() * 50 - 25;
series = insert(series, { value, timestamp });
}
return series;
}, []);
const heater2Temp = useMemo(() => {
const { initialTimeSeries, insert } = createTimeSeries(
TWENTY_MILLISECOND,
ONE_SECOND,
FIVE_SECOND,
ONE_HOUR,
);
let series = initialTimeSeries;
const now = Date.now();
for (let i = 0; i < 50; i++) {
const timestamp = now - (50 - i) * 100;
const value = 160 + Math.sin(i / 5) * 2;
series = insert(series, { value, timestamp });
}
return series;
}, []);
const heater2Power = useMemo(() => {
const { initialTimeSeries, insert } = createTimeSeries(
TWENTY_MILLISECOND,
ONE_SECOND,
FIVE_SECOND,
ONE_HOUR,
);
let series = initialTimeSeries;
const now = Date.now();
for (let i = 0; i < 50; i++) {
const timestamp = now - (50 - i) * 100;
const value = 520 + Math.random() * 50 - 25;
series = insert(series, { value, timestamp });
}
return series;
}, []);
const heater3Temp = useMemo(() => {
const { initialTimeSeries, insert } = createTimeSeries(
TWENTY_MILLISECOND,
ONE_SECOND,
FIVE_SECOND,
ONE_HOUR,
);
let series = initialTimeSeries;
const now = Date.now();
for (let i = 0; i < 50; i++) {
const timestamp = now - (50 - i) * 100;
const value = 155 + Math.sin(i / 5) * 2;
series = insert(series, { value, timestamp });
}
return series;
}, []);
const heater3Power = useMemo(() => {
const { initialTimeSeries, insert } = createTimeSeries(
TWENTY_MILLISECOND,
ONE_SECOND,
FIVE_SECOND,
ONE_HOUR,
);
let series = initialTimeSeries;
const now = Date.now();
for (let i = 0; i < 50; i++) {
const timestamp = now - (50 - i) * 100;
const value = 510 + Math.random() * 50 - 25;
series = insert(series, { value, timestamp });
}
return series;
}, []);
const heater4Temp = useMemo(() => {
const { initialTimeSeries, insert } = createTimeSeries(
TWENTY_MILLISECOND,
ONE_SECOND,
FIVE_SECOND,
ONE_HOUR,
);
let series = initialTimeSeries;
const now = Date.now();
for (let i = 0; i < 50; i++) {
const timestamp = now - (50 - i) * 100;
const value = 165 + Math.sin(i / 5) * 2;
series = insert(series, { value, timestamp });
}
return series;
}, []);
const heater4Power = useMemo(() => {
const { initialTimeSeries, insert } = createTimeSeries(
TWENTY_MILLISECOND,
ONE_SECOND,
FIVE_SECOND,
ONE_HOUR,
);
let series = initialTimeSeries;
const now = Date.now();
for (let i = 0; i < 50; i++) {
const timestamp = now - (50 - i) * 100;
const value = 530 + Math.random() * 50 - 25;
series = insert(series, { value, timestamp });
}
return series;
}, []);
const heater5Temp = useMemo(() => {
const { initialTimeSeries, insert } = createTimeSeries(
TWENTY_MILLISECOND,
ONE_SECOND,
FIVE_SECOND,
ONE_HOUR,
);
let series = initialTimeSeries;
const now = Date.now();
for (let i = 0; i < 50; i++) {
const timestamp = now - (50 - i) * 100;
const value = 158 + Math.sin(i / 5) * 2;
series = insert(series, { value, timestamp });
}
return series;
}, []);
const heater5Power = useMemo(() => {
const { initialTimeSeries, insert } = createTimeSeries(
TWENTY_MILLISECOND,
ONE_SECOND,
FIVE_SECOND,
ONE_HOUR,
);
let series = initialTimeSeries;
const now = Date.now();
for (let i = 0; i < 50; i++) {
const timestamp = now - (50 - i) * 100;
const value = 515 + Math.random() * 50 - 25;
series = insert(series, { value, timestamp });
}
return series;
}, []);
const heater6Temp = useMemo(() => {
const { initialTimeSeries, insert } = createTimeSeries(
TWENTY_MILLISECOND,
ONE_SECOND,
FIVE_SECOND,
ONE_HOUR,
);
let series = initialTimeSeries;
const now = Date.now();
for (let i = 0; i < 50; i++) {
const timestamp = now - (50 - i) * 100;
const value = 162 + Math.sin(i / 5) * 2;
series = insert(series, { value, timestamp });
}
return series;
}, []);
const heater6Power = useMemo(() => {
const { initialTimeSeries, insert } = createTimeSeries(
TWENTY_MILLISECOND,
ONE_SECOND,
FIVE_SECOND,
ONE_HOUR,
);
let series = initialTimeSeries;
const now = Date.now();
for (let i = 0; i < 50; i++) {
const timestamp = now - (50 - i) * 100;
const value = 525 + Math.random() * 50 - 25;
series = insert(series, { value, timestamp });
}
return series;
}, []);
return (
<Page>
<ControlGrid>
<HeatingZone
title={"Heater 1"}
heatingState={undefined}
heatingTimeSeries={heater1Temp}
heatingPower={heater1Power}
onChangeTargetTemp={(temp) => console.log("Set Heater 1 temp:", temp)}
min={0}
max={300}
/>
<HeatingZone
title={"Heater 2"}
heatingState={undefined}
heatingTimeSeries={heater2Temp}
heatingPower={heater2Power}
onChangeTargetTemp={(temp) => console.log("Set Heater 2 temp:", temp)}
min={0}
max={300}
/>
<HeatingZone
title={"Heater 3"}
heatingState={undefined}
heatingTimeSeries={heater3Temp}
heatingPower={heater3Power}
onChangeTargetTemp={(temp) => console.log("Set Heater 3 temp:", temp)}
min={0}
max={300}
/>
<HeatingZone
title={"Heater 4"}
heatingState={undefined}
heatingTimeSeries={heater4Temp}
heatingPower={heater4Power}
onChangeTargetTemp={(temp) => console.log("Set Heater 4 temp:", temp)}
min={0}
max={300}
/>
<HeatingZone
title={"Heater 5"}
heatingState={undefined}
heatingTimeSeries={heater5Temp}
heatingPower={heater5Power}
onChangeTargetTemp={(temp) => console.log("Set Heater 5 temp:", temp)}
min={0}
max={300}
/>
<HeatingZone
title={"Heater 6"}
heatingState={undefined}
heatingTimeSeries={heater6Temp}
heatingPower={heater6Power}
onChangeTargetTemp={(temp) => console.log("Set Heater 6 temp:", temp)}
min={0}
max={300}
/>
</ControlGrid>
</Page>
);
}
@@ -18,6 +18,12 @@ export function GluetexPage() {
title: "Addons",
icon: "lu:Puzzle",
},
{
link: "heaters",
activeLink: "heaters",
title: "Heaters",
icon: "lu:Flame",
},
{
link: "graphs",
activeLink: "graphs",
@@ -4,10 +4,7 @@
*/
import { useMemo, useState, useEffect } from "react";
import {
createTimeSeries,
TimeSeries,
} from "@/lib/timeseries";
import { createTimeSeries, TimeSeries } from "@/lib/timeseries";
import { MachineIdentificationUnique } from "@/machines/types";
// ========== Type Definitions ==========
@@ -351,7 +348,7 @@ export function useGluetexNamespace(
ONE_HOUR,
);
let series = initialTimeSeries;
// Add some initial simulated values
const now = Date.now();
for (let i = 0; i < 50; i++) {
@@ -359,7 +356,7 @@ export function useGluetexNamespace(
const value = 90 + Math.sin(i / 5) * 30; // Oscillating between 60 and 120
series = insert(series, { value, timestamp });
}
return series;
}, []);
@@ -371,14 +368,14 @@ export function useGluetexNamespace(
ONE_HOUR,
);
let series = initialTimeSeries;
const now = Date.now();
for (let i = 0; i < 50; i++) {
const timestamp = now - (50 - i) * 100;
const value = 14.5 + Math.random() * 1; // Around 15 m/min with variation
series = insert(series, { value, timestamp });
}
return series;
}, []);
@@ -390,14 +387,14 @@ export function useGluetexNamespace(
ONE_HOUR,
);
let series = initialTimeSeries;
const now = Date.now();
for (let i = 0; i < 50; i++) {
const timestamp = now - (50 - i) * 100;
const value = 25 + Math.random() * 5; // Around 25-30 rpm
series = insert(series, { value, timestamp });
}
return series;
}, []);
@@ -409,14 +406,14 @@ export function useGluetexNamespace(
ONE_HOUR,
);
let series = initialTimeSeries;
const now = Date.now();
for (let i = 0; i < 50; i++) {
const timestamp = now - (50 - i) * 100;
const value = 35 + Math.sin(i / 3) * 10; // Oscillating around 35 degrees
series = insert(series, { value, timestamp });
}
return series;
}, []);
@@ -428,14 +425,14 @@ export function useGluetexNamespace(
ONE_HOUR,
);
let series = initialTimeSeries;
const now = Date.now();
for (let i = 0; i < 50; i++) {
const timestamp = now - (50 - i) * 100;
const value = i * 0.5; // Gradually increasing progress
series = insert(series, { value, timestamp });
}
return series;
}, []);
@@ -447,14 +444,14 @@ export function useGluetexNamespace(
ONE_HOUR,
);
let series = initialTimeSeries;
const now = Date.now();
for (let i = 0; i < 50; i++) {
const timestamp = now - (50 - i) * 100;
const value = 85.0 + Math.sin(i / 10) * 3; // Oscillating around 85°C
series = insert(series, { value, timestamp });
}
return series;
}, []);
@@ -466,14 +463,14 @@ export function useGluetexNamespace(
ONE_HOUR,
);
let series = initialTimeSeries;
const now = Date.now();
for (let i = 0; i < 50; i++) {
const timestamp = now - (50 - i) * 100;
const value = 125.0 + Math.sin(i / 8) * 2; // Oscillating around 125°C
series = insert(series, { value, timestamp });
}
return series;
}, []);
@@ -485,14 +482,14 @@ export function useGluetexNamespace(
ONE_HOUR,
);
let series = initialTimeSeries;
const now = Date.now();
for (let i = 0; i < 50; i++) {
const timestamp = now - (50 - i) * 100;
const value = 11.5 + Math.random() * 1; // Around 12 m/min with variation
series = insert(series, { value, timestamp });
}
return series;
}, []);
+8
View File
@@ -17,6 +17,7 @@ import { GluetexSettingPage } from "@/machines/winder/gluetex/GluetexSettings";
import { GluetexGraphsPage } from "@/machines/winder/gluetex/GluetexGraphs";
import { GluetexPresetsPage } from "@/machines/winder/gluetex/GluetexPresetsPage";
import { GluetexAddonsPage } from "@/machines/winder/gluetex/GluetexAddonsPage";
import { GluetexHeatersPage } from "@/machines/winder/gluetex/GluetexHeatersPage";
import { Extruder2Page } from "@/machines/extruder/extruder2/Extruder2Page";
import { Extruder2ControlPage } from "@/machines/extruder/extruder2/Extruder2ControlPage";
import { Extruder2SettingsPage } from "@/machines/extruder/extruder2/Extruder2Settings";
@@ -181,6 +182,12 @@ export const gluetexAddonsRoute = createRoute({
component: () => <GluetexAddonsPage />,
});
export const gluetexHeatersRoute = createRoute({
getParentRoute: () => gluetexRoute,
path: "heaters",
component: () => <GluetexHeatersPage />,
});
export const laser1SerialRoute = createRoute({
getParentRoute: () => machinesRoute,
path: "laser1/$serial",
@@ -383,6 +390,7 @@ export const rootTree = RootRoute.addChildren([
gluetexGraphsRoute,
gluetexPresetsRoute,
gluetexAddonsRoute,
gluetexHeatersRoute,
]),
extruder2Route.addChildren([