Skip to content

Commit

Permalink
Merge pull request #4 from jdejaegh/use_feature_value_belaqi
Browse files Browse the repository at this point in the history
Use FeatureValue for some BelAQI functions
  • Loading branch information
jdejaegh authored Jun 29, 2024
2 parents 45a72b9 + 169bcd2 commit 7fe28b7
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 21 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ async def get_current_belaqi():
position=(50.85, 4.35) # (lat, lon) for Brussels
)

print(f"Current BelAQI index for Brussels: {result}")
print(f"Current BelAQI index for Brussels: {result.get('value')}")


if __name__ == '__main__':
Expand Down
31 changes: 20 additions & 11 deletions src/open_irceline/belaqi.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from typing import Tuple, Dict, Final

from .api import IrcelineRioClient, IrcelineForecastClient
from .data import BelAqiIndex, RioFeature, ForecastFeature
from .data import BelAqiIndex, RioFeature, ForecastFeature, FeatureValue

# Ratio values from Figure 2 at
# https://www.irceline.be/en/air-quality/measurements/air-quality-index-november-2022/info_nov2022
Expand Down Expand Up @@ -117,7 +117,7 @@ def belaqi_index_hourly(pm10: float, pm25: float, o3: float, no2: float) -> BelA


async def belaqi_index_rio_hourly(rio_client: IrcelineRioClient, position: Tuple[float, float],
timestamp: datetime | None = None) -> BelAqiIndex:
timestamp: datetime | None = None) -> FeatureValue:
"""
Get current BelAQI index value for the given position using the rio_client
Raise ValueError if one or more components are not available
Expand All @@ -128,25 +128,30 @@ async def belaqi_index_rio_hourly(rio_client: IrcelineRioClient, position: Tuple
"""
if timestamp is None:
timestamp = datetime.utcnow()

features = [RioFeature.PM10_HMEAN, RioFeature.PM25_HMEAN, RioFeature.O3_HMEAN, RioFeature.NO2_HMEAN]

components = await rio_client.get_data(
timestamp=timestamp,
features=[RioFeature.PM10_HMEAN,
RioFeature.PM25_HMEAN,
RioFeature.O3_HMEAN,
RioFeature.NO2_HMEAN],
features=features,
position=position
)

return belaqi_index_hourly(
ts = min([components.get(f, {}).get('timestamp') for f in features
if components.get(f, {}).get('timestamp') is not None])

belaqi = belaqi_index_hourly(
pm10=components.get(RioFeature.PM10_HMEAN, {}).get('value', -1),
pm25=components.get(RioFeature.PM25_HMEAN, {}).get('value', -1),
o3=components.get(RioFeature.O3_HMEAN, {}).get('value', -1),
no2=components.get(RioFeature.NO2_HMEAN, {}).get('value', -1)
)

return FeatureValue(timestamp=ts, value=belaqi)


async def belaqi_index_forecast_daily(forecast_client: IrcelineForecastClient, position: Tuple[float, float],
timestamp: date | None = None) -> Dict[date, BelAqiIndex | None]:
timestamp: date | None = None) -> Dict[date, FeatureValue]:
"""
Get forecasted BelAQI index value for the given position using the forecast_client.
Data is downloaded for the given day and the four next days
Expand All @@ -169,15 +174,19 @@ async def belaqi_index_forecast_daily(forecast_client: IrcelineForecastClient, p

result = dict()

for _, day in components.keys():
days = {day for _, day in components.keys()}
timestamps = {v.get('timestamp') for v in components.values() if v.get('timestamp') is not None}
timestamp = min(timestamps)
for day in days:
try:
result[day] = belaqi_index_daily(
belaqi = belaqi_index_daily(
pm10=components.get((ForecastFeature.PM10_DMEAN, day), {}).get('value', -1),
pm25=components.get((ForecastFeature.PM25_DMEAN, day), {}).get('value', -1),
o3=components.get((ForecastFeature.O3_MAXHMEAN, day), {}).get('value', -1) * O3_MAX_HMEAN_TO_MAX8HMEAN,
no2=components.get((ForecastFeature.NO2_MAXHMEAN, day), {}).get('value', -1) * NO2_MAX_HMEAN_TO_DMEAN
)
result[day] = FeatureValue(timestamp=timestamp, value=belaqi)
except (ValueError, TypeError):
result[day] = None
result[day] = FeatureValue(timestamp=timestamp, value=None)

return result
12 changes: 6 additions & 6 deletions src/open_irceline/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,6 @@ class ForecastFeature(IrcelineFeature):
PM25_DMEAN = 'chimere_pm25_dmean'


class FeatureValue(TypedDict):
# Timestamp at which the value was computed
timestamp: datetime | date
value: int | float | None


class BelAqiIndex(Enum):
EXCELLENT = 1
VERY_GOOD = 2
Expand All @@ -54,3 +48,9 @@ class BelAqiIndex(Enum):
BAD = 8
VERY_BAD = 9
HORRIBLE = 10


class FeatureValue(TypedDict):
# Timestamp at which the value was computed
timestamp: datetime | date
value: int | float | BelAqiIndex | None
6 changes: 3 additions & 3 deletions tests/test_belaqi.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ async def test_belaqi_index_forecast():

assert set(result.keys()) == expected_days
for v in result.values():
assert v == BelAqiIndex.MODERATE
assert v.get('value') == BelAqiIndex.MODERATE


async def test_belaqi_index_forecast_missing_day():
Expand All @@ -244,7 +244,7 @@ async def test_belaqi_index_forecast_missing_day():
expected_days = {date(2024, 6, 21) + timedelta(days=i) for i in range(5)}
assert set(result.keys()) == expected_days
for v in result.values():
assert v is None
assert v.get('value') is None


@freeze_time(datetime.fromisoformat("2024-06-23T12:30:09.581Z"))
Expand All @@ -254,7 +254,7 @@ async def test_belaqi_index_actual():
pos = (50.55, 4.85)

result = await belaqi_index_rio_hourly(client, pos)
assert result == BelAqiIndex.GOOD
assert result.get('value') == BelAqiIndex.GOOD


@freeze_time(datetime.fromisoformat("2024-06-23T12:30:09.581Z"))
Expand Down

0 comments on commit 7fe28b7

Please sign in to comment.