Compare commits
8 Commits
81d9022052
...
5eae8e1d6a
| Author | SHA1 | Date | |
|---|---|---|---|
| 5eae8e1d6a | |||
| 1dc0866fe3 | |||
| 5e368938bc | |||
| 18c6b5e4cb | |||
| 5cfb27c3ad | |||
| 70b78b6275 | |||
| 3d988314aa | |||
| 1e71bc5372 |
@@ -17,22 +17,22 @@
|
|||||||
after: "05:00:00"
|
after: "05:00:00"
|
||||||
before: "23:00:00"
|
before: "23:00:00"
|
||||||
|
|
||||||
- condition: not
|
|
||||||
conditions:
|
|
||||||
- condition: state
|
|
||||||
entity_id: device_tracker.snowywhite_location_tracker
|
|
||||||
state: "not_home"
|
|
||||||
|
|
||||||
action:
|
action:
|
||||||
- choose:
|
- choose:
|
||||||
|
|
||||||
# ÅBN (Arriving)
|
# ÅBN (kun hvis bil er aktiv)
|
||||||
- conditions:
|
- conditions:
|
||||||
- condition: trigger
|
- condition: trigger
|
||||||
id: arriving
|
id: arriving
|
||||||
|
|
||||||
- condition: state
|
- condition: state
|
||||||
entity_id: cover.anne
|
entity_id: cover.anne
|
||||||
state: "closed"
|
state: "closed"
|
||||||
|
|
||||||
|
- condition: template
|
||||||
|
value_template: >
|
||||||
|
{{ state_attr('device_tracker.snowywhite_location_tracker', 'speed') not in [None, 'unknown'] }}
|
||||||
|
|
||||||
sequence:
|
sequence:
|
||||||
- service: cover.open_cover
|
- service: cover.open_cover
|
||||||
target:
|
target:
|
||||||
@@ -40,23 +40,29 @@
|
|||||||
|
|
||||||
- service: notify.mobile_app_clausiphone15
|
- service: notify.mobile_app_clausiphone15
|
||||||
data:
|
data:
|
||||||
message: "Garage opened (arrival detected)"
|
message: "Garage opened (arrival by car)"
|
||||||
|
|
||||||
# LUK (Leaving)
|
# LUK (kun hvis bil er aktiv)
|
||||||
- conditions:
|
- conditions:
|
||||||
- condition: trigger
|
- condition: trigger
|
||||||
id: leaving
|
id: leaving
|
||||||
|
|
||||||
- condition: state
|
- condition: state
|
||||||
entity_id: cover.anne
|
entity_id: cover.anne
|
||||||
state: "open"
|
state: "open"
|
||||||
|
|
||||||
|
- condition: template
|
||||||
|
value_template: >
|
||||||
|
{{ state_attr('device_tracker.snowywhite_location_tracker', 'speed') not in [None, 'unknown'] }}
|
||||||
|
|
||||||
sequence:
|
sequence:
|
||||||
|
- delay: "00:00:20" # giver tid til at du faktisk er kørt ud
|
||||||
|
|
||||||
- service: cover.close_cover
|
- service: cover.close_cover
|
||||||
target:
|
target:
|
||||||
entity_id: cover.anne
|
entity_id: cover.anne
|
||||||
|
|
||||||
- service: notify.mobile_app_clausiphone15
|
- service: notify.mobile_app_clausiphone15
|
||||||
data:
|
data:
|
||||||
message: "Garage closed (departure detected)"
|
message: "Garage closed (departure by car)"
|
||||||
|
|
||||||
mode: single
|
mode: single
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,6 @@
|
|||||||
entity_id: binary_sensor.family_presence
|
entity_id: binary_sensor.family_presence
|
||||||
to: "off"
|
to: "off"
|
||||||
|
|
||||||
condition:
|
|
||||||
- condition: template
|
|
||||||
value_template: "{{ trigger.from_state.state != 'unavailable' }}"
|
|
||||||
|
|
||||||
action:
|
action:
|
||||||
- service: input_datetime.set_datetime
|
- service: input_datetime.set_datetime
|
||||||
target:
|
target:
|
||||||
@@ -36,41 +32,37 @@
|
|||||||
mode: single
|
mode: single
|
||||||
|
|
||||||
trigger:
|
trigger:
|
||||||
# Tjek løbende mens huset er tomt
|
|
||||||
- platform: time_pattern
|
- platform: time_pattern
|
||||||
minutes: "/5"
|
minutes: "/5"
|
||||||
|
|
||||||
condition:
|
condition:
|
||||||
# Huset er tomt
|
|
||||||
- condition: state
|
- condition: state
|
||||||
entity_id: binary_sensor.family_presence
|
entity_id: binary_sensor.family_presence
|
||||||
state: "off"
|
state: "off"
|
||||||
|
|
||||||
# Har været tomt i 30 min (robust)
|
|
||||||
- condition: template
|
- condition: template
|
||||||
value_template: >
|
value_template: >
|
||||||
{{ states('input_datetime.house_became_empty') not in ['unknown','unavailable',''] and
|
{{ states('input_datetime.house_became_empty') not in ['unknown','unavailable',''] and
|
||||||
(as_timestamp(now()) - as_timestamp(states('input_datetime.house_became_empty'))) > 1800 }}
|
(as_timestamp(now()) - as_timestamp(states('input_datetime.house_became_empty'))) > 1800 }}
|
||||||
|
|
||||||
# Max 2 gange dagligt
|
|
||||||
- condition: numeric_state
|
- condition: numeric_state
|
||||||
entity_id: input_number.roborock_auto_runs_today
|
entity_id: input_number.roborock_auto_runs_today
|
||||||
below: 2
|
below: 2
|
||||||
|
|
||||||
# Støvsuger klar (robust state check)
|
|
||||||
- condition: template
|
- condition: template
|
||||||
value_template: >
|
value_template: >
|
||||||
{{ states('vacuum.roborock_s8_pro_ultra') in ['docked','idle','charging'] }}
|
{{ states('vacuum.roborock_s8_pro_ultra') in ['docked','idle','charging'] }}
|
||||||
|
|
||||||
# Batteri OK
|
- condition: template
|
||||||
- condition: numeric_state
|
value_template: >
|
||||||
entity_id: vacuum.roborock_s8_pro_ultra
|
{% set b = state_attr('vacuum.roborock_s8_pro_ultra','battery_level') %}
|
||||||
attribute: battery_level
|
{{ b is number and b > 20 }}
|
||||||
above: 20
|
|
||||||
|
|
||||||
action:
|
action:
|
||||||
- alias: "Start cleaning (retry op til 3 gange)"
|
- variables:
|
||||||
repeat:
|
started: false
|
||||||
|
|
||||||
|
- repeat:
|
||||||
count: 3
|
count: 3
|
||||||
sequence:
|
sequence:
|
||||||
- service: button.press
|
- service: button.press
|
||||||
@@ -79,13 +71,42 @@
|
|||||||
|
|
||||||
- delay: "00:00:20"
|
- delay: "00:00:20"
|
||||||
|
|
||||||
- condition: state
|
- if:
|
||||||
entity_id: vacuum.roborock_s8_pro_ultra
|
- condition: state
|
||||||
state: "cleaning"
|
entity_id: vacuum.roborock_s8_pro_ultra
|
||||||
|
state: "cleaning"
|
||||||
|
then:
|
||||||
|
- variables:
|
||||||
|
started: true
|
||||||
|
- stop: "Cleaning started"
|
||||||
|
|
||||||
- service: input_number.increment
|
- choose:
|
||||||
target:
|
|
||||||
entity_id: input_number.roborock_auto_runs_today
|
# ✅ SUCCESS → send notifikation
|
||||||
|
- conditions:
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ started }}"
|
||||||
|
sequence:
|
||||||
|
- service: input_number.increment
|
||||||
|
target:
|
||||||
|
entity_id: input_number.roborock_auto_runs_today
|
||||||
|
|
||||||
|
- service: notify.mobile_app_clausiphone15
|
||||||
|
data:
|
||||||
|
title: "🧹 Roborock startet"
|
||||||
|
message: >
|
||||||
|
Rengøring startet automatisk.
|
||||||
|
Hus har været tomt i {{ ((as_timestamp(now()) - as_timestamp(states('input_datetime.house_became_empty'))) / 60) | int }} min.
|
||||||
|
|
||||||
|
# ❌ FAIL → send fejl-notifikation
|
||||||
|
- conditions:
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ not started }}"
|
||||||
|
sequence:
|
||||||
|
- service: notify.mobile_app_clausiphone15
|
||||||
|
data:
|
||||||
|
title: "⚠️ Roborock start fejlede"
|
||||||
|
message: "Automation forsøgte 3 gange uden succes."
|
||||||
|
|
||||||
- id: roborock_stop_when_home
|
- id: roborock_stop_when_home
|
||||||
alias: Roborock Stop When Someone Comes Home
|
alias: Roborock Stop When Someone Comes Home
|
||||||
@@ -105,3 +126,8 @@
|
|||||||
- service: vacuum.return_to_base
|
- service: vacuum.return_to_base
|
||||||
target:
|
target:
|
||||||
entity_id: vacuum.roborock_s8_pro_ultra
|
entity_id: vacuum.roborock_s8_pro_ultra
|
||||||
|
|
||||||
|
- service: notify.mobile_app_clausiphone15
|
||||||
|
data:
|
||||||
|
title: "🏠 Roborock stoppet"
|
||||||
|
message: "Rengøring stoppet fordi nogen er kommet hjem."
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
- alias: Tesla set charge deadline at 13:00
|
||||||
|
id: tesla_set_charge_deadline_daily
|
||||||
|
trigger:
|
||||||
|
- platform: time
|
||||||
|
at: "13:05:00"
|
||||||
|
|
||||||
|
action:
|
||||||
|
- service: input_datetime.set_datetime
|
||||||
|
target:
|
||||||
|
entity_id: input_datetime.tesla_charge_deadline
|
||||||
|
data:
|
||||||
|
datetime: >
|
||||||
|
{{ (now() + timedelta(days=1))
|
||||||
|
.replace(hour=7, minute=0, second=0, microsecond=0) }}
|
||||||
|
|
||||||
|
mode: single
|
||||||
|
|
||||||
|
|
||||||
|
- alias: Tesla set charge deadline when plugged in
|
||||||
|
id: tesla_set_charge_deadline_on_plug
|
||||||
|
trigger:
|
||||||
|
- platform: state
|
||||||
|
entity_id: binary_sensor.snowywhite_charger
|
||||||
|
to: "on"
|
||||||
|
|
||||||
|
action:
|
||||||
|
- service: input_datetime.set_datetime
|
||||||
|
target:
|
||||||
|
entity_id: input_datetime.tesla_charge_deadline
|
||||||
|
data:
|
||||||
|
datetime: >
|
||||||
|
{{ (now() + timedelta(days=1))
|
||||||
|
.replace(hour=7, minute=0, second=0, microsecond=0) }}
|
||||||
|
|
||||||
|
mode: single
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
- alias: Tesla smart charging v3
|
- alias: Tesla smart charging v4
|
||||||
id: tesla_smart_charging_v3
|
id: tesla_smart_charging_v4
|
||||||
mode: restart
|
mode: restart
|
||||||
|
|
||||||
trigger:
|
trigger:
|
||||||
@@ -7,55 +7,65 @@
|
|||||||
minutes: "/5"
|
minutes: "/5"
|
||||||
|
|
||||||
condition:
|
condition:
|
||||||
# Ensure deadline is valid and in the future
|
# Valid future deadline
|
||||||
- condition: template
|
- condition: template
|
||||||
value_template: >
|
value_template: >
|
||||||
{% set deadline = states('input_datetime.tesla_charge_deadline') %}
|
{% set deadline = states('input_datetime.tesla_charge_deadline') %}
|
||||||
{{ deadline not in ['unknown','unavailable',''] and as_timestamp(deadline) > as_timestamp(now()) }}
|
{{ deadline not in ['unknown','unavailable','']
|
||||||
|
and as_timestamp(deadline) > as_timestamp(now()) }}
|
||||||
|
|
||||||
# Only run when car is connected
|
# Car must be connected
|
||||||
- condition: template
|
- condition: state
|
||||||
value_template: >
|
entity_id: binary_sensor.snowywhite_charger
|
||||||
{{ states('binary_sensor.tesla_connected') == 'on' }}
|
state: "on"
|
||||||
|
|
||||||
action:
|
action:
|
||||||
|
- variables:
|
||||||
|
charge_now: "{{ is_state('binary_sensor.tesla_charge_now', 'on') }}"
|
||||||
|
charger_on: "{{ is_state('switch.home_charging', 'on') }}"
|
||||||
|
|
||||||
- choose:
|
- choose:
|
||||||
|
|
||||||
# -------------------------
|
# -------------------------
|
||||||
# Charge if cheap
|
# START charging (cheap hour)
|
||||||
# -------------------------
|
# -------------------------
|
||||||
- conditions:
|
- conditions:
|
||||||
- condition: template
|
- condition: template
|
||||||
value_template: >
|
value_template: "{{ charge_now and not charger_on }}"
|
||||||
{{ states('binary_sensor.tesla_charge_now') == 'on' }}
|
|
||||||
|
|
||||||
sequence:
|
sequence:
|
||||||
# Reset charger if stuck in finished state
|
- service: system_log.write
|
||||||
- choose:
|
data:
|
||||||
- conditions:
|
message: "Tesla: START charging (cheap hour)"
|
||||||
- condition: template
|
level: info
|
||||||
value_template: >
|
|
||||||
{{ states('sensor.home_charger_mode') == 'connected_finished' }}
|
|
||||||
sequence:
|
|
||||||
- service: switch.turn_off
|
|
||||||
target:
|
|
||||||
entity_id: switch.home_charging
|
|
||||||
- delay: "00:00:05"
|
|
||||||
|
|
||||||
# Turn charger on
|
|
||||||
- service: switch.turn_on
|
- service: switch.turn_on
|
||||||
target:
|
target:
|
||||||
entity_id: switch.home_charging
|
entity_id: switch.home_charging
|
||||||
|
|
||||||
# -------------------------
|
# -------------------------
|
||||||
# Stop charging if not cheap
|
# STOP charging (not cheap)
|
||||||
# -------------------------
|
# -------------------------
|
||||||
- conditions:
|
- conditions:
|
||||||
- condition: template
|
- condition: template
|
||||||
value_template: >
|
value_template: "{{ not charge_now and charger_on }}"
|
||||||
{{ states('binary_sensor.tesla_charge_now') != 'on' }}
|
|
||||||
|
|
||||||
sequence:
|
sequence:
|
||||||
|
- service: system_log.write
|
||||||
|
data:
|
||||||
|
message: "Tesla: STOP charging (not cheap)"
|
||||||
|
level: info
|
||||||
|
|
||||||
- service: switch.turn_off
|
- service: switch.turn_off
|
||||||
target:
|
target:
|
||||||
entity_id: switch.home_charging
|
entity_id: switch.home_charging
|
||||||
|
|
||||||
|
# -------------------------
|
||||||
|
# Default: do nothing
|
||||||
|
# -------------------------
|
||||||
|
- service: system_log.write
|
||||||
|
data:
|
||||||
|
message: >
|
||||||
|
Tesla: No action (charge_now={{ charge_now }},
|
||||||
|
charger_on={{ charger_on }})
|
||||||
|
level: debug
|
||||||
|
|||||||
@@ -1,15 +1,74 @@
|
|||||||
- sensor:
|
sensors:
|
||||||
- name: tesla_kwh_needed
|
tesla_kwh_needed:
|
||||||
unit_of_measurement: "kWh"
|
friendly_name: "Tesla kWh Needed"
|
||||||
state: >
|
unit_of_measurement: "kWh"
|
||||||
{% set capacity = 75 %}
|
value_template: >
|
||||||
{% set soc = states('sensor.snowywhite_battery')|float(0) %}
|
{% set capacity = 75 %}
|
||||||
{% set limit = states('number.snowywhite_charge_limit')|float(100) %}
|
{% set soc = states('sensor.snowywhite_battery') | float(0) %}
|
||||||
{{ ((limit - soc)/100 * capacity)|round(2) }}
|
{% set limit = states('number.snowywhite_charge_limit') | float(100) %}
|
||||||
|
{{ [0, ((limit - soc)/100 * capacity)] | max | round(2) }}
|
||||||
|
|
||||||
- name: tesla_charge_hours_needed
|
tesla_charge_hours_needed:
|
||||||
unit_of_measurement: "h"
|
friendly_name: "Tesla Charge Hours Needed"
|
||||||
state: >
|
unit_of_measurement: "h"
|
||||||
{% set power = 11 %}
|
value_template: >
|
||||||
{% set kwh = states('sensor.tesla_kwh_needed')|float(0) %}
|
{% set power = 11 %}
|
||||||
{{ (kwh / power)|round(2) }}
|
{% set kwh = states('sensor.tesla_kwh_needed') | float(0) %}
|
||||||
|
{{ (kwh / power)|round(2) }}
|
||||||
|
|
||||||
|
tesla_charging_plan:
|
||||||
|
friendly_name: "Tesla Charging Plan"
|
||||||
|
value_template: >
|
||||||
|
{% set deadline_raw = states('input_datetime.tesla_charge_deadline') %}
|
||||||
|
{% set deadline_ts = as_timestamp(deadline_raw)
|
||||||
|
if deadline_raw not in ['unknown','unavailable',''] else none %}
|
||||||
|
|
||||||
|
{% set hours_needed = [1,
|
||||||
|
states('sensor.tesla_charge_hours_needed') | float(0) | round(0, 'ceil')
|
||||||
|
] | max %}
|
||||||
|
|
||||||
|
{% set prices = (state_attr('sensor.energidataservice','today') or [])
|
||||||
|
+ (state_attr('sensor.energidataservice','tomorrow') or []) %}
|
||||||
|
|
||||||
|
{% set valid = [] %}
|
||||||
|
{% for p in prices %}
|
||||||
|
{% if p.hour is defined and p.hour %}
|
||||||
|
{% set ts = as_timestamp(p.hour) %}
|
||||||
|
{% if not deadline_ts or ts <= deadline_ts %}
|
||||||
|
{% set valid = valid + [p] %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% set cheapest = (valid | sort(attribute='price'))[:hours_needed] %}
|
||||||
|
|
||||||
|
{% set times = cheapest
|
||||||
|
| map(attribute='hour')
|
||||||
|
| map('as_timestamp')
|
||||||
|
| map('timestamp_local')
|
||||||
|
| list %}
|
||||||
|
|
||||||
|
{{ times | join(', ') if times | count > 0 else 'none' }}
|
||||||
|
|
||||||
|
binary_sensors:
|
||||||
|
tesla_charge_now:
|
||||||
|
friendly_name: "Tesla Charge Now"
|
||||||
|
device_class: power
|
||||||
|
value_template: >
|
||||||
|
{% set hours_needed = [1, states('sensor.tesla_charge_hours_needed') | float(0) | round(0, 'ceil')] | max %}
|
||||||
|
{% set deadline_raw = states('input_datetime.tesla_charge_deadline') %}
|
||||||
|
{% set deadline_ts = as_timestamp(deadline_raw) if deadline_raw not in ['unknown','unavailable',''] else none %}
|
||||||
|
{% set prices = (state_attr('sensor.energidataservice','today') or []) + (state_attr('sensor.energidataservice','tomorrow') or []) %}
|
||||||
|
{% set valid_prices = [] %}
|
||||||
|
{% for p in prices %}
|
||||||
|
{% if p.hour is defined and p.hour %}
|
||||||
|
{% set ts = as_timestamp(p.hour) %}
|
||||||
|
{% if not deadline_ts or ts <= deadline_ts %}
|
||||||
|
{% set valid_prices = valid_prices + [p] %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% set cheapest = (valid_prices | sort(attribute='price'))[:hours_needed] %}
|
||||||
|
{% set now_ts = now().replace(minute=0, second=0, microsecond=0).timestamp() %}
|
||||||
|
{% set cheapest_ts = cheapest | map(attribute='hour') | map('as_timestamp') | list %}
|
||||||
|
{{ now_ts in cheapest_ts }}
|
||||||
|
|||||||
Reference in New Issue
Block a user