diff --git a/custom_components/irm_kmi/pollen.py b/custom_components/irm_kmi/pollen.py index 2a461ca..0131412 100644 --- a/custom_components/irm_kmi/pollen.py +++ b/custom_components/irm_kmi/pollen.py @@ -11,8 +11,8 @@ _LOGGER = logging.getLogger(__name__) 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__( @@ -70,9 +70,40 @@ class PollenParser: 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 diff --git a/img/pollens.png b/img/pollens.png index e786a94..611d5fd 100644 Binary files a/img/pollens.png and b/img/pollens.png differ diff --git a/requirements.txt b/requirements.txt index 3aee243..caa27a4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -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 \ No newline at end of file diff --git a/requirements_tests.txt b/requirements_tests.txt index 1e11992..8ca13d0 100644 --- a/requirements_tests.txt +++ b/requirements_tests.txt @@ -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 \ No newline at end of file diff --git a/tests/fixtures/pollens-2025.svg b/tests/fixtures/pollens-2025.svg new file mode 100644 index 0000000..b2d6ecc --- /dev/null +++ b/tests/fixtures/pollens-2025.svg @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + Active pollen + + + + + + + + + + + + + + active + active + Alder + Hazel + + + + + diff --git a/tests/test_pollen.py b/tests/test_pollen.py index 19bd81c..c705da0 100644 --- a/tests/test_pollen.py +++ b/tests/test_pollen.py @@ -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'}