Skip to content

Instantly share code, notes, and snippets.

@ALERTua
Created November 19, 2025 18:44
Show Gist options
  • Select an option

  • Save ALERTua/62fb3baa524195f6b7971b330a5400d5 to your computer and use it in GitHub Desktop.

Select an option

Save ALERTua/62fb3baa524195f6b7971b330a5400d5 to your computer and use it in GitHub Desktop.
Dynamic Ecoflow charging speed according to the time left until the next power outage
{% set debug = false %}
{# ==== CONFIGURATION ==== #}
{% set charging_speed_eid = 'number.delta_pro_api_ac_charging_power' %}
{% set main_capacity_eid = 'sensor.delta_pro_api_main_remain_capacity' %}
{% set slave_capacity_eid = 'sensor.delta_pro_api_slave_1_remain_capacity' %}
{% set battery_level_eid = 'sensor.delta_pro_api_battery_level' %}
{% set target_battery_level_eid = 'number.delta_pro_api_max_charge_level' %}
{% set next_outage_eid = 'sensor.kiiv_dtek_3_1_next_planned_outage' %}
{% set battery_voltage = 51 %}
{% set nominal_capacity_mah = 80000 %}
{% set mah_to_wh = battery_voltage / 1000 %}
{% set nominal_capacity_wh = nominal_capacity_mah * mah_to_wh * 2 %}
{% set charging_speed_limit = 1800 %}
{% set charge_margin_pct = 0 %}
{% set charge_margin_min = 15 %}
{# ==== LIVE DATA ==== #}
{% set main_capacity = states(main_capacity_eid) | float(0) %}
{% set slave_capacity = states(slave_capacity_eid) | float(0) %}
{% set measured_capacity_wh = (main_capacity + slave_capacity) * mah_to_wh %}
{% set battery_level = states(battery_level_eid) | float(0) %}
{% set target_level = states(target_battery_level_eid) | float(100) %}
{% set charging_speed_now = states(charging_speed_eid) | float(0) %}
{% set step = state_attr(charging_speed_eid, 'step') | float(1) %}
{% set speed_max = state_attr(charging_speed_eid, 'max') | float(0) %}
{% set speed_min = state_attr(charging_speed_eid, 'min') | float(0) %}
{% set next_outage = states(next_outage_eid) | as_datetime %}
{# ==== ESTIMATE CHARGE TIME ==== #}
{% if battery_level < target_level %}
{% set energy_needed = (target_level - battery_level) / 100 * nominal_capacity_wh %}
{% set assumed_speed = [speed_max, charging_speed_limit] | min %}
{% set minutes_until_charged = (energy_needed / assumed_speed * 60) | int %}
{% else %}
{% set minutes_until_charged = 0 %}
{% set energy_needed = 0 %}
{% set assumed_speed = 0 %}
{% endif %}
{# ==== CALCULATE TIME TO OUTAGE ==== #}
{% if next_outage %}
{% set minutes_until_outage = ((next_outage - now()).total_seconds() / 60) | int %}
{% set minutes_until_outage = [minutes_until_outage, 0] | max %}
{% else %}
{% set minutes_until_outage = 0 %}
{% endif %}
{# ==== CALCULATE EFFECTIVE SPEED ==== #}
{% if minutes_until_outage > 0 and minutes_until_charged > 0 %}
{% set effective_outage_time = minutes_until_outage * (1 - charge_margin_pct / 100) - charge_margin_min %}
{% set effective_outage_time = [effective_outage_time, 1] | max %}
{# --- Compute required power --- #}
{% set required_power = (energy_needed * 60.0 / effective_outage_time) %}
{# --- Safety margin --- #}
{% set required_power = required_power * 1.05 %}
{# --- Round up to nearest step --- #}
{% set raw_speed = ((required_power + step - 1) / step) | int * step %}
{# --- Clamp to limits --- #}
{% set speed = [raw_speed, speed_max, charging_speed_limit] | min %}
{% set speed = [speed, speed_min] | max %}
{% else %}
{% set speed = speed_min %}
{% set raw_speed = 0 %}
{% set required_power = 0 %}
{% set effective_outage_time = 0 %}
{% endif %}
{# ==== ESTIMATE TIME @ RECOMMENDED SPEED ==== #}
{% if speed > 0 %}
{% set estimated_time_at_speed = (energy_needed / speed * 60) | int %}
{% else %}
{% set estimated_time_at_speed = 0 %}
{% endif %}
{# ==== DEBUG ==== #}
{% if debug %}
{% set lines = [
"🔧 **DEBUG MODE**",
"----------------",
"Main cap (mAh): " ~ main_capacity,
"Slave cap (mAh): " ~ slave_capacity,
"Measured total (Wh): " ~ (measured_capacity_wh | round(1)),
"Nominal total (Wh): " ~ (nominal_capacity_wh | round(1)),
"Battery level: " ~ battery_level ~ "%",
"Target level: " ~ target_level ~ "%",
"Energy needed (Wh): " ~ (energy_needed | round(1)),
"Assumed speed (W): " ~ assumed_speed,
"Estimated time @ assumed speed: " ~ minutes_until_charged ~ " min",
"Next outage: " ~ (next_outage if next_outage else "none"),
"Minutes until outage: " ~ minutes_until_outage,
"Effective outage time (min): " ~ effective_outage_time,
"Required power (no rounding): " ~ (required_power | round(1)),
"Step size (W): " ~ step,
"Raw speed (stepped): " ~ raw_speed,
"Estimated time @ recommended speed: " ~ estimated_time_at_speed ~ " min",
"Speed limits: min=" ~ speed_min ~ ", max=" ~ speed_max ~ ", limit=" ~ charging_speed_limit,
"----------------",
("⚠️ WARNING: Target cannot be reached in time!" if estimated_time_at_speed > effective_outage_time else "✅ Within outage window"),
"----------------",
"✅ Final recommended speed: " ~ (speed | int) ~ " W"
] %}
{{ lines | join('\n') }}
{% else %}
{{ speed | int }}
{% endif %}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment