implmemtace cuttoff genportu
Some checks failed
CI and deploy / migration-check (push) Failing after 9s
CI and deploy / deploy (push) Has been skipped

This commit is contained in:
Dusan Vojacek
2026-04-20 10:41:10 +02:00
parent d8dbb284fd
commit b8515f30df
15 changed files with 265 additions and 5 deletions

View File

@@ -158,6 +158,10 @@ function buildPlanTableRows(visibleSlots: PlanningIntervalDto[]): PlanTableRow[]
return rows
}
function hasGenCutoff(slots: PlanningIntervalDto[]): boolean {
return slots.some((s) => s.deye_gen_cutoff_enabled != null)
}
function horizonToggleClass(active: boolean): string {
return active
? 'border-cyan-600 bg-cyan-950/50 text-cyan-100'
@@ -339,6 +343,27 @@ function deyeModeBadge(i: PlanningIntervalDto): { label: string; klass: string;
}
}
function genCutoffBadge(i: PlanningIntervalDto): { show: boolean; label: string; klass: string; title: string } {
// Nevizualizovat na site bez GEN cut-off (null/undefined ve všech slotech).
if (i.deye_gen_cutoff_enabled == null) {
return { show: false, label: '', klass: '', title: '' }
}
if (i.deye_gen_cutoff_enabled === true) {
return {
show: true,
label: 'GEN CUT',
klass: 'bg-red-500/15 text-red-200 ring-1 ring-red-500/35',
title: 'GEN port cut-off (BA81): reg179 bits0-1=2 (MI export cutoff ON)',
}
}
return {
show: true,
label: 'GEN OK',
klass: 'bg-slate-700/30 text-slate-400 ring-1 ring-slate-600/30',
title: 'GEN port připojen (cut-off OFF)',
}
}
function tableRowClass(
i: PlanningIntervalDto,
selected: boolean,
@@ -658,6 +683,7 @@ export default function Planning() {
}, [chartMergedSlots, nowMs, chartHorizonH, slotFloorMs])
const planTableRows = useMemo(() => buildPlanTableRows(visibleSlots), [visibleSlots])
const showGenCut = useMemo(() => hasGenCutoff(visibleSlots), [visibleSlots])
const xTicks = useMemo(() => {
if (!chartIntervals.length) return undefined
@@ -1079,6 +1105,11 @@ export default function Planning() {
</span>
</th>
<th className="whitespace-nowrap py-2 pr-2 font-medium">Deye setpoint</th>
{showGenCut ? (
<th className="whitespace-nowrap py-2 pr-2 font-medium" title="GEN port cut-off (BA81 / mikroinvertory)">
GEN
</th>
) : null}
<th className="whitespace-nowrap py-2 pr-2 font-medium">SoC %</th>
<th className="whitespace-nowrap py-2 pr-2 font-medium">FVE W</th>
<th className="whitespace-nowrap py-2 pr-2 font-medium">Dům W</th>
@@ -1105,7 +1136,7 @@ export default function Planning() {
key={`sum-${row.dayKey}`}
className="border-b border-slate-700/90 bg-slate-800/70 text-slate-200"
>
<td colSpan={12} className="px-2 py-2 text-xs font-medium">
<td colSpan={showGenCut ? 13 : 12} className="px-2 py-2 text-xs font-medium">
<span className="text-slate-100">{row.dateLabel}</span>
<span className="mx-2 text-slate-600">·</span>
<span className="text-slate-400">FVE celkem</span>{' '}
@@ -1165,6 +1196,22 @@ export default function Planning() {
</span>
</div>
</td>
{showGenCut ? (
<td className="pr-2">
{(() => {
const g = genCutoffBadge(i)
if (!g.show) return <span className="text-slate-600"></span>
return (
<span
className={`inline-flex items-center rounded-md px-2 py-0.5 text-[10px] font-semibold ${g.klass}`}
title={g.title}
>
{g.label}
</span>
)
})()}
</td>
) : null}
<td className="pr-2 font-mono tabular-nums text-slate-300">
{i.battery_soc_target_pct != null
? `${i.battery_soc_target_pct.toFixed(1)}`

View File

@@ -17,6 +17,8 @@ export type PlanningIntervalDto = {
grid_setpoint_w: number | null
/** Explicitní fyzický režim Deye pro slot (PASSIVE/SELL/CHARGE). */
deye_physical_mode?: 'PASSIVE' | 'SELL' | 'CHARGE' | null
/** True = solver plánuje odpojit GEN port (MI export cutoff) v tomto slotu (BA81). */
deye_gen_cutoff_enabled?: boolean | null
ev1_setpoint_w: number | null
ev2_setpoint_w: number | null
ev_charge_power_w?: number | null