An Home Assistant powered Weather Underground PWS

Hi, I’ve been contributing to wunderground PWS for some years with actual weather stations, however I moved now and while I’m not adding an actual weather station to my place I decided to just report temperature and humidity information about my area (that were missing) using the sensors I’ve outside my place.

And I decided to try to get there by just using native HA (it could have been easier with AppAdemon, but hey, need to play with templates!).

So here what I’ve in my configuration.yaml (it could have been also moved an automation, but configuration would have needed a rest_command anyways, so I preferred to keep all in the same place)

input_text:
  pws_update_password:
    initial: !secret wunderground_pws_update_password
    mode: password

rest_command:
  update_pws:
    method: GET
    url: >-
      {%- set RT_THRESHOLD = 60 %}
      {%- set RT_MIN = 2.5 %}
      {%- set pws_id = 'YOUR_PWS_ID' -%}
      {%- set pws_password = states('input_text.pws_update_password') -%}

      {%- macro temp_f(temp) -%}
      {{ '{:.2f}'.format((temp | float * 9/5) + 32) }}
      {%- endmacro -%}

      {%- macro pressure_inhg(sensor) -%}
      {{ '{:.4f}'.format(states(sensor) | float * (1 / 33.86389)) }}
      {%- endmacro -%}

      {%- macro last_change() -%}
      {%- set data = namespace(temps=[]) -%}
      {%- for v in varargs -%}
        {%- set data.temps = data.temps + [v.last_changed  | as_timestamp] -%}
      {%- endfor -%}
      {{ data.temps | max }}
      {%- endmacro -%}

      {%- macro dew_point(temp, hum) -%}
      {%- set a = 17.27 -%}
      {%- set b = 237.7 -%}
      {%- set gamma = ((a * temp | float) / (b + temp | float)) + log(hum | float / 100.0) -%}
      {{ (b * gamma) / (a - gamma) }}
      {%- endmacro -%}

      {# List the sensors involved here #}
      {%- set last_update_time = last_change(
        states.sensor.patio_temperature,
        states.sensor.patio_humidity,
        states.sensor.terrace_temperature,
        states.sensor.terrace_humidity,
        states.sensor.terrace_pressure
        ) | float -%}

      {%- set main_temperature = states('sensor.terrace_temperature') | float -%}
      {%- set main_humidity = states('sensor.terrace_humidity') | float -%}

      {%- set update_data = dict() %}
      {%- set pws_data = dict(
        ID=pws_id,
        PASSWORD=pws_password,
        action='updateraw',
        softwaretype='homeassistant PWS template 0.5',
        dateutc=last_update_time | timestamp_custom('%Y-%m-%d %H:%M:%S', False, 'now'),
        tempf=temp_f(main_temperature),
        temp2f=temp_f(states('sensor.patio_temperature')),
        humidity=main_humidity,
        humidity2=states('sensor.patio_humidity'),
        baromin=pressure_inhg('sensor.terrace_pressure'),
        dewptf=temp_f(dew_point(main_temperature, main_humidity))
      ) -%}

      {%- set update_diff = utcnow() | as_timestamp - last_update_time -%}

      {%- if (update_diff < RT_THRESHOLD) -%}
      {%- set update_data = dict(realtime=1, rtfreq='{:.2f}'.format([RT_MIN, update_diff] | max)) %}
      https://rtupdate.wunderground.com/
      {%- else -%}
      https://weatherstation.wunderground.com/
      {%- endif -%}
      weatherstation/updateweatherstation.php?

      {%- macro make_uri(dict) -%}
      {%- for k, v in dict.items() -%}
        {{ k }}={{ v | urlencode }} {%- if not loop.last -%} & {%- endif -%}
      {%- endfor -%}
      {%- endmacro -%}

      {{ make_uri(pws_data) }}&{{ make_uri(update_data) }}

Then you can add an automation to make this trigger when involved sensors are changed (or just updated, that’s why those templates):

alias: PWS Wunderground Update
description: ''
trigger:
- platform: state
  entity_id: sensor.patio_temperature
- platform: template
  value_template: '{{ (utcnow() - states.sensor.patio_temperature.last_changed).seconds
    < 1 }}'
- platform: state
  entity_id: sensor.terrace_temperature
- platform: template
  value_template: '{{ (utcnow() - states.sensor.terrace_temperature.last_changed).seconds
    < 1 }}'
- platform: state
  entity_id: sensor.patio_humidity
- platform: template
  value_template: '{{ (utcnow() - states.sensor.patio_humidity.last_changed).seconds
    < 1 }}'
- platform: state
  entity_id: sensor.terrace_humidity
- platform: template
  value_template: '{{ (utcnow() - states.sensor.terrace_humidity.last_changed).seconds
    < 1 }}'
- platform: state
  entity_id: sensor.terrace_pressure
- platform: template
  value_template: '{{ (utcnow() - states.sensor.terrace_pressure.last_changed).seconds
    < 1 }}'
condition:
- condition: or
  conditions:
  - condition: template
    value_template: '{{ (utcnow() - states.sensor.patio_temperature.last_changed).seconds
      < 60 }}'
  - condition: template
    value_template: '{{ (utcnow() - states.sensor.patio_humidity.last_changed).seconds
      < 60 }}'
  - condition: template
    value_template: '{{ (utcnow() - states.sensor.terrace_temperature.last_changed).seconds
      < 60 }}'
  - condition: template
    value_template: '{{ (utcnow() - states.sensor.terrace_humidity.last_changed).seconds
      < 60 }}'
  - condition: template
    value_template: '{{ (utcnow() - states.sensor.terrace_pressure.last_changed).seconds
      < 60 }}'
action:
- service: rest_command.update_pws
mode: parallel
max: 20

This could be probably improved more and moved into a Blueprint if someone may be interested, but well… That’s it for now.

The good part of it is that by now running a PWS, you’ll be eligible to get an API key that you can use with the wunderground integration in order to get further information about the other PWS’s around or general weather.

2 Likes

Great… I’m doing it the same way for a couple of years now, but without macros, with just one-line REST command including all calculations like this:

rest_command:
  wunderreport:
    url: "https://weatherstation.wunderground.com/weatherstation/updateweatherstation.php?ID=YOURIDHERE&PASSWORD=YOURPASSWORDHERE&dateutc=now&tempf={{ ((states('sensor.outer_temeperature_c'))| float(default=0)*1.8+32) | round(1) }}&baromin={{ ((states('sensor.outer_pressure_mbar'))| float(default=1013)*0.029529980164712) | round(2) }}&humidity={{ ((states('sensor.outer_humidity')))| float(default=50)| round(0) }}&dewptf={{ (((((((states('sensor.outer_humidity'))| float(default=50)| round(0)))/100)**0.125)*(112+(0.9*(states('sensor.outer_temperature_c'))| float(default=0)))+(0.1*(states('sensor.outer_temperature_c'))| float(default=0))-112)*1.8+32) | round(1) }}&winddir={{ ((((states('sensor.winddir'))| float(default=0)) | int)}}&windspeedmph={{ (((states('sensor.windspeedmph'))| float(default=0)))) | round(1) }}&windgustmph={{ (((states('sensor.windgustmph')) | float(default=0)))) | round(1) }}&softwaretype=homeassistant%20version%201.1.1&action=updateraw"
    verify_ssl: false

Additionally I have an automation, which runs this rest command every five minutes. Will try it your way, it seems much easier to edit or change something (I always get some errors and have to correct them many times when I try to edit my CF :slight_smile: ).

1 Like

Thanks you so much, awesome!