egorin backend: демо-данные горэлектросети (5 ТП/РП + автопарк бригад с автовышкой, события ТП)

This commit is contained in:
german
2026-07-08 23:01:31 +03:00
parent b2836af333
commit 8d0e26a02b
+45 -31
View File
@@ -1,28 +1,35 @@
// Демо-данные (fallback, когда реальные источники не сконфигурированы).
// Транспорт «двигается» — формируются живые треки, как от реальных устройств.
// Сценарий: городские электросети — трансформаторные подстанции + бригадный автопарк.
import { upsertEntity, addPosition, setChannels, updateChannel, addEvent, setEnergySeries, setTrips } from './store.js';
export function seedDemo() {
// Энерго-щит (стационар)
upsertEntity({ id: 'cab-07', clientId: 'tempelhoff', name: 'Щит КТП-7', type: 'energy', online: false, lat: 44.08, lon: 43.0, telemetry: { pwr_ext: 0, pwr_int: 3.9, temp: 24 } });
// --- Трансформаторные подстанции / РП (узлы энергомониторинга, стационар) ---
const subs = [
['tp-14', 'ТП-14 «Бештау»', 44.082, 43.002, false, { load: 0, u: 0, i: 0, temp: 23 }, { feeder: 'ВЛ-10 «Север»' }],
['tp-07', 'ТП-7 «Центр»', 44.048, 43.058, true, { load: 184, u: 402, i: 265, temp: 41 }, { feeder: 'ВЛ-10 «Центр»' }],
['tp-03', 'ТП-3 «Западный»', 44.041, 43.02, true, { load: 96, u: 398, i: 139, temp: 33 }, { feeder: 'ВЛ-10 «Запад»' }],
['tp-09', 'ТП-9 «Южный»', 44.018, 43.07, true, { load: 142, u: 401, i: 205, temp: 37 }, { feeder: 'ВЛ-10 «Юг»' }],
['rp-02', 'РП-2 (распределительный пункт)', 44.062, 43.045, true, { load: 310, u: 6300, i: 29, temp: 29 }, { feeder: 'ПС 110/10 «Город»' }],
];
subs.forEach(([id, name, lat, lon, online, t, meta]) => upsertEntity({ id, clientId: 'tempelhoff', name, type: 'energy', online, lat, lon, telemetry: t, meta }));
// Сетевые узлы mesh2
// --- Сетевые узлы mesh2 (раздел «Сеть») ---
const nodes = [
['mesh2-hub', 'finik-хаб', 44.072, 43.05, { latency: 1.2, uplink: 940, clients: 38, cpu: 17 }, { ip: '10.200.0.1', role: 'Центральный хаб mesh2' }],
['mesh2-kn1', 'Keenetic · Склад', 44.064, 43.058, { latency: 3.4, uplink: 310, clients: 12, cpu: 22 }, { ip: '10.200.1.2', role: 'Спица · склад' }],
['mesh2-kn2', 'Keenetic · Ферма', 44.081, 43.041, { latency: 5.1, uplink: 95, clients: 7, cpu: 19 }, { ip: '10.200.2.2', role: 'Спица · ферма' }],
['mesh2-kn1', 'Keenetic · РЭС-1', 44.064, 43.058, { latency: 3.4, uplink: 310, clients: 12, cpu: 22 }, { ip: '10.200.1.2', role: 'Спица · РЭС-1' }],
['mesh2-kn2', 'Keenetic · Диспетчерская', 44.081, 43.041, { latency: 5.1, uplink: 95, clients: 7, cpu: 19 }, { ip: '10.200.2.2', role: 'Спица · диспетчерская' }],
];
nodes.forEach(([id, name, lat, lon, t, meta]) => upsertEntity({ id, clientId: 'tempelhoff', name, type: 'network', online: true, lat, lon, telemetry: t, meta }));
// Каналы Wiren Board
// Каналы Wiren Board (телеметрия щита ТП)
setChannels([
{ id: 'mr6c_214/K1', device: 'WB-MR6C #214', name: 'Освещение цех', kind: 'relay', on: true },
{ id: 'mr6c_214/K2', device: 'WB-MR6C #214', name: 'Ворота', kind: 'relay', on: false },
{ id: 'mdm3_30/CH1', device: 'WB-MDM3 #30', name: 'Свет офис', kind: 'dimmer', on: true, level: 65 },
{ id: 'mr6c_214/IN1', device: 'WB-MR6C #214', name: 'Датчик двери', kind: 'input', on: false },
{ id: 'mr6c_214/K1', device: 'WB-MR6C #214', name: 'Ввод №1 (секц. выкл.)', kind: 'relay', on: true },
{ id: 'mr6c_214/K2', device: 'WB-MR6C #214', name: 'Ввод №2 (резерв АВР)', kind: 'relay', on: false },
{ id: 'mdm3_30/CH1', device: 'WB-MDM3 #30', name: 'Освещение ТП', kind: 'dimmer', on: true, level: 65 },
{ id: 'mr6c_214/IN1', device: 'WB-MR6C #214', name: 'Дверь ТП (охрана)', kind: 'input', on: false },
]);
// Энерго-ряд за сутки
// Энерго-ряд за сутки (суммарная нагрузка сети)
setEnergySeries(
Array.from({ length: 24 }, (_, h) => {
const s = Math.max(0, Math.sin(((h - 6) / 12) * Math.PI));
@@ -30,47 +37,54 @@ export function seedDemo() {
}),
);
// Поездки (журнал)
// Поездки бригад (журнал)
setTrips([
{ id: 't1', entityId: 'veh-123', start: new Date(Date.now() - 6 * 3.6e6).toISOString(), end: new Date(Date.now() - 5.2 * 3.6e6).toISOString(), from: 'База', to: 'Пятигорск', distanceKm: 18.4, durationMin: 48, maxSpeed: 78, avgSpeed: 41 },
{ id: 't2', entityId: 'veh-123', start: new Date(Date.now() - 2 * 3.6e6).toISOString(), end: new Date(Date.now() - 1.4 * 3.6e6).toISOString(), from: 'Ессентуки', to: 'База', distanceKm: 31.6, durationMin: 37, maxSpeed: 91, avgSpeed: 51 },
{ id: 't1', entityId: 'veh-avar', start: new Date(Date.now() - 6 * 3.6e6).toISOString(), end: new Date(Date.now() - 5.2 * 3.6e6).toISOString(), from: 'РЭС-1', to: 'ТП-9 «Южный»', distanceKm: 18.4, durationMin: 48, maxSpeed: 78, avgSpeed: 41 },
{ id: 't2', entityId: 'veh-agp22', start: new Date(Date.now() - 2 * 3.6e6).toISOString(), end: new Date(Date.now() - 1.4 * 3.6e6).toISOString(), from: 'База', to: 'ул. Лесная (ЛЭП)', distanceKm: 12.6, durationMin: 34, maxSpeed: 61, avgSpeed: 33 },
]);
addEvent({ id: 'e1', entityId: 'cab-07', callsign: 'Щит КТП-7', severity: 'critical', type: 'power_loss', text: 'Пропадание сетевого питания, переход на ИБП.', ts: new Date().toISOString(), ackRequired: true });
// Стартовые события
addEvent({ id: 'e1', entityId: 'tp-14', callsign: 'ТП-14 «Бештау»', severity: 'critical', type: 'power_loss', text: 'Пропадание питания на ВЛ-10 «Север». Потребители обесточены, выехала ВЛ-1.', ts: new Date().toISOString(), ackRequired: true });
addEvent({ id: 'e2', entityId: 'tp-07', callsign: 'ТП-7 «Центр»', severity: 'warning', type: 'overload', text: 'Перегрев трансформатора 41 °C при нагрузке 184 кВт.', ts: new Date().toISOString() });
// Подвижные объекты + стартовые позиции
// --- Бригадный автопарк (5 машин, включая автовышку) — подвижные объекты ---
const moving = {
'veh-123': { name: 'ГАЗель-123', lat: 44.05, lon: 43.06, hd: 0.4 },
'veh-204': { name: 'МТЗ-82 трактор', lat: 44.02, lon: 43.11, hd: 1.2 },
'veh-agp22': { name: 'Автовышка АГП-22', lat: 44.046, lon: 43.062, hd: 0.4, drive: true, meta: { boom: 'поднята' } },
'veh-vl1': { name: 'Бригада ВЛ-1 (ГАЗель)', lat: 44.081, lon: 43.001, hd: 1.0, drive: false },
'veh-avar': { name: 'Аварийная бригада (УАЗ)', lat: 44.058, lon: 43.041, hd: 2.1, drive: true },
'veh-kabel': { name: 'Кабельщики (ГАЗ-3309)', lat: 44.033, lon: 43.089, hd: 3.4, drive: true },
'veh-master': { name: 'Мастер участка (Нива)', lat: 44.069, lon: 43.073, hd: 5.0, drive: true },
};
Object.entries(moving).forEach(([id, m]) =>
upsertEntity({ id, clientId: 'tempelhoff', name: m.name, type: 'transport', online: true, lat: m.lat, lon: m.lon, telemetry: { speed: 0, sat: 10, fuel: 55, voltage: 13.6 } }),
upsertEntity({ id, clientId: 'tempelhoff', name: m.name, type: 'transport', online: true, lat: m.lat, lon: m.lon, telemetry: { speed: 0, sat: 11, fuel: 55, voltage: 13.7 }, meta: m.meta }),
);
// Тикер «движения» → живые треки (имитация приёма с устройств)
// Тикер «движения» → живые треки
setInterval(() => {
for (const [id, m] of Object.entries(moving)) {
m.hd += (Math.random() - 0.5) * 0.6;
const speed = id === 'veh-204' ? Math.round(Math.random() * 12) : Math.round(35 + Math.random() * 45);
const step = (speed / 3600) * 0.02;
m.lat += Math.cos(m.hd) * step;
m.lon += Math.sin(m.hd) * step;
addPosition(id, +m.lat.toFixed(5), +m.lon.toFixed(5), { speed, sat: 9 + Math.round(Math.random() * 4), fuel: 50, voltage: 13.6 });
const speed = m.drive ? Math.round(20 + Math.random() * 45) : 0;
if (m.drive) {
m.hd += (Math.random() - 0.5) * 0.6;
const step = (speed / 3600) * 0.02;
m.lat += Math.cos(m.hd) * step;
m.lon += Math.sin(m.hd) * step;
}
addPosition(id, +m.lat.toFixed(5), +m.lon.toFixed(5), { speed, sat: 9 + Math.round(Math.random() * 4), fuel: 50, voltage: 13.7 });
}
}, 3000);
// Датчик двери: периодическая смена статуса + событие — демонстрация live-обновления по WS
// Дверь ТП: периодическая смена статуса + событие (демо live-обновления по WS)
let door = false;
setInterval(() => {
door = !door;
updateChannel('mr6c_214/IN1', { on: door });
addEvent({
id: 'door-' + new Date().toISOString(),
entityId: 'cab-07',
callsign: 'Датчик двери · WB-MR6C #214',
entityId: 'tp-07',
callsign: 'Дверь ТП-7 · WB-MR6C #214',
severity: door ? 'warning' : 'info',
type: door ? 'door_open' : 'door_closed',
text: door ? 'Дверь шкафа открыта' : 'Дверь шкафа закрыта',
text: door ? 'Несанкц. доступ: дверь ТП-7 открыта' : 'Дверь ТП-7 закрыта',
ts: new Date().toISOString(),
});
}, 9000);