Skip to content

Commit 2702118

Browse files
mabry1985Claude Agentclaude
authored
Home Assistant sensor bridge (#42)
* refactor: Home Assistant sensor bridge * refactor: Home Assistant sensor bridge --------- Co-authored-by: Claude Agent <agent@protolabsai.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 46d620b commit 2702118

File tree

15 files changed

+261
-1120
lines changed

15 files changed

+261
-1120
lines changed

apps/server/src/routes/sensors/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ export function createSensorRoutes(sensorRegistryService: SensorRegistryService)
220220
* Queue a command for delivery to an IoT device.
221221
* Body: { action: 'set' | 'toggle' | 'reboot'; payload?: Record<string, unknown> }
222222
*/
223+
223224
router.post('/:id/command', (req, res) => {
224225
try {
225226
const { id } = req.params;

apps/server/src/server/services.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -438,8 +438,8 @@ export async function createServices(dataDir: string, repoRoot: string): Promise
438438
settingsService,
439439
healthMonitorService
440440
);
441-
// Sensor Registry (external sensor data ingestion + SQLite history persistence)
442-
const sensorRegistryService = new SensorRegistryService(events, getHomemakerDb());
441+
// Sensor Registry (external sensor data ingestion)
442+
const sensorRegistryService = new SensorRegistryService(events);
443443

444444
// Context Aggregator (reads sensor readings → unified UserPresenceState)
445445
const contextAggregator = new ContextAggregator(sensorRegistryService);

apps/server/src/services/scheduler.module.ts

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -250,24 +250,6 @@ export function register(container: ServiceContainer): void {
250250
true
251251
);
252252

253-
// Register daily sensor history cleanup — runs at 3 AM daily
254-
// Deletes sensor readings older than SENSOR_HISTORY_RETENTION_DAYS (default 30)
255-
await schedulerService.registerTask(
256-
'sensor-history:cleanup',
257-
'Sensor History Cleanup',
258-
'0 3 * * *',
259-
() => {
260-
const result = container.sensorRegistryService.cleanupOldReadings();
261-
if (result.deleted > 0) {
262-
events.emit('sensor:history-cleanup', {
263-
deleted: result.deleted,
264-
timestamp: new Date().toISOString(),
265-
});
266-
}
267-
},
268-
true
269-
);
270-
271253
// Initialize and register daily standup cron (every 15 minutes)
272254
container.dailyStandupService.initialize(
273255
settingsService,

apps/server/src/services/sensor-registry-service.ts

Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
* sensor:data-received — when a sensor reports a reading
1515
*/
1616

17-
import * as BetterSqlite3 from 'better-sqlite3';
1817
import { createLogger } from '@protolabsai/utils';
1918
import crypto from 'node:crypto';
2019
import type {
@@ -40,41 +39,20 @@ const STALE_TTL_MS = 5 * 60 * 1000;
4039
/** How long after the last reading a sensor is considered "offline" (15 minutes) */
4140
const OFFLINE_TTL_MS = 15 * 60 * 1000;
4241

43-
/** Default number of days to retain sensor history readings */
44-
const DEFAULT_RETENTION_DAYS = 30;
45-
46-
/** Row shape returned by the sensor_readings table */
47-
interface SensorReadingRow {
48-
sensorId: string;
49-
data: string;
50-
receivedAt: string;
51-
}
52-
53-
/** Row shape returned by aggregation queries */
54-
interface AggregatedRow {
55-
period: string;
56-
avg: number;
57-
min: number;
58-
max: number;
59-
count: number;
60-
}
61-
6242
export class SensorRegistryService {
6343
private sensors = new Map<string, SensorConfig>();
6444
private readings = new Map<string, SensorReading>();
6545
private commandQueue = new Map<string, SensorCommand[]>();
6646
private events?: EventEmitter;
67-
private db?: BetterSqlite3.Database;
6847

6948
/** Current tracked WebSocket client count for the builtin:websocket-clients sensor */
7049
private _wsClientCount = 0;
7150

7251
/** Interval handle for the Electron idle time poller */
7352
private _electronIdleInterval?: ReturnType<typeof setInterval>;
7453

75-
constructor(events?: EventEmitter, db?: BetterSqlite3.Database) {
54+
constructor(events?: EventEmitter) {
7655
this.events = events;
77-
this.db = db;
7856
}
7957

8058
/**
@@ -236,19 +214,6 @@ export class SensorRegistryService {
236214
// Store the latest reading (replaces previous)
237215
this.readings.set(input.sensorId, reading);
238216

239-
// Persist to SQLite for historical queries (fire-and-forget — never blocks the hot path)
240-
if (this.db) {
241-
try {
242-
this.db
243-
.prepare(
244-
'INSERT OR REPLACE INTO sensor_readings (sensorId, data, receivedAt) VALUES (?, ?, ?)'
245-
)
246-
.run(input.sensorId, JSON.stringify(input.data), receivedAt);
247-
} catch (err) {
248-
logger.warn(`Failed to persist sensor reading for "${input.sensorId}" to SQLite`, err);
249-
}
250-
}
251-
252217
// Update sensor's lastSeenAt
253218
sensor.lastSeenAt = receivedAt;
254219
this.sensors.set(sensor.id, sensor);

apps/ui/src/components/layout/sidebar/hooks/use-navigation.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import {
1515
Trophy,
1616
Cpu,
1717
DollarSign,
18-
Wrench,
1918
KeyRound,
2019
} from 'lucide-react';
2120
import type { NavSection, NavItem } from '../types';
@@ -122,11 +121,6 @@ export function useNavigation({
122121
label: 'Maintenance',
123122
icon: CalendarClock,
124123
},
125-
{
126-
id: 'vendors',
127-
label: 'Vendors',
128-
icon: Wrench,
129-
},
130124
{
131125
id: 'chat',
132126
label: 'Chat',

apps/ui/src/components/views/vendors-view/add-vendor-dialog.tsx

Lines changed: 0 additions & 194 deletions
This file was deleted.

0 commit comments

Comments
 (0)