mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 15:17:35 +00:00
Parse AirNow observation timezone correctly (#122006)
Parse observation timezone correctly Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
This commit is contained in:
parent
bd3efe57f7
commit
705af35dd6
@ -14,10 +14,32 @@ ATTR_API_POLLUTANT = "Pollutant"
|
|||||||
ATTR_API_REPORT_DATE = "DateObserved"
|
ATTR_API_REPORT_DATE = "DateObserved"
|
||||||
ATTR_API_REPORT_HOUR = "HourObserved"
|
ATTR_API_REPORT_HOUR = "HourObserved"
|
||||||
ATTR_API_REPORT_TZ = "LocalTimeZone"
|
ATTR_API_REPORT_TZ = "LocalTimeZone"
|
||||||
ATTR_API_REPORT_TZINFO = "LocalTimeZoneInfo"
|
|
||||||
ATTR_API_STATE = "StateCode"
|
ATTR_API_STATE = "StateCode"
|
||||||
ATTR_API_STATION = "ReportingArea"
|
ATTR_API_STATION = "ReportingArea"
|
||||||
ATTR_API_STATION_LATITUDE = "Latitude"
|
ATTR_API_STATION_LATITUDE = "Latitude"
|
||||||
ATTR_API_STATION_LONGITUDE = "Longitude"
|
ATTR_API_STATION_LONGITUDE = "Longitude"
|
||||||
DEFAULT_NAME = "AirNow"
|
DEFAULT_NAME = "AirNow"
|
||||||
DOMAIN = "airnow"
|
DOMAIN = "airnow"
|
||||||
|
|
||||||
|
SECONDS_PER_HOUR = 3600
|
||||||
|
|
||||||
|
# AirNow seems to only use standard time zones,
|
||||||
|
# but we include daylight savings for completeness/futureproofing.
|
||||||
|
US_TZ_OFFSETS = {
|
||||||
|
"HST": -10 * SECONDS_PER_HOUR,
|
||||||
|
"HDT": -9 * SECONDS_PER_HOUR,
|
||||||
|
# AirNow returns AKT instead of AKST or AKDT, use standard
|
||||||
|
"AKT": -9 * SECONDS_PER_HOUR,
|
||||||
|
"AKST": -9 * SECONDS_PER_HOUR,
|
||||||
|
"AKDT": -8 * SECONDS_PER_HOUR,
|
||||||
|
"PST": -8 * SECONDS_PER_HOUR,
|
||||||
|
"PDT": -7 * SECONDS_PER_HOUR,
|
||||||
|
"MST": -7 * SECONDS_PER_HOUR,
|
||||||
|
"MDT": -6 * SECONDS_PER_HOUR,
|
||||||
|
"CST": -6 * SECONDS_PER_HOUR,
|
||||||
|
"CDT": -5 * SECONDS_PER_HOUR,
|
||||||
|
"EST": -5 * SECONDS_PER_HOUR,
|
||||||
|
"EDT": -4 * SECONDS_PER_HOUR,
|
||||||
|
"AST": -4 * SECONDS_PER_HOUR,
|
||||||
|
"ADT": -3 * SECONDS_PER_HOUR,
|
||||||
|
}
|
||||||
|
@ -12,7 +12,6 @@ from pyairnow.errors import AirNowError
|
|||||||
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||||
from homeassistant.util import dt as dt_util
|
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
ATTR_API_AQI,
|
ATTR_API_AQI,
|
||||||
@ -27,7 +26,6 @@ from .const import (
|
|||||||
ATTR_API_REPORT_DATE,
|
ATTR_API_REPORT_DATE,
|
||||||
ATTR_API_REPORT_HOUR,
|
ATTR_API_REPORT_HOUR,
|
||||||
ATTR_API_REPORT_TZ,
|
ATTR_API_REPORT_TZ,
|
||||||
ATTR_API_REPORT_TZINFO,
|
|
||||||
ATTR_API_STATE,
|
ATTR_API_STATE,
|
||||||
ATTR_API_STATION,
|
ATTR_API_STATION,
|
||||||
ATTR_API_STATION_LATITUDE,
|
ATTR_API_STATION_LATITUDE,
|
||||||
@ -98,9 +96,7 @@ class AirNowDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
|||||||
# Copy Report Details
|
# Copy Report Details
|
||||||
data[ATTR_API_REPORT_DATE] = obv[ATTR_API_REPORT_DATE]
|
data[ATTR_API_REPORT_DATE] = obv[ATTR_API_REPORT_DATE]
|
||||||
data[ATTR_API_REPORT_HOUR] = obv[ATTR_API_REPORT_HOUR]
|
data[ATTR_API_REPORT_HOUR] = obv[ATTR_API_REPORT_HOUR]
|
||||||
data[ATTR_API_REPORT_TZINFO] = await dt_util.async_get_time_zone(
|
data[ATTR_API_REPORT_TZ] = obv[ATTR_API_REPORT_TZ]
|
||||||
obv[ATTR_API_REPORT_TZ]
|
|
||||||
)
|
|
||||||
|
|
||||||
# Copy Station Details
|
# Copy Station Details
|
||||||
data[ATTR_API_STATE] = obv[ATTR_API_STATE]
|
data[ATTR_API_STATE] = obv[ATTR_API_STATE]
|
||||||
|
@ -4,9 +4,10 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import datetime
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
from dateutil import parser
|
||||||
|
|
||||||
from homeassistant.components.sensor import (
|
from homeassistant.components.sensor import (
|
||||||
SensorDeviceClass,
|
SensorDeviceClass,
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
@ -34,12 +35,13 @@ from .const import (
|
|||||||
ATTR_API_PM25,
|
ATTR_API_PM25,
|
||||||
ATTR_API_REPORT_DATE,
|
ATTR_API_REPORT_DATE,
|
||||||
ATTR_API_REPORT_HOUR,
|
ATTR_API_REPORT_HOUR,
|
||||||
ATTR_API_REPORT_TZINFO,
|
ATTR_API_REPORT_TZ,
|
||||||
ATTR_API_STATION,
|
ATTR_API_STATION,
|
||||||
ATTR_API_STATION_LATITUDE,
|
ATTR_API_STATION_LATITUDE,
|
||||||
ATTR_API_STATION_LONGITUDE,
|
ATTR_API_STATION_LONGITUDE,
|
||||||
DEFAULT_NAME,
|
DEFAULT_NAME,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
US_TZ_OFFSETS,
|
||||||
)
|
)
|
||||||
|
|
||||||
ATTRIBUTION = "Data provided by AirNow"
|
ATTRIBUTION = "Data provided by AirNow"
|
||||||
@ -69,6 +71,18 @@ def station_extra_attrs(data: dict[str, Any]) -> dict[str, Any]:
|
|||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
def aqi_extra_attrs(data: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
"""Process extra attributes for main AQI sensor."""
|
||||||
|
return {
|
||||||
|
ATTR_DESCR: data[ATTR_API_AQI_DESCRIPTION],
|
||||||
|
ATTR_LEVEL: data[ATTR_API_AQI_LEVEL],
|
||||||
|
ATTR_TIME: parser.parse(
|
||||||
|
f"{data[ATTR_API_REPORT_DATE]} {data[ATTR_API_REPORT_HOUR]}:00 {data[ATTR_API_REPORT_TZ]}",
|
||||||
|
tzinfos=US_TZ_OFFSETS,
|
||||||
|
).isoformat(),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
SENSOR_TYPES: tuple[AirNowEntityDescription, ...] = (
|
SENSOR_TYPES: tuple[AirNowEntityDescription, ...] = (
|
||||||
AirNowEntityDescription(
|
AirNowEntityDescription(
|
||||||
key=ATTR_API_AQI,
|
key=ATTR_API_AQI,
|
||||||
@ -76,16 +90,7 @@ SENSOR_TYPES: tuple[AirNowEntityDescription, ...] = (
|
|||||||
state_class=SensorStateClass.MEASUREMENT,
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
device_class=SensorDeviceClass.AQI,
|
device_class=SensorDeviceClass.AQI,
|
||||||
value_fn=lambda data: data.get(ATTR_API_AQI),
|
value_fn=lambda data: data.get(ATTR_API_AQI),
|
||||||
extra_state_attributes_fn=lambda data: {
|
extra_state_attributes_fn=aqi_extra_attrs,
|
||||||
ATTR_DESCR: data[ATTR_API_AQI_DESCRIPTION],
|
|
||||||
ATTR_LEVEL: data[ATTR_API_AQI_LEVEL],
|
|
||||||
ATTR_TIME: datetime.strptime(
|
|
||||||
f"{data[ATTR_API_REPORT_DATE]} {data[ATTR_API_REPORT_HOUR]}",
|
|
||||||
"%Y-%m-%d %H",
|
|
||||||
)
|
|
||||||
.replace(tzinfo=data[ATTR_API_REPORT_TZINFO])
|
|
||||||
.isoformat(),
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
AirNowEntityDescription(
|
AirNowEntityDescription(
|
||||||
key=ATTR_API_PM10,
|
key=ATTR_API_PM10,
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
'DateObserved': '2020-12-20',
|
'DateObserved': '2020-12-20',
|
||||||
'HourObserved': 15,
|
'HourObserved': 15,
|
||||||
'Latitude': '**REDACTED**',
|
'Latitude': '**REDACTED**',
|
||||||
'LocalTimeZoneInfo': 'PST',
|
'LocalTimeZone': 'PST',
|
||||||
'Longitude': '**REDACTED**',
|
'Longitude': '**REDACTED**',
|
||||||
'O3': 0.048,
|
'O3': 0.048,
|
||||||
'PM10': 12,
|
'PM10': 12,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user