Last active
March 3, 2025 20:46
-
-
Save hanzoh/51cf37537a9f980e5d0bcfddd624de3d to your computer and use it in GitHub Desktop.
Simulate home battery from Home Assistant data
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
drop table tmp_battery_sim; | |
create table tmp_battery_sim (start timestamp without time zone, energy_in_battery numeric, energy_not_consumed_from_grid numeric, savings_from_battery numeric); | |
do $$ | |
declare | |
-- Variables | |
t record; | |
vn_battery numeric := 0.0; | |
vn_battery_prev numeric := 0.0; | |
vn_grid_savings numeric := 0.0; | |
-- Constants | |
cv_feedin_sensor varchar := 'sensor.stromzahler_energie_einspeisung'; | |
cv_grid_sensor varchar := 'sensor.stromzahler_energie_bezug'; | |
cn_grid_price numeric := 0.3085; | |
cn_feedin_comp numeric := 0.0694; | |
cn_invert_max numeric := 4.0; | |
cn_efficiency numeric := 0.9; | |
cn_battery_cap numeric := 26.0; | |
begin | |
for t in ( | |
select | |
to_timestamp(s.start_ts) at time zone 'Europe/Berlin' as start, | |
-- Rename sensors as to and from grid | |
case m.statistic_id | |
when cv_feedin_sensor then 'to_grid' | |
when cv_grid_sensor then 'from_grid' | |
end as direction, | |
coalesce(round(s.state::numeric-lag(s.state) over (partition by m.statistic_id order by s.start_ts)::numeric,3),0.0) as energy | |
from statistics s | |
join statistics_meta m | |
on s.metadata_id = m.id | |
-- Energy sensors from meter for both directions | |
where m.statistic_id in ( | |
cv_feedin_sensor, | |
cv_grid_sensor | |
) | |
order by start, direction desc | |
) | |
loop | |
-- Maximum Power of Inverter | |
if t.energy > cn_invert_max then t.energy := cn_invert_max; end if; | |
-- Charge Battery | |
if t.direction = 'to_grid' then | |
-- Charge/Discharge efficiency combined in one factor | |
vn_battery := vn_battery + t.energy*cn_efficiency; | |
-- Battery cannot be charged higher than max capacity | |
if vn_battery > cn_battery_cap then vn_battery := cn_battery_cap; end if; | |
end if; | |
-- Save battery state before discharge | |
vn_battery_prev := vn_battery; | |
-- Discharge Battery | |
if t.direction = 'from_grid' then | |
vn_battery := vn_battery - t.energy; | |
-- Batttery cannot be discharged below 0 | |
if vn_battery < 0.0 then vn_battery := 0.0; end if; | |
end if; | |
vn_grid_savings := vn_battery_prev-vn_battery; | |
if t.direction = 'from_grid' then | |
insert into tmp_battery_sim (start, energy_in_battery, energy_not_consumed_from_grid, savings_from_battery) | |
values (t.start, vn_battery, vn_grid_savings, vn_grid_savings*(cn_grid_price-cn_feedin_comp)); | |
end if; | |
end loop; | |
end$$; | |
-- Show all calculated data | |
select start, energy_in_battery, energy_not_consumed_from_grid from tmp_battery_sim; | |
-- Savings per month | |
select extract(year from start), extract(month from start), sum(energy_not_consumed_from_grid) | |
from tmp_battery_sim | |
group by extract(year from start), extract(month from start) | |
order by 1,2; | |
-- Savings per year in Euro | |
select extract(year from start), sum(energy_not_consumed_from_grid), sum(savings_from_battery) | |
from tmp_battery_sim | |
group by extract(year from start) | |
order by 1; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment