Pollen Sensor for Germany based on DWD (Deutscher Wetter Dienst)

When you go on the opendata link, you got a JSON String. I used the content number for the different region, not like the other variant of this sensor here in this thread, which is using the partregion_id into the content path.

I extract from JSON String, for my region, into a sensor attribute for a template sensor. Like above.

As an example for my region “Westl. Niedersachsen/Bremen” it is the content number “3”:

It may work for some time, but it will fail over time. The data is sorted by the number you choose, but the content may change, if other data will get available.

Right now you have 26 or 27 “content numbers”, if more info from other or new weather stations comes available, they will be added to this file, so the numbering will change.

Tbh I don’t see any advantage at all to simply use a number over an id, that is unique and therefore lasting much longer. :slight_smile: And you already got where you needed to be to find out the correct partregion_id. :slight_smile:

Ok, the problem is, I don’t know how to extract the partregion_id for a REST Sensor, to use it like me :thinking:

Where did you see a REST sensor in this component? Oh, you use a REST sensor, you don’t use this component… :crazy_face:

Please, explain a little further what you’re doing or trying to do, shouldn’t be that big of a problem to get what we want out of this json-file. :slight_smile:

I am using this, to extract the pollution for my region into the attributes of my dwd_pollen REST-Sensor. And with this sensor I go into a template for the state and icon for each pollen typ.

    json_attributes_path: "$.content[3]"
    json_attributes:
        - region_name
        - Pollen

The problem is, what you described, is when the content number change. So I need a way to extract the JSON Path for my region with region_id and not with the content number. It would be nice, when the pollen path is into the sensor attributes of my dwd_pollen sensor. Like now :crazy_face:

I tried to extract this over the region_id, but my knowledge about JSON isn’t that big

What I still don’t get, 2nd screenshot.
If I blow this into a new yaml sitting in a sensors directory (using sensor: !include_dir_list sensors/)
why the heck does it moan about:
a) 2 lines in a yaml starting " platform: rest" <== editor moans about that one
b) having a line " platform: rest" and somewhere later " platform template" <== editor moans aswell

HA is something a real lottery, especially if being new with it collection interesting stuff from within this community. Since even if things are marked “solved” this doesn’t mean it’ll work at all.

The worst one was the one mention at pt. a) since the HA editor flagged this RED while the settings>server>check configuration validated it green. Means nice to have such checks but as long as these tend to act as a lottery either the whole configuration is sort of rolling dice.

Just besode the fact that I got everything running by now and simply want to thank for the detailed explanation incl. the one with the content number some lines below. Works like a dream.

Even though the topic is quite old, I wanted to share my slightly improved sensor since I managed to solve the issue of dealing with the array and only picking the item for the partregion_id I’m interested in (by using JSONPath) and not using an unreliable array index which can change.

sensor:
  # DWD Pollen, see: https://opendata.dwd.de/climate_environment/health/alerts/Beschreibung_pollen_s31fg.pdf
  # (partregion_id=111 for "Oberrhein und unteres Neckartal")
  - platform: rest
    scan_interval: 3600
    name: "DWD Pollen"
    resource: https://opendata.dwd.de/climate_environment/health/alerts/s31fg.json
    json_attributes_path: "$..content[?(@.partregion_id==111)].Pollen"
    json_attributes:
      - Erle
      - Beifuss
      - Ambrosia
      - Birke
      - Esche
      - Hasel
      - Graeser
      - Roggen
    value_template: "{{ value_json.last_update }}"
  - platform: template
    sensors:
      dwd_pollen_erle:
        icon_template: "mdi:tree-outline"
        friendly_name: "Erle"
        value_template: >-
          {% set dwd_state = state_attr('sensor.dwd_pollen', 'Erle')['today'] %}
          {% if dwd_state == "3" %}6{% elif dwd_state == "2-3"%}5{% elif dwd_state == "2"%}4{% elif dwd_state == "1-2"%}3{% elif dwd_state == "1"%}2{% elif dwd_state == "0-1"%}1{% else %}0{% endif %}
        attribute_templates:
          today: >-
            {% set dwd_state = state_attr('sensor.dwd_pollen', 'Erle')['today'] %}
            {% if dwd_state == "3" %}6{% elif dwd_state == "2-3"%}5{% elif dwd_state == "2"%}4{% elif dwd_state == "1-2"%}3{% elif dwd_state == "1"%}2{% elif dwd_state == "0-1"%}1{% else %}0{% endif %}
          tomorrow: >-
            {% set dwd_state = state_attr('sensor.dwd_pollen', 'Erle')['tomorrow'] %}
            {% if dwd_state == "3" %}6{% elif dwd_state == "2-3"%}5{% elif dwd_state == "2"%}4{% elif dwd_state == "1-2"%}3{% elif dwd_state == "1"%}2{% elif dwd_state == "0-1"%}1{% else %}0{% endif %}

You have to replace the 111 in the json_attributes_path of the first REST sensor with your partregion_id. This REST sensor then has one attribute for each pollen type. The second sensor (template type) is just an example, you have to repeat this for every pollen type, it’s sadly quite repetitive. Its value is a number between 0 and 6 (indicating the intensity today) and the attributes contain todays’ and tomorrows’ intensity. So you’re quite flexible with using it in a Lovelace card.

5 Likes

That’s a great snippet to use, thanks a lot! :slight_smile:

But as far as I can see, this doesn’t work, does it? :wink: Either you call the rest sensor “DWD Pollenbelastung” or you change the template sensors from
{% set dwd_state = state_attr('sensor.dwd_pollenbelastung', 'Erle')['today'] %}
to
{% set dwd_state = state_attr('sensor.dwd_pollen', 'Erle')['today'] %}

Either way great contribution! :slight_smile:

@dyfcom
I am very sorry, I totally missed your reply and didn’t answer. Sorry for that! Fortunately @rkallensee did a great job with his snippet. :slight_smile:

Thanks for the hint - absolutely true. :sweat_smile: I fixed my example.

2 Likes

No Problem, it is still working for me. But! I swith to the great example from @rkallensee and it working like a charm!

Im new to Home Assistant and had my Allergietest today, now i used ur template to add all the Pollen i need, works perfect.
Could u please share ur lovelace card as an example? I dont know how to begin :frowning:

Thanks in advance

Just use the entity the template sensor provides. :slight_smile: To stay with the example from @rkallensee from above, this is your entity:

- type: entity
  entity: sensor.dwd_pollen_erle

I am now using a custom integration for it and it works perfectly GitHub - mampfes/hacs_dwd_pollenflug: Adds pollen forecasts from DWD to Home Assistant.

My hope was something nicer than just the entities with the Stat :). And I don’t know how to add the attribute for tomorrow. That’s why I ask. :slight_smile:

EDIT: Learning by doing :slight_smile: found a way with multiple entity row

:slight_smile: Then you should ask for that. :smiley: I answered your request for “a begin”.

But you seem to have found a starting point, that’s the important thing! FWIW here is a part of one of my configs to show the “Pollenbelastung” on one of my tablets.

# Lovelace view
- type: custom:stack-in-card
  mode: horizontal
  cards:
    - type: markdown
      content: >
        Birkenpollen
    - type: custom:bar-card
      entity: sensor.dwd_pollenbelastung_birke
      name: Heute
      height: 20px
      icon: none
      limit_value: true
      min: 0
      max: 6
      color: *color_lightgrey
      severity:
        - to: 0
          color: *color_lightgrey
        - from: 1
          to: 2
          color: *color_yellow
        - from: 3
          to: 4
          color: *color_orange
        - from: 5
          to: 6
          color: *color_red
      positions:
        name: inside
        indicator: off
        icon: off
        value: inside
    - type: custom:bar-card
      entity: sensor.dwd_pollenbelastung_birke_tomorrow
      name: Morgen
      height: 20px
      icon: none
      limit_value: true
      min: 0
      max: 6
      color: *color_lightgrey
      severity:
        - to: 0
          color: *color_lightgrey
        - from: 1
          to: 2
          color: *color_yellow
        - from: 3
          to: 4
          color: *color_orange
        - from: 5
          to: 6
          color: *color_red
      positions:
        name: inside
        indicator: off
        icon: off
        value: inside
- type: custom:stack-in-card
  mode: horizontal
  cards:
    - type: markdown
      content: >
        Gräserpollen
    - type: custom:bar-card
      entity: sensor.dwd_pollenbelastung_graeser
      name: Heute
      height: 20px
      icon: none
      limit_value: true
      min: 0
      max: 6
      color: *color_lightgrey
      severity:
        - to: 0
          color: *color_lightgrey
        - from: 1
          to: 2
          color: *color_yellow
        - from: 3
          to: 4
          color: *color_orange
        - from: 5
          to: 6
          color: *color_red
      positions:
        name: inside
        indicator: off
        icon: off
        value: inside
    - type: custom:bar-card
      entity: sensor.dwd_pollenbelastung_graeser_tomorrow
      name: Morgen
      height: 20px
      icon: none
      limit_value: true
      min: 0
      max: 6
      color: *color_lightgrey
      severity:
        - to: 0
          color: *color_lightgrey
        - from: 1
          to: 2
          color: *color_yellow
        - from: 3
          to: 4
          color: *color_orange
        - from: 5
          to: 6
          color: *color_red
      positions:
        name: inside
        indicator: off
        icon: off
        value: inside
- type: custom:stack-in-card
  mode: horizontal
  cards:
    - type: markdown
      content: >
        Haselpollen
    - type: custom:bar-card
      entity: sensor.dwd_pollenbelastung_hasel
      name: Heute
      height: 20px
      icon: none
      limit_value: true
      min: 0
      max: 6
      color: *color_lightgrey
      severity:
        - from: -1
          to: 0
          color: *color_lightgrey
        - from: 1
          to: 2
          color: *color_yellow
        - from: 3
          to: 4
          color: *color_orange
        - from: 5
          to: 6
          color: *color_red
      positions:
        name: inside
        indicator: off
        icon: off
        value: inside
    - type: custom:bar-card
      entity: sensor.dwd_pollenbelastung_hasel_tomorrow
      name: Morgen
      height: 20px
      icon: none
      limit_value: true
      min: 0
      max: 6
      color: *color_lightgrey
      severity:
        - from: -1
          to: 0
          color: *color_lightgrey
        - from: 1
          to: 2
          color: *color_yellow
        - from: 3
          to: 4
          color: *color_orange
        - from: 5
          to: 6
          color: *color_red
      positions:
        name: inside
        indicator: off
        icon: off
        value: inside
# template code
- platform: rest
  scan_interval: 3600
  name: "DWD Pollenbelastung"
  resource: https://opendata.dwd.de/climate_environment/health/alerts/s31fg.json
  json_attributes_path: "$..content[?(@.partregion_id==XXX)].Pollen"
  json_attributes:
    #- Erle
    #- Beifuss
    #- Ambrosia
    - Birke
    #- Esche
    - Hasel
    - Graeser
    #- Roggen
  value_template: "{{ value_json.last_update }}"
- platform: template
  sensors:
    dwd_pollenbelastung_birke:
      icon_template: "mdi:tree-outline"
      friendly_name: "Birke"
      value_template: >-
        {% set dwd_state = state_attr('sensor.dwd_pollenbelastung', 'Birke')['today'] %}
        {% if dwd_state == "3" %}6{% elif dwd_state == "2-3"%}5{% elif dwd_state == "2"%}4{% elif dwd_state == "1-2"%}3{% elif dwd_state == "1"%}2{% elif dwd_state == "0-1"%}1{% else %}0{% endif %}
      attribute_templates:
        today: >-
          {% set dwd_state = state_attr('sensor.dwd_pollenbelastung', 'Birke')['today'] %}
          {% if dwd_state == "3" %}6{% elif dwd_state == "2-3"%}5{% elif dwd_state == "2"%}4{% elif dwd_state == "1-2"%}3{% elif dwd_state == "1"%}2{% elif dwd_state == "0-1"%}1{% else %}0{% endif %}
        tomorrow: >-
          {% set dwd_state = state_attr('sensor.dwd_pollenbelastung', 'Birke')['tomorrow'] %}
          {% if dwd_state == "3" %}6{% elif dwd_state == "2-3"%}5{% elif dwd_state == "2"%}4{% elif dwd_state == "1-2"%}3{% elif dwd_state == "1"%}2{% elif dwd_state == "0-1"%}1{% else %}0{% endif %}
    dwd_pollenbelastung_hasel:
      icon_template: "mdi:tree-outline"
      friendly_name: "Hasel"
      value_template: >-
        {% set dwd_state = state_attr('sensor.dwd_pollenbelastung', 'Hasel')['today'] %}
        {% if dwd_state == "3" %}6{% elif dwd_state == "2-3"%}5{% elif dwd_state == "2"%}4{% elif dwd_state == "1-2"%}3{% elif dwd_state == "1"%}2{% elif dwd_state == "0-1"%}1{% else %}0{% endif %}
      attribute_templates:
        today: >-
          {% set dwd_state = state_attr('sensor.dwd_pollenbelastung', 'Hasel')['today'] %}
          {% if dwd_state == "3" %}6{% elif dwd_state == "2-3"%}5{% elif dwd_state == "2"%}4{% elif dwd_state == "1-2"%}3{% elif dwd_state == "1"%}2{% elif dwd_state == "0-1"%}1{% else %}0{% endif %}
        tomorrow: >-
          {% set dwd_state = state_attr('sensor.dwd_pollenbelastung', 'Hasel')['tomorrow'] %}
          {% if dwd_state == "3" %}6{% elif dwd_state == "2-3"%}5{% elif dwd_state == "2"%}4{% elif dwd_state == "1-2"%}3{% elif dwd_state == "1"%}2{% elif dwd_state == "0-1"%}1{% else %}0{% endif %}
    dwd_pollenbelastung_graeser:
      icon_template: "mdi:grass"
      friendly_name: "Gräser"
      value_template: >-
        {% set dwd_state = state_attr('sensor.dwd_pollenbelastung', 'Graeser')['today'] %}
        {% if dwd_state == "3" %}6{% elif dwd_state == "2-3"%}5{% elif dwd_state == "2"%}4{% elif dwd_state == "1-2"%}3{% elif dwd_state == "1"%}2{% elif dwd_state == "0-1"%}1{% else %}0{% endif %}
      attribute_templates:
        today: >-
          {% set dwd_state = state_attr('sensor.dwd_pollenbelastung', 'Graeser')['today'] %}
          {% if dwd_state == "3" %}6{% elif dwd_state == "2-3"%}5{% elif dwd_state == "2"%}4{% elif dwd_state == "1-2"%}3{% elif dwd_state == "1"%}2{% elif dwd_state == "0-1"%}1{% else %}0{% endif %}
        tomorrow: >-
          {% set dwd_state = state_attr('sensor.dwd_pollenbelastung', 'Graeser')['tomorrow'] %}
          {% if dwd_state == "3" %}6{% elif dwd_state == "2-3"%}5{% elif dwd_state == "2"%}4{% elif dwd_state == "1-2"%}3{% elif dwd_state == "1"%}2{% elif dwd_state == "0-1"%}1{% else %}0{% endif %}
    dwd_pollenbelastung_birke_tomorrow:
      icon_template: "mdi:tree-outline"
      friendly_name: "Birke Morgen"
      value_template: "{{ state_attr('sensor.dwd_pollenbelastung_birke', 'tomorrow') }}"
    dwd_pollenbelastung_hasel_tomorrow:
      icon_template: "mdi:tree-outline"
      friendly_name: "Hasel Morgen"
      value_template: "{{ state_attr('sensor.dwd_pollenbelastung_hasel', 'tomorrow') }}"
    dwd_pollenbelastung_graeser_tomorrow:
      icon_template: "mdi:grass"
      friendly_name: "Gräser Morgen"
      value_template: "{{ state_attr('sensor.dwd_pollenbelastung_graeser', 'tomorrow') }}"

This gives you six small bars to show today and tomorrow for the three different sensors (in my case Birke, Hael und Gräser). The bar gets coloured from green to red according to the value.

Looks like this (fortunately no values for today :+1: ):
ha_dwd_pollen_01

1 Like

I kinda want to share my janky (and unfinished) approach:

I use the hacs integration to get the entities and I integrate everything into the lovelace like this:
Screenshot 2021-11-16 154610

type: custom:vertical-stack-in-card
cards:
  - type: glance
    title: 'Pollenflug:'
    entities:
      - entity: sensor.pollenflug_ambrosia
      - entity: sensor.pollenflug_beifuss
      - entity: sensor.pollenflug_birke
      - entity: sensor.pollenflug_erle
    show_state: false
    state_color: true
  - type: glance
    entities:
      - entity: sensor.pollenflug_esche
      - entity: sensor.pollenflug_graeser
      - entity: sensor.pollenflug_hasel
      - entity: sensor.pollenflug_roggen
    state_color: true
    show_state: false

To get the custom icons I downloaded the plant icons as svgs from a different integration (for some scandinavian pollen card, but I dont know which one anymore. But thanks to that creator! Here a download for the people who like the icons). I extracted the svgs (added the rye and deleted the allergens that hat no matching sensor). Then I used the custom icon feature of the “Fontawesome icons” integration (created a Folder named “custom_icons” in the config and dropped the svgs in there).
Then I added the following lines in the customize.yaml:

sensor.pollenflug_ambrosia:
  icon: fapro:ambrosia
  templates:
    icon_color: >
      if (state === '0') return '#5ebf0f';
      if (state === '0.5') return '#a8bf0f';
      if (state === '1') return '#bfb10f';
      if (state === '1.5') return '#bf900f';
      if (state === '2') return '#bf730f';
      if (state === '2.5') return '#bf4a0f';
      if (state === '3') return '#bf0f0f';
sensor.pollenflug_beifuss:
  icon: fapro:beifuss
  templates:
    icon_color: >
      if (state === '0') return '#5ebf0f';
      if (state === '0.5') return '#a8bf0f';
      if (state === '1') return '#bfb10f';
      if (state === '1.5') return '#bf900f';
      if (state === '2') return '#bf730f';
      if (state === '2.5') return '#bf4a0f';
      if (state === '3') return '#bf0f0f';
sensor.pollenflug_birke:
  icon: fapro:birke
  templates:
    icon_color: >
      if (state === '0') return '#5ebf0f';
      if (state === '0.5') return '#a8bf0f';
      if (state === '1') return '#bfb10f';
      if (state === '1.5') return '#bf900f';
      if (state === '2') return '#bf730f';
      if (state === '2.5') return '#bf4a0f';
      if (state === '3') return '#bf0f0f';
sensor.pollenflug_erle:
  icon: fapro:erle
  templates:
    icon_color: >
      if (state === '0') return '#5ebf0f';
      if (state === '0.5') return '#a8bf0f';
      if (state === '1') return '#bfb10f';
      if (state === '1.5') return '#bf900f';
      if (state === '2') return '#bf730f';
      if (state === '2.5') return '#bf4a0f';
      if (state === '3') return '#bf0f0f';
sensor.pollenflug_esche:
  icon: fapro:esche
  templates:
    icon_color: >
      if (state === '0') return '#5ebf0f';
      if (state === '0.5') return '#a8bf0f';
      if (state === '1') return '#bfb10f';
      if (state === '1.5') return '#bf900f';
      if (state === '2') return '#bf730f';
      if (state === '2.5') return '#bf4a0f';
      if (state === '3') return '#bf0f0f';
sensor.pollenflug_graeser:
  icon: fapro:gras
  templates:
    icon_color: >
      if (state === '0') return '#5ebf0f';
      if (state === '0.5') return '#a8bf0f';
      if (state === '1') return '#bfb10f';
      if (state === '1.5') return '#bf900f';
      if (state === '2') return '#bf730f';
      if (state === '2.5') return '#bf4a0f';
      if (state === '3') return '#bf0f0f';
sensor.pollenflug_hasel:
  icon: fapro:hasel
  templates:
    icon_color: >
      if (state === '0') return '#5ebf0f';
      if (state === '0.5') return '#a8bf0f';
      if (state === '1') return '#bfb10f';
      if (state === '1.5') return '#bf900f';
      if (state === '2') return '#bf730f';
      if (state === '2.5') return '#bf4a0f';
      if (state === '3') return '#bf0f0f';
sensor.pollenflug_roggen:
  icon: fapro:roggen
  templates:
    icon_color: >
      if (state === '0') return '#5ebf0f';
      if (state === '0.5') return '#a8bf0f';
      if (state === '1') return '#bfb10f';
      if (state === '1.5') return '#bf900f';
      if (state === '2') return '#bf730f';
      if (state === '2.5') return '#bf4a0f';
      if (state === '3') return '#bf0f0f';

Maybe you can see now where it doesnt work as I hoped. Theoretically the icons should be colored in hues from green over yellow to red with pollen intensity but I couldn’t get the custom coloring to work.

I kinda put this project aside 'til maybe spring when pollen will become a problem, or until I stumble upon a solution. Maybe one of you can help me fix it.

Edit: you have to install custom-ui and remove one = from the code then it works (thanks MangoMC for the troubleshooting)

2 Likes

This is amazing!

1 Like

With my basic knowledge I think it’s a “=” too much :slight_smile:

1 Like

I got it to work, the only thing u need is install custom-ui from hacs and it works :smiley:

1 Like

🤦 Oh man what an oversight. Thanks for the tipp it now works for me as well