Skip to content

Commit

Permalink
Restart on config save/regen and fix flash all
Browse files Browse the repository at this point in the history
  • Loading branch information
miklschmidt committed Jan 6, 2024
1 parent c25a5ba commit 0122cba
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 41 deletions.
4 changes: 2 additions & 2 deletions src/helpers/board.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { Board } from '../zods/boards';
import { ToolheadHelper } from './toolhead';

export const getBoardSerialPath = (board: Board, toolhead?: ToolheadHelper<any>): string => {
export const getBoardSerialPath = (board: Board, toolhead?: ToolheadHelper<any> | null): string => {
if (board.isHost && 'serialPath' in board && board.serialPath != null) {
return board.serialPath;
}
return '/dev/RatOS/' + getBoardChipId(board, toolhead);
};

export const getBoardChipId = (board: Board, toolhead?: ToolheadHelper<any>): string => {
export const getBoardChipId = (board: Board, toolhead?: ToolheadHelper<any> | null): string => {
if (board.isHost) {
throw new Error('Cannot get chip ID for a host board');
}
Expand Down
11 changes: 11 additions & 0 deletions src/server/helpers/klipper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { MoonrakerPrinterState, parseMoonrakerHTTPResponse } from '../../zods/moonraker';

export const restartKlipper = async (force = false) => {
const printerState = parseMoonrakerHTTPResponse(
await fetch('http://localhost:7125/printer/objects/query?query=printer'),
MoonrakerPrinterState,
).result.status.print_state.state;
if (force || ['error', 'complete', 'canceled', 'standby'].includes(printerState)) {
await fetch('http://localhost:7125/printer/firmware_restart', { method: 'POST' });
}
};
2 changes: 1 addition & 1 deletion src/server/routers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const appRouter = router({
reboot: publicProcedure.mutation(async () => {
setTimeout(() => {
promisify(exec)('reboot');
}, 2000);
}, 500);
return {
result: 'success',
};
Expand Down
90 changes: 54 additions & 36 deletions src/server/routers/mcu.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { z } from 'zod';
import fs, { readFileSync } from 'fs';
import fs, { existsSync, readFileSync } from 'fs';
import { exec } from 'child_process';
import { promisify } from 'util';
import { TRPCError } from '@trpc/server';
Expand All @@ -15,7 +15,7 @@ import { copyFile } from 'fs/promises';
import { serverSchema } from '../../env/schema.mjs';
import { replaceInFileByLine } from '../helpers/file-operations';
import { ToolheadHelper } from '../../helpers/toolhead';
import { deserializeToolheadConfiguration } from './printer';
import { deserializeToolheadConfiguration, loadSerializedConfig } from './printer';
import { ServerCache } from '../helpers/cache';

const inputSchema = z.object({
Expand Down Expand Up @@ -65,7 +65,7 @@ export const updateDetectionStatus = async (boards: BoardWithDetectionStatus[],

export const compileFirmware = async <T extends boolean>(
board: Board,
toolhead?: ToolheadHelper<any>,
toolhead?: ToolheadHelper<any> | null,
skipCompile?: T,
): Promise<T extends true ? string : Awaited<ReturnType<typeof runSudoScript>>> => {
let compileResult = null;
Expand Down Expand Up @@ -272,42 +272,74 @@ export const mcuRouter = router({
includeHost: true,
})
.mutation(async ({ ctx }) => {
const connectedBoards = ctx.boards.filter(
(b) => detect(b) && b.flashScript && b.compileScript && b.disableAutoFlash !== true,
);
const environment = serverSchema.parse(process.env);
const filePath = path.join(environment.RATOS_DATA_DIR, 'last-printer-settings.json');
if (!existsSync(filePath)) {
throw new Error("Couldn't find printer settings file: " + filePath);
}
const config = await loadSerializedConfig(filePath);
const toolheadHelpers = config.toolheads.map((t) => {
return new ToolheadHelper(t);
});
const connectedBoards: { board: Board; toolhead: ToolheadHelper<any> | null }[] = ctx.boards
.map((b) => {
if (b.flashScript && b.compileScript && b.disableAutoFlash !== true) {
if (detect(b)) {
return { board: b, toolhead: null };
}
const toolboard =
toolheadHelpers
.map((th) => {
if (detect(b, th)) {
return { board: b, toolhead: th };
}
})
.find((b) => b != null) ?? null;
return toolboard;
}
return null;
})
.filter(Boolean);
const flashResults: {
board: Board;
result: 'success' | 'error';
message: string;
}[] = [];
for (const b of connectedBoards) {
try {
const current = AutoFlashableBoard.parse(b);
await runSudoScript(
'board-script.sh',
path.join(
const current = AutoFlashableBoard.parse(b.board);
compileFirmware(b.board, b.toolhead);
let flashResult = null;
try {
const flashScript = path.join(
current.path.replace(`${process.env.RATOS_CONFIGURATION_PATH}/boards/`, ''),
current.compileScript,
),
);
await runSudoScript(
'board-script.sh',
path.join(current.path.replace(`${process.env.RATOS_CONFIGURATION_PATH}/boards/`, ''), current.flashScript),
);
current.flashScript,
);
flashResult = b.toolhead
? await runSudoScript('flash-path.sh', getBoardSerialPath(b.board, b.toolhead))
: await runSudoScript('board-script.sh', flashScript);
} catch (e) {
const message = e instanceof Error ? e.message : e;
throw new TRPCError({
code: 'INTERNAL_SERVER_ERROR',
message: `Could not flash firmware to ${b.board.name}: \n\n ${flashResult?.stdout ?? message}`,
cause: e,
});
}
flashResults.push({
board: b,
board: b.board,
result: 'success',
message: `${b.manufacturer} ${b.name} was successfully flashed.`,
message: `${b.board.manufacturer} ${b.board.name} was successfully flashed.`,
});
} catch (e) {
const message = e instanceof Error ? e.message : e;
flashResults.push({
board: b,
board: b.board,
result: 'error',
message:
typeof message === 'string'
? message
: `Unknown error occured while flashing ${b.manufacturer} ${b.name}`,
: `Unknown error occured while flashing ${b.board.manufacturer} ${b.board.name}`,
});
}
}
Expand Down Expand Up @@ -352,21 +384,7 @@ export const mcuRouter = router({
message: `The path ${input.flashPath} does not exist.`,
});
}
let compileResult = null;
try {
const compileScript = path.join(
ctx.board.path.replace(`${process.env.RATOS_CONFIGURATION_PATH}/boards/`, ''),
ctx.board.compileScript,
);
compileResult = await runSudoScript('board-script.sh', compileScript);
} catch (e) {
const message = e instanceof Error ? e.message : e;
throw new TRPCError({
code: 'INTERNAL_SERVER_ERROR',
message: `Could not compile firmware for ${ctx.board.name}: ${compileResult?.stdout ?? message}'}`,
cause: e,
});
}
await compileFirmware(ctx.board, ctx.toolhead);
let flashResult = null;
try {
const flashScript = path.join(
Expand Down
11 changes: 9 additions & 2 deletions src/server/routers/printer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import { inferRouterInputs, inferRouterOutputs } from '@trpc/server';
import { ToolheadHelper } from '../../helpers/toolhead';
import { PrinterAxis } from '../../zods/motion';
import { ServerCache } from '../helpers/cache';
import { restartKlipper } from '../helpers/klipper';

function isNodeError(error: any): error is NodeJS.ErrnoException {
return error instanceof Error;
Expand Down Expand Up @@ -572,7 +573,11 @@ export const printerRouter = router({
};
}),
regenerateConfiguration: publicProcedure.mutation(async () => {
return await regenerateKlipperConfiguration<false>();
const res = await regenerateKlipperConfiguration();
if (res.some((r) => r.action === 'created' || r.action === 'overwritten')) {
restartKlipper();
}
return res;
}),
saveConfiguration: publicProcedure
.input(
Expand All @@ -584,7 +589,9 @@ export const printerRouter = router({
.mutation(async (ctx) => {
const { config: serializedConfig, overwritePrinterCfg } = ctx.input;
const config = await deserializePrinterConfiguration(serializedConfig);
return await generateKlipperConfiguration(config, overwritePrinterCfg);
const configResult = await generateKlipperConfiguration(config, overwritePrinterCfg);
restartKlipper();
return configResult;
}),
});

Expand Down
34 changes: 34 additions & 0 deletions src/zods/moonraker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { z } from 'zod';

export const MoonrakerBaseResult = z.object({
eventtime: z.number(),
});
export const MoonrakerPrinterState = MoonrakerBaseResult.extend({
status: z.object({
print_state: z.object({
state: z.union([
z.literal('paused'),
z.literal('printing'),
z.literal('complete'),
z.literal('error'),
z.literal('canceled'),
z.literal('standby'),
]),
}),
}),
});

export const MoonrakerHTTPResponse = z.object({
result: MoonrakerBaseResult.passthrough(),
});

export const parseMoonrakerHTTPResponse = <T extends z.ZodType<z.output<typeof MoonrakerBaseResult>>>(
result: unknown,
responseZod: T,
): z.output<typeof MoonrakerHTTPResponse> & { result: z.output<T> } => {
const response = MoonrakerHTTPResponse.parse(result);
return {
...response,
result: responseZod.parse(response.result),
};
};

0 comments on commit 0122cba

Please sign in to comment.