Gå til innhold
  • Bli medlem

Frankensteins monster; jeg gav Claude Code direkte tilgang til Home Assistant og lot den lage en effektleddautomasjon!


Anbefalte innlegg

Skrevet

Jeg har brukt Home Assistant i mange år, siden 2019 eller der omkring. De første årene hadde jeg mye tid til å lære, leke og styre på med automasjoner, men de siste par årene har tiden ikke strukket til fordi det skjer så mye annet. Sånn er livet.

 

Jeg har hatt strømsparingsautomasjoner tidligere som først og fremst forsøkte å unngå strømtopper. Etter Norgespris er det å holde seg innenfor effekttariffene som gjelder. Jeg har stadig gode ideer for å løse dette, men ikke tiden til å virkelig sette meg ned å snekre sammen en grei løsning.

 

Jeg har utforsket Claude Code til andre småprosjekter i det siste, og latt meg imponere over hva man kan få til hvis man bare er streng og har en god ide på hva man vil ha (og ikke vil ha!). Så kom jeg på den kjetterske ideen å undersøke om det var mulig å gi Claude Code frie tøyler til å gjøre hva den vil med Home Assistant-installasjonen min. Og det fungerte overraskende bra!

 

Etter litt prøving og feiling endte jeg opp med følgende metode:

 

  • Installere Samba Add-on i HA slik at jeg (og Claude) får direkte tilgang til config/ mappa og yaml-filene.
  • Lage en API-token som Claude fikk bruke til akkurat den den ville. Den laget sitt eget API-hjelper-script og var veldig kreativ!
  • Gav en detaljert beskrivelse av hva jeg ville ha og itererte meg frem til en relativt kompleks og effektiv automasjon.
  • Personlig bruker jeg Zed med Claud Code, men her finnes det flere muligher.

 

Utviklingsprosessen er ganske vill! Siden Claude kan avlese data fra entiteter i sanntid og feilsøke og rette småfeil etterhvert som de oppstår, går man raskt fra idé, til halvveis fungerende automasjon, til finsliping av flisespikking! Tilsammen har jeg bare brukt to-tre timer fra start til slutt. Nå har jeg ikke fått stresstestet automasjonen over tid, men har plukket ut de feilene jeg kunne finne.

 

Rekker ikke utdype mer nå, det er seint og tiden strekker ikke til. Men bare å stille spørsmål og dele egne erfaringer med lignende eksperimenter, jeg sjekker innom innimellom.

 

Automasjonen ligger i spoileren for de som tørr å teste den :P

 

Spoiler
# =============================================================================
# POWER MANAGER - Effekttariff-optimalisering for Home Assistant
# =============================================================================
# Holder timeforbruk under 5kWh samtidig som det optimaliseres rundt 3-timers-topp snittet.
#
# INSTALLASJON:
# 1. Lagre som: config/packages/power_manager.yaml
# 2. Legg til i configuration.yaml:
#      homeassistant:
#        packages:
#          power_manager: !include packages/power_manager.yaml
# 3. Start Home Assistant på nytt
# 4. Rediger managed_devices under, deretter: Developer Tools → YAML → Reload All
# =============================================================================

homeassistant:
  customize:
    package.node_anchors:
      # =========================================================================
      # ENHETSKONFIGURASJON - Rediger denne listen
      # =========================================================================
      # priority: 1 = viktig (kobles fra sist), 5 = minst viktig (kobles fra først)
      # watts: omtrentlig konstant strømforbruk når på
      # power_sensor: (valgfritt) bruk faktisk strømavlesning i stedet for fast watts-verdi
      #
      # Eksempel:
      #   - entity_id: switch.ev_charger
      #     priority: 5
      #     watts: 7400
      #
      #   - entity_id: switch.varmtvannstank
      #     priority: 4
      #     watts: 2000
      #     power_sensor: sensor.varmtvannstank_power
      # =========================================================================
      managed_devices: &managed_devices
        - entity_id: switch.soverom_ovn_plugg_bryter
          priority: 2
          watts: 1500
        - entity_id: switch.kontorovn_bryter
          priority: 3
          watts: 2000
        - entity_id: switch.stuepanelovn_bryter
          priority: 5
          watts: 500
        - entity_id: switch.varmtvannstank_bryter
          priority: 5
          watts: 950
          power_sensor: sensor.varmtvannstank_kraft

      # =========================================================================
      # VARSLINGSMÅL - Rediger denne listen
      # =========================================================================
      notification_targets: &notification_targets
        - service: notify.motorola_edge_50_pro

# =============================================================================
# INNDATA-HJELPERE
# =============================================================================

input_boolean:
  power_manager_enabled:
    name: Power Manager Enabled
    icon: mdi:lightning-bolt

  power_manager_notifications:
    name: Power Manager Notifications
    icon: mdi:bell

input_number:
  power_manager_max_kwh:
    name: Max kWh per Hour
    min: 1
    max: 10
    step: 0.1
    initial: 5.0
    unit_of_measurement: kWh
    icon: mdi:speedometer

  power_manager_target_kwh:
    name: Target kWh (with margin)
    min: 1
    max: 10
    step: 0.1
    initial: 4.8
    unit_of_measurement: kWh
    icon: mdi:target

  power_manager_restore_threshold_watts:
    name: Restore Threshold (Watts)
    min: 500
    max: 10000
    step: 100
    initial: 3500
    unit_of_measurement: W
    icon: mdi:arrow-up-bold
    mode: box

  power_manager_min_off_time:
    name: Minimum Off Time (minutes)
    min: 1
    max: 30
    step: 1
    initial: 5
    unit_of_measurement: min
    icon: mdi:timer-lock

input_select:
  power_manager_target_tier:
    name: Target Power Tier
    options:
      - "Auto (lowest tier above current)"
      - "Tier 1"
      - "Tier 2"
      - "Tier 3"
      - "Tier 4"
      - "Manual target only"
    initial: "Auto (lowest tier above current)"
    icon: mdi:stairs

input_text:
  power_manager_shed_devices:
    name: Currently Shed Devices
    max: 255
    initial: "[]"

  power_manager_shed_timestamps:
    name: Shed Timestamps
    max: 255
    initial: "{}"

  power_manager_shed_watts:
    name: Shed Watts
    max: 255
    initial: "{}"

  power_manager_power_tiers:
    name: Power Tiers (kW)
    max: 255
    initial: "[5, 10, 15, 20]"

# =============================================================================
# MALSENSORER
# =============================================================================

template:
  - sensor:
      - name: "Power Manager Projected Hour Usage"
        unique_id: power_manager_projected_hour_usage
        unit_of_measurement: kWh
        state_class: measurement
        icon: mdi:chart-line
        state: >
          {% set current_kwh = states('sensor.amsleser_houruse') | float(0) %}
          {% set current_watts = states('sensor.amsleser_p') | float(0) %}
          {% set minutes_left = 60 - now().minute - (now().second / 60) %}
          {% set hours_left = minutes_left / 60 %}
          {% if minutes_left < 2 %}
            {{ current_kwh | round(3) }}
          {% else %}
            {% set projected = current_kwh + (current_watts / 1000 * hours_left) %}
            {% set dampening_factor = 0.9 if minutes_left < 5 else 1.0 %}
            {% set safe_projection = current_kwh + ((projected - current_kwh) * dampening_factor) %}
            {{ safe_projection | round(3) }}
          {% endif %}

      - name: "Power Manager Projected Watts"
        unique_id: power_manager_projected_watts
        unit_of_measurement: W
        device_class: power
        state_class: measurement
        icon: mdi:chart-line-variant
        state: >
          {% set current_kwh = states('sensor.amsleser_houruse') | float(0) %}
          {% set current_watts = states('sensor.amsleser_p') | float(0) %}
          {% set minutes_left = 60 - now().minute - (now().second / 60) %}
          {% set hours_left = minutes_left / 60 %}
          {% if minutes_left < 2 %}
            {{ (current_kwh * 1000) | round(0) }}
          {% else %}
            {% set projected = current_kwh + (current_watts / 1000 * hours_left) %}
            {% set dampening_factor = 0.9 if minutes_left < 5 else 1.0 %}
            {% set safe_projection = current_kwh + ((projected - current_kwh) * dampening_factor) %}
            {{ (safe_projection * 1000) | round(0) }}
          {% endif %}

      - name: "Power Manager Hours Remaining"
        unique_id: power_manager_hours_remaining
        unit_of_measurement: h
        state_class: measurement
        icon: mdi:clock-outline
        state: >
          {{ ((60 - now().minute - (now().second / 60)) / 60) | round(3) }}

      - name: "Power Manager Peak Analysis"
        unique_id: power_manager_peak_analysis
        icon: mdi:chart-bar
        state: >
          {% set peaks = [
            states('sensor.amsleser_peaks0') | float(0),
            states('sensor.amsleser_peaks1') | float(0),
            states('sensor.amsleser_peaks2') | float(0)
          ] | sort(reverse=true) %}
          {{ ((peaks[0] + peaks[1] + peaks[2]) / 3) | round(2) }} kWh avg
        attributes:
          peak_1: "{{ states('sensor.amsleser_peaks0') | float(0) }}"
          peak_2: "{{ states('sensor.amsleser_peaks1') | float(0) }}"
          peak_3: "{{ states('sensor.amsleser_peaks2') | float(0) }}"
          peaks_sorted: >
            {{ [
              states('sensor.amsleser_peaks0') | float(0),
              states('sensor.amsleser_peaks1') | float(0),
              states('sensor.amsleser_peaks2') | float(0)
            ] | sort(reverse=true) }}
          lowest_peak: >
            {% set peaks = [
              states('sensor.amsleser_peaks0') | float(0),
              states('sensor.amsleser_peaks1') | float(0),
              states('sensor.amsleser_peaks2') | float(0)
            ] | sort %}
            {{ peaks[0] }}
          would_become_peak: >
            {% set peaks = [
              states('sensor.amsleser_peaks0') | float(0),
              states('sensor.amsleser_peaks1') | float(0),
              states('sensor.amsleser_peaks2') | float(0)
            ] | sort %}
            {{ states('sensor.power_manager_projected_hour_usage') | float(0) > peaks[0] }}

      - name: "Power Manager Selected Tier"
        unique_id: power_manager_selected_tier
        unit_of_measurement: kWh
        state_class: measurement
        icon: mdi:layers-triple
        state: >
          {% set tiers = states('input_text.power_manager_power_tiers') | from_json | default([5, 10, 15, 20]) %}
          {% set selection = states('input_select.power_manager_target_tier') %}
          {% set current_usage = states('sensor.power_manager_projected_hour_usage') | float(0) %}
          
          {% if selection == 'Manual target only' %}
            {{ states('input_number.power_manager_target_kwh') | float(4.8) }}
          {% elif selection == 'Auto (lowest tier above current)' %}
            {% set ns = namespace(selected=None) %}
            {% for tier in tiers | sort %}
              {% if ns.selected is none and tier > current_usage %}
                {% set ns.selected = tier %}
              {% endif %}
            {% endfor %}
            {{ ns.selected if ns.selected is not none else (tiers | sort | last) }}
          {% elif selection == 'Tier 1' %}
            {{ tiers[0] if tiers | length > 0 else 5 }}
          {% elif selection == 'Tier 2' %}
            {{ tiers[1] if tiers | length > 1 else 10 }}
          {% elif selection == 'Tier 3' %}
            {{ tiers[2] if tiers | length > 2 else 15 }}
          {% elif selection == 'Tier 4' %}
            {{ tiers[3] if tiers | length > 3 else 20 }}
          {% else %}
            {{ states('input_number.power_manager_target_kwh') | float(4.8) }}
          {% endif %}

      - name: "Power Manager Smart Target"
        unique_id: power_manager_smart_target
        unit_of_measurement: kWh
        state_class: measurement
        icon: mdi:target-variant
        state: >
          {% set peaks = [
            states('sensor.amsleser_peaks0') | float(0),
            states('sensor.amsleser_peaks1') | float(0),
            states('sensor.amsleser_peaks2') | float(0)
          ] | sort %}
          {% set lowest_peak = peaks[0] %}
          {% set tier_target = states('sensor.power_manager_selected_tier') | float(0) %}
          {% set user_target = states('input_number.power_manager_target_kwh') | float(4.8) %}
          {% set effective_target = tier_target if tier_target > 0 else user_target %}
          {{ [lowest_peak, effective_target] | min | round(3) }}

      - name: "Power Manager Safe Watts"
        unique_id: power_manager_safe_watts
        unit_of_measurement: W
        state_class: measurement
        icon: mdi:flash
        state: >
          {% set target = states('input_number.power_manager_target_kwh') | float(4.8) %}
          {% set current_kwh = states('sensor.amsleser_houruse') | float(0) %}
          {% set hours_left = states('sensor.power_manager_hours_remaining') | float(0.001) %}
          {% set headroom = target - current_kwh %}
          {{ ((headroom / hours_left) * 1000) | round(0) }}

      - name: "Power Manager Status"
        unique_id: power_manager_status
        icon: >
          {% set projected = states('sensor.power_manager_projected_hour_usage') | float(0) %}
          {% set target = states('input_number.power_manager_target_kwh') | float(4.8) %}
          {% set max_kwh = states('input_number.power_manager_max_kwh') | float(5.0) %}
          {% if projected >= max_kwh %}mdi:alert-circle
          {% elif projected >= target %}mdi:alert
          {% elif projected >= target * 0.9 %}mdi:information
          {% else %}mdi:check-circle{% endif %}
        state: >
          {% set projected = states('sensor.power_manager_projected_hour_usage') | float(0) %}
          {% set target = states('input_number.power_manager_target_kwh') | float(4.8) %}
          {% set max_kwh = states('input_number.power_manager_max_kwh') | float(5.0) %}
          {% set shed_count = (states('input_text.power_manager_shed_devices') | from_json | default([])) | length %}
          {% if projected >= max_kwh %}Critical - {{ shed_count }} shed
          {% elif projected >= target %}Warning - {{ shed_count }} shed
          {% elif shed_count > 0 %}Recovering - {{ shed_count }} shed
          {% else %}Normal{% endif %}

      - name: "Power Manager Shed Info"
        unique_id: power_manager_shed_info
        icon: mdi:power-plug-off
        state: >
          {% set shed = states('input_text.power_manager_shed_devices') | from_json | default([]) %}
          {% if shed | length == 0 %}No devices shed
          {% elif shed | length == 1 %}1 device shed
          {% else %}{{ shed | length }} devices shed
          {% endif %}
        attributes:
          # Rådata (for kompatibilitet)
          shed_devices: "{{ states('input_text.power_manager_shed_devices') | from_json | default([]) }}"
          shed_count: "{{ (states('input_text.power_manager_shed_devices') | from_json | default([])) | length }}"
          
          # Formatert visningstekst (for dashboard)
          display_text: >
            {% set shed = states('input_text.power_manager_shed_devices') | from_json | default([]) %}
            {% set timestamps = states('input_text.power_manager_shed_timestamps') | from_json | default({}) %}
            {% if shed | length == 0 %}
               All devices online
            {% else %}
              {% set ns = namespace(lines=[]) %}
              {% for entity_id in shed %}
                {% set friendly = state_attr(entity_id, 'friendly_name') | default(entity_id.replace('switch.', '').replace('_', ' ') | title) %}
                {% set shed_time = timestamps.get(entity_id, none) %}
                {% if shed_time %}
                  {% set elapsed = (now() - (shed_time | as_datetime | as_local)).total_seconds() / 60 %}
                  {% set ns.lines = ns.lines + ['🔌 ' ~ friendly ~ ' (' ~ elapsed | int ~ 'm)'] %}
                {% else %}
                  {% set ns.lines = ns.lines + ['🔌 ' ~ friendly] %}
                {% endif %}
              {% endfor %}
              {{ ns.lines | join('\n') }}
            {% endif %}
          
          # Detaljert liste med metadata (for avanserte kort)
          shed_details: >
            {% set shed = states('input_text.power_manager_shed_devices') | from_json | default([]) %}
            {% set timestamps = states('input_text.power_manager_shed_timestamps') | from_json | default({}) %}
            {% set ns = namespace(items=[]) %}
            {% for entity_id in shed %}
              {% set friendly = state_attr(entity_id, 'friendly_name') | default(entity_id.replace('switch.', '').replace('_', ' ') | title) %}
              {% set shed_time = timestamps.get(entity_id, none) %}
              {% set elapsed_min = 0 %}
              {% if shed_time %}
                {% set elapsed_min = ((now() - (shed_time | as_datetime | as_local)).total_seconds() / 60) | int %}
              {% endif %}
              {% set ns.items = ns.items + [{
                'entity_id': entity_id,
                'friendly_name': friendly,
                'shed_time': shed_time,
                'elapsed_minutes': elapsed_min
              }] %}
            {% endfor %}
            {{ ns.items }}
          
          # Enkel kommaseparert liste med vennlige navn
          friendly_names: >
            {% set shed = states('input_text.power_manager_shed_devices') | from_json | default([]) %}
            {% set ns = namespace(names=[]) %}
            {% for entity_id in shed %}
              {% set friendly = state_attr(entity_id, 'friendly_name') | default(entity_id.replace('switch.', '').replace('_', ' ') | title) %}
              {% set ns.names = ns.names + [friendly] %}
            {% endfor %}
            {{ ns.names | join(', ') if ns.names | length > 0 else 'None' }}

      - name: "Power Manager Shed Watts"
        unique_id: power_manager_shed_watts
        unit_of_measurement: W
        device_class: power
        state_class: measurement
        icon: mdi:power-plug-off
        state: >
          {% set managed_devices = [
            {'entity_id': 'switch.soverom_ovn_plugg_bryter', 'watts': 1500},
            {'entity_id': 'switch.mancave_ovnbryter', 'watts': 1500},
            {'entity_id': 'switch.kontorovn_bryter', 'watts': 2000},
            {'entity_id': 'switch.stuepanelovn_bryter', 'watts': 500},
            {'entity_id': 'switch.varmtvannstank_bryter', 'watts': 950}
          ] %}
          {% set shed = states('input_text.power_manager_shed_devices') | from_json | default([]) %}
          {% set ns = namespace(watts=0) %}
          {% for dev in managed_devices %}
            {% if dev.entity_id in shed %}
              {% set ns.watts = ns.watts + dev.watts %}
            {% endif %}
          {% endfor %}
          {{ ns.watts }}

# =============================================================================
# SKRIPT
# =============================================================================

script:
  power_manager_evaluate:
    alias: "Power Manager - Evaluate & Act"
    mode: single
    sequence:
      - condition: state
        entity_id: input_boolean.power_manager_enabled
        state: "on"
      - variables:
          managed_devices: *managed_devices
          current_watts: "{{ states('sensor.amsleser_p') | float(0) }}"
          current_kwh: "{{ states('sensor.amsleser_houruse') | float(0) }}"
          hours_left: "{{ ((60 - now().minute - (now().second / 60)) / 60) | float(0.001) }}"
          projected_kwh: "{{ current_kwh + (current_watts / 1000 * hours_left) }}"
          smart_target: "{{ states('sensor.power_manager_smart_target') | float(0) }}"
          user_target: "{{ states('input_number.power_manager_target_kwh') | float(4.8) }}"
          target_kwh: "{{ smart_target if smart_target > 0 else user_target }}"
          max_kwh: "{{ states('input_number.power_manager_max_kwh') | float(5.0) }}"
          restore_threshold: "{{ states('input_number.power_manager_restore_threshold_watts') | float(3500) }}"
          min_off_minutes: "{{ states('input_number.power_manager_min_off_time') | float(5) }}"
          shed_devices: "{{ states('input_text.power_manager_shed_devices') | from_json | default([]) }}"
          shed_timestamps: "{{ states('input_text.power_manager_shed_timestamps') | from_json | default({}) }}"
          shed_watts: "{{ states('input_text.power_manager_shed_watts') | from_json | default({}) }}"
          safe_watts: "{{ ((target_kwh - current_kwh) / hours_left * 1000) | int }}"
          excess_watts: "{{ (current_watts - safe_watts) | int }}"
          would_become_peak: "{{ state_attr('sensor.power_manager_peak_analysis', 'would_become_peak') | default(false) }}"
          urgency: >
            {% if projected_kwh >= max_kwh %}critical
            {% elif would_become_peak %}high
            {% elif projected_kwh >= target_kwh %}normal
            {% else %}low{% endif %}
      - choose:
          # KRITISK: Nær absolutt maks
          - conditions:
              - "{{ projected_kwh >= max_kwh * 0.98 }}"
            sequence:
              - service: script.power_manager_shed
                data:
                  target_watts: "{{ excess_watts + 500 }}"
                  managed_devices: "{{ managed_devices }}"
                  shed_devices: "{{ shed_devices }}"
                  shed_timestamps: "{{ shed_timestamps }}"
                  shed_watts: "{{ shed_watts }}"
                  urgency: critical
          # KOBLE FRA: Overskrider mål
          - conditions:
              - "{{ projected_kwh > target_kwh }}"
              - "{{ excess_watts > 0 }}"
            sequence:
              - service: script.power_manager_shed
                data:
                  target_watts: "{{ excess_watts }}"
                  managed_devices: "{{ managed_devices }}"
                  shed_devices: "{{ shed_devices }}"
                  shed_timestamps: "{{ shed_timestamps }}"
                  shed_watts: "{{ shed_watts }}"
                  urgency: "{{ urgency }}"
          # GJENOPPRETT: Lavt forbruk, enheter frakoblet
          - conditions:
              - "{{ shed_devices | length > 0 }}"
              - "{{ current_watts < restore_threshold }}"
              - "{{ projected_kwh < target_kwh * 0.95 }}"
            sequence:
              - service: script.power_manager_restore
                data:
                  available_watts: "{{ (safe_watts - current_watts) | int }}"
                  managed_devices: "{{ managed_devices }}"
                  shed_devices: "{{ shed_devices }}"
                  shed_timestamps: "{{ shed_timestamps }}"
                  shed_watts: "{{ shed_watts }}"
                  min_off_minutes: "{{ min_off_minutes }}"

  power_manager_shed:
    alias: "Power Manager - Shed Devices"
    mode: single
    fields:
      target_watts:
        description: Watts to shed
      managed_devices:
        description: Device list
      shed_devices:
        description: Currently shed
      shed_timestamps:
        description: Shed times
      shed_watts:
        description: Actual watts when shed
      urgency:
        description: Urgency level
    sequence:
      - variables:
          # Kandidater: på, ikke frakoblet, trekker faktisk strøm, prioritet 5 først
          candidates: >
            {% set ns = namespace(devices=[]) %}
            {% for dev in managed_devices | sort(attribute='priority', reverse=true) %}
              {% if dev.entity_id not in shed_devices and is_state(dev.entity_id, 'on') %}
                {% set power_sensor = dev.get('power_sensor', none) %}
                {% if power_sensor %}
                  {% set actual_watts = states(power_sensor) | float(0) %}
                {% else %}
                  {% set actual_watts = dev.watts %}
                {% endif %}
                {% if actual_watts > 10 %}
                  {% set ns.devices = ns.devices + [{'entity_id': dev.entity_id, 'priority': dev.priority, 'watts': actual_watts | int}] %}
                {% endif %}
              {% endif %}
            {% endfor %}
            {{ ns.devices }}
          # Velg minimum antall enheter for å dekke target_watts
          to_shed: >
            {% set ns = namespace(devices=[], total=0) %}
            {% set target = (target_watts | int) + (500 if urgency == 'high' else 0) %}
            {% for dev in candidates %}
              {% if ns.total < target %}
                {% set ns.devices = ns.devices + [dev.entity_id] %}
                {% set ns.total = ns.total + dev.watts %}
              {% endif %}
            {% endfor %}
            {{ ns.devices }}
      - condition: "{{ to_shed | length > 0 }}"
      - repeat:
          for_each: "{{ to_shed }}"
          sequence:
            - service: homeassistant.turn_off
              target:
                entity_id: "{{ repeat.item }}"
            - delay:
                milliseconds: 100
      - variables:
          new_shed: "{{ shed_devices + to_shed }}"
          new_timestamps: >
            {% set ns = namespace(items=[]) %}
            {% for k, v in shed_timestamps.items() %}
              {% set ns.items = ns.items + [[k, v]] %}
            {% endfor %}
            {% for entity in to_shed %}
              {% set ns.items = ns.items + [[entity, now().isoformat()]] %}
            {% endfor %}
            {{ dict(ns.items) }}
          new_watts: >
            {% set ns = namespace(items=[]) %}
            {% for k, v in shed_watts.items() %}
              {% set ns.items = ns.items + [[k, v]] %}
            {% endfor %}
            {% for candidate in candidates %}
              {% if candidate.entity_id in to_shed %}
                {% set ns.items = ns.items + [[candidate.entity_id, candidate.watts]] %}
              {% endif %}
            {% endfor %}
            {{ dict(ns.items) }}
      - service: input_text.set_value
        target:
          entity_id: input_text.power_manager_shed_devices
        data:
          value: "{{ new_shed | to_json }}"
      - service: input_text.set_value
        target:
          entity_id: input_text.power_manager_shed_timestamps
        data:
          value: "{{ new_timestamps | to_json }}"
      - service: input_text.set_value
        target:
          entity_id: input_text.power_manager_shed_watts
        data:
          value: "{{ new_watts | to_json }}"
      - condition: state
        entity_id: input_boolean.power_manager_notifications
        state: "on"
      - variables:
          notification_targets: *notification_targets
      - repeat:
          for_each: "{{ notification_targets }}"
          sequence:
            - service: "{{ repeat.item.service }}"
              data:
                title: "{{ '🚨' if urgency == 'critical' else '⚠️' if urgency == 'high' else '' }} Power Manager"
                message: "Shed {{ to_shed | length }}: {{ to_shed | map('regex_replace', 'switch.', '') | join(', ') }}"

  power_manager_restore:
    alias: "Power Manager - Restore Device"
    mode: single
    fields:
      available_watts:
        description: Available capacity
      managed_devices:
        description: Device list
      shed_devices:
        description: Currently shed
      shed_timestamps:
        description: Shed times
      shed_watts:
        description: Actual watts when shed
      min_off_minutes:
        description: Min off time
    sequence:
      - variables:
          min_off_seconds: "{{ (min_off_minutes | float) * 60 }}"
          # Kandidater: frakoblet, minimum tid passert, prioritet 1 først
          candidates: >
            {% set ns = namespace(devices=[]) %}
            {% for dev in managed_devices | sort(attribute='priority') %}
              {% if dev.entity_id in shed_devices %}
                {% set shed_time = shed_timestamps.get(dev.entity_id, '2000-01-01T00:00:00') %}
                {% set elapsed = (now() - (shed_time | as_datetime | as_local)).total_seconds() %}
                {% if elapsed >= min_off_seconds %}
                  {% set actual_watts = shed_watts.get(dev.entity_id, dev.watts) %}
                  {% set ns.devices = ns.devices + [{'entity_id': dev.entity_id, 'watts': actual_watts, 'elapsed': elapsed}] %}
                {% endif %}
              {% endif %}
            {% endfor %}
            {{ ns.devices }}
          # Finn én enhet som passer
          to_restore: >
            {% for dev in candidates %}
              {% if dev.watts <= (available_watts | int) %}{{ dev.entity_id }}{% break %}{% endif %}
            {% else %}{% endfor %}
      - condition: "{{ to_restore | default('') | length > 0 }}"
      - service: homeassistant.turn_on
        target:
          entity_id: "{{ to_restore }}"
      - variables:
          new_shed: "{{ shed_devices | reject('eq', to_restore) | list }}"
          new_timestamps: >
            {% set ns = namespace(items=[]) %}
            {% for k, v in shed_timestamps.items() %}
              {% if k != to_restore %}
                {% set ns.items = ns.items + [[k, v]] %}
              {% endif %}
            {% endfor %}
            {{ dict(ns.items) }}
          new_watts: >
            {% set ns = namespace(items=[]) %}
            {% for k, v in shed_watts.items() %}
              {% if k != to_restore %}
                {% set ns.items = ns.items + [[k, v]] %}
              {% endif %}
            {% endfor %}
            {{ dict(ns.items) }}
      - service: input_text.set_value
        target:
          entity_id: input_text.power_manager_shed_devices
        data:
          value: "{{ new_shed | to_json }}"
      - service: input_text.set_value
        target:
          entity_id: input_text.power_manager_shed_timestamps
        data:
          value: "{{ new_timestamps | to_json }}"
      - service: input_text.set_value
        target:
          entity_id: input_text.power_manager_shed_watts
        data:
          value: "{{ new_watts | to_json }}"
      - condition: state
        entity_id: input_boolean.power_manager_notifications
        state: "on"
      - variables:
          notification_targets: *notification_targets
      - repeat:
          for_each: "{{ notification_targets }}"
          sequence:
            - service: "{{ repeat.item.service }}"
              data:
                title: " Power Manager"
                message: "Restored: {{ to_restore | regex_replace('switch.', '') }}"

  power_manager_restore_all:
    alias: "Power Manager - Force Restore All"
    mode: single
    sequence:
      - variables:
          shed_devices: "{{ states('input_text.power_manager_shed_devices') | from_json | default([]) }}"
      - repeat:
          for_each: "{{ shed_devices }}"
          sequence:
            - service: homeassistant.turn_on
              target:
                entity_id: "{{ repeat.item }}"
            - delay:
                milliseconds: 200
      - service: input_text.set_value
        target:
          entity_id: input_text.power_manager_shed_devices
        data:
          value: "[]"
      - service: input_text.set_value
        target:
          entity_id: input_text.power_manager_shed_timestamps
        data:
          value: "{}"
      - service: input_text.set_value
        target:
          entity_id: input_text.power_manager_shed_watts
        data:
          value: "{}"

  power_manager_update_shed_watts:
    alias: "Power Manager - Update Shed Watts"
    mode: single
    sequence:
      - variables:
          managed_devices: *managed_devices
          shed: "{{ states('input_text.power_manager_shed_devices') | from_json | default([]) }}"
          total_watts: >
            {% set ns = namespace(watts=0) %}
            {% for dev in managed_devices %}
              {% if dev.entity_id in shed %}
                {% set ns.watts = ns.watts + dev.watts %}
              {% endif %}
            {% endfor %}
            {{ ns.watts }}
      - service: input_number.set_value
        target:
          entity_id: input_number.power_manager_shed_watts_display
        data:
          value: "{{ total_watts }}"

# Ekstra hjelper for visning av frakoblede watt
input_number:
  power_manager_shed_watts_display:
    name: Currently Shed Load
    min: 0
    max: 50000
    step: 1
    unit_of_measurement: W
    icon: mdi:power-plug-off
    mode: box

# =============================================================================
# AUTOMATISERINGER
# =============================================================================

automation:
  - id: power_manager_monitor
    alias: "Power Manager - Monitor"
    mode: single
    triggers:
      - trigger: time_pattern
        minutes: "/1"
    conditions:
      - condition: state
        entity_id: input_boolean.power_manager_enabled
        state: "on"
    actions:
      - service: script.power_manager_evaluate
      - service: script.power_manager_update_shed_watts

  - id: power_manager_rapid_response
    alias: "Power Manager - Rapid Response"
    mode: single
    triggers:
      - trigger: numeric_state
        entity_id: sensor.power_manager_projected_hour_usage
        above: input_number.power_manager_target_kwh
        for:
          seconds: 10
    conditions:
      - condition: state
        entity_id: input_boolean.power_manager_enabled
        state: "on"
    actions:
      - service: script.power_manager_evaluate

  - id: power_manager_critical
    alias: "Power Manager - Critical Response"
    mode: single
    triggers:
      - trigger: template
        value_template: >
          {{ states('sensor.power_manager_projected_hour_usage') | float(0) >= 
             states('input_number.power_manager_max_kwh') | float(5) * 0.98 }}
    conditions:
      - condition: state
        entity_id: input_boolean.power_manager_enabled
        state: "on"
    actions:
      - service: script.power_manager_evaluate

  - id: power_manager_hour_reset
    alias: "Power Manager - Hour Transition"
    mode: single
    triggers:
      - trigger: time_pattern
        minutes: "0"
    conditions:
      - condition: state
        entity_id: input_boolean.power_manager_enabled
        state: "on"
    actions:
      - delay:
          seconds: 30
      - service: script.power_manager_evaluate

  - id: power_manager_disabled
    alias: "Power Manager - Restore on Disable"
    mode: single
    triggers:
      - trigger: state
        entity_id: input_boolean.power_manager_enabled
        to: "off"
    actions:
      - service: script.power_manager_restore_all

 

 

Bli med i samtalen

Du kan publisere innhold nå og registrere deg senere. Hvis du har en konto, logg inn nå for å poste med kontoen din.

Gjest
Skriv svar til emnet...

×   Du har limt inn tekst med formatering.   Lim inn uten formatering i stedet

  Du kan kun bruke opp til 75 smilefjes.

×   Lenken din har blitt bygget inn på siden automatisk.   Vis som en ordinær lenke i stedet

×   Tidligere tekst har blitt gjenopprettet.   Tøm tekstverktøy

×   Du kan ikke lime inn bilder direkte. Last opp eller legg inn bilder fra URL.

×
×
  • Opprett ny...

Viktig informasjon

Vi har plassert informasjonskapsler/cookies på din enhet for å gjøre denne siden bedre. Du kan justere dine innstillinger for informasjonskapsler, ellers vil vi anta at dette er ok for deg.