Skip to content

Commit

Permalink
Merge pull request #32 from briis/version-1-0-0
Browse files Browse the repository at this point in the history
Bump to 1.0.0
  • Loading branch information
briis authored Nov 18, 2023
2 parents 8a98ea8 + 075c112 commit c01b8d6
Show file tree
Hide file tree
Showing 15 changed files with 405 additions and 10 deletions.
12 changes: 9 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,18 @@

Date: `2023-11-18`

This release is now V1.0, as all the relevant entities from the previous release are now implemented. Unfortunately my PR for getting this in to Default HACS is not merged yet, but I hope that this will happen soon, and when this does the previous integration will be removed.

### Changes

- Added new sensor `Power Save Mode` that shows the Power Mode of a Tempest device. Attributes of the sensor gives a textual explanation. For more information [read here](https://help.weatherflow.com/hc/en-us/articles/360048877194-Solar-Power-Rechargeable-Battery)
- Bump pyweatherflow-forecast to 1.0.0
- Added new sensor `UV Description`, detailing the current UV value (For translated values please update the language file in the *translations* directory)
- Added new sensor `Staton Information`, detailing data about the Tempest Station (For translated values please update the language file in the *translations* directory)
- Added new sensor `Power Save Mode` that shows the Power Mode of a Tempest device. Attributes of the sensor gives a textual explanation. For more information [read here](https://help.weatherflow.com/hc/en-us/articles/360048877194-Solar-Power-Rechargeable-Battery) Closes (#27)
- Added new sensor `Beaufort Description`, detailing the current Beaufort value with a descriptive text (For translated values please update the language file in the *translations* directory) Closes (#27)
- Added new sensor `UV Description`, detailing the current UV value (For translated values please update the language file in the *translations* directory) Closes (#27)
- Added new sensor `Staton Name`, detailing data about the Tempest Station (For translated values please update the language file in the *translations* directory) Closes (#27)
- Added new Binary Sensor `Is Freezing`. On when the Celcius temperature is below 0. (Closes #26)
- Added new Binary Sensor `Is Lightning`. On when Lightning strikes are detected. (Closes #26)
- Added new Binary Sensor `Is Raining`. On when the rain rate is above 0mm. (Closes #26)

### TODO
- If sensors have been installed, and the user selectes to remove them again, ensure they are deleted from Home Assistant. Currently they must be manually removed.
Expand Down
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,16 @@ You can configure more than 1 instance of the Integration by using a different S

Here is the list of sensors that the program generates. Calculated means, if No, then data comes directly from the Weather Station, if yes, it is a sensor that is derived from some of the other sensors. Not all sensors show up on all installations. It depends on where in the world your station is located.

### Binary Sensors
All entities are prefixed with `[STATION NAME]_binary_sensors_`

| Sensor Name | Description | Calculated |
| --- | --- | --- |
| Is Freezing | On when the Celcius temperature is below 0 | Yes |
| Is Lightning | On when Lightning strikes are detected | Yes |
| Is Raining | On when the rain rate is above 0mm | Yes |

### Sensors
All entities are prefixed with `[STATION NAME]_sensors_`

| Sensor Name | Description | Calculated |
Expand All @@ -85,6 +95,7 @@ All entities are prefixed with `[STATION NAME]_sensors_`
| Barometric Pressure | The Barometric pressure | No |
| Battery | The % of charge on the Battery (Tempest device only) | Yes |
| Beaufort | Beaufort scale is an empirical measure that relates wind speed to observed conditions at sea or on land | Yes |
| Beaufort Description | A descriptive text of the Beaufort value | Yes |
| Cloud Base| The cloud height altitude above sea level | Yes |
| Data Updated | The time of the last data update. Disabled by default. | No |
| Delta T | Difference between Air Temperature and Wet Bulb Temperature | No |
Expand All @@ -111,9 +122,11 @@ All entities are prefixed with `[STATION NAME]_sensors_`
| Pressure Trend | Returns Steady, Falling or Rising determined by the rate of change over the past 3 hours| No |
| Sea Level Pressure | Preasure measurement at Sea Level | No |
| Solar Radiation | Electromagnetic radiation emitted by the sun | No |
| Staton Name | Station Name as state and more information about the station in the Attributes | Yes |
| Station Pressure | Pressure measurement where the station is located | No |
| Temperature | Outside Temperature | No |
| Time of last lightning strike | When the last lightning strike occurred | No |
| UV Description | A descriptive text of the UV Index | Yes |
| UV Index | The UV index | No |
| Voltage | The Voltage of the Tempest device | No |
| Visibility | Distance to the horizon | Yes |
Expand Down
8 changes: 6 additions & 2 deletions custom_components/weatherflow_forecast/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
WeatherFlowForecastInternalServerError,
WeatherFlowForecastWongStationId,
WeatherFlowSensorData,
WeatherFlowStationData,
)

from homeassistant.config_entries import ConfigEntry
Expand All @@ -34,7 +35,7 @@
CONF_STATION_ID,
)

PLATFORMS = [Platform.WEATHER, Platform.SENSOR]
PLATFORMS = [Platform.WEATHER, Platform.SENSOR, Platform.BINARY_SENSOR]

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -121,6 +122,7 @@ def __init__(self, hass: HomeAssistant, config: MappingProxyType[str, Any], add_
self.daily_forecast: WeatherFlowForecastDaily = []
self.hourly_forecast: WeatherFlowForecastHourly = []
self.sensor_data: WeatherFlowSensorData = {}
self.station_data: WeatherFlowStationData = {}

def initialize_data(self) -> bool:
"""Establish connection to API."""
Expand Down Expand Up @@ -157,6 +159,7 @@ async def fetch_data(self) -> Self:
if self._add_sensors:
try:
resp: WeatherFlowForecastData = await self._weather_data.async_fetch_sensor_data()
station_info: WeatherFlowStationData = await self._weather_data.async_get_station()
except WeatherFlowForecastWongStationId as unauthorized:
_LOGGER.debug(unauthorized)
raise Unauthorized from unauthorized
Expand All @@ -170,9 +173,10 @@ async def fetch_data(self) -> Self:
_LOGGER.debug(notreadyerror)
raise ConfigEntryNotReady from notreadyerror

if not resp:
if not resp or not station_info:
raise CannotConnect()
self.sensor_data = resp
self.station_data = station_info
# _LOGGER.debug(vars(self.sensor_data))

return self
123 changes: 123 additions & 0 deletions custom_components/weatherflow_forecast/binary_sensor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
"""Support for WeatherFlow binary sensor data."""
from __future__ import annotations

import logging

from dataclasses import dataclass
from types import MappingProxyType
from typing import Any

from homeassistant.components.binary_sensor import (
BinarySensorDeviceClass,
BinarySensorEntity,
BinarySensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
CONF_NAME,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from homeassistant.helpers.update_coordinator import (
CoordinatorEntity,
DataUpdateCoordinator,
)

from . import WeatherFlowForecastDataUpdateCoordinator
from .const import (
ATTR_ATTRIBUTION,
CONF_STATION_ID,
DOMAIN,
MANUFACTURER,
MODEL,
)

@dataclass
class WeatherFlowBinarySensorEntityDescription(BinarySensorEntityDescription):
"""Describes WeatherFlow binary sensor entity."""


BINARY_SENSOR_TYPES: tuple[WeatherFlowBinarySensorEntityDescription, ...] = (
WeatherFlowBinarySensorEntityDescription(
key="is_freezing",
name="Is Freezing",
icon="mdi:snowflake-alert",
device_class=BinarySensorDeviceClass.COLD
),
WeatherFlowBinarySensorEntityDescription(
key="is_lightning",
name="Is Lightning",
icon="mdi:flash-alert",
device_class=BinarySensorDeviceClass.SAFETY
),
WeatherFlowBinarySensorEntityDescription(
key="is_raining",
name="Is Raining",
icon="mdi:water-percent-alert",
device_class=BinarySensorDeviceClass.MOISTURE
),
)

_LOGGER = logging.getLogger(__name__)

async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: AddEntitiesCallback) -> None:
"""WeatherFlow binary sensor platform."""
coordinator: WeatherFlowForecastDataUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id]

if coordinator.data.sensor_data == {}:
return

entities: list[WeatherFlowBinarySensor[Any]] = [
WeatherFlowBinarySensor(coordinator, description, config_entry)
for description in BINARY_SENSOR_TYPES if getattr(coordinator.data.sensor_data, description.key) is not None
]

async_add_entities(entities, False)

class WeatherFlowBinarySensor(CoordinatorEntity[DataUpdateCoordinator], BinarySensorEntity):
"""A WeatherFlow binary sensor."""

entity_description: WeatherFlowBinarySensorEntityDescription
_attr_has_entity_name = True

def __init__(
self,
coordinator: WeatherFlowForecastDataUpdateCoordinator,
description: WeatherFlowBinarySensorEntityDescription,
config: MappingProxyType[str, Any]
) -> None:
"""Initialize a WeatherFlow binary sensor."""
super().__init__(coordinator)
self.entity_description = description
self._config = config
self._coordinator = coordinator
self._hw_version = " - Not Available" if self._coordinator.data.station_data.firmware_revision is None else self._coordinator.data.station_data.firmware_revision

self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, f"{self._config.data[CONF_STATION_ID]}_binary")},
entry_type=DeviceEntryType.SERVICE,
manufacturer=MANUFACTURER,
model=MODEL,
name=f"{self._config.data[CONF_NAME]} Binary Sensors",
configuration_url=f"https://tempestwx.com/station/{self._config.data[CONF_STATION_ID]}/grid",
hw_version=f"FW V{self._hw_version}",
)
self._attr_attribution = ATTR_ATTRIBUTION
self._attr_unique_id = f"{config.data[CONF_STATION_ID]} {description.key}"

@property
def is_on(self) -> StateType:
"""Return state of the sensor."""

return (
getattr(self.coordinator.data.sensor_data, self.entity_description.key)
if self.coordinator.data.sensor_data else None
)

async def async_added_to_hass(self):
"""When entity is added to hass."""
self.async_on_remove(
self.coordinator.async_add_listener(self.async_write_ha_state)
)
3 changes: 3 additions & 0 deletions custom_components/weatherflow_forecast/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

ATTR_ATTRIBUTION = "Weather data delivered by WeatherFlow"
ATTR_DESCRIPTION = "description"
ATTR_HW_FIRMWARE_REVISION = "Firmware Revision"
ATTR_HW_SERIAL_NUMBER = "Serial Number"
ATTR_HW_STATION_ID = "Station ID"

BATTERY_MODE_DESCRIPTION = [
"All sensors enabled and operating at full performance. Wind sampling interval every 3 seconds",
Expand Down
4 changes: 2 additions & 2 deletions custom_components/weatherflow_forecast/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"iot_class": "cloud_polling",
"issue_tracker": "https://github.com/briis/weatherflow_forecast/issues",
"requirements": [
"pyweatherflow-forecast==0.6.4"
"pyweatherflow-forecast==1.0.0"
],
"version": "0.3.3"
"version": "1.0.0"
}
34 changes: 32 additions & 2 deletions custom_components/weatherflow_forecast/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@
from .const import (
ATTR_ATTRIBUTION,
ATTR_DESCRIPTION,
ATTR_HW_FIRMWARE_REVISION,
ATTR_HW_SERIAL_NUMBER,
ATTR_HW_STATION_ID,
BATTERY_MODE_DESCRIPTION,
CONCENTRATION_GRAMS_PER_CUBIC_METER,
CONF_FIRMWARE_REVISION,
CONF_STATION_ID,
DOMAIN,
MANUFACTURER,
Expand Down Expand Up @@ -106,6 +108,12 @@ class WeatherFlowSensorEntityDescription(SensorEntityDescription):
icon="mdi:windsock",
state_class=SensorStateClass.MEASUREMENT,
),
WeatherFlowSensorEntityDescription(
key="beaufort_description",
name="Beaufort Description",
icon="mdi:windsock",
translation_key="beaufort",
),
WeatherFlowSensorEntityDescription(
key="brightness",
name="Illuminance",
Expand Down Expand Up @@ -300,6 +308,11 @@ class WeatherFlowSensorEntityDescription(SensorEntityDescription):
device_class=SensorDeviceClass.IRRADIANCE,
state_class=SensorStateClass.MEASUREMENT,
),
WeatherFlowSensorEntityDescription(
key="station_name",
name="Station Name",
icon="mdi:hubspot",
),
WeatherFlowSensorEntityDescription(
key="station_pressure",
name="Station Pressure",
Expand All @@ -323,6 +336,12 @@ class WeatherFlowSensorEntityDescription(SensorEntityDescription):
icon="mdi:sun-wireless",
suggested_display_precision=1,
),
WeatherFlowSensorEntityDescription(
key="uv_description",
name="UV Description",
icon="mdi:sun-wireless",
translation_key="uv_description",
),
WeatherFlowSensorEntityDescription(
key="visibility",
name="Visibility",
Expand Down Expand Up @@ -428,6 +447,8 @@ def __init__(
super().__init__(coordinator)
self.entity_description = description
self._config = config
self._coordinator = coordinator
self._hw_version = " - Not Available" if self._coordinator.data.station_data.firmware_revision is None else self._coordinator.data.station_data.firmware_revision

self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, self._config.data[CONF_STATION_ID])},
Expand All @@ -436,7 +457,7 @@ def __init__(
model=MODEL,
name=f"{self._config.data[CONF_NAME]} Sensors",
configuration_url=f"https://tempestwx.com/station/{self._config.data[CONF_STATION_ID]}/grid",
hw_version=f"FW V{self._config.data.get(CONF_FIRMWARE_REVISION, ' - Not Available')}",
hw_version=f"FW V{self._hw_version}",
)
self._attr_attribution = ATTR_ATTRIBUTION
self._attr_unique_id = f"{config.data[CONF_STATION_ID]} {description.key}"
Expand Down Expand Up @@ -466,6 +487,15 @@ def extra_state_attributes(self) -> None:
return {
ATTR_DESCRIPTION: BATTERY_MODE_DESCRIPTION[sensor_value],
}
if self.entity_description.key == "station_name":
sensor_value = getattr(self.coordinator.data.sensor_data,
self.entity_description.key) if self.coordinator.data.sensor_data else None
if sensor_value is not None:
return {
ATTR_HW_FIRMWARE_REVISION: self._coordinator.data.station_data.firmware_revision,
ATTR_HW_SERIAL_NUMBER: self._coordinator.data.station_data.serial_number,
ATTR_HW_STATION_ID: str(self._config.data[CONF_STATION_ID]),
}

async def async_added_to_hass(self):
"""When entity is added to hass."""
Expand Down
27 changes: 27 additions & 0 deletions custom_components/weatherflow_forecast/translations/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,33 @@
"nw": "SZ",
"nnw": "SSZ"
}
},
"beaufort": {
"state": {
"calm": "Bezvětří",
"light_air": "Klidný vánek",
"light_breeze": "Lehký vánek",
"gentle_breeze": "Mírný vánek",
"moderate_breeze": "Střední vítr",
"fresh_breeze": "Střední vítr",
"strong_breeze": "Silný vítr",
"moderate_gale": "Mírnější vichr",
"fresh_gale": "Střední vichr",
"strong_gale": "Silný vichr",
"storm": "Bouřka",
"violent_storm": "Silná bouřka",
"hurricane": "Vichřice"
}
},
"uv_description": {
"state": {
"extreme": "Extrémní",
"very-high": "Velmi vysoké",
"high": "Vysoké",
"moderate": "Střední",
"low": "Nízké",
"none": "Žádné"
}
}
}
}
Expand Down
Loading

0 comments on commit c01b8d6

Please sign in to comment.