🌤 WUnderground data uploader

In the end it was a simple typo with the station ID. After updating that, everything works perfectly and has been working great for over a month now.

Thanks for the blueprint!

Hi there. Great blueprint. I have two recommondations:

  • for the pressure, you should also allow devices of type barometric_pressure, else, we are missing some devices in the drop down, for example netatmo devices.
  • For the current precipitation, some devices give mm/h as a unit, not only mm. If they do, you don’t convert into inches.
    Regards, Edi

Hi @eiten,

Thanks for the suggestion! I added barometric_pressure to the entity selector in this branch.
Can you check if this works for you?

For a precipitation with a unit of measurement of mm/h, we need to convert this to a total precipitation to work for WUnderground. If I recall the request documentation correctly.

Slightly off topic (hope you don’t mind Dirk), but in case of interest to anyone I’ve been able to tweak an Automation created from this Blueprint to allow upload to the Weather Observation Website (WOW) from Met Ɖireann in Ireland which in itself is part of the Global WOW network of crowdsourced weather observations.
The Met Ɖireann WOW upload piggybacks on the UK Met Office site (here) and their API is documented here.

The upload structure is very similar to the WUnderground one so it was really a case of 1) change upload URL 2) changing the Station/Site ID naming and 3) removing the sensors from the payload that WUnderground has but WOW doesn’t…

1 Like

Hi @Gav_in,

No problem, I was meaning to look into uploading to WOW after creating the WUnderground blueprint but haven’t made time to look into it.
Can you share how you dit this (or create a PR on my GitHub)? I was planned to tweak the blueprint to support both WUnderground and WOW (and maybe also other services) so this very helpfull.

1 Like

No worries…given that I’ve butchered an Automation created from your Blueprint rather than updated it to work with two services, I’ll post the full edited automation code here rather than a PR…

The changes I’ve made are…

URL is now url: http://wow.metoffice.gov.uk/automaticreading?{{ payload }}
PAYLOAD after removing data that WOW doesn’t need, changing the names for some of the variables, and adding in a ā€œ&softwaretypeā€ tag is now …

    {% set data = namespace(sensors=[]) %}

    {% for i in [['rtfreq', rtfreq]
          ,['baromin', baromin]
          ,['tempf', tempf]
          ,['dewptf', dewptf]
          ,['humidity', humidity]
          ,['windspeedmph', windspeedmph]
          ,['windgustmph', windgustmph]
          ,['winddir', winddir]
          ,['rainin', rainin]
          ,['dailyrainin', dailyrainin]
          ]%}
      {% if i[1] != '' %}
        {% set data.sensors = data.sensors + ['{}={}'.format(i[0], (i[1] if i[0] == 'rtfreq'
                                              else (i[1] | round(3)) | string))] %}
      {% endif %}
    {% endfor %}

    {% set _payload = 'siteid=' + station_id %} {% set _payload = _payload +
    '&siteAuthenticationKey=' + station_key %} {% set _payload = _payload +
    '&dateutc=now' %} {% set _payload = _payload + '&' if data.sensors | length
    > 0 else '' %} {% set _payload = _payload + data.sensors | join('&') %} {%
    set _payload = _payload + '&softwaretype=homeassistant' %} {{ _payload }}

Also had to enclose my station_key into " as it’s a number for this service so was seen as int rather than str and couldn’t concatenate into the URL

And I’ve added a 30 sec delay before the CURL command so that my WUnderground and WOW commands aren’t firing at exactly the same time.


FULL AUTOMATION

description: >-
  adapted from WUnderground Uploader Blueprint
  https://community.home-assistant.io/t/wunderground-data-uploader/330332
triggers:
  - entity_id:
      - sensor.my_wind_strength
      - sensor.my_wind_gust_strength
      - sensor.my_rain_rain
      - sensor.my_outdoor_temperature
      - sensor.my_humidity
    trigger: state
actions:
  - alias: Check if station_id and station_key exist
    if:
      - condition: template
        value_template: |
          {{      station_id != ''
              and station_key != ''
          }}
    then:
      - delay:
          hours: 0
          minutes: 0
          seconds: 30
          milliseconds: 0
      - data:
          url: http://wow.metoffice.gov.uk/automaticreading?{{ payload }}
        action: shell_command.curl_get
  - alias: Wait to prevent multiple uploads
    delay:
      seconds: "{{ delay | int }}"
mode: single
max_exceeded: silent
variables:
  station_id: LONG_CODE_FOR_YOUR_WOW_STATION_ID
  station_key: "six digit code"
  sensor_baro: sensor.my_outdoor_pressure
  sensor_temp: sensor.my_outdoor_temperature
  sensor_dewpt: ""
  calculate_dewpt: true
  sensor_humidity: sensor.my_outdoor_humidity
  sensor_windspeed: sensor.my_wind_wind_strength
  sensor_windgust: sensor.my_wind_gust_strength
  sensor_winddir: sensor.my_wind_wind_direction
  sensor_rain: sensor.my_rain_rain
  sensor_dailyrain: sensor.my_rain_rain_today
  sensor_indoortemp: ""
  sensor_indoorhumidity: ""
  sensor_solarradiation: ""
  sensor_UV: ""
  rtfreq: 450
  delay: 15
  baromin: >
    {% set unit_of_measurement = state_attr(sensor_baro, 'unit_of_measurement')
    %} {{ sensor_baro if sensor_baro == ''
        else (states(sensor_baro) | float(default=0)) if unit_of_measurement not in ['mbar', 'hPa']
          else ((states(sensor_baro) | float(default=0)) / 33.8639) }}
  tempf: >
    {% set unit_of_measurement = state_attr(sensor_temp, 'unit_of_measurement')
    %} {{ sensor_temp if sensor_temp == ''
        else ((states(sensor_temp) | float(default=0)) if unit_of_measurement == '°F'
          else ((states(sensor_temp) | float(default=0)) * 1.8) + 32) }}
  humidity: >
    {{ sensor_humidity if sensor_humidity == '' else (states(sensor_humidity) |
    float(default=0)) }}
  windspeedmph: >
    {% set unit_of_measurement = state_attr(sensor_windspeed,
    'unit_of_measurement') %} {{ sensor_windspeed if sensor_windspeed == ''
        else (states(sensor_windspeed) | float(default=0)) * (0.6213 if unit_of_measurement == 'km/h' else 1) }}
  windgustmph: >
    {% set unit_of_measurement = state_attr(sensor_windgust,
    'unit_of_measurement') %} {{ sensor_windgust if sensor_windgust == ''
        else (states(sensor_windgust) | float(default=0)) * (0.6213 if unit_of_measurement == 'km/h' else 1) }}
  winddir: >
    {% set candidate_wind_direction = states(sensor_winddir) %} {% set
    wind_direction_float = candidate_wind_direction | float(default=-1) %} {% if
    wind_direction_float == -1 %}
      {% set directions_map16 = {'N': 0, 'NNE': 22.5, 'NE': 45, 'ENE': 67.5, 'E': 90, 'ESE': 112.5, 'SE': 135, 'SSE': 157.5, 'S': 180, 'SSW': 202.5, 'SW': 225, 'WSW': 247.5, 'W': 270, 'WNW': 292.5, 'NW': 315, 'NNW': 337.5} %}
      {% set candidate_wind_direction = candidate_wind_direction.upper() %}
      {{ directions_map16.get(candidate_wind_direction, '') | float(default=0) }}
    {%- else -%}
      {{ wind_direction_float }}
    {%- endif %}
  rainin: >
    {% set unit_of_measurement = state_attr(sensor_rain, 'unit_of_measurement')
    %} {{ sensor_rain if sensor_rain == ''
        else ((states(sensor_rain) | float(default=0)) / (25.4 if unit_of_measurement == 'mm' else 1)) }}
  dailyrainin: >
    {% set unit_of_measurement = state_attr(sensor_dailyrain,
    'unit_of_measurement') %} {{ sensor_dailyrain if sensor_dailyrain == ''
        else ((states(sensor_dailyrain) | float(default=0)) / (25.4 if unit_of_measurement == 'mm' else 1)) }}
  dewptf_calculated: >
    {% set unit_of_measurement = state_attr(sensor_temp, 'unit_of_measurement')
    %} {% set T = ((states(sensor_temp) | float(default=0)) if
    unit_of_measurement == '°C'
                else ((states(sensor_temp) | float(default=0)) - 32) / 1.8) %}
    {% set RH = humidity %} {% set dewpt = '' %} {% if sensor_temp != '' and
    sensor_humidity != '' %}
      {% set A = log(RH / 100, default=0.0) + (17.62 * T / (243.12 + T)) %}
      {% set dewpt = 243.12 * A / (17.62 - A) %}
      {% set dewpt = (dewpt * 1.8) + 32 %}
    {% endif %} {{ dewpt }}
  dewptf: >
    {% set unit_of_measurement = state_attr(sensor_dewpt, 'unit_of_measurement')
    %} {{ (dewptf_calculated if calculate_dewpt is true
        else sensor_dewpt) if sensor_dewpt == ''
          else ((states(sensor_dewpt) | float(default=0)) if unit_of_measurement == '°F'
            else ((states(sensor_dewpt) | float(default=0)) * 1.8) + 32) }}
  payload: >
    {% set data = namespace(sensors=[]) %}

    {% for i in [['rtfreq', rtfreq]
          ,['baromin', baromin]
          ,['tempf', tempf]
          ,['dewptf', dewptf]
          ,['humidity', humidity]
          ,['windspeedmph', windspeedmph]
          ,['windgustmph', windgustmph]
          ,['winddir', winddir]
          ,['rainin', rainin]
          ,['dailyrainin', dailyrainin]
          ]%}
      {% if i[1] != '' %}
        {% set data.sensors = data.sensors + ['{}={}'.format(i[0], (i[1] if i[0] == 'rtfreq'
                                              else (i[1] | round(3)) | string))] %}
      {% endif %}
    {% endfor %}

    {% set _payload = 'siteid=' + station_id %} {% set _payload = _payload +
    '&siteAuthenticationKey=' + station_key %} {% set _payload = _payload +
    '&dateutc=now' %} {% set _payload = _payload + '&' if data.sensors | length
    > 0 else '' %} {% set _payload = _payload + data.sensors | join('&') %} {%
    set _payload = _payload + '&softwaretype=homeassistant' %} {{ _payload }}

Let me know if you need anything else or if it’s not making sense…

HI @Gav_in, thanks for the code!
In my repo, I created a separate branch to change my blueprint to have WUnderground and WOW services to upload to. You can find the blueprint here.
Can you check if this works for you?

Just to be clear, I haven’ t read the API documentation nor have a account at WOW. I hope to look into it in the coming weeks.

If this works for you and I spend some time reading the documentation, I will merge this branch into the main branch.

1 Like

had a quick look and it’s throwing an error…think there’s a typo in the Payload around ā€œstation_idā€ and ā€œstation_keyā€ā€¦you’ve renamed them in the inputs but not in the payload and that’s the issue

this payload seems to be all good…

wu_payload: >
    {% set data = namespace(sensors=[]) %}

    {% for i in [['rtfreq', rtfreq]
          ,['baromin', baromin]
          ,['tempf', tempf]
          ,['dewptf', dewptf]
          ,['humidity', humidity]
          ,['windspeedmph', windspeedmph]
          ,['windgustmph', windgustmph]
          ,['winddir', winddir]
          ,['rainin', rainin]
          ,['dailyrainin', dailyrainin]
          ,['indoortempf', indoortempf]
          ,['indoorhumidity', indoorhumidity]
          ,['solarradiation', solarradiation]
          ,['UV', UV]
          ]%}
      {% if i[1] != '' %}
        {% set data.sensors = data.sensors + ['{}={}'.format(i[0], (i[1] if i[0] == 'rtfreq'
                                              else (i[1] | round(3)) | string))] %}
      {% endif %}
    {% endfor %}

    {% set _payload = 'ID=' + wu_station_id %}
    {% set _payload = _payload + '&PASSWORD=' + wu_station_key %}
    {% set _payload = _payload + '&action=updateraww' %}
    {% set _payload = _payload + '&realtime=1' %}
    {% set _payload = _payload + '&dateutc=now' %}
    {% set _payload = _payload + '&' if data.sensors | length > 0 else '' %}
    {% set _payload = _payload + data.sensors | join('&') %}
    {{ _payload }}
  wow_payload: >
    {% set data = namespace(sensors=[]) %}

    {% for i in [['rtfreq', rtfreq]
          ,['baromin', baromin]
          ,['tempf', tempf]
          ,['dewptf', dewptf]
          ,['humidity', humidity]
          ,['windspeedmph', windspeedmph]
          ,['windgustmph', windgustmph]
          ,['winddir', winddir]
          ,['rainin', rainin]
          ,['dailyrainin', dailyrainin]
          ]%}
      {% if i[1] != '' %}
        {% set data.sensors = data.sensors + ['{}={}'.format(i[0], (i[1] if i[0] == 'rtfreq'
                                              else (i[1] | round(3)) | string))] %}
      {% endif %}
    {% endfor %}

    {% set _payload = 'siteid=' + wow_site_id %}
    {% set _payload = _payload + '&siteAuthenticationKey=' + wow_site_auth_key %}
    {% set _payload = _payload + '&dateutc=now' %}
    {% set _payload = _payload + '&' if data.sensors | length > 0 else '' %}
    {% set _payload = _payload + data.sensors | join('&') %}
    {% set _payload = _payload + '&softwaretype=homeassistant' %}    
    {{ _payload }}

and as a final update, checked both WU & WOW and the latest observations with new blueprint are both uploaded and live…

Hi @Gav_in,

Thanks for testing, I corrected the wrong variables and all should work now.

1 Like

yeah…the updated Payload I posted worked fine and is still going strong…thanks for putting it all together

Good to hear! I’ll look into the specs and release it to the main branch if I’ve tested it some more.

1 Like

Hi @dvandonkelaar

Thanks a lot, it works. Sorry for the long delay!

Hi @eiten,

Good to know, I merged the changes in the main branch.

I’ve been occasionally getting error code 52 when the blueprint runs the curl shell command.

ERROR (MainThread) [homeassistant.components.shell_command] Error running command: curl -X GET {{ url }}, return code: 52

I’m wonder what causes ā€œreturn code 52ā€. Is this a Wunderground issue?

In my recent traces, I don’t see error code 52.
If I search for this error code, it states: curl: (52) Empty reply from server (source).
This seems a WUnderground issue, but I don’t know for sure.

1 Like

Can we upload pm2.5 and pm10 sensor data with this?

Hi @jruben4,

Yes, In the upload protocol the PM2.5 (upload key AqPM2.5) and PM10 (upload key AqPM10) options are available.
Unforutnately, I don’t have these outdoor sensors in my Home Assistant and therefore can’t test it.

If you feel confident, you can make a Github PR. If not, I could make a test-branch so you can test.

Hi! Thanks for the blueprint, it’s working fine.
I searched through the conversation, but didn’t find it.
My sensor reports total rain since boot. How do I report it? Because it’s sending the total rain to WU: https://www.wunderground.com/dashboard/pws/ISANTA1587

Nevermind, I figured it out myself.
I used these:

utility_meter:
  rain_hourly:
    source: sensor.emax_w6_4_97_rain_total
    cycle: hourly
  rain_daily:
    source: sensor.emax_w6_4_97_rain_total
    cycle: daily

Used rain_daily on Daily rain sensor and rain_hourly on Rain sensor.

Hi,

When setting up the blueprint today, I was surprised to find my barometer sensors weren’t showing up. Turns out it’s because they were set up with the atmospheric_pressure device_class, whereas the blueprint is only accepting pressure or barometric_pressure classes. I don’t see barometric_pressure as being a valid device_class, maybe it used to be when the blueprint was created.

So I forked the blueprint and replaced barometric_pressure with atmospheric_pressure, and also added device_classes to the wind speed and direction sensors as well as the irradiance sensor, because otherwise they present all the sensors in home assistant and searching is an annoying speed bump. I couldn’t think of a reason why the class should be omitted on those.

Lastly I added the default shell_command.curl_get which is specified in original post, and added a default refresh_frequency value of 5 minutes, just to smooth out creating the automation. I submitted a PR to the Dirk’s repo but it’s also available here.

1 Like