DB: bazénové čerpadlo přes Shelly relé (V085)
- ems.asset_pool_pump (endpoint http, rated_power_w, min_run_min, daily_runtime_min jako aktuální sezónní hodnota, schedulable) - ems.telemetry_pool_pump — 1min hypertable (is_on, power_w, energy_wh_total) - signal_def POOL_PUMP_ON (bool) pro ovládání přes signal infrastrukturu - fn_telemetry_pool_pump_sample (R__092), vw_asset_pool_pump_http_poll (R__093) - fn_signal_enqueue_bool (R__094) — SQL-first zařazení bool signálu do fronty Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
107
db/migration/V085__pool_shelly.sql
Normal file
107
db/migration/V085__pool_shelly.sql
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
-- Bazénové čerpadlo přes Shelly relé (Gen2 RPC).
|
||||||
|
-- (a) asset + 1min telemetrie vlastním pollingem (Shelly drží jen okamžitý stav a čítač
|
||||||
|
-- aenergy.total — historii si stavíme sami jako u ostatních zařízení, 60 s),
|
||||||
|
-- (b) ovládání on/off přes existující signal infrastrukturu (signal_def POOL_PUMP_ON,
|
||||||
|
-- route http_rest na Switch.Set — route je per site, seed v docs/04-modules/pool-shelly.md),
|
||||||
|
-- (c) plánovač: odložitelná zátěž s denní povinnou dobou filtrace (follow-up, viz docs).
|
||||||
|
|
||||||
|
-- ------------------------------------------------------------
|
||||||
|
-- Aktivum: bazénové čerpadlo za Shelly relé
|
||||||
|
-- ------------------------------------------------------------
|
||||||
|
create table ems.asset_pool_pump (
|
||||||
|
id serial primary key,
|
||||||
|
site_id int not null references ems.site (id),
|
||||||
|
code text not null,
|
||||||
|
manufacturer text,
|
||||||
|
model text,
|
||||||
|
endpoint_id int references ems.site_endpoint (id),
|
||||||
|
shelly_switch_id int not null default 0,
|
||||||
|
rated_power_w int not null,
|
||||||
|
min_run_min int not null default 15,
|
||||||
|
daily_runtime_min int not null default 240,
|
||||||
|
schedulable boolean not null default true,
|
||||||
|
notes text,
|
||||||
|
constraint uq_asset_pool_pump_site_code unique (site_id, code)
|
||||||
|
);
|
||||||
|
|
||||||
|
comment on table ems.asset_pool_pump is
|
||||||
|
'Bazénové (filtrační) čerpadlo spínané přes Shelly relé (Gen2 RPC, HTTP). Konstantní příkon, odložitelná zátěž s denní povinnou dobou běhu.';
|
||||||
|
|
||||||
|
comment on column ems.asset_pool_pump.site_id is
|
||||||
|
'Vazba na lokalitu.';
|
||||||
|
|
||||||
|
comment on column ems.asset_pool_pump.code is
|
||||||
|
'Kód aktiva, unikátní v rámci lokality. Příklad: pool-pump-01.';
|
||||||
|
|
||||||
|
comment on column ems.asset_pool_pump.endpoint_id is
|
||||||
|
'HTTP endpoint Shelly relé (ems.site_endpoint, endpoint_type http_api nebo shelly_http). Bez endpointu se čerpadlo nepolluje.';
|
||||||
|
|
||||||
|
comment on column ems.asset_pool_pump.shelly_switch_id is
|
||||||
|
'Id Switch komponenty v Shelly Gen2 RPC (Switch.GetStatus?id=N). U 1kanálových relé 0.';
|
||||||
|
|
||||||
|
comment on column ems.asset_pool_pump.rated_power_w is
|
||||||
|
'Jmenovitý příkon čerpadla ve W. Plánovač s ním počítá jako s konstantním výkonem při běhu.';
|
||||||
|
|
||||||
|
comment on column ems.asset_pool_pump.min_run_min is
|
||||||
|
'Minimální nepřerušený běh v minutách (ochrana čerpadla před krátkým cyklováním). Násobky 15min slotů.';
|
||||||
|
|
||||||
|
comment on column ems.asset_pool_pump.daily_runtime_min is
|
||||||
|
'Denní povinná doba filtrace v minutách — AKTUÁLNÍ sezónní hodnota (léto typ. více, zima méně / 0). Mění ji provozovatel ručně podle sezóny; plnohodnotný sezónní profil (tabulka měsíc → minuty) je follow-up, viz docs/04-modules/pool-shelly.md. 0 = filtrace vypnutá (mimo sezónu).';
|
||||||
|
|
||||||
|
comment on column ems.asset_pool_pump.schedulable is
|
||||||
|
'true = plánovač smí rozkládat běh do levných/přebytkových slotů; false = EMS jen měří, nespíná.';
|
||||||
|
|
||||||
|
-- ------------------------------------------------------------
|
||||||
|
-- 1min telemetrie (TimescaleDB hypertable)
|
||||||
|
-- ------------------------------------------------------------
|
||||||
|
create table ems.telemetry_pool_pump (
|
||||||
|
site_id int not null references ems.site (id),
|
||||||
|
pump_id int not null references ems.asset_pool_pump (id),
|
||||||
|
measured_at timestamptz not null,
|
||||||
|
is_on boolean,
|
||||||
|
power_w int,
|
||||||
|
energy_wh_total bigint,
|
||||||
|
primary key (pump_id, measured_at)
|
||||||
|
);
|
||||||
|
|
||||||
|
comment on table ems.telemetry_pool_pump is
|
||||||
|
'Telemetrie bazénového čerpadla ze Shelly relé (Gen2 Switch.GetStatus), 1min polling. TimescaleDB hypertable. Historie se staví výhradně tady — Shelly ji nedrží.';
|
||||||
|
|
||||||
|
comment on column ems.telemetry_pool_pump.site_id is
|
||||||
|
'Vazba na lokalitu.';
|
||||||
|
|
||||||
|
comment on column ems.telemetry_pool_pump.pump_id is
|
||||||
|
'Vazba na ems.asset_pool_pump.';
|
||||||
|
|
||||||
|
comment on column ems.telemetry_pool_pump.measured_at is
|
||||||
|
'Čas měření (UTC).';
|
||||||
|
|
||||||
|
comment on column ems.telemetry_pool_pump.is_on is
|
||||||
|
'Stav relé (Switch.GetStatus output).';
|
||||||
|
|
||||||
|
comment on column ems.telemetry_pool_pump.power_w is
|
||||||
|
'Okamžitý činný příkon ve W (Switch.GetStatus apower). NULL pokud model neměří výkon.';
|
||||||
|
|
||||||
|
comment on column ems.telemetry_pool_pump.energy_wh_total is
|
||||||
|
'Kumulativní čítač energie ve Wh (Switch.GetStatus aenergy.total). Po výpadku napájení Shelly může čítač začít znovu — energii za interval počítat jako kladnou diferenci.';
|
||||||
|
|
||||||
|
select create_hypertable(
|
||||||
|
'ems.telemetry_pool_pump',
|
||||||
|
'measured_at',
|
||||||
|
chunk_time_interval => interval '1 week',
|
||||||
|
if_not_exists => true
|
||||||
|
);
|
||||||
|
|
||||||
|
create index idx_telemetry_pool_pump_site_time
|
||||||
|
on ems.telemetry_pool_pump (site_id, measured_at desc);
|
||||||
|
|
||||||
|
-- ------------------------------------------------------------
|
||||||
|
-- Signál pro ovládání relé (route per site se seeduje provozně, šablona v docs)
|
||||||
|
-- ------------------------------------------------------------
|
||||||
|
insert into ems.signal_def (code, value_type, description)
|
||||||
|
values (
|
||||||
|
'POOL_PUMP_ON',
|
||||||
|
'bool',
|
||||||
|
'Požadovaný stav bazénového čerpadla (Shelly relé). Doručuje signal_service přes signal_route http_rest na Shelly Gen2 Switch.Set, readback verify přes Switch.GetStatus. Hodnotu nastavuje plánovač / operátor (fn_signal_enqueue_bool).'
|
||||||
|
)
|
||||||
|
on conflict (code) do nothing;
|
||||||
32
db/routines/R__092_fn_telemetry_pool_pump_sample.sql
Normal file
32
db/routines/R__092_fn_telemetry_pool_pump_sample.sql
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
create or replace function ems.fn_telemetry_pool_pump_sample(
|
||||||
|
p_site_id int,
|
||||||
|
p_pump_id int,
|
||||||
|
p_measured_at timestamptz,
|
||||||
|
p_is_on boolean,
|
||||||
|
p_power_w int,
|
||||||
|
p_energy_wh_total bigint
|
||||||
|
)
|
||||||
|
returns void
|
||||||
|
language sql
|
||||||
|
as $fn$
|
||||||
|
insert into ems.telemetry_pool_pump (
|
||||||
|
site_id,
|
||||||
|
pump_id,
|
||||||
|
measured_at,
|
||||||
|
is_on,
|
||||||
|
power_w,
|
||||||
|
energy_wh_total
|
||||||
|
)
|
||||||
|
values (
|
||||||
|
p_site_id,
|
||||||
|
p_pump_id,
|
||||||
|
p_measured_at,
|
||||||
|
p_is_on,
|
||||||
|
p_power_w,
|
||||||
|
p_energy_wh_total
|
||||||
|
)
|
||||||
|
on conflict (pump_id, measured_at) do nothing;
|
||||||
|
$fn$;
|
||||||
|
|
||||||
|
comment on function ems.fn_telemetry_pool_pump_sample is
|
||||||
|
'Insert 1min telemetrie bazénového čerpadla (Shelly Switch.GetStatus: output, apower, aenergy.total). Volá telemetry_collector.poll_pool_pumps.';
|
||||||
59
db/routines/R__094_fn_signal_enqueue_bool.sql
Normal file
59
db/routines/R__094_fn_signal_enqueue_bool.sql
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
create or replace function ems.fn_signal_enqueue_bool(
|
||||||
|
p_site_id int,
|
||||||
|
p_signal_code text,
|
||||||
|
p_value boolean
|
||||||
|
)
|
||||||
|
returns int
|
||||||
|
language plpgsql
|
||||||
|
as $fn$
|
||||||
|
declare
|
||||||
|
v_route record;
|
||||||
|
v_value_text text;
|
||||||
|
v_count int := 0;
|
||||||
|
begin
|
||||||
|
-- Zařadí bool signál do odchozí fronty pro všechny aktivní routy (site, kód).
|
||||||
|
-- Transformaci na text dělá per route stejně jako backend (_bool_to_text):
|
||||||
|
-- transform_json->'map_bool'->>'true'/'false', default '1'/'0'.
|
||||||
|
for v_route in
|
||||||
|
select r.id, r.site_id, r.destination_type, r.destination_key, r.transform_json
|
||||||
|
from ems.signal_route r
|
||||||
|
where r.site_id = p_site_id
|
||||||
|
and r.signal_code = p_signal_code
|
||||||
|
and r.enabled = true
|
||||||
|
loop
|
||||||
|
v_value_text := coalesce(
|
||||||
|
v_route.transform_json -> 'map_bool' ->> (case when p_value then 'true' else 'false' end),
|
||||||
|
case when p_value then '1' else '0' end
|
||||||
|
);
|
||||||
|
|
||||||
|
insert into ems.signal_state (
|
||||||
|
site_id, signal_code, destination_type, destination_key,
|
||||||
|
last_desired_value_text, updated_at
|
||||||
|
)
|
||||||
|
values (
|
||||||
|
p_site_id, p_signal_code, v_route.destination_type, v_route.destination_key,
|
||||||
|
v_value_text, now()
|
||||||
|
)
|
||||||
|
on conflict (site_id, signal_code, destination_type, destination_key)
|
||||||
|
do update set
|
||||||
|
last_desired_value_text = excluded.last_desired_value_text,
|
||||||
|
updated_at = now();
|
||||||
|
|
||||||
|
insert into ems.signal_outbound_journal (
|
||||||
|
route_id, site_id, signal_code, value_text, value_num, status,
|
||||||
|
attempt_count, next_attempt_at
|
||||||
|
)
|
||||||
|
values (
|
||||||
|
v_route.id, p_site_id, p_signal_code, v_value_text,
|
||||||
|
case when p_value then 1 else 0 end, 'queued', 0, now()
|
||||||
|
);
|
||||||
|
|
||||||
|
v_count := v_count + 1;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
return v_count;
|
||||||
|
end;
|
||||||
|
$fn$;
|
||||||
|
|
||||||
|
comment on function ems.fn_signal_enqueue_bool is
|
||||||
|
'Zařadí bool signál (např. POOL_PUMP_ON) do signal_outbound_journal pro všechny aktivní routy daného site a kódu; doručení a verify řeší signal_service (každých 15 s). Vrací počet zařazených řádků. Použití: select ems.fn_signal_enqueue_bool(1, ''POOL_PUMP_ON'', true);';
|
||||||
18
db/views/R__093_vw_asset_pool_pump_http_poll.sql
Normal file
18
db/views/R__093_vw_asset_pool_pump_http_poll.sql
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
drop view if exists ems.vw_asset_pool_pump_http_poll;
|
||||||
|
|
||||||
|
create view ems.vw_asset_pool_pump_http_poll as
|
||||||
|
select
|
||||||
|
pp.site_id,
|
||||||
|
pp.id as pump_id,
|
||||||
|
pp.code,
|
||||||
|
pp.shelly_switch_id,
|
||||||
|
se.protocol,
|
||||||
|
se.host,
|
||||||
|
se.port
|
||||||
|
from ems.asset_pool_pump pp
|
||||||
|
join ems.site_endpoint se on se.id = pp.endpoint_id
|
||||||
|
where se.enabled = true
|
||||||
|
and se.endpoint_type in ('http_api', 'shelly_http');
|
||||||
|
|
||||||
|
comment on view ems.vw_asset_pool_pump_http_poll is
|
||||||
|
'Bazénová čerpadla se Shelly HTTP endpointem pro telemetry_collector (Gen2 RPC polling, 60 s).';
|
||||||
Reference in New Issue
Block a user