feat: integrate Tailwind CSS for improved styling and layout

- Added Tailwind CSS and its Vite plugin to the frontend project.
- Updated App.svelte to enhance UI with Tailwind classes, including a new layout for the serial monitor and command tester.
- Improved logging functionality by increasing log history and adding more detailed log messages.
- Refactored SendBox.svelte for consistent styling with Tailwind.
- Enhanced Pico firmware to support structured event logging and command parsing.
- Updated README_PICO_SERIAL.md to provide comprehensive documentation on serial communication and backend integration.
- Added .dockerignore to optimize Docker builds by excluding unnecessary files.
This commit is contained in:
2025-08-30 14:18:57 +02:00
parent d607308b1d
commit 46899ef7be
13 changed files with 1258 additions and 184 deletions

View File

@@ -1,8 +1,29 @@
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { NestExpressApplication } from '@nestjs/platform-express';
import { join } from 'path';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(process.env.PORT ?? 3000);
const app = await NestFactory.create<NestExpressApplication>(AppModule, {
bufferLogs: true,
});
// Serve static frontend (built assets copied to /app/public in container)
const publicDir = join(process.cwd(), 'public');
app.useStaticAssets(publicDir);
// Basic health endpoint
app.getHttpAdapter().get('/healthz', (_req: any, res: any) => {
res.json({ ok: true, ts: Date.now() });
});
const port = Number(process.env.PORT || 3000);
await app.listen(port);
// eslint-disable-next-line no-console
console.log(`[bootstrap] Listening on :${port}`);
}
bootstrap();
bootstrap().catch((e) => {
// eslint-disable-next-line no-console
console.error('Fatal bootstrap error', e);
process.exit(1);
});

View File

@@ -139,16 +139,44 @@ export class SerialService implements OnModuleDestroy, OnModuleInit {
this.close();
}
onModuleInit() {
const port = process.env.SERIAL_PORT;
const baud = process.env.SERIAL_BAUD ? Number(process.env.SERIAL_BAUD) : undefined;
if (port) {
async onModuleInit() {
// Priority: explicit env vars > auto-detect
const explicit = process.env.SERIAL_PORT || process.env.PICO_SERIAL_PORT;
const baud = Number(process.env.SERIAL_BAUD || process.env.PICO_BAUD || 115200);
if (explicit) {
try {
console.log('[SerialService] AUTO opening port from SERIAL_PORT=', port, 'baud=', baud ?? 115200);
this.open(port, baud ?? 115200);
console.log('[SerialService] AUTO opening explicit port', explicit, 'baud=', baud);
this.open(explicit, baud);
return;
} catch (e: any) {
console.warn('[SerialService] AUTO open failed', e?.message ?? e);
console.warn('[SerialService] explicit open failed', e?.message ?? e);
}
}
// Attempt auto-detect of Pico (USB first, then common UART paths)
try {
const ports = await this.listPorts();
// Prefer vendorId 2e8a (Pico)
let candidate = ports.find(p => (p.vendorId || '').toLowerCase() === '2e8a');
if (!candidate) {
const common = ['/dev/serial0', '/dev/ttyACM0', '/dev/ttyAMA0'];
candidate = ports.find(p => p.path && common.includes(p.path));
}
// Windows fallback: highest numbered COM port
if (!candidate) {
const winCom = ports
.filter(p => /^COM\d+$/i.test(p.path))
.sort((a, b) => Number(b.path.replace(/\D/g, '')) - Number(a.path.replace(/\D/g, '')))[0];
if (winCom) candidate = winCom;
}
if (candidate && candidate.path) {
console.log('[SerialService] AUTO opening detected port', candidate.path);
this.open(candidate.path, baud);
} else {
console.log('[SerialService] No serial port auto-detected (will remain idle)');
}
} catch (e: any) {
console.warn('[SerialService] auto-detect failed', e?.message ?? e);
}
}
}