mirror of
https://github.com/jdejaegh/irm-kmi-ha.git
synced 2025-06-27 19:49:26 +02:00
Compare commits
No commits in common. "b78c8a6779601a55f00b2577cda9af43dbc5c9f2" and "082770f480959506d238d8328d28a245718be5d2" have entirely different histories.
b78c8a6779
...
082770f480
7 changed files with 6 additions and 98 deletions
|
@ -12,5 +12,5 @@
|
||||||
"svgwrite==1.4.3",
|
"svgwrite==1.4.3",
|
||||||
"aiofile==3.9.0"
|
"aiofile==3.9.0"
|
||||||
],
|
],
|
||||||
"version": "0.2.26"
|
"version": "0.2.25"
|
||||||
}
|
}
|
|
@ -11,8 +11,8 @@ _LOGGER = logging.getLogger(__name__)
|
||||||
class PollenParser:
|
class PollenParser:
|
||||||
"""
|
"""
|
||||||
Extract pollen level from an SVG provided by the IRM KMI API.
|
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 or the dot on the color scale.
|
To get the data, match pollen names and pollen levels that are vertically aligned. Then, map the value to the
|
||||||
Then, map the value to the corresponding color on the scale.
|
corresponding color on the scale.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
|
@ -70,40 +70,9 @@ class PollenParser:
|
||||||
pollen_levels = {e.attrib.get('x', None): POLLEN_LEVEL_TO_COLOR[self._get_elem_text(e)]
|
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}
|
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():
|
for position, pollen in pollens.items():
|
||||||
# Determine pollen level based on text
|
|
||||||
if position is not None and position in pollen_levels:
|
if position is not None and position in pollen_levels:
|
||||||
pollen_data[pollen] = pollen_levels[position]
|
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}")
|
_LOGGER.debug(f"Pollen data: {pollen_data}")
|
||||||
return pollen_data
|
return pollen_data
|
||||||
|
|
BIN
img/pollens.png
BIN
img/pollens.png
Binary file not shown.
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 87 KiB |
|
@ -1,6 +1,6 @@
|
||||||
aiohttp==3.11.11
|
aiohttp==3.11.11
|
||||||
async-timeout==4.0.3
|
async-timeout==4.0.3
|
||||||
homeassistant==2025.1.4
|
homeassistant==2024.12.5
|
||||||
voluptuous==0.15.2
|
voluptuous==0.15.2
|
||||||
svgwrite==1.4.3
|
svgwrite==1.4.3
|
||||||
aiofile==3.9.0
|
aiofile==3.9.0
|
|
@ -1,5 +1,5 @@
|
||||||
homeassistant==2025.1.4
|
homeassistant==2024.12.5
|
||||||
pytest_homeassistant_custom_component==0.13.205
|
pytest_homeassistant_custom_component==0.13.195
|
||||||
pytest
|
pytest
|
||||||
freezegun
|
freezegun
|
||||||
isort
|
isort
|
55
tests/fixtures/pollens-2025.svg
vendored
55
tests/fixtures/pollens-2025.svg
vendored
|
@ -1,55 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<svg viewBox="35 88 129.0 50.0" version="1.1" id="svg740" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<defs id="defs737"/>
|
|
||||||
<g id="layer1">
|
|
||||||
<rect id="rectangle-white" x="35" y="88" width="129.0" height="50.0" rx="5" fill="grey" fill-opacity="1"/>
|
|
||||||
<g id="g1495" transform="translate(30.342966,94.25)">
|
|
||||||
<g id="layer1-2">
|
|
||||||
<ellipse style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583" id="path268" cx="13.312511" cy="0.0"
|
|
||||||
rx="1.6348698" ry="1.5258785"/>
|
|
||||||
<ellipse style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583" id="path272" cx="16.208567"
|
|
||||||
cy="1.463598" rx="1.1366237" ry="1.1366239"/>
|
|
||||||
<rect style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583" id="rect326" width="0.79407966"
|
|
||||||
height="3.5655735" x="12.923257" y="1.401318"/>
|
|
||||||
<rect style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583" id="rect328" width="0.68508834"
|
|
||||||
height="2.5535111" x="15.866023" y="2.36669"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
<text xml:space="preserve"
|
|
||||||
style="font-family:Arial,Helvetica,sans-serif;font-size:6.0px;fill:#ffffff;stroke-width:0.264583"
|
|
||||||
x="54.476421" y="98.75" id="text228"><tspan id="tspan226" style="fill:#ffffff;stroke-width:0.264583" x="54.476421" y="98.75">Active pollen</tspan></text>
|
|
||||||
<text xml:space="preserve"
|
|
||||||
style="font-family:Arial,Helvetica,sans-serif;font-size:6.0px;fill:#ffffff;stroke-width:0.264583"
|
|
||||||
x="139.37601" y="98.75" id="text334"><tspan id="tspan332" style="stroke-width:0.264583" x="139.37601" y="98.75"/></text>
|
|
||||||
<rect style="fill:#607eaa;stroke-width:0.264583" id="rect392" width="127.80161" height="0.44039145"
|
|
||||||
x="35.451504" y="105.5"/>
|
|
||||||
<g transform="translate(36.0,120.0) scale(0.4,0.4)">
|
|
||||||
<path d="M138.65 33.5C140.5 33.5 142.017 31.9964 141.833 30.1555C141.065 22.499 137.677 15.3011 132.188 9.81192C125.906 3.52946 117.385 6.7078e-07 108.5 0C99.6153 -6.7078e-07 91.0944 3.52945 84.8119 9.81192C79.3228 15.3011 75.9352 22.499 75.1673 30.1555C74.9826 31.9964 76.4998 33.5 78.35 33.5V33.5C80.2002 33.5 81.6784 31.9943 81.909 30.1586C82.6472 24.2828 85.3177 18.7814 89.5495 14.5495C94.5755 9.52356 101.392 6.7 108.5 6.7C115.608 6.7 122.424 9.52356 127.45 14.5495C131.682 18.7814 134.353 24.2828 135.091 30.1586C135.322 31.9943 136.8 33.5 138.65 33.5V33.5Z"
|
|
||||||
fill="#70AC48" id="path12394"/>
|
|
||||||
<path d="M138.65 33.5C140.5 33.5 142.017 31.9964 141.832 30.1555C141.242 24.271 139.101 18.6259 135.602 13.8092C131.443 8.0858 125.58 3.82575 118.852 1.63961C112.123 -0.546536 104.876 -0.546535 98.1475 1.63961C91.4192 3.82575 85.5558 8.0858 81.3975 13.8092L86.8179 17.7474C90.1445 13.1686 94.8353 9.7606 100.218 8.01168C105.6 6.26277 111.399 6.26277 116.781 8.01168C122.164 9.7606 126.855 13.1686 130.181 17.7474C132.849 21.4187 134.529 25.6916 135.09 30.1586C135.321 31.9943 136.799 33.5 138.65 33.5V33.5Z"
|
|
||||||
fill="#FED966" id="path12396"/>
|
|
||||||
<path d="M138.65 33.5C140.5 33.5 142.017 31.9964 141.832 30.1555C141.418 26.0285 140.24 22.0042 138.348 18.2913C135.948 13.5809 132.467 9.50535 128.19 6.39793C123.913 3.29052 118.962 1.23946 113.74 0.412444C108.519 -0.414569 103.175 0.00594664 98.1475 1.63961L100.218 8.01169C104.24 6.70476 108.515 6.36834 112.692 7.02995C116.869 7.69157 120.831 9.33242 124.252 11.8183C127.674 14.3043 130.458 17.5647 132.379 21.3331C133.79 24.1034 134.705 27.0904 135.09 30.1587C135.321 31.9944 136.799 33.5 138.65 33.5V33.5Z"
|
|
||||||
fill="#EE7D31" id="path12398"/>
|
|
||||||
<path d="M138.65 33.5C140.5 33.5 142.017 31.9965 141.832 30.1555C141.242 24.271 139.101 18.626 135.602 13.8092C131.443 8.08584 125.58 3.82579 118.852 1.63965L116.781 8.01173C122.164 9.76064 126.855 13.1687 130.181 17.7474C132.849 21.4188 134.529 25.6917 135.091 30.1587C135.321 31.9944 136.799 33.5 138.65 33.5V33.5Z"
|
|
||||||
fill="#C00000" id="path12400"/>
|
|
||||||
<path d="M138.65 33.4999C140.5 33.4999 142.017 31.9963 141.833 30.1554C141.242 24.2709 139.102 18.6258 135.602 13.8091L130.182 17.7472C132.849 21.4186 134.53 25.6915 135.091 30.1585C135.322 31.9942 136.8 33.4999 138.65 33.4999V33.4999Z"
|
|
||||||
fill="#70309F" id="path12402"/>
|
|
||||||
<path d="M239.65 33.5C241.5 33.5 243.017 31.9964 242.833 30.1555C242.065 22.499 238.677 15.3011 233.188 9.81192C226.906 3.52946 218.385 6.7078e-07 209.5 0C200.615 -6.7078e-07 192.094 3.52945 185.812 9.81192C180.323 15.3011 176.935 22.499 176.167 30.1555C175.983 31.9964 177.5 33.5 179.35 33.5V33.5C181.2 33.5 182.678 31.9943 182.909 30.1586C183.647 24.2828 186.318 18.7814 190.55 14.5495C195.576 9.52356 202.392 6.7 209.5 6.7C216.608 6.7 223.424 9.52356 228.45 14.5495C232.682 18.7814 235.353 24.2828 236.091 30.1586C236.322 31.9943 237.8 33.5 239.65 33.5V33.5Z"
|
|
||||||
fill="#cccccc" id="path12404"/>
|
|
||||||
<path d="M239.65 33.5C241.5 33.5 243.017 31.9964 242.832 30.1555C242.242 24.271 240.101 18.6259 236.602 13.8092C232.443 8.0858 226.58 3.82575 219.852 1.63961C213.123 -0.546536 205.876 -0.546535 199.147 1.63961C192.419 3.82575 186.556 8.0858 182.397 13.8092L187.818 17.7474C191.145 13.1686 195.835 9.7606 201.218 8.01168C206.6 6.26277 212.399 6.26277 217.781 8.01168C223.164 9.7606 227.855 13.1686 231.181 17.7474C233.849 21.4187 235.529 25.6916 236.09 30.1586C236.321 31.9943 237.799 33.5 239.65 33.5V33.5Z"
|
|
||||||
fill="#cccccc" id="path12406"/>
|
|
||||||
<path d="M239.65 33.5C241.5 33.5 243.017 31.9964 242.832 30.1555C242.418 26.0285 241.24 22.0042 239.348 18.2913C236.948 13.5809 233.467 9.50535 229.19 6.39793C224.913 3.29052 219.962 1.23946 214.74 0.412444C209.519 -0.414569 204.175 0.00594664 199.147 1.63961L201.218 8.01169C205.24 6.70476 209.515 6.36834 213.692 7.02995C217.869 7.69157 221.831 9.33242 225.252 11.8183C228.674 14.3043 231.458 17.5647 233.379 21.3331C234.79 24.1034 235.705 27.0904 236.09 30.1587C236.321 31.9944 237.799 33.5 239.65 33.5V33.5Z"
|
|
||||||
fill="#cccccc" id="path12408"/>
|
|
||||||
<path d="M239.65 33.5C241.5 33.5 243.017 31.9965 242.832 30.1555C242.242 24.271 240.101 18.626 236.602 13.8092C232.443 8.08584 226.58 3.82579 219.852 1.63965L217.781 8.01173C223.164 9.76064 227.855 13.1687 231.181 17.7474C233.849 21.4188 235.529 25.6917 236.091 30.1587C236.321 31.9944 237.799 33.5 239.65 33.5V33.5Z"
|
|
||||||
fill="#cccccc" id="path12410"/>
|
|
||||||
<path d="M239.65 33.4999C241.5 33.4999 243.017 31.9963 242.833 30.1554C242.242 24.2709 240.102 18.6258 236.602 13.8091L231.182 17.7472C233.849 21.4186 235.53 25.6915 236.091 30.1585C236.322 31.9942 237.8 33.4999 239.65 33.4999V33.4999Z"
|
|
||||||
fill="#cccccc" id="path12412"/>
|
|
||||||
<text xml:space="preserve" id="text12907"><tspan id="tspan12905" x="109.0" y="33.7" style="font-family:Arial,Helvetica,sans-serif;font-size:10px;text-align:center;text-anchor:middle;fill:#cccccc"> active</tspan></text>
|
|
||||||
<text xml:space="preserve" id="text13637"><tspan id="tspan13635" x="209.0" y="33.7" style="font-family:Arial,Helvetica,sans-serif;font-size:10px;text-align:center;text-anchor:middle;fill:#cccccc"> active</tspan></text>
|
|
||||||
<text xml:space="preserve" id="text13641"><tspan id="tspan13639" x="109.0" y="-15.0" style="font-family:Arial,Helvetica,sans-serif;font-size:14px;text-align:center;text-anchor:middle;fill:#ffffff"> Alder</tspan></text>
|
|
||||||
<text xml:space="preserve" id="text13645"><tspan id="tspan13643" x="209.0" y="-15.0" style="font-family:Arial,Helvetica,sans-serif;font-size:14px;text-align:center;text-anchor:middle;fill:#ffffff"> Hazel</tspan></text>
|
|
||||||
<circle style="fill:#ffffff" id="cursor1" cx="79.99277625299781" cy="24.274981671564106" r="4.0"/>
|
|
||||||
<circle style="fill:#ffffff" id="cursor2" cx="-99999999" cy="-99999999" r="4.0"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 7.8 KiB |
|
@ -22,12 +22,6 @@ def test_svg_two_pollen_parsing():
|
||||||
assert data == {'birch': 'none', 'oak': 'none', 'hazel': 'none', 'mugwort': 'active', 'alder': 'none',
|
assert data == {'birch': 'none', 'oak': 'none', 'hazel': 'none', 'mugwort': 'active', 'alder': 'none',
|
||||||
'grasses': 'red', 'ash': '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():
|
def test_pollen_options():
|
||||||
assert set(PollenParser.get_option_values()) == {'green', 'yellow', 'orange', 'red', 'purple', 'active', 'none'}
|
assert set(PollenParser.get_option_values()) == {'green', 'yellow', 'orange', 'red', 'purple', 'active', 'none'}
|
||||||
|
|
Loading…
Add table
Reference in a new issue