Texas Electricity Grid Monitor

Did you have to do anything special to get Smart Meter Texas working? I had it working for a while then the addon lost the ability to log in. I can log in manually with the same credentials but the addon won’t work for me.

I had the same issue. It actually will prevent the HA restore from completing. If you still have it installed I would recommend uninstalling it. I learned that the hard way.

I’m using the node-red implementation.

The instructions are a bit out of date. Below are the changes I had to make to get it to work.

in configuration.yaml add:

homeassistant:
  customize_glob:
    sensor.smart_meter_texas_*:
      state_class: total_increasing

For the SMT package:

smartmetertexas:
  mqtt:
    sensor:
      - state_topic: "smt/reading"
        unit_of_measurement: "kWh"
        name: Smart Meter Texas Current Reading
        unique_id: smart_meter_texas_current_reading
        device_class: energy

  utility_meter:
    hourly_energy:
      source: sensor.smart_meter_texas_current_reading
      name: Hourly Energy
      cycle: hourly
    daily_energy:
      source: sensor.smart_meter_texas_current_reading
      name: Daily Energy
      cycle: daily
    monthly_energy:
      source: sensor.smart_meter_texas_current_reading
      name: Monthly Energy
      cycle: monthly


  input_number:
    smtexas_energy_cost:
      icon: mdi:currency-usd
      name: Electricity Cost
      mode: box
      min: 0
      max: 2.50
      step: .001
      unit_of_measurement: "$/kWh"
2 Likes

Very cool. I looked into Smart Meter TX a while ago, but my utility (City of Austin) did not support it. Will check again to see if anything has changed.

This is somewhat untested but in theory, it should work. These 2 sensors return the least amout of forecast committed & total capacity for the day. My thought is if forecast availability drops below X (like last July) then do something.

I think ERCOT publishes a re-forecast every 5 minutes. Currently, the scan interval is set at 1 hour but that should be more than adequate.

ercot:
  sensor:  

    - platform: rest
      scan_interval: 3600
      unique_id: ercot_forecast_capacity_availability
      icon: mdi:transmission-tower
      name: "Ercot Forecast Capacity Availability"
      resource: "https://www.ercot.com/api/1/services/read/dashboards/todays-outlook.json"
      value_template: >-
        {%set vcount = namespace(forecastpercentage1=10,forecastpercentage2 = 0) %}
        {% for x in value_json.data %}
          {% if value_json.data[loop.index0].forecast|int == 1%}                
              {%set vcount.forecastpercentage2= value_json.data[loop.index0].demand|float /value_json.data[loop.index0].available|float %}
              {%if vcount.forecastpercentage1|float > vcount.forecastpercentage2|float%}
                {%set vcount.forecastpercentage1 = vcount.forecastpercentage2 %}
              {%endif%}
          {%endif%}                             
                          
        {%endfor%}
        {{(100-(vcount.forecastpercentage1|float*100))|round(1)}}

    - platform: rest
      scan_interval: 3600
      unique_id: ercot_forecast_commited_availability
      icon: mdi:transmission-tower
      name: "Ercot Forecast Commited Availability"
      resource: "https://www.ercot.com/api/1/services/read/dashboards/todays-outlook.json"
      value_template: >-
        {%set vcount = namespace(forecastpercentage1=10,forecastpercentage2 = 0) %}
        {% for x in value_json.data %}
          {% if value_json.data[loop.index0].forecast|int == 1%}                
              {%set vcount.forecastpercentage2= value_json.data[loop.index0].demand|float /value_json.data[loop.index0].capacity|float %}
              {%if vcount.forecastpercentage1|float > vcount.forecastpercentage2|float%}
                {%set vcount.forecastpercentage1 = vcount.forecastpercentage2 %}
              {%endif%}
          {%endif%}                                             
        {%endfor%}
        {{(100-(vcount.forecastpercentage1|float*100))|round(1)}}

So, the ERCOT grid gauge from the scrape was working perfectly, but then Home Assistant notified me that scrape had been moved and would break after two revisions. It was kind of cryptic, but I think the reason for the notice was that there is now a scrape integration in HA core.

I installed the integration and attempted to transfer the settings into the configuration with no luck.

Has anyone else moved this to the scrape integration, and if so what were the config parameters that needed to be entered?

For resource configure -
Resource:
https://www.ercot.com/content/cdr/html/as_capacity_monitor.html

Method: GET

Authentication method: basic

For sensor configure -
Select*:
body > div:nth-child(1) > table.tableStyle:nth-child(4) > tbody > tr:nth-child(42) > td.labelClassCenter:nth-child(2)

value template:
{{ value.replace(",", “”) | int }}

I use the REST sensor for the meter

- platform: rest

      scan_interval: 300

      unique_id: ercot_status

      icon: mdi:transmission-tower

      name: Ercot Status

      resource: "https://www.ercot.com/api/1/services/read/dashboards/daily-prc.json"

      value_template: "{{value_json.current_condition.state}}"

      json_attributes_path: "$.current_condition"

      json_attributes:

        - energy_level_value

        - title

        - condition_note

        - eea_level

        - prc_value

        - datetime

Looks like Ercot changed their API yesterday. the URI changed https://www.ercot.com/api/1/services/read/dashboards/supply-demand.json

Updated max capacity & committed sensor:

    - platform: rest
      scan_interval: 3600
      unique_id: ercot_forecast_capacity_availability
      icon: mdi:transmission-tower
      name: "Ercot Forecast Capacity Availability"
      resource: "https://www.ercot.com/api/1/services/read/dashboards/supply-demand.json"
      value_template: >-
        {%set vcount = namespace(forecastpercentage1=10,forecastpercentage2 = 0) %}
        {% for x in value_json.data %}
          {% if value_json.data[loop.index0].forecast|int == 1%}                
              {%set vcount.forecastpercentage2= value_json.data[loop.index0].demand|float /value_json.data[loop.index0].available|float %}
              {%if vcount.forecastpercentage1|float > vcount.forecastpercentage2|float%}
                {%set vcount.forecastpercentage1 = vcount.forecastpercentage2 %}
              {%endif%}
          {%endif%}                             
                          
        {%endfor%}
        {{(100-(vcount.forecastpercentage1|float*100))|round(1)}}

    - platform: rest
      scan_interval: 3600
      unique_id: ercot_forecast_commited_availability
      icon: mdi:transmission-tower
      name: "Ercot Forecast Commited Availability"
      resource: "https://www.ercot.com/api/1/services/read/dashboards/supply-demand.json"
      value_template: >-
        {%set vcount = namespace(forecastpercentage1=10,forecastpercentage2 = 0) %}
        {% for x in value_json.data %}
          {% if value_json.data[loop.index0].forecast|int == 1%}                
              {%set vcount.forecastpercentage2= value_json.data[loop.index0].demand|float /value_json.data[loop.index0].capacity|float %}
              {%if vcount.forecastpercentage1|float > vcount.forecastpercentage2|float%}
                {%set vcount.forecastpercentage1 = vcount.forecastpercentage2 %}
              {%endif%}
          {%endif%}                                             
        {%endfor%}
        {{(100-(vcount.forecastpercentage1|float*100))|round(1)}}

Thank you! I was thinking something was wrong.

Hi Mike - I’ve been using this method for a Scrape sensor successfully, until it stopped working on June 8. The data source is still there, but my sensor is showing “unknown”. I can’t decipher the Select logic,so could you provide the updated configuration to use to get this working again? Thanks!

I just had to update mine too and really didn’t understand why because it didn’t look like anything had changed. Here is what I am using now:

Resource: https://www.ercot.com/content/cdr/html/as_capacity_monitor.html

Sensor: body > div:nth-child(2) > table.tableStyle:nth-child(4) > tbody > tr:nth-child(53) > td.labelClassCenter:nth-child(2)

Hope that helps.

1 Like

Awesome! Works great. Thanks very much!

Here’s a sensor for the current wholesale price per kilowatt. I needed something that would alert me so that I would know to dump the Powerwalls to the grid. Normally the wholesale price is around $0.02. Yesterday it hit nearly $5.00. It is one of my first sensors and some of my first Jija, so feedback and tips welcome. It basically loops through the JSON response and delivers the wholesale average that corresponds to the highest timestamp in the record.


- platform: rest
    scan_interval: 900
    unit_of_measurement: "$"
    unique_id: ercot_realtime_system_wide_prices
    icon: mdi:transmission-tower
    name: "ERCOT Realtime Wholesale per kWh"
    resource: "https://www.ercot.com/api/1/services/read/dashboards/systemWidePrices.json"
    value_template: >-
      {% set nsmi = namespace(max_interval = 0) %}
      {% set nshba = namespace(hbBusAvg = 0) %}
      {% for data in value_json.rtSppData %}
        {% if data['interval'] > nsmi.max_interval %}
          {% set nsmi.max_interval = data['interval'] %}
          {% set nshba.hbBusAvg = data['hbBusAvg'] %}
        {% endif %}
      {% endfor %}
      {{nshba.hbBusAvg/1000}}

I’m currently getting “Entity not available: sensor.grid_operating_reserves” Does yours still work? Do you mind providing your sensor configuration?

This post from above should be the needed config.

Thank you so much for this info. I was struggling with the github config. I was able to get it to collect data but the Current Reading sensor didn’t work in the Energy Dashboard. Your changes work great!

I did have to remove the smartmetertexas: value at the top of the smt package and also added a sensor for the hourly energy reading.

packages/smartmetertexas.yaml

  mqtt:
    sensor:
      - state_topic: "smt/reading"
        unit_of_measurement: "kWh"
        name: Smart Meter Texas Current Reading
        unique_id: smart_meter_texas_current_reading
        device_class: energy

  sensor:
    - platform: template
      sensors:

        smtexas_energy_last_hour:
          friendly_name: Hourly Energy
          unit_of_measurement: 'kWh'
          value_template: "{{ state_attr('sensor.hourly_energy','last_period') }}"
          icon_template: mdi:counter

  utility_meter:
    hourly_energy:
      source: sensor.smart_meter_texas_current_reading
      name: Hourly Energy
      cycle: hourly
    daily_energy:
      source: sensor.smart_meter_texas_current_reading
      name: Daily Energy
      cycle: daily
    monthly_energy:
      source: sensor.smart_meter_texas_current_reading
      name: Monthly Energy
      cycle: monthly

  input_number:
    smtexas_energy_cost:
      icon: mdi:currency-usd
      name: Electricity Cost
      mode: box
      min: 0
      max: 2.50
      step: .001
      unit_of_measurement: "$/kWh"

This post might be redundant but hopefully this helps another following mnewm4’s great templates.

I did some tinkering and reading through this thread and had to make changes to get this working for me as of 8 September 2023. I am running:

  • Home Assistant 2023.9.0
  • Supervisor 2023.08.3
  • Operating System 10.5
  • Frontend 20230906.1 - latest

I added this into my configuration.yaml to add the sensors ‘sensor.ercot_status’ (for the text conditions in the later Markdown card) and ‘sensor.ercot_reserves’ (for the needle gauge card) into the “sensor:” section of the file.

configuration.yaml:

sensor:
# there may be tons of other sensors in here already
  - platform: rest
    scan_interval: 300
    unique_id: ercot_status
    icon: mdi:transmission-tower
    name: Ercot Status
    resource: "https://www.ercot.com/api/1/services/read/dashboards/daily-prc.json"
    value_template: "{{value_json.current_condition.state}}"
    json_attributes_path: "$.current_condition"
    json_attributes:
      - energy_level_value
      - title
      - condition_note
      - eea_level
      - prc_value
      - datetime
  - platform: template
    sensors:
      ercot_reserves:
        unique_id: ercot_grid_operating_reserves
        friendly_name: "Ercot Operating Reserves"
        unit_of_measurement: MW
        icon_template: mdi:transmission-tower
        value_template: >-
          {{states.sensor.ercot_status.attributes.prc_value.replace(",", "") }}

I then added these into a default Lovelace card of “Vertical Stack” with the following yaml code:

type: vertical-stack
cards:
  - type: gauge
    entity: sensor.ercot_reserves
    needle: true
    min: 1
    max: 7000
    segments:
      - from: 1
        color: '#000000'
      - from: 1000
        color: '#FF0000'
      - from: 1750
        color: '#FFA500'
      - from: 2300
        color: '#FFFF00'
      - from: 2900
        color: '#008000'
    name: Electricity Grid Operating Reserves
    unit: MW
  - type: markdown
    content: >-
      <table width="100%">
      <tr>
      <td><h2> {{ state_attr('sensor.ercot_status','title') }} </h2> </td>
      <td align='right'><font color='#44739e'> <ha-icon icon="{{ state_attr( 'sensor.ercot_status', 'icon' ) }}"></font></ha-icon></td>
      </tr>
      <tr>
      <td colspan="2"> {{ state_attr( 'sensor.ercot_status', 'condition_note' )
      }} </td>
      </tr>
      </table>

And that results in this Vertical Stack card:

If the Markdown card doesn’t work on a copy and paste, then double check that the copy paste operation from your browser over to your card yaml input didn’t insert and create extra line breaks. For example, the “<td align… </ha-icon></td>” should be on one line and “<td colspan… </td>” should be on one line inside the card’s yaml.

Best of luck!

2 Likes

Just validating, @selfjc’s post above worked “out of the box” for me in January 2024. Thanks for the research and effort all!

Thank you @selfjc I just added the Ercot Grid Monitor :smiley: and confirming it is still properly working in June of 2024!

Thanks for the code and dashboard example. I played around with it, rewriting based on rest (vs. sensor | platform | rest). Not necessarily better, just an alternative.

For my purposes (and given the size of the json payload returned by the ERCOT API, 653KB), I reduced the scan interval to once every 15 minutes.

rest:
  - scan_interval: 900
    resource: "https://www.ercot.com/api/1/services/read/dashboards/daily-prc.json"
    sensor:
      - name: Ercot Status
        unique_id: ercot_status
        icon: mdi:transmission-tower
        value_template: >
          {{ value_json.current_condition.state }}
        json_attributes_path: "$.current_condition"
        json_attributes:
          - "energy_level_value"
          - "title"
          - "condition_note"
          - "eea_level"
          - "prc_value"
          - "datetime"
      - name: Ercot Grid Operating Reserves
        unique_id: ercot_grid_operating_reserves
        icon: mdi:transmission-tower
        value_template: >
          {{ value_json.current_condition.prc_value.replace(",", "") | int(0) }}
      - name: Ercot Status Last Updated
        unique_id: ercot_status_last_updated
        icon: mdi:calendar-clock
        value_template: >
          {{ value_json.lastUpdated }}

I also made some mods to the dashboard card based on the legend on the ERCOT Grid Conditions Dashboard.

  • Updated the max value to 15,000 (based on y axis of the Daily PRC graph)
  • Altered the number of segments
    • One for each of the condition levels in the ERCOT legend
    • Matched the colors to those of the legend
    • Adjusted the ranges to mostly match the legend; there aren’t specific MW values documented in the legend so I just went with 1000 increments as it seemed to make sense. The next time we are in an energy reduction period, I’ll be watching to see what conditions are reported for those ranges.
  • I added a sensor for ERCOT status last update date and time (from the JSON) and display it at bottom of the card.
type: vertical-stack
cards:
  - type: gauge
    entity: sensor.ercot_grid_operating_reserves
    needle: true
    min: 1
    max: 15000
    segments:
      - from: 1
        color: '#000000'
      - from: 1500
        color: '#9d311f'
      - from: 2000
        color: '#dc3545'
      - from: 2500
        color: '#fd7e14'
      - from: 3500
        color: '#ffc107'
      - from: 4500
        color: '#28a745'
      - from: 5500
        color: '#008000'
    name: Electricity Grid Operating Reserves
    unit: MW
  - type: markdown
    content: |-
      <table width="100%">
        <tr>
          <td><h2>{{ state_attr('sensor.ercot_status', 'title') }}</h2></td>
          <td align="right">
            <font color="#44739e">
              <ha-icon icon="{{ state_attr('sensor.ercot_status', 'icon') }}"></ha-icon>
            </font>
          </td>
        </tr>
        <tr>
          <td colspan="2">{{ state_attr('sensor.ercot_status', 'condition_note') }}</td>
        </tr>
        <tr>
          <td colspan="2"><br>Last updated: {{ states('sensor.ercot_status_last_updated') }}</td>
        </tr>
      </table>

1 Like