78 lines
2.1 KiB
TypeScript
78 lines
2.1 KiB
TypeScript
import { useCallback, useEffect, useState } from 'react'
|
|
import { getJson } from '../api/postgrest'
|
|
import type { AuditTodayHourlyRow } from '../types/ems'
|
|
|
|
const POLL_MS = 30_000
|
|
|
|
function parseNum(v: string | number | null | undefined): number | null {
|
|
if (v == null) return null
|
|
if (typeof v === 'number' && !Number.isNaN(v)) return v
|
|
const n = Number(v)
|
|
return Number.isFinite(n) ? n : null
|
|
}
|
|
|
|
export type TelemetryChartPoint = {
|
|
timeLabel: string
|
|
ts: number
|
|
pv_kw: number | null
|
|
load_kw: number | null
|
|
battery_kw: number | null
|
|
grid_kw: number | null
|
|
}
|
|
|
|
export function useTelemetryToday(siteId: number | null) {
|
|
const [points, setPoints] = useState<TelemetryChartPoint[]>([])
|
|
const [ready, setReady] = useState(false)
|
|
const [error, setError] = useState<string | null>(null)
|
|
|
|
const load = useCallback(async () => {
|
|
if (siteId == null) {
|
|
setPoints([])
|
|
setError(null)
|
|
setReady(true)
|
|
return
|
|
}
|
|
try {
|
|
const rows = await getJson<AuditTodayHourlyRow[]>('/vw_audit_today_hourly', {
|
|
site_id: `eq.${siteId}`,
|
|
order: 'hour_local.asc',
|
|
})
|
|
if (!Array.isArray(rows) || rows.length === 0) {
|
|
setPoints([])
|
|
setError(null)
|
|
return
|
|
}
|
|
const mapped: TelemetryChartPoint[] = rows.map((r) => {
|
|
const d = new Date(r.hour_local)
|
|
return {
|
|
ts: d.getTime(),
|
|
timeLabel: d.toLocaleTimeString('cs-CZ', {
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
timeZone: 'Europe/Prague',
|
|
}),
|
|
pv_kw: parseNum(r.avg_pv_kw),
|
|
load_kw: parseNum(r.avg_load_kw),
|
|
battery_kw: parseNum(r.avg_battery_kw),
|
|
grid_kw: parseNum(r.avg_grid_kw),
|
|
}
|
|
})
|
|
setPoints(mapped)
|
|
setError(null)
|
|
} catch {
|
|
setPoints([])
|
|
setError('Hodinová data auditu se nepodařila načíst')
|
|
} finally {
|
|
setReady(true)
|
|
}
|
|
}, [siteId])
|
|
|
|
useEffect(() => {
|
|
void load()
|
|
const id = window.setInterval(() => void load(), POLL_MS)
|
|
return () => window.clearInterval(id)
|
|
}, [load])
|
|
|
|
return { points, ready, error, hasChartData: points.length > 0, reload: load }
|
|
}
|