Skip to content

Commit

Permalink
Merge pull request #25 from StevenLooman/master
Browse files Browse the repository at this point in the history
Don't go to unknown state when update fails + add template example
  • Loading branch information
gieljnssns authored Aug 10, 2021
2 parents 70ad1d3 + 58d9757 commit 42dcb0b
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 45 deletions.
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ sensor:
- next_rain_forecast
```
Your sensors default name will be sensor.ba_{monitored_condition}
Your sensors default name will be `sensor.buienalarm_{monitored_condition}`.

You can provide a timeframe: Minutes to look ahead for precipitation forecast (min: 5 / max: 120) - Default value: 60

Expand All @@ -24,3 +24,21 @@ values for next_rain_forecast can be:
- Unknown: No rain forecast within timeframe
- 0: It is currently raining
- N: Rain is forecasted within N minutes


## Next rain forecast in minutes

The `buienalarm_next_rain_forecast` sensor returns a date/time of the next rain forecast. To get the time-in-minutes to the next rain forecast a template sensor can be used. Add this template sensor to your configuration:

```yaml
template:
- sensor:
- name: "Buienalarm Next rain forecast (min)"
unit_of_measurement: "min"
state: >
{% if as_timestamp(states('sensor.buienalarm_next_rain_forecast')) %}
{{ ( ( as_timestamp(states('sensor.buienalarm_next_rain_forecast')) - as_timestamp(now()) ) / 60 ) | round }}
{% else %}
{{ states('nonexistent') }}
{% endif %}
```
29 changes: 16 additions & 13 deletions custom_components/buienalarm/const.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,28 @@
"""Support for Buienalarm weather service."""

import logging
from datetime import timedelta
from typing import NamedTuple
import logging

from homeassistant.const import (
TEMP_CELSIUS,
LENGTH_MILLIMETERS,
TIME_MINUTES,
)
from homeassistant.const import LENGTH_MILLIMETERS, TEMP_CELSIUS

SensorType = NamedTuple(
"SensorType",
[
("name", str),
("unit", str),
("icon", str),
])
],
)


LOGGER = logging.getLogger(__package__)
UPDATE_INTERVAL = timedelta(seconds=300)
ATTRIBUTION = "Data provided by Buienalarm B.V."
DEFAULT_TIMEFRAME = 60
DEFAULT_NAME = "ba"
ICON_THERMOMETER = "mdi:thermometer"
ICON_WEATHER_POURING = "mdi:weather-pouring"
ITEM_TEMP = "temperature"
ITEM_PRECIP_NOW = "precipitation"
ITEM_PRECIP_FORECAST_AVG = "precipitation_forecast_average"
Expand All @@ -33,23 +32,27 @@
ITEM_TEMP: SensorType(
"Temperature",
TEMP_CELSIUS,
"mdi:thermometer"),
ICON_THERMOMETER),
ITEM_PRECIP_NOW: SensorType(
"Precipitation",
LENGTH_MILLIMETERS + "/h",
"mdi:weather-pouring"),
ICON_WEATHER_POURING
),
ITEM_PRECIP_FORECAST_AVG: SensorType(
"Precipitation forecast average",
LENGTH_MILLIMETERS + "/h",
"mdi:weather-pouring"),
ICON_WEATHER_POURING,
),
ITEM_PRECIP_FORECAST_TOTAL: SensorType(
"Precipitation forecast total",
LENGTH_MILLIMETERS,
"mdi:weather-pouring"),
ICON_WEATHER_POURING
),
ITEM_NEXT_RAIN_FORECAST: SensorType(
"Next rain forecast",
TIME_MINUTES,
"mdi:weather-pouring"),
None,
ICON_WEATHER_POURING
),
}
CONF_TIMEFRAME = "timeframe"
CONF_CONDITION_PRECIPITATION = "precipitation"
4 changes: 2 additions & 2 deletions custom_components/buienalarm/manifest.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"domain": "buienalarm",
"name": "Buienalarm",
"version": "1.8",
"version": "1.9",
"documentation": "https://github.com/gieljnssns/buienalarm-sensor-homeassistant/tree/master",
"requirements": ["pybuienalarm==0.1.0"],
"requirements": ["pybuienalarm==0.1.1"],
"dependencies": [],
"codeowners": ["@gieljnssns"]
}
65 changes: 36 additions & 29 deletions custom_components/buienalarm/sensor.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
"""Support for Buienalarm weather service."""

from datetime import timedelta
from datetime import datetime, timedelta
from typing import Any, Mapping, Optional, Union

from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.components.sensor import SensorEntity
import voluptuous as vol
from buienalarm.pybuienalarm import Buienalarm
from homeassistant.components.sensor import PLATFORM_SCHEMA, SensorEntity
from homeassistant.const import (
ATTR_ATTRIBUTION,
CONF_LATITUDE,
Expand All @@ -13,33 +14,28 @@
CONF_NAME,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.helpers.update_coordinator import (
CoordinatorEntity,
DataUpdateCoordinator,
)
from homeassistant.util import dt as dt_util
from homeassistant.helpers import config_validation as cv
import voluptuous as vol

from buienalarm.pybuienalarm import Buienalarm
from .const import (
ATTRIBUTION,
CONF_TIMEFRAME,
DEFAULT_NAME,
DEFAULT_TIMEFRAME,
ITEM_NEXT_RAIN_FORECAST,
ITEM_PRECIP_FORECAST_AVG,
ITEM_PRECIP_FORECAST_TOTAL,
ITEM_PRECIP_NOW,
ITEM_TEMP,
ITEM_PRECIP_FORECAST_TOTAL,
ITEM_PRECIP_FORECAST_AVG,
ITEM_NEXT_RAIN_FORECAST,
LOGGER as _LOGGER,
SENSOR_TYPES,
SensorType,
UPDATE_INTERVAL,
)

from .const import LOGGER as _LOGGER
from .const import SENSOR_TYPES, UPDATE_INTERVAL, SensorType

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
Expand Down Expand Up @@ -80,10 +76,16 @@ async def async_setup_platform(

api = Buienalarm(longitude, latitude)

client_name = config.get(CONF_NAME)
def api_update():
"""Fetch Buienalarm data."""
api.update(safe=True)
_LOGGER.debug("New data: %s", api.data)

async def async_api_update():
"""."""
await hass.async_add_executor_job(api.update)
"""Schedule fetch Buienalarm data."""
await hass.async_add_executor_job(api_update)

client_name = config.get(CONF_NAME)
coordinator = DataUpdateCoordinator(
hass,
_LOGGER,
Expand All @@ -107,7 +109,7 @@ def __init__(
api: Buienalarm,
sensor_type_name: str,
client_name: str,
timeframe: timedelta = timedelta(minutes=60)
timeframe: timedelta = timedelta(minutes=60),
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator)
Expand Down Expand Up @@ -138,27 +140,32 @@ def device_state_attributes(self) -> Mapping[str, Any]:
ATTR_ATTRIBUTION: ATTRIBUTION,
}

if "forecast" in self._sensor_type_name and \
self._api.has_data:
attr[CONF_TIMEFRAME] = self._timeframe / self._api.delta
if self._is_forecast_sensor and self._api.has_data:
timeframe_minutes = int(self._timeframe.total_seconds() / 60)
attr[CONF_TIMEFRAME] = f"{timeframe_minutes} min"

return attr

@property
def state(self) -> Optional[Union[str, float]]:
def _is_forecast_sensor(self):
"""Is forecast sensor?"""
return "forecast" in self._sensor_type_name

@property
def state(self) -> Optional[Union[datetime, float]]:
"""Get state."""
_LOGGER.debug("Get state: %s", self._sensor_type_name)
if not self._api.has_data:
return None

if self._sensor_type_name == ITEM_TEMP:
return self._api.temperature
return round(self._api.temperature, 1)
elif self._sensor_type_name == ITEM_PRECIP_NOW:
return self._precipitation_now
return round(self._precipitation_now, 1)
elif self._sensor_type_name == ITEM_PRECIP_FORECAST_TOTAL:
return self._precipitation_forecast_total
return round(self._precipitation_forecast_total, 1)
elif self._sensor_type_name == ITEM_PRECIP_FORECAST_AVG:
return self._precipitation_forecast_average
return round(self._precipitation_forecast_average, 1)
elif self._sensor_type_name == ITEM_NEXT_RAIN_FORECAST:
return self._next_rain_forecast
else:
Expand All @@ -180,19 +187,19 @@ def _precipitation_now(self) -> float:
return self._precipitation_values[0]

@property
def _next_rain_forecast(self) -> Optional[str]:
def _next_rain_forecast(self) -> Optional[datetime]:
"""Get next rain forecast."""
for precip_at in self._precipitation:
if precip_at.value > 0.0:
return str(precip_at.timestamp)
return precip_at.timestamp

return None

@property
def _precipitation(self):
"""Get precipitation within timeframe, starting from now."""
count = self._timeframe_value_count
return self._api.precipitation_from_now[0:count] # Slice up to our timeframe.
return self._api.precipitation_from_now[0:count] # Slice to our timeframe.

@property
def _precipitation_values(self):
Expand Down

0 comments on commit 42dcb0b

Please sign in to comment.