# Ecosmart wholesale price sensors for Home Assistant.
#
# Setup
#   1. secrets.yaml (Check Configuration fails if this secret is missing):
#        ecos_api_key: "Bearer ecos_live_your_key_here"
#      The word Bearer is part of the secret.
#   2. GET https://api.ecosmart.co.nz/rest/v1/me and copy `poc` and `icp`.
#   3. Replace *poc_from_GET_me with your poc (e.g. HAY2201) and
#      *icp_from_GET_me with your quoted icp (e.g. "0000123456ABCDE").
#      Leave them and Home Assistant refuses to save:
#      found undefined alias 'poc_from_GET_me'.
#   4. Packages: drop this file in config/packages/ with
#        homeassistant:
#          packages: !include_dir_named packages
#      Otherwise paste the `rest:` and `template:` blocks into configuration.yaml.
#
# These are wholesale energy prices at the grid exit point, not a complete
# retail rate. Forecasts are indicative. Ecosmart publishes the signal; it
# does not control your inverter, battery or EV charger.
#
# Docs: https://www.ecosmart.co.nz/electricity/api/

rest:
  - resource: https://api.ecosmart.co.nz/rest/v1/gxps/*poc_from_GET_me/spot
    params:
      poc: *poc_from_GET_me
    scan_interval: 300
    headers:
      Authorization: !secret ecos_api_key
    sensor:
      - name: Spot price
        unique_id: ecos_spot_price
        value_template: "{{ value_json.priceCentsPerKwhInclGst | round(2) }}"
        unit_of_measurement: "c/kWh"
        state_class: measurement
        availability: "{{ not value_json.isStale }}"
        json_attributes:
          - observedAt
          - ageSeconds
          - isStale
          - priceDollarsPerMwh

  - resource: https://api.ecosmart.co.nz/rest/v1/gxps/*poc_from_GET_me/forecast
    params:
      hours: 24
      poc: *poc_from_GET_me
    scan_interval: 1800
    headers:
      Authorization: !secret ecos_api_key
    sensor:
      - name: Spot forecast
        unique_id: ecos_spot_forecast
        value_template: "{{ value_json.points[0].priceCentsPerKwhInclGst | round(2) }}"
        unit_of_measurement: "c/kWh"
        availability: "{{ value_json.points | length > 0 }}"
        json_attributes:
          - points
          - coveredHours
          - publishedAt

  # Optional. Delete this rest: item if you do not want tomorrow's ranking.
  # cheap and expensive half-hours (JSON fields cheap/dear) — ranked, not a consecutive block.
  - resource: https://api.ecosmart.co.nz/rest/v1/windows
    params:
      icp: *icp_from_GET_me
      n: 6
    scan_interval: 1800
    headers:
      Authorization: !secret ecos_api_key
    sensor:
      - name: Tomorrow cheapest half-hour
        unique_id: ecos_windows_cheap_start
        value_template: >
          {% if value_json.cheap is defined and value_json.cheap | length > 0 %}
            {{ value_json.cheap[0]['startsAt'] }}
          {% elif value_json.code is defined %}
            {{ value_json.code }}
          {% else %}
            unknown
          {% endif %}
        json_attributes:
          - cheap
          - dear
          - networkTou
          - tradingDate
          - indicative
          - unavailableReason
          - code
          - message

template:
  - sensor:
      - name: Cheapest 90 minutes
        unique_id: ecos_cheapest_window
        state: >
          {% set pts = state_attr('sensor.spot_forecast', 'points') or [] %}
          {% if pts | length < 3 %}
            unknown
          {% else %}
            {% set ns = namespace(best=None, cost=None) %}
            {% for i in range(pts | length - 2) %}
              {% set c = (pts[i].priceCentsPerKwhInclGst
                        + pts[i+1].priceCentsPerKwhInclGst
                        + pts[i+2].priceCentsPerKwhInclGst) / 3 %}
              {% if ns.cost is none or c < ns.cost %}
                {% set ns.cost = c %}
                {% set ns.best = i %}
              {% endif %}
            {% endfor %}
            {{ pts[ns.best].startsAt }}
          {% endif %}
  - binary_sensor:
      - name: Spot is cheap
        unique_id: ecos_spot_cheap
        # Pick your own threshold — 10 c/kWh incl. GST is only an example.
        state: "{{ states('sensor.spot_price') | float(999) < 10 }}"
