feat: initial release of interactive electrical circuit & panel mapper

This commit is contained in:
wmantly committed 2026-10-20 15:51:46 -04:00
commit 3ed8193565
17 files changed
+7222

No files matched your search

+151
View File
@@ -0,0 +1,151 @@
'use strict';
const fs = require('fs');
const path = require('path');
const db = require('../models/db');
const conf = require('../conf/base');
function seedDatabase(force = false) {
const deviceCount = db.prepare('SELECT COUNT(*) as count FROM devices').get().count;
if (deviceCount > 0 && !force) {
console.log(`Database already contains ${deviceCount} devices. Skipping seed.`);
return;
}
console.log('Seeding electrical chart database...');
const rawSeedPath = path.join(__dirname, '../seeds_raw.json');
if (!fs.existsSync(rawSeedPath)) {
throw new Error('seeds_raw.json not found!');
}
const rawData = JSON.parse(fs.readFileSync(rawSeedPath, 'utf8'));
const tx = db.transaction(() => {
// Clear existing
db.prepare('DELETE FROM devices').run();
db.prepare('DELETE FROM breakers').run();
db.prepare('DELETE FROM panels').run();
db.prepare('DELETE FROM structures').run();
db.prepare('DELETE FROM edges').run();
db.prepare('DELETE FROM rooms').run();
// 1. Panels
const insertPanel = db.prepare(`
INSERT INTO panels (id, name, location, model, bus_rating, notes)
VALUES (?, ?, ?, ?, ?, ?)
`);
insertPanel.run('subpanel', 'GE PowerMark Gold Load Center', 'Utility / Hallway', 'TM1210CCUG / TM1212CCU', '125A 120/240V', 'Feeds West Wing & Rec Room branch circuits. Uses THQP 1/2-inch slim tandem breakers.');
insertPanel.run('main', 'Main Service Panel (Square D QO)', 'Service Entrance / Utility', 'QO 2-Tier Split Enclosure', '100A / 200A 120/240V', 'Main disconnect in lower compartment, branch distribution in upper compartment with transformer adjacent.');
// 2. Breakers
const breakersList = [
// Subpanel Odd (Left side)
{ id: 'sub-1', panel_id: 'subpanel', slot: 1, sub_slot: null, label: '1', description: 'Bed-Bath HEAT (240V Pole A)', amps: 50, poles: 2, voltage: 240, color: '#e03131', notes: 'Pairs with slot 12' },
{ id: 'sub-3', panel_id: 'subpanel', slot: 3, sub_slot: null, label: '3', description: 'Hall & Vermont', amps: 20, poles: 1, voltage: 120, color: '#f59f00', notes: 'Hallway lighting & convenience outlets' },
{ id: 'sub-5', panel_id: 'subpanel', slot: 5, sub_slot: null, label: '5', description: 'Loft Outlet', amps: 20, poles: 1, voltage: 120, color: '#37b24d', notes: 'Upper loft receptacles' },
{ id: 'sub-7A', panel_id: 'subpanel', slot: 7, sub_slot: 'A', label: '7A', description: 'Rec Room Light', amps: 15, poles: 1, voltage: 120, color: '#1098ad', notes: 'Central luminaire & key switch runs' },
{ id: 'sub-7B', panel_id: 'subpanel', slot: 7, sub_slot: 'B', label: '7B', description: 'Rec Room Outlets', amps: 20, poles: 1, voltage: 120, color: '#1c7ed6', notes: 'North & west perimeter receptacles' },
{ id: 'sub-9A', panel_id: 'subpanel', slot: 9, sub_slot: 'A', label: '9A', description: 'Rec Room Main Circuit', amps: 15, poles: 1, voltage: 120, color: '#4263eb', notes: 'THQP slim tandem pole' },
{ id: 'sub-9B', panel_id: 'subpanel', slot: 9, sub_slot: 'B', label: '9B', description: 'Rec Room Aux', amps: 15, poles: 1, voltage: 120, color: '#7048e8', notes: 'THQP slim tandem pole' },
{ id: 'sub-11A', panel_id: 'subpanel', slot: 11, sub_slot: 'A', label: '11A', description: 'Rec Room Light Primary', amps: 15, poles: 1, voltage: 120, color: '#ae3ec9', notes: 'Lighting circuit' },
{ id: 'sub-11B', panel_id: 'subpanel', slot: 11, sub_slot: 'B', label: '11B', description: 'Rec Room Light Aux', amps: 15, poles: 1, voltage: 120, color: '#d6336c', notes: 'Lighting circuit' },
// Subpanel Even (Right side)
{ id: 'sub-2', panel_id: 'subpanel', slot: 2, sub_slot: null, label: '2', description: 'Water Heater (240V Pole A)', amps: 30, poles: 2, voltage: 240, color: '#f76707', notes: 'Tied 2-pole breaker with slot 4' },
{ id: 'sub-4', panel_id: 'subpanel', slot: 4, sub_slot: null, label: '4', description: 'Water Heater (240V Pole B)', amps: 30, poles: 2, voltage: 240, color: '#f76707', notes: 'Tied 2-pole breaker with slot 2' },
{ id: 'sub-6A', panel_id: 'subpanel', slot: 6, sub_slot: 'A', label: '6A', description: 'Rec Room Lite & Short Wall', amps: 20, poles: 1, voltage: 120, color: '#0ca678', notes: 'Traced across central rooms, pool, and east wing' },
{ id: 'sub-6B', panel_id: 'subpanel', slot: 6, sub_slot: 'B', label: '6B', description: 'Rec Room Tandem Aux', amps: 20, poles: 1, voltage: 120, color: '#66a80f', notes: 'THQP slim tandem' },
{ id: 'sub-8A', panel_id: 'subpanel', slot: 8, sub_slot: 'A', label: '8A', description: 'Open / Spare A', amps: 20, poles: 1, voltage: 120, color: '#868e96', notes: 'Physical empty slot' },
{ id: 'sub-8B', panel_id: 'subpanel', slot: 8, sub_slot: 'B', label: '8B', description: 'Open / Spare B', amps: 20, poles: 1, voltage: 120, color: '#adb5bd', notes: 'Physical empty slot' },
{ id: 'sub-10', panel_id: 'subpanel', slot: 10, sub_slot: null, label: '10', description: 'Spare / Available', amps: 20, poles: 1, voltage: 120, color: '#495057', notes: '' },
{ id: 'sub-12', panel_id: 'subpanel', slot: 12, sub_slot: null, label: '12', description: 'Bed-Bath HEAT (240V Pole B)', amps: 50, poles: 2, voltage: 240, color: '#e03131', notes: 'Pairs with slot 1' },
// Main Panel Breakers
{ id: 'main-disc', panel_id: 'main', slot: 1, sub_slot: null, label: 'MAIN', description: 'Main Service Disconnect', amps: 100, poles: 2, voltage: 240, color: '#c92a2a', notes: 'Service entrance main breaker' },
{ id: 'main-sub', panel_id: 'main', slot: 2, sub_slot: null, label: 'SUB-FEED', description: 'Feeder to GE Subpanel', amps: 60, poles: 2, voltage: 240, color: '#1864ab', notes: 'Heavy gauge feeder to load center' },
{ id: 'main-range', panel_id: 'main', slot: 3, sub_slot: null, label: 'RANGE', description: 'Electric Range / Kitchen Cooktop', amps: 50, poles: 2, voltage: 240, color: '#5f3dc4', notes: '50A 240V branch' },
{ id: 'main-dryer', panel_id: 'main', slot: 4, sub_slot: null, label: 'DRYER', description: 'Electric Clothes Dryer', amps: 30, poles: 2, voltage: 240, color: '#a61e4d', notes: '30A 240V branch' },
{ id: 'main-hvac', panel_id: 'main', slot: 5, sub_slot: null, label: 'HVAC', description: 'Air Handler & Heat Pump', amps: 40, poles: 2, voltage: 240, color: '#0b7285', notes: '40A 240V branch' },
{ id: 'main-util', panel_id: 'main', slot: 6, sub_slot: null, label: 'UTIL-1', description: 'Utility Room & Chime Transformer', amps: 15, poles: 1, voltage: 120, color: '#2b8a3e', notes: 'Feeds transformer and basement utility lights' }
];
const insertBreaker = db.prepare(`
INSERT INTO breakers (id, panel_id, slot, sub_slot, label, description, amps, poles, voltage, color, notes)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);
for (const b of breakersList) {
insertBreaker.run(b.id, b.panel_id, b.slot, b.sub_slot, b.label, b.description, b.amps, b.poles, b.voltage, b.color, b.notes);
}
// 3. Structures
const insertStruct = db.prepare(`
INSERT INTO structures (id, drawio_id, type, x, y, w, h, label, style)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
`);
for (const s of rawData.structures) {
insertStruct.run(s.id, s.drawio_id, s.type, s.x, s.y, s.w, s.h, s.label, s.style);
}
// 4. Edges
const insertEdge = db.prepare(`
INSERT INTO edges (id, drawio_id, source, target, style)
VALUES (?, ?, ?, ?, ?)
`);
for (const e of rawData.edges) {
insertEdge.run(e.id, e.drawio_id, e.source, e.target, e.style);
}
// 5. Pre-map identified devices from field notes
// 7B: Outlets on north wall of bedroom 1 & 2, and west wall
const map7B = ['dev-89', 'dev-90', 'dev-87'];
// 7A: Central luminaire
const map7A = ['dev-63'];
// 6A: Central devices, pool area, and east wing runs annotated with 6A
const map6A = ['dev-34', 'dev-35', 'dev-58', 'dev-80', 'dev-92', 'dev-184', 'dev-61', 'dev-62'];
// 6. Devices
const insertDevice = db.prepare(`
INSERT INTO devices (id, drawio_id, type, orig_x, orig_y, orig_w, orig_h, cx, cy, room, zone, breaker_id, label, notes, color)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);
for (const d of rawData.devices) {
let assignedBreaker = null;
let notes = '';
if (map7B.includes(d.id)) {
assignedBreaker = 'sub-7B';
notes = 'Verified on circuit 7B from field tracing';
} else if (map7A.includes(d.id)) {
assignedBreaker = 'sub-7A';
notes = 'Verified central luminaire on circuit 7A';
} else if (map6A.includes(d.id)) {
assignedBreaker = 'sub-6A';
notes = 'Verified on circuit 6A from field tracing';
}
insertDevice.run(
d.id,
d.drawio_id,
d.type,
d.x,
d.y,
d.w,
d.h,
d.cx,
d.cy,
d.room,
d.zone,
assignedBreaker,
d.label,
notes,
d.color
);
}
});
tx();
console.log('Database seeded successfully.');
}
module.exports = { seedDatabase };