🌤 WUnderground data uploader

Description

A blueprint to upload Home Assistant sensor data to WUnderground.
The WUnderground data upload for weather stations is based on a GET request, so it is possible to achieve these results within an automation.
Yes, I know. WUnderground pulled a free service down, but I support the idea of a community based weather station.

This blueprint needs to execute a shell_command. This service needs to be enabled with, for example, the following YAML.

shell_command:
  curl_get: 'curl -X GET {{ url }}'

Disclaimer

The blueprint is created because the Netatmo to WUnderground upload isn’t working (it’s possible in the WUnderground ‘add station’ wizard, but fails). The sensor data is formatted based on the information in my available sensors and unit_of_measurement values, so there could be a bug in formatting.

Blueprint

Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.


blueprint:
  name: WUnderground upload
  description: >
    Upload data from Home Assistant to WUnderground.

    Config:
      The station_id and station_key variable must be fetched from WUnderground.
      The sensor_* variables are the sensors whos data will be uploaded
      The trigger_entities variable specifies the entries to trigger state changes on (this could be a list)
      The curl_command_service variable specifies the CURL-service to execute.
      The refresh_frequency variable specifies the frequency the sensors update their data
      The dewpoint temperature can be calculated based on the outdoor temperature and the outdoor humidity.
        By default, it will be calculated, to disable this set calculate_dewpt to false.

    The CURL-service must exist in Home Assistant.
    This can be configured with the following YAML
      shell_command:
        curl_get: 'curl -X GET {{ url }}'

    Automation config example:
      automation:
        - id: wunderground_data_upload
          alias: WUnderground data upload
          use_blueprint:
            path: wunderground_upload.yaml
            input:
              station_id: !secret wunderground_station_id
              station_key: !secret wunderground_station_key
              sensor_baro: 'sensor.outdoor_pressure'
              sensor_temp: 'sensor.outdoor_temperature'
              sensor_humidity: 'sensor.outdoor_humidity'
              sensor_rain: 'sensor.outdoor_rain'
              sensor_dailyrain: 'sensor.outdoor_rain_today'
              refresh_frequency: 300
              trigger_entities:
                - sensor.outdoor_temperature
                - sensor.outdoor_humidity
                - sensor.outdoor_rain
                - sensor.outdoor_rain_today
              curl_command_service: shell_command.curl_get
  domain: automation
  source_url: "https://github.com/dvandonkelaar/home-assistant-blueprints/raw/main/wunderground_upload.yaml"
  input:
    station_id:
      name: Station ID
      default: ''
    station_key:
      name: Station key
      default: ''
    sensor_baro:
      name: Barometer sensor
      selector:
        entity:
          domain: sensor
          device_class: pressure
      default: ''
    sensor_temp:
      name: Temperature sensor
      selector:
        entity:
          domain: sensor
          device_class: temperature
      default: ''
    sensor_dewpt:
      name: Dew point sensor
      selector:
        entity:
          domain: sensor
          device_class: temperature
      default: ''
    calculate_dewpt:
      name: Calculate dewpoint
      description:
        Dewpoint calculation is only possible if the outdoor temperature and outdoor humidity sensor are available.
      selector:
        boolean:
      default: true
    sensor_humidity:
      name: Humidity sensor
      selector:
        entity:
          domain: sensor
          device_class: humidity
      default: ''
    sensor_windspeed:
      name: Wind speed sensor
      selector:
        entity:
          domain: sensor
      default: ''
    sensor_windgust:
      name: Wind gust sensor
      selector:
        entity:
          domain: sensor
      default: ''
    sensor_winddir:
      name: Wind direction sensor
      selector:
        entity:
          domain: sensor
      default: ''
    sensor_rain:
      name: Rain sensor
      selector:
        entity:
          domain: sensor
      default: ''
    sensor_dailyrain:
      name: Daily rain sensor
      selector:
        entity:
          domain: sensor
      default: ''
    sensor_indoortemp:
      name: Indoor temperature sensor
      selector:
        entity:
          domain: sensor
          device_class: temperature
      default: ''
    sensor_indoorhumidity:
      name: Indoor humidity sensor
      selector:
        entity:
          domain: sensor
          device_class: humidity
      default: ''
    sensor_solarradiation:
      name: Solar Radiation sensor
      selector:
        entity:
          domain: sensor
      default: ''
    sensor_UV:
      name: UV Index sensor
      selector:
        entity:
          domain: sensor
      default: ''
    refresh_frequency:
      name: Refresh frequency (seconds)
      selector:
        number:
          min: 1
          max: 10800
          step: 1
          unit_of_measurement: seconds
    trigger_entities:
      name: Trigger entities
      selector:
        entity:
      default: ''
    curl_command_service:
      name: CURL command service
      selector:
        text:
      default: ''
    delay:
      name: Delay after publishing results
      selector:
        number:
          min: 0
          max: 10800
          step: 1
          unit_of_measurement: seconds
      default: 10

mode: single
max_exceeded: silent

trigger:
  - platform: state
    entity_id: !input trigger_entities

variables:
  station_id: !input station_id
  station_key: !input station_key
  sensor_baro: !input sensor_baro
  sensor_temp: !input sensor_temp
  sensor_dewpt: !input sensor_dewpt
  calculate_dewpt: !input calculate_dewpt
  sensor_humidity: !input sensor_humidity
  sensor_windspeed: !input sensor_windspeed
  sensor_windgust: !input sensor_windgust
  sensor_winddir: !input sensor_winddir
  sensor_rain: !input sensor_rain
  sensor_dailyrain: !input sensor_dailyrain
  sensor_indoortemp: !input sensor_indoortemp
  sensor_indoorhumidity: !input sensor_indoorhumidity
  sensor_solarradiation: !input sensor_solarradiation
  sensor_UV: !input sensor_UV
  rtfreq: !input refresh_frequency
  delay: !input delay
  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: >
    {{ sensor_winddir if sensor_winddir == ''
        else (states(sensor_winddir) | float(default=0)) }}
  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)) }}
  indoortempf: >
    {% set unit_of_measurement = state_attr(sensor_indoortemp, 'unit_of_measurement') %}
    {{ sensor_indoortemp if sensor_indoortemp == ''
        else ((states(sensor_indoortemp) | float(default=0)) if unit_of_measurement == '°F'
          else ((states(sensor_indoortemp) | float(default=0)) * 1.8) + 32) }}
  indoorhumidity: >
    {{ sensor_indoorhumidity if sensor_indoorhumidity == ''
        else (states(sensor_indoorhumidity) | float(default=0)) }}
  solarradiation: >
    {% set unit_of_measurement = state_attr(sensor_solarradiation, 'unit_of_measurement') %}
    {{ sensor_solarradiation if sensor_solarradiation == ''
        else ((states(sensor_solarradiation) / 126.7) | float(default=0)) if unit_of_measurement == 'lux'
          else (states(sensor_solarradiation) | float(default=0)) }}
  UV: >
    {{ sensor_UV if sensor_UV == ''
        else (states(sensor_UV) | int(default=0)) }}
  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]
          ,['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=' + station_id %}
    {% set _payload = _payload + '&PASSWORD=' + 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 }}

action:
  - alias: "Check if station_id and station_key exist"
    if: >
      {{      station_id != ''
          and station_key != ''
      }}
    then:
      - service: !input curl_command_service
        data:
          url: "https://weatherstation.wunderground.com/weatherstation/updateweatherstation.php?{{ payload }}"
  - alias: "Wait to prevent multiple uploads"
    delay:
      seconds: "{{ delay | int }}"

Automation example


automation:
  - id: wunderground_data_upload
    alias: WUnderground data upload
    use_blueprint:
      path: wunderground_upload.yaml
      input:
      station_id: !secret wunderground_station_id
      station_key: !secret wunderground_station_key
      sensor_baro: 'sensor.outdoor_pressure'
      sensor_temp: 'sensor.outdoor_temperature'
      sensor_humidity: 'sensor.outdoor_humidity'
      sensor_rain: 'sensor.outdoor_rain'
      sensor_dailyrain: 'sensor.outdoor_rain_today'
      refresh_frequency: 300
      trigger_entities:
        - sensor.outdoor_temperature
        - sensor.outdoor_humidity
        - sensor.outdoor_rain
        - sensor.outdoor_rain_today
      curl_command_service: shell_command.curl_get

7 Likes

Thanks!!!

Works great here :smiley:

You’re welcome! During the rain today, I discovered the unit_of_measurement conversion for rain was incorrect.
I updated the blueprint and also added a roundoff of 2 decimals instead of 1 (for better mm to inch conversion).
For me it’s not clear how Home Assistant keeps track of blueprint updates, but please check if you have the latest version.

Update

The dewpoint temperature can be calculated based on the outdoor temperature and the outdoor humidity.
By default, it will be calculated. To disable this set calculate_dewpt to false.

Hello, I just came across the article and I’m not happy with the development of Wunderground either. I bought a weather station and registered it with Wunderground because of that and now it is no longer available in HA. could you help me to get this to work am a beginner and so this is a bit difficult.

There is a custom integration that retrieves data from WUnderground, the default WUnderground integration from Home Assistant doesn’t work.
See the Home-Assistant-wundergroundpws GitHub page for more info.

Thank you very much for your contribution! It was a great help!

Hi,
thanks for your contribution!
I just noticed that sensor_indoorhumidity should not have “temperature” as device class.

Thanks!

EDIT: actually there’s something more that is preventing this blueprint to work, I will investigate further. At the moment, after fixing that device class I mentioned, I get an error on curl_get shell command…

Thanks for the reply, I fixed it in the github file. Apparently, there is no warning for this if a sensor is added via YAML.

Dit you manage to add the curl_get to home-assistant? See the code below.

shell_command:
  curl_get: 'curl -X GET {{ url }}'

Howdy, HA noob here - I dont understand what I need to do with your shell command? eg do I put this in the configuration.yaml file or run it one time from the CLI?

Apologies in advance for the dumb question.

PS if I want the dew point calculated, do I need to manually create an entity for this data?

Btw, I tried putting these lines into configuration.yaml:

sensor:
  - platform: command_line
    command: SENSOR_COMMAND


shell_command:
  curl_get: 'curl -X GET {{ url }}'

But it doesnt seem to have any impact - Im still not seeing my Netatmo data appear in my Wunderground PWS. Im also not seeing any errors in HA logbook, so I’m a touch confused.

Screen Shot 2022-08-13 at 3.21.56 pm

NVM, Im an idiot - I was using the wrong key. I used the Access WU Data API key instead of the “Station Key”. :man_facepalming:

Love your work @dvandonkelaar it’s much appreciated. :sunglasses:

https://www.wunderground.com/dashboard/pws/IMELBO809

I know this thread is a bit old, but I just came across it to allow me to upload my non-networked Ambient weather data which I’m getting into HA via rtl433/MQTT. However, I had to do some work to get it working for some reason. It wouldn’t upload at all and kept giving an error:
Unable to determine action @ data[‘action’][0]. Got None

I initially gutted the action section to remove the check for the IDs since I knew they were set and I got it working, but I’ve since fixed it to work again. I also had some issues with some values not getting uploaded. This seemed to be a side effect of fixing the warning about the round() function and adding a default.

Finally, I added upload of Solar Radiation and UV Index.

My fork is here:

Hi, I am new to HA. I have troubles executing the blueprint. I got the following error:

Stopped because an error was encountered at September 23, 2022 at 9:14:25 AM (runtime: 0.02 seconds)
Template rendered invalid service: shell_command: curl_get: 'curl -X GET ’

probably i put the wrong text into CURL command service. what should I put there?

Post what you have for your Shell Command here and we can maybe see what’s wrong.
What you need (in your configuration.yaml file) is exactly as per the first post…so it should be

shell_command:
  curl_get: 'curl -X GET {{ url }}'

Thank you. I did like you suggested in the beginning and I am still getting the same error.
I have this entered:

That looks like a screen grab from Developer Tools within Home Assistant…the code posted needs to be in your config files (in configuration.yaml). Try that and you’ll be up and running.

(Developer Tools, where you are entering the command, is more for trying things out or running something once rather than a permanent thing.
Developer Tools - Home Assistant)

Thank you again. It seems Iike becouse I am a newbie I can set things up corerectly.
I have WUnderground upload in Blueprints, I create an automation and filled out all fields (a screen shot shows a portion of these filled out fields). Are saying that I need to update .yaml under Development Tool with the code?

I had the netatmo-wundeground integration working in node.js without any problems for 2 month until last week. Results were sent but where not shown on WU and that’s why I started to look for other ways and I came across HA. Unfortunatelly setting this up is above my possibilities.
Thanks anyway for your patience.

Hey…no worries…we all have to start from somewhere…still learning everyday myself on here :slight_smile:

Am with you now…the original screenshot was part of your automation (from the blueprint) so that makes sense…
The part you are missing (I think) is that you don’t have the Shell Command setup so that the Automation can call it…so you need to set this up.
To do that you’ll need to edit your configuration.yaml file and add the shell command…so outside of Home Assistant open your configuration.yaml file in whatever text/code editor you use (the file is in your Config directory - if you can’t access your config folder you might need to install for example the Samba addon to allow you browse to it) and add the code I quoted to the file…save it…reboot and with any luck you are good to go :+1:t2:

(let me know how you get on and we’ll get it sorted)

Thank you @dvandonkelaar ery much for your contribution! It was a great help!

I am trying to add the pm2.5 sensor to your blueprint, but unfortunately it doesn’t work :frowning:
I added some extra lines of code to your blueprint:

Do I have to add or change anything else?