Add per-TRV control panel + valve/wifi telemetry, restyle dashboard radiator icon
Backend: - New valve_position column, populated from shellies/<id>/info alongside wifi_rssi (was already a column, never actually written to). - New GET/POST /api/devices/:id/trv-status and /trv-control routes, mirroring the mhi-status/mhi-control and daikin-status/daikin-control pattern. Control goes through the existing setTargetWithRetry() reliability pipeline. Frontend: - New TrvControlPanel.tsx: +/- setpoint control debounced 1s after the last click before firing a command (these are battery/deep-sleep valves going through a real retry/backoff pipeline, not a cheap register write like MHI/ Daikin), plus room temp, valve position %, wifi signal, and a live "time since last update" readout. Wired into ZoneDetailModal for shelly_trv rows. - ZoneCard dashboard tile: radiator icon now just shows red when heating_active (valve open) / grey when idle, with only the target setpoint alongside it (dropped the room-temp half, redundant with the zone-level temp line above).
This commit is contained in:
parent
807a27ca1b
commit
d818bd1e7a
9 changed files with 212 additions and 7 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import { requireAuth, requireCap } from '../auth.js'
|
||||
import { pool, logActivity } from '../db.js'
|
||||
import { batchSetZoneTemperature } from '../lib/mqtt.js'
|
||||
import { batchSetZoneTemperature, setTargetWithRetry } from '../lib/mqtt.js'
|
||||
import { commandAcDevice } from '../lib/ac-control.js'
|
||||
import * as mhiDriver from '../lib/drivers/mhi-modbus.js'
|
||||
|
||||
|
|
@ -140,4 +140,55 @@ export async function overrideRoutes(app) {
|
|||
|
||||
return { ok }
|
||||
})
|
||||
|
||||
// GET /api/devices/:id/trv-status — live status for one assigned Shelly TRV, served
|
||||
// from the push-populated cache (mqtt.js keeps current_target_temp/current_room_temp/
|
||||
// battery_pct fresh from shellies/+/status, valve_position/wifi_rssi from
|
||||
// shellies/+/info) — same "read the row, don't round-trip" shape as mhi_mqtt/daikin.
|
||||
app.get('/api/devices/:id/trv-status', { preHandler: requireCap('view') }, async (req, reply) => {
|
||||
const { rows } = await pool.query(
|
||||
`SELECT * FROM zone_devices WHERE id = $1 AND device_type = 'shelly_trv'`,
|
||||
[req.params.id]
|
||||
)
|
||||
if (!rows.length) return reply.status(404).send({ error: 'TRV not found' })
|
||||
const device = rows[0]
|
||||
|
||||
return {
|
||||
external_ref: device.external_ref,
|
||||
setpoint: device.current_target_temp != null ? Number(device.current_target_temp) : undefined,
|
||||
roomTemp: device.current_room_temp != null ? Number(device.current_room_temp) : undefined,
|
||||
heatingActive: device.heating_active,
|
||||
valvePosition: device.valve_position,
|
||||
wifiRssi: device.wifi_rssi,
|
||||
batteryPct: device.battery_pct,
|
||||
targetOrigin: device.target_origin,
|
||||
lastSeen: device.last_seen,
|
||||
statusUpdatedAt: device.status_updated_at,
|
||||
}
|
||||
})
|
||||
|
||||
// POST /api/devices/:id/trv-control — explicit staff setpoint change from the room
|
||||
// modal's TrvControlPanel. Body: { tempC }. Goes through setTargetWithRetry() for the
|
||||
// full reliability pipeline (30s->30min backoff, HTTP wake-up fallback) — same
|
||||
// function the zone-level /override route above uses per-device, just for one TRV.
|
||||
app.post('/api/devices/:id/trv-control', { preHandler: requireCap('control') }, async (req, reply) => {
|
||||
const { rows } = await pool.query(
|
||||
`SELECT * FROM zone_devices WHERE id = $1 AND device_type = 'shelly_trv'`,
|
||||
[req.params.id]
|
||||
)
|
||||
if (!rows.length) return reply.status(404).send({ error: 'TRV not found' })
|
||||
const device = rows[0]
|
||||
const tempC = Number(req.body?.tempC)
|
||||
if (!Number.isFinite(tempC)) return reply.status(400).send({ error: 'tempC must be a number' })
|
||||
|
||||
const ok = await setTargetWithRetry({ external_ref: device.external_ref, device_ip: device.device_ip }, tempC)
|
||||
|
||||
await logActivity(device.zone_id, 'device_command', {
|
||||
note: `TRV manual setpoint on ${device.location || device.discovered_name || device.external_ref}: ${tempC}°C${ok ? '' : ' — FAILED'}`,
|
||||
source: 'manual',
|
||||
userEmail: req.user.email,
|
||||
})
|
||||
|
||||
return { ok }
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue