Ports the state machine, retry/backoff, and guest-override detection from the retired homeassistant-newbook-heating-component, without depending on Home Assistant. Backend (Fastify/pg) + frontend (React/Vite/TS) following standard stack conventions; LXC 128 (127 was already taken by utilities). MHI/Midea/Daikin/boiler drivers and the shared MQTT broker (LXC 104) are later phases/infra, not included here. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
27 lines
1.4 KiB
TypeScript
27 lines
1.4 KiB
TypeScript
import { Thermometer, BatteryLow } from 'lucide-react'
|
|
import type { ZoneStatus } from '../types'
|
|
import { ROOM_STATE_LABELS } from '../types'
|
|
|
|
export default function ZoneCard({ zone, onClick }: { zone: ZoneStatus; onClick: () => void }) {
|
|
const unhealthy = zone.devices.filter(d => d.health_state !== 'healthy').length
|
|
const lowBattery = zone.devices.some(d => d.battery_pct != null && d.battery_pct < 30)
|
|
|
|
return (
|
|
<div className={`card zone-card st-${zone.room_state}`} onClick={onClick}>
|
|
<div className="zone-card-title">
|
|
<span>{zone.name}</span>
|
|
{!zone.auto_mode && <span className="badge badge-outline">Manual</span>}
|
|
</div>
|
|
<div className={`badge badge-st-${zone.room_state}`}>{ROOM_STATE_LABELS[zone.room_state]}</div>
|
|
<div className="zone-card-temp">
|
|
<Thermometer size={16} strokeWidth={1.75} style={{ verticalAlign: '-2px', marginRight: 4 }} />
|
|
{Number(zone.target_temp).toFixed(1)}°C
|
|
</div>
|
|
<div className="zone-card-meta">
|
|
<span>{zone.device_count ?? zone.devices.length} device{(zone.device_count ?? zone.devices.length) === 1 ? '' : 's'}</span>
|
|
{unhealthy > 0 && <span style={{ color: 'var(--health-degraded)' }}>{unhealthy} needs attention</span>}
|
|
{lowBattery && <BatteryLow size={13} strokeWidth={1.75} color="var(--health-degraded)" />}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|