Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix pollen data parsing #70

Merged
merged 3 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 33 additions & 2 deletions custom_components/irm_kmi/pollen.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
class PollenParser:
"""
Extract pollen level from an SVG provided by the IRM KMI API.
To get the data, match pollen names and pollen levels that are vertically aligned. Then, map the value to the
corresponding color on the scale.
To get the data, match pollen names and pollen levels that are vertically aligned or the dot on the color scale.
Then, map the value to the corresponding color on the scale.
"""

def __init__(
Expand Down Expand Up @@ -70,9 +70,40 @@ def get_pollen_data(self) -> dict:
pollen_levels = {e.attrib.get('x', None): POLLEN_LEVEL_TO_COLOR[self._get_elem_text(e)]
for e in elements if 'tspan' in e.tag and self._get_elem_text(e) in POLLEN_LEVEL_TO_COLOR}

level_dots = {e.attrib.get('cx', None) for e in elements if 'circle' in e.tag}
print(level_dots)

# For each pollen name found, check the text just below.
# As of January 2025, the text is always 'active' and the dot shows the real level
# If text says 'active', check the dot; else trust the text
for position, pollen in pollens.items():
# Determine pollen level based on text
if position is not None and position in pollen_levels:
pollen_data[pollen] = pollen_levels[position]
print(f"{pollen} is {pollen_data[pollen]} according to text")

# If text is 'active' or if there is no text, check the dot as a fallback
if pollen_data[pollen] not in {'none', 'active'}:
_LOGGER.debug(f"{pollen} trusting text")
else:
for dot in level_dots:
try:
relative_x_position = float(position) - float(dot)
except TypeError:
pass
else:
if 24 <= relative_x_position <= 34:
pollen_data[pollen] = 'green'
elif 13 <= relative_x_position <= 23:
pollen_data[pollen] = 'yellow'
elif -5 <= relative_x_position <= 5:
pollen_data[pollen] = 'orange'
elif -23 <= relative_x_position <= -13:
pollen_data[pollen] = 'red'
elif -34 <= relative_x_position <= -24:
pollen_data[pollen] = 'purple'

_LOGGER.debug(f"{pollen} is {pollen_data[pollen]} according to dot")

_LOGGER.debug(f"Pollen data: {pollen_data}")
return pollen_data
Binary file modified img/pollens.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
aiohttp==3.11.11
async-timeout==4.0.3
homeassistant==2024.12.5
homeassistant==2025.1.4
voluptuous==0.15.2
svgwrite==1.4.3
aiofile==3.9.0
4 changes: 2 additions & 2 deletions requirements_tests.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
homeassistant==2024.12.5
pytest_homeassistant_custom_component==0.13.195
homeassistant==2025.1.4
pytest_homeassistant_custom_component==0.13.205
pytest
freezegun
isort
55 changes: 55 additions & 0 deletions tests/fixtures/pollens-2025.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions tests/test_pollen.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ def test_svg_two_pollen_parsing():
assert data == {'birch': 'none', 'oak': 'none', 'hazel': 'none', 'mugwort': 'active', 'alder': 'none',
'grasses': 'red', 'ash': 'none'}

def test_svg_two_pollen_parsing_2025_update():
with open("tests/fixtures/pollens-2025.svg", "r") as file:
svg_data = file.read()
data = PollenParser(svg_data).get_pollen_data()
assert data == {'birch': 'none', 'oak': 'none', 'hazel': 'active', 'mugwort': 'none', 'alder': 'green',
'grasses': 'none', 'ash': 'none'}

def test_pollen_options():
assert set(PollenParser.get_option_values()) == {'green', 'yellow', 'orange', 'red', 'purple', 'active', 'none'}
Expand Down