From 0b018ad4086c950a6dfd9d4888aa5eae24177ad2 Mon Sep 17 00:00:00 2001 From: Marco Gosselink Date: Sat, 30 Sep 2023 19:16:52 +0200 Subject: [PATCH] Initial version --- .gitignore | 1 + README.md | 32 ++ custom_components/davis_vantage/__init__.py | 69 ++++ .../davis_vantage/assets/icon.png | Bin 0 -> 17775 bytes .../davis_vantage/assets/icon@2x.png | Bin 0 -> 47224 bytes .../davis_vantage/assets/logo.png | Bin 0 -> 52356 bytes .../davis_vantage/assets/logo2.png | Bin 0 -> 4864 bytes .../davis_vantage/binary_sensor.py | 73 ++++ custom_components/davis_vantage/client.py | 95 +++++ .../davis_vantage/config_flow.py | 161 ++++++++ custom_components/davis_vantage/const.py | 16 + .../davis_vantage/coordinator.py | 43 ++ custom_components/davis_vantage/manifest.json | 17 + custom_components/davis_vantage/sensor.py | 349 ++++++++++++++++ custom_components/davis_vantage/strings.json | 36 ++ .../davis_vantage/translations/en.json | 40 ++ custom_components/davis_vantage/utils.py | 383 ++++++++++++++++++ hacs.json | 5 + 18 files changed, 1320 insertions(+) create mode 100644 .gitignore create mode 100755 README.md create mode 100755 custom_components/davis_vantage/__init__.py create mode 100755 custom_components/davis_vantage/assets/icon.png create mode 100755 custom_components/davis_vantage/assets/icon@2x.png create mode 100755 custom_components/davis_vantage/assets/logo.png create mode 100755 custom_components/davis_vantage/assets/logo2.png create mode 100755 custom_components/davis_vantage/binary_sensor.py create mode 100755 custom_components/davis_vantage/client.py create mode 100755 custom_components/davis_vantage/config_flow.py create mode 100755 custom_components/davis_vantage/const.py create mode 100755 custom_components/davis_vantage/coordinator.py create mode 100755 custom_components/davis_vantage/manifest.json create mode 100755 custom_components/davis_vantage/sensor.py create mode 100755 custom_components/davis_vantage/strings.json create mode 100755 custom_components/davis_vantage/translations/en.json create mode 100755 custom_components/davis_vantage/utils.py create mode 100755 hacs.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..496ee2c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store \ No newline at end of file diff --git a/README.md b/README.md new file mode 100755 index 0000000..3237a71 --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +![Version](https://img.shields.io/github/v/release/MarcoGos/davis_vantage?include_prereleases) + +# Davis Vantage + +This is a custom integration for the Davis Vantage Pro2 and Vue. + +## Installation + +Via HACS: + +- Add the following custom repository as an integration: + - MarcoGos/davis_vantage +- Restart Home Assistant +- Add the integration to Home Assistant + +## Setup + +During the setup of the integration the serial port of the weather station needs to be provided. + +Examples: +- tcp:192.168.0.18:1111 +- serial:/dev/ttyUSB0:19200:8N1 + +![Setup](/assets/setup.png) + +## What to expect + +The following sensors will be registered: + +![Sensors](/assets/sensors.png) + +The sensor information is updated every 30 seconds. diff --git a/custom_components/davis_vantage/__init__.py b/custom_components/davis_vantage/__init__.py new file mode 100755 index 0000000..a42e026 --- /dev/null +++ b/custom_components/davis_vantage/__init__.py @@ -0,0 +1,69 @@ +"""The Davis Vantage integration.""" +from __future__ import annotations +from typing import Any +import logging + +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant +from homeassistant.helpers.device_registry import DeviceEntryType +from homeassistant.helpers.entity import DeviceInfo +from homeassistant.const import Platform + +from .client import DavisVantageClient +from .const import DOMAIN, NAME, VERSION, MANUFACTURER +from .coordinator import DavisVantageDataUpdateCoordinator + +PLATFORMS: list[Platform] = [ + Platform.SENSOR, + Platform.BINARY_SENSOR +] + +_LOGGER: logging.Logger = logging.getLogger(__package__) + +async def async_setup(hass: HomeAssistant, config: Any) -> bool: + return True + +async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: + """Set up Davis Vantage from a config entry.""" + if hass.data.get(DOMAIN) is None: + hass.data.setdefault(DOMAIN, {}) + + _LOGGER.debug(f"entry.data: {entry.data}") + + protocol = entry.data.get("protocol", "") + link = entry.data.get("link", "") + rain_collector = entry.data.get("rain_collector", "0.01""") + windrose8 = entry.data.get("windrose8", False) + + client = DavisVantageClient(hass, protocol, link, rain_collector, windrose8) + + device_info = DeviceInfo( + entry_type=DeviceEntryType.SERVICE, + identifiers={(DOMAIN, entry.entry_id)}, + manufacturer=MANUFACTURER, + name=NAME, + sw_version=VERSION + ) + + hass.data[DOMAIN][entry.entry_id] = coordinator = DavisVantageDataUpdateCoordinator( + hass=hass, client=client, device_info=device_info) + + await coordinator.async_config_entry_first_refresh() + + await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) + entry.async_on_unload(entry.add_update_listener(async_reload_entry)) + + return True + + +async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: + """Unload a config entry.""" + if unloaded := await hass.config_entries.async_unload_platforms(entry, PLATFORMS): + hass.data[DOMAIN].pop(entry.entry_id) + return unloaded + + +async def async_reload_entry(hass: HomeAssistant, entry: ConfigEntry) -> None: + """Reload config entry.""" + await async_unload_entry(hass, entry) + await async_setup_entry(hass, entry) diff --git a/custom_components/davis_vantage/assets/icon.png b/custom_components/davis_vantage/assets/icon.png new file mode 100755 index 0000000000000000000000000000000000000000..12ac77637a299e283e9eacd450ed083ca1008cc9 GIT binary patch literal 17775 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

8k1sz=t3!WXL_Bw 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%0D}oie7`|C;kM!j*MFU6e0sn+_myC^nv~+ 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 UF5ug;MR~m5DyYj>%9@7$A69ESoB#j- literal 0 HcmV?d00001 diff --git a/custom_components/davis_vantage/assets/logo.png b/custom_components/davis_vantage/assets/logo.png new file mode 100755 index 0000000000000000000000000000000000000000..798c2277effb572f8ea2ec7af33079db560cbf5b GIT binary patch literal 52356 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 literal 0 HcmV?d00001 diff --git a/custom_components/davis_vantage/assets/logo2.png b/custom_components/davis_vantage/assets/logo2.png new file mode 100755 index 0000000000000000000000000000000000000000..c60ddfb6b1cd9d88a3338c92b5ec6e9134443182 GIT binary patch literal 4864 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 mXH0;L0Ob6!ONfgT None: + """Set up Davis Vantage sensors based on a config entry.""" + coordinator = hass.data[DOMAIN][entry.entry_id] + + entities: list[DavisVantageBinarySensor] = [] + + # Add all binary sensors described above. + for description in DESCRIPTIONS: + entities.append( + DavisVantageBinarySensor( + coordinator=coordinator, + entry_id=entry.entry_id, + description=description, + ) + ) + + async_add_entities(entities) + + +class DavisVantageBinarySensor(CoordinatorEntity[DavisVantageDataUpdateCoordinator], BinarySensorEntity): + """Defines a Davis Vantage sensor.""" + + _attr_has_entity_name = True + + def __init__( + self, + coordinator: DavisVantageDataUpdateCoordinator, + entry_id: str, + description: BinarySensorEntityDescription, + ) -> None: + """Initialize Davis Vantage sensor.""" + super().__init__(coordinator=coordinator) + + self.entity_id = ( + f"{BINARY_SENSOR_DOMAIN}.{DEFAULT_NAME}_{description.name}".lower() + ) + self.entity_description = description + self._attr_name = description.name # type: ignore + self._attr_unique_id = f"{entry_id}-{DEFAULT_NAME} {self.name}" + self._attr_device_info = coordinator.device_info + + @property + def is_on(self) -> bool | None: + """Return the is_on of the sensor.""" + key = self.entity_description.key + data = self.coordinator.data + if key not in data: + return None + return data.get(key, False) # type: ignore \ No newline at end of file diff --git a/custom_components/davis_vantage/client.py b/custom_components/davis_vantage/client.py new file mode 100755 index 0000000..79257b5 --- /dev/null +++ b/custom_components/davis_vantage/client.py @@ -0,0 +1,95 @@ +from typing import Any +from datetime import datetime +import logging +from pyvantagepro import VantagePro2 +from pyvantagepro.parser import LoopDataParserRevB + +from homeassistant.core import HomeAssistant + +from .utils import * +from .const import RAIN_COLLECTOR_METRIC, PROTOCOL_NETWORK, PROTOCOL_SERIAL + +TIMEOUT = 10 + +_LOGGER: logging.Logger = logging.getLogger(__package__) + +class DavisVantageClient: + def __init__( + self, + hass: HomeAssistant, + protocol: str, + link: str, + rain_collector: str, + windrose8: bool + ) -> None: + self._hass = hass + self._protocol = protocol + self._link = link + self._windrose8 = windrose8 + self._rain_collector = rain_collector + self._last_data = LoopDataParserRevB + + async def async_get_current_data(self) -> LoopDataParserRevB | None: + """Get current date from weather station.""" + data = self._last_data + try: + vantagepro2 = VantagePro2.from_url(self.get_link()) # type: ignore + # vantagepro2.link.open() # type: ignore + data = vantagepro2.get_current_data() + if data: + self.add_additional_info(data) + self.convert_values(data) + data['LastError'] = "No error" + self._last_data = data + else: + data['LastError'] = "Couldn't acquire data" + except Exception as e: + _LOGGER.warning(f"Couldn't acquire data from {self._link}") + data['LastError'] = f"Couldn't acquire data: {e}" # type: ignore + # finally: + # vantagepro2.link.close() # type: ignore + return data # type: ignore + + async def async_get_davis_time(self) -> datetime | None: + """Get time from weather station.""" + data = None + try: + vantagepro2 = VantagePro2.from_url(self.get_link()) # type: ignore + # vantagepro2.link.open() # type: ignore + data = vantagepro2.gettime() + except Exception: + _LOGGER.warning(f"Couldn't acquire data from {self._link}") + # finally: + # vantagepro2.link.close() # type: ignore + return data + + def add_additional_info(self, data: dict[str, Any]) -> None: + data['HeatIndex'] = calc_heat_index(data['TempOut'], data['HumOut']) + data['WindChill'] = calc_wind_chill(data['TempOut'], data['WindSpeed']) + data['FeelsLike'] = calc_feels_like(data['TempOut'], data['HumOut'], data['WindSpeed']) + data['WindDirRose'] = get_wind_rose(data['WindDir'], self._windrose8) + data['DewPoint'] = calc_dew_point(data['TempOut'], data['HumOut']) + data['WindSpeedBft'] = convert_kmh_to_bft(convert_to_kmh(data['WindSpeed10Min'])) + data['IsRaining'] = data['RainRate'] > 0 + + def convert_values(self, data: dict[str, Any]) -> None: + data['Datetime'] = convert_to_iso_datetime(data['Datetime'], ZoneInfo(self._hass.config.time_zone)) + data['BarTrend'] = get_baro_trend(data['BarTrend']) + data['UV'] = get_uv(data['UV']) + data['ForecastRuleNo'] = get_forecast_string(data['ForecastRuleNo']) + data['RainCollector'] = self._rain_collector + data['WindRoseSetup'] = 8 if self._windrose8 else 16 + if data['RainCollector'] == RAIN_COLLECTOR_METRIC: + self.correct_rain_values(data) + + def correct_rain_values(self, data: dict[str, Any]): + data['RainDay'] *= 2/2.54 + data['RainMonth'] *= 2/2.54 + data['RainYear'] *= 2/2.54 + data['RainRate'] *= 2/2.54 + + def get_link(self) -> str | None: + if self._protocol == PROTOCOL_NETWORK: + return f"tcp:{self._link}" + if self._protocol == PROTOCOL_SERIAL: + return f"serial:{self._link}:19200:8N1" diff --git a/custom_components/davis_vantage/config_flow.py b/custom_components/davis_vantage/config_flow.py new file mode 100755 index 0000000..588dfc5 --- /dev/null +++ b/custom_components/davis_vantage/config_flow.py @@ -0,0 +1,161 @@ +"""Config flow for Davis Vantage integration.""" +from __future__ import annotations + +import logging +from typing import Any +import voluptuous as vol +import serial +import serial.tools.list_ports + +from homeassistant import config_entries +from homeassistant.core import HomeAssistant +from homeassistant.data_entry_flow import FlowResult +from homeassistant.exceptions import HomeAssistantError +from homeassistant.helpers.selector import selector #type: ignore + +from .const import ( + NAME, + DOMAIN, + DEFAULT_SYNC_INTERVAL, + RAIN_COLLECTOR_IMPERIAL, + RAIN_COLLECTOR_METRIC, + PROTOCOL_NETWORK, + PROTOCOL_SERIAL +) +from .client import DavisVantageClient + +_LOGGER = logging.getLogger(__name__) + + +class PlaceholderHub: + """Placeholder class to make tests pass.""" + + def __init__(self, hass: HomeAssistant) -> None: + """Initialize.""" + self._hass = hass + + async def authenticate(self, protocol: str, link: str) -> bool: + """Test if we can find data for the given link.""" + _LOGGER.info(f"authenticate called") + client = DavisVantageClient(self._hass, protocol, link, '', False) + return await client.async_get_davis_time() != None + + +async def validate_input(hass: HomeAssistant, data: dict[str, Any]) -> dict[str, Any]: + """Validate the user input allows us to connect. + + Data has the keys from STEP_USER_DATA_SCHEMA with values provided by the user. + """ + hub = PlaceholderHub(hass) + if not await hub.authenticate(data["protocol"], data["link"]): + raise InvalidAuth + + # Return info that you want to store in the config entry. + return {"title": NAME} + + +class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): + """Handle a config flow for Davis Vantage.""" + + VERSION = 1 + protocol: str + link: str + + async def async_step_user( + self, user_input: dict[str, Any] | None = None + ) -> FlowResult: + """Handle the initial step.""" + if user_input is not None: + self.protocol = user_input['protocol'] + if self.protocol == PROTOCOL_SERIAL: + return await self.async_step_setup_serial() + + return await self.async_step_setup_network() + + list_of_types = [PROTOCOL_SERIAL, PROTOCOL_NETWORK] + schema = vol.Schema({vol.Required('protocol'): vol.In(list_of_types)}) + return self.async_show_form(step_id="user", data_schema=schema) + + async def async_step_setup_serial( + self, user_input: dict[str, Any] | None = None + ) -> FlowResult: + + if user_input is not None: + self.link = user_input['link'] + return await self.async_step_setup_other_info() + + ports = await self.hass.async_add_executor_job(serial.tools.list_ports.comports) + list_of_ports = { + port.device: f"{port}, s/n: {port.serial_number or 'n/a'}" + + (f" - {port.manufacturer}" if port.manufacturer else "") + for port in ports + } + + STEP_USER_DATA_SCHEMA = vol.Schema( + { + vol.Required("link"): vol.In(list_of_ports) + } + ) + + return self.async_show_form( + step_id="setup_serial", data_schema=STEP_USER_DATA_SCHEMA + ) + + async def async_step_setup_network( + self, user_input: dict[str, Any] | None = None + ) -> FlowResult: + if user_input is not None: + self.link = user_input['link'] + return await self.async_step_setup_other_info() + + STEP_USER_DATA_SCHEMA = vol.Schema( + { + vol.Required("link"): str + } + ) + + return self.async_show_form( + step_id="setup_network", data_schema=STEP_USER_DATA_SCHEMA + ) + + async def async_step_setup_other_info( + self, user_input: dict[str, Any] | None = None + ) -> FlowResult: + + errors = {} + if user_input is not None: + await self.async_set_unique_id(DOMAIN) + self._abort_if_unique_id_configured() + user_input['protocol'] = self.protocol + user_input['link'] = self.link + try: + info = await validate_input(self.hass, user_input) + except CannotConnect: + errors["base"] = "cannot_connect" + except InvalidAuth: + errors["base"] = "invalid_auth" + except Exception: + _LOGGER.exception("Unexpected exception") + errors["base"] = "unknown" + else: + return self.async_create_entry(title=info["title"], data=user_input) + + list_of_rain_collector = [RAIN_COLLECTOR_IMPERIAL, RAIN_COLLECTOR_METRIC] + STEP_USER_DATA_SCHEMA = vol.Schema( + { + vol.Required("interval", default=DEFAULT_SYNC_INTERVAL): int, #type: ignore + vol.Required("rain_collector"): vol.In(list_of_rain_collector), + vol.Required("windrose8"): bool + } + ) + + return self.async_show_form( + step_id="setup_other_info", data_schema=STEP_USER_DATA_SCHEMA, errors=errors + ) + +class CannotConnect(HomeAssistantError): + """Error to indicate we cannot connect.""" + + +class InvalidAuth(HomeAssistantError): + """Error to indicate there is invalid auth.""" diff --git a/custom_components/davis_vantage/const.py b/custom_components/davis_vantage/const.py new file mode 100755 index 0000000..9457458 --- /dev/null +++ b/custom_components/davis_vantage/const.py @@ -0,0 +1,16 @@ +"""Constants for the Davis Vantage integration.""" + +NAME = "Davis Vantage" +DOMAIN = "davis_vantage" +MANUFACTURER = "Davis" +MODEL = "Vantage Pro2/Vue" +VERSION = "0.0.1" + +DEFAULT_SYNC_INTERVAL = 30 # seconds +DEFAULT_NAME = NAME + +RAIN_COLLECTOR_IMPERIAL = '0.01"' +RAIN_COLLECTOR_METRIC = '0.2 mm' + +PROTOCOL_NETWORK = 'Netwerk' +PROTOCOL_SERIAL = 'Serial' \ No newline at end of file diff --git a/custom_components/davis_vantage/coordinator.py b/custom_components/davis_vantage/coordinator.py new file mode 100755 index 0000000..5cfdf2f --- /dev/null +++ b/custom_components/davis_vantage/coordinator.py @@ -0,0 +1,43 @@ +from datetime import timedelta +from typing import Any +import logging + +from homeassistant.helpers.update_coordinator import UpdateFailed, DataUpdateCoordinator +from homeassistant.helpers.entity import DeviceInfo +from homeassistant.core import HomeAssistant +from pyvantagepro.parser import LoopDataParserRevB + +from .client import DavisVantageClient +from .const import ( + DEFAULT_SYNC_INTERVAL, + DOMAIN, +) + +_LOGGER: logging.Logger = logging.getLogger(__package__) + +class DavisVantageDataUpdateCoordinator(DataUpdateCoordinator): + """Class to manage fetching data from the weather station.""" + data: LoopDataParserRevB + + def __init__(self, hass: HomeAssistant, client: DavisVantageClient, device_info: DeviceInfo) -> None: + """Initialize.""" + self.client: DavisVantageClient = client + self.platforms: list[str] = [] + self.last_updated = None + self.device_info = device_info + + super().__init__( + hass, + _LOGGER, + name=DOMAIN, + update_interval=timedelta(seconds=DEFAULT_SYNC_INTERVAL), + ) + + async def _async_update_data(self) -> dict[str, Any]: + """Update data via library.""" + try: + data: LoopDataParserRevB = await self.client.async_get_current_data() # type: ignore + return data + except Exception as exception: + _LOGGER.error(f"Error DavisVantageDataUpdateCoordinator _async_update_data: {exception}") + raise UpdateFailed() from exception diff --git a/custom_components/davis_vantage/manifest.json b/custom_components/davis_vantage/manifest.json new file mode 100755 index 0000000..085629e --- /dev/null +++ b/custom_components/davis_vantage/manifest.json @@ -0,0 +1,17 @@ +{ + "domain": "davis_vantage", + "name": "Davis Vantage", + "version": "0.0.1", + "config_flow": true, + "documentation": "https://github.com/MarcoGos/davis_vantage", + "requirements": ["PyVantagePro==0.3.2"], + "ssdp": [], + "zeroconf": [], + "homekit": {}, + "dependencies": [], + "codeowners": [ + "@MarcoGos" + ], + "iot_class": "", + "integration_type": "hub" +} diff --git a/custom_components/davis_vantage/sensor.py b/custom_components/davis_vantage/sensor.py new file mode 100755 index 0000000..e4bb910 --- /dev/null +++ b/custom_components/davis_vantage/sensor.py @@ -0,0 +1,349 @@ +from homeassistant.components.sensor import ( + DOMAIN as SENSOR_DOMAIN, + SensorEntity, + SensorEntityDescription, + SensorDeviceClass +) +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import PERCENTAGE, DEGREE, UnitOfSpeed, UnitOfLength, UnitOfVolumetricFlux, UnitOfElectricPotential, UnitOfTemperature, UnitOfPressure +from homeassistant.core import HomeAssistant +from homeassistant.helpers.entity import EntityCategory +from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.typing import StateType +from homeassistant.helpers.update_coordinator import CoordinatorEntity + +from .const import DEFAULT_NAME, DOMAIN +from .coordinator import DavisVantageDataUpdateCoordinator + +DESCRIPTIONS: list[SensorEntityDescription] = [ + SensorEntityDescription( + key="Datetime", + name="Davis Time", + icon="mdi:clock", + device_class=SensorDeviceClass.TIMESTAMP, + entity_category=EntityCategory.DIAGNOSTIC + ), + SensorEntityDescription( + key="TempOut", + name="Temperature (Outside)", + device_class=SensorDeviceClass.TEMPERATURE, + state_class="measurement", + native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, + suggested_display_precision=1 + ), + SensorEntityDescription( + key="TempIn", + name="Temperature (Inside)", + device_class=SensorDeviceClass.TEMPERATURE, + state_class="measurement", + native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, + suggested_display_precision=1 + ), + SensorEntityDescription( + key="HeatIndex", + name="Heat Index", + icon="mdi:sun-thermometer-outline", + device_class=SensorDeviceClass.TEMPERATURE, + state_class="measurement", + native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, + suggested_display_precision=1 + ), + SensorEntityDescription( + key="WindChill", + name="Wind Chill", + icon="mdi:snowflake-thermometer", + device_class=SensorDeviceClass.TEMPERATURE, + state_class="measurement", + native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, + suggested_display_precision=1 + ), + SensorEntityDescription( + key="FeelsLike", + name="Feels Like", + icon="mdi:download-circle-outline", + device_class=SensorDeviceClass.TEMPERATURE, + state_class="measurement", + native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, + suggested_display_precision=1 + ), + SensorEntityDescription( + key="DewPoint", + name="Dew Point", + icon="mdi:water-thermometer-outline", + device_class=SensorDeviceClass.TEMPERATURE, + state_class="measurement", + native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, + suggested_display_precision=1 + ), + SensorEntityDescription( + key="Barometer", + name="Barometric Pressure", + device_class=SensorDeviceClass.PRESSURE, + state_class="measurement", + native_unit_of_measurement=UnitOfPressure.INHG, + suggested_display_precision=2 + ), + SensorEntityDescription( + key="BarTrend", + name="Barometric Trend" + ), + SensorEntityDescription( + key="HumIn", + name="Humidity (Inside)", + device_class=SensorDeviceClass.HUMIDITY, + state_class="measurement", + native_unit_of_measurement=PERCENTAGE, + suggested_display_precision=0 + ), + SensorEntityDescription( + key="HumOut", + name="Humidity (Outside)", + device_class=SensorDeviceClass.HUMIDITY, + state_class="measurement", + native_unit_of_measurement=PERCENTAGE, + suggested_display_precision=0 + ), + SensorEntityDescription( + key="WindSpeed", + name="Wind Speed", + icon="mdi:weather-windy", + device_class=SensorDeviceClass.WIND_SPEED, + state_class="measurement", + native_unit_of_measurement=UnitOfSpeed.MILES_PER_HOUR, + suggested_display_precision=1 + ), + SensorEntityDescription( + key="WindSpeed10Min", + name="Wind Speed (Average)", + icon="mdi:weather-windy", + device_class=SensorDeviceClass.WIND_SPEED, + state_class="measurement", + native_unit_of_measurement=UnitOfSpeed.MILES_PER_HOUR, + suggested_display_precision=1 + ), + SensorEntityDescription( + key="WindDir", + name="Wind Direction", + icon="mdi:compass-outline", + state_class="measurement", + native_unit_of_measurement=DEGREE, + suggested_display_precision=0 + ), + SensorEntityDescription( + key="WindDirRose", + name="Wind Direction Rose", + icon="mdi:compass-outline" + ), + SensorEntityDescription( + key="WindSpeedBft", + name="Wind Speed (Bft)", + icon="mdi:weather-windy", + state_class="measurement", + entity_registry_enabled_default=False + ), + SensorEntityDescription( + key="RainDay", + name="Rain (Day)", + icon="mdi:water", + device_class=SensorDeviceClass.PRECIPITATION, + state_class="total_increasing", + native_unit_of_measurement=UnitOfLength.INCHES, + suggested_display_precision=1 + ), + SensorEntityDescription( + key="RainMonth", + name="Rain (Month)", + icon="mdi:water", + device_class=SensorDeviceClass.PRECIPITATION, + native_unit_of_measurement=UnitOfLength.INCHES, + suggested_display_precision=1 + ), + SensorEntityDescription( + key="RainYear", + name="Rain (Year)", + icon="mdi:water", + device_class=SensorDeviceClass.PRECIPITATION, + native_unit_of_measurement=UnitOfLength.INCHES, + suggested_display_precision=1 + ), + SensorEntityDescription( + key="RainRate", + name="Rain Rate", + icon="mdi:water", + device_class=SensorDeviceClass.PRECIPITATION_INTENSITY, + state_class="measurement", + native_unit_of_measurement=UnitOfVolumetricFlux.INCHES_PER_HOUR, + suggested_display_precision=1 + ), + SensorEntityDescription( + key="UV", + name="UV Level", + icon="mdi:sun-wireless-outline", + state_class="measurement", + entity_registry_enabled_default=False + ), + SensorEntityDescription( + key="SolarRad", + name="Solar Radiation", + icon="mdi:sun-wireless-outline", + state_class="measurement", + entity_registry_enabled_default=False + ), + SensorEntityDescription( + key="BatteryVolts", + name="Battery Voltage", + device_class=SensorDeviceClass.VOLTAGE, + native_unit_of_measurement=UnitOfElectricPotential.VOLT, + entity_category=EntityCategory.DIAGNOSTIC, + suggested_display_precision=1 + ), + SensorEntityDescription( + key="ForecastIcon", + name="Forecast Icon", + entity_registry_enabled_default=False + ), + SensorEntityDescription( + key="ForecastRuleNo", + name="Forecast Rule", + icon="mdi:binoculars" + ), + SensorEntityDescription( + key="LastError", + name="Last Error", + icon="mdi:message-alert-outline", + entity_category=EntityCategory.DIAGNOSTIC + ), + SensorEntityDescription( + key="RainCollector", + name="Rain Collector", + icon="mdi:bucket-outline", + entity_category=EntityCategory.DIAGNOSTIC + ), + SensorEntityDescription( + key="WindRoseSetup", + name="Cardinal Directions", + icon="mdi:compass-rose", + entity_category=EntityCategory.DIAGNOSTIC + ), + SensorEntityDescription( + key="ExtraTemps01", + name="Extra Temperature 1", + native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, + device_class=SensorDeviceClass.TEMPERATURE, + state_class="measurement", + entity_registry_enabled_default=False, + suggested_display_precision=1 + ), + SensorEntityDescription( + key="ExtraTemps02", + name="Extra Temperature 2", + native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, + device_class=SensorDeviceClass.TEMPERATURE, + state_class="measurement", + entity_registry_enabled_default=False, + suggested_display_precision=1 + ), + SensorEntityDescription( + key="ExtraTemps03", + name="Extra Temperature 3", + native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, + device_class=SensorDeviceClass.TEMPERATURE, + state_class="measurement", + entity_registry_enabled_default=False, + suggested_display_precision=1 + ), + SensorEntityDescription( + key="ExtraTemps04", + name="Extra Temperature 4", + native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, + device_class=SensorDeviceClass.TEMPERATURE, + state_class="measurement", + entity_registry_enabled_default=False, + suggested_display_precision=1 + ), + SensorEntityDescription( + key="ExtraTemps05", + name="Extra Temperature 5", + native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, + device_class=SensorDeviceClass.TEMPERATURE, + state_class="measurement", + entity_registry_enabled_default=False, + suggested_display_precision=1 + ), + SensorEntityDescription( + key="ExtraTemps06", + name="Extra Temperature 6", + native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, + device_class=SensorDeviceClass.TEMPERATURE, + state_class="measurement", + entity_registry_enabled_default=False, + suggested_display_precision=1 + ), + SensorEntityDescription( + key="ExtraTemps07", + name="Extra Temperature 7", + native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, + device_class=SensorDeviceClass.TEMPERATURE, + state_class="measurement", + entity_registry_enabled_default=False, + suggested_display_precision=1 + ) +] + +async def async_setup_entry( + hass: HomeAssistant, + entry: ConfigEntry, + async_add_entities: AddEntitiesCallback, +) -> None: + """Set up Davis Vantage sensors based on a config entry.""" + coordinator = hass.data[DOMAIN][entry.entry_id] + + entities: list[DavisVantageSensor] = [] + + # Add all meter sensors described above. + for description in DESCRIPTIONS: + entities.append( + DavisVantageSensor( + coordinator=coordinator, + entry_id=entry.entry_id, + description=description, + ) + ) + + async_add_entities(entities) + + +class DavisVantageSensor(CoordinatorEntity[DavisVantageDataUpdateCoordinator], SensorEntity): + """Defines a Davis Vantage sensor.""" + + _attr_has_entity_name = True + + def __init__( + self, + coordinator: DavisVantageDataUpdateCoordinator, + entry_id: str, + description: SensorEntityDescription, + ) -> None: + """Initialize Davis Vantage sensor.""" + super().__init__(coordinator=coordinator) + + self.entity_id = ( + f"{SENSOR_DOMAIN}.{DEFAULT_NAME}_{description.name}".lower() + ) + self.entity_description = description + self._attr_name = description.name # type: ignore + self._attr_unique_id = f"{entry_id}-{DEFAULT_NAME} {self.name}" + self._attr_device_info = coordinator.device_info + + @property + def native_value(self) -> StateType: + """Return the state of the sensor.""" + key = self.entity_description.key + data = self.coordinator.data + if key not in data: + return None + if self.entity_description.native_unit_of_measurement != None: + default_value = 0 + else: + default_value = '-' + return data.get(key, default_value) # type: ignore diff --git a/custom_components/davis_vantage/strings.json b/custom_components/davis_vantage/strings.json new file mode 100755 index 0000000..704dc29 --- /dev/null +++ b/custom_components/davis_vantage/strings.json @@ -0,0 +1,36 @@ +{ + "config": { + "step": { + "user": { + "data": { + "link": "[%key:common::config_flow::data::link%]" + } + }, + "setup_serial": { + "data": { + "link": "[%key:common::config_flow::data::link%]" + } + }, + "setup_network": { + "data": { + "link": "[%key:common::config_flow::data::link%]" + } + }, + "setup_other_info": { + "data": { + "interval": "[%key:common::config_flow::data::interval%]", + "rain_collector": "[%key:common::config_flow::data::rain_collector%]", + "windrose8": "[%key:common::config_flow::data::windrose8%]" + } + } + }, + "error": { + "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", + "invalid_auth": "[%key:common::config_flow::error::invalid_auth%]", + "unknown": "[%key:common::config_flow::error::unknown%]" + }, + "abort": { + "already_configured": "[%key:common::config_flow::abort::already_configured_device%]" + } + } +} diff --git a/custom_components/davis_vantage/translations/en.json b/custom_components/davis_vantage/translations/en.json new file mode 100755 index 0000000..cde8750 --- /dev/null +++ b/custom_components/davis_vantage/translations/en.json @@ -0,0 +1,40 @@ +{ + "config": { + "abort": { + "already_configured": "Device is already configured" + }, + "error": { + "cannot_connect": "Failed to connect", + "invalid_auth": "Looks like the weather station isn't reacting, try again.", + "unknown": "Unexpected error" + }, + "step": { + "user": { + "data": { + "protocol": "Protocol", + "link": "Link", + "interval": "Interval", + "rain_collector": "Rain collector", + "windrose8": "Wind rose with 8 cardinal directions" + } + }, + "setup_serial": { + "data": { + "link": "Device" + } + }, + "setup_network": { + "data": { + "link": "Host" + } + }, + "setup_other_info": { + "data": { + "interval": "Interval", + "rain_collector": "Rain collector", + "windrose8": "Wind rose with 8 cardinal directions" + } + } + } + } +} \ No newline at end of file diff --git a/custom_components/davis_vantage/utils.py b/custom_components/davis_vantage/utils.py new file mode 100755 index 0000000..9a03e61 --- /dev/null +++ b/custom_components/davis_vantage/utils.py @@ -0,0 +1,383 @@ +import math +from datetime import datetime +# from time import strftime +from zoneinfo import ZoneInfo +from typing import Any + +ForecastStrings = ["Mostly clear and cooler.", +"Mostly clear with little temperature change.", +"Mostly clear for 12 hrs. with little temperature change.", +"Mostly clear for 12 to 24 hrs. and cooler.", +"Mostly clear with little temperature change.", +"Partly cloudy and cooler.", +"Partly cloudy with little temperature change.", +"Partly cloudy with little temperature change.", +"Mostly clear and warmer.", +"Partly cloudy with little temperature change.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds and warmer. Precipitation possible within 24 to 48 hrs.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds with little temperature change. Precipitation possible within 24 hrs.", +"Mostly clear with little temperature change.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds with little temperature change. Precipitation possible within 12 hrs.", +"Mostly clear with little temperature change.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds and warmer. Precipitation possible within 24 hrs.", +"Mostly clear and warmer. Increasing winds.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds and warmer. Precipitation possible within 12 hrs. Increasing winds.", +"Mostly clear and warmer. Increasing winds.", +"Increasing clouds and warmer.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds and warmer. Precipitation possible within 12 hrs. Increasing winds.", +"Mostly clear and warmer. Increasing winds.", +"Increasing clouds and warmer.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds and warmer. Precipitation possible within 12 hrs. Increasing winds.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Mostly clear and warmer. Precipitation possible within 48 hrs.", +"Mostly clear and warmer.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds with little temperature change. Precipitation possible within 24 to 48 hrs.", +"Increasing clouds with little temperature change.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds and warmer. Precipitation possible within 12 to 24 hrs.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds and warmer. Precipitation possible within 12 to 24 hrs. Windy.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds and warmer. Precipitation possible within 12 to 24 hrs. Windy.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds and warmer. Precipitation possible within 6 to 12 hrs.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds and warmer. Precipitation possible within 6 to 12 hrs. Windy.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds and warmer. Precipitation possible within 12 to 24 hrs. Windy.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds and warmer. Precipitation possible within 12 hrs.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds and warmer. Precipitation likely.", +"clearing and cooler. Precipitation ending within 6 hrs.", +"Partly cloudy with little temperature change.", +"clearing and cooler. Precipitation ending within 6 hrs.", +"Mostly clear with little temperature change.", +"Clearing and cooler. Precipitation ending within 6 hrs.", +"Partly cloudy and cooler.", +"Partly cloudy with little temperature change.", +"Mostly clear and cooler.", +"clearing and cooler. Precipitation ending within 6 hrs.", +"Mostly clear with little temperature change.", +"Clearing and cooler. Precipitation ending within 6 hrs.", +"Mostly clear and cooler.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds with little temperature change. Precipitation possible within 24 hrs.", +"Mostly cloudy and cooler. Precipitation continuing.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Mostly cloudy and cooler. Precipitation likely.", +"Mostly cloudy with little temperature change. Precipitation continuing.", +"Mostly cloudy with little temperature change. Precipitation likely.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds and cooler. Precipitation possible and windy within 6 hrs.", +"Increasing clouds with little temperature change. Precipitation possible and windy within 6 hrs.", +"Mostly cloudy and cooler. Precipitation continuing. Increasing winds.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Mostly cloudy and cooler. Precipitation likely. Increasing winds.", +"Mostly cloudy with little temperature change. Precipitation continuing. Increasing winds.", +"Mostly cloudy with little temperature change. Precipitation likely. Increasing winds.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds and cooler. Precipitation possible within 12 to 24 hrs. Possible wind shift to the W, NW, or N.", +"Increasing clouds with little temperature change. Precipitation possible within 12 to 24 hrs. Possible wind shift to the W, NW, or N.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds and cooler. Precipitation possible within 6 hrs. Possible wind shift to the W, NW, or N.", +"Increasing clouds with little temperature change. Precipitation possible within 6 hrs. Possible wind shift to the W, NW, or N.", +"Mostly cloudy and cooler. Precipitation ending within 12 hrs. Possible wind shift to the W, NW, or N.", +"Mostly cloudy and cooler. Possible wind shift to the W, NW, or N.", +"Mostly cloudy with little temperature change. Precipitation ending within 12 hrs. Possible wind shift to the W, NW, or N.", +"Mostly cloudy with little temperature change. Possible wind shift to the W, NW, or N.", +"Mostly cloudy and cooler. Precipitation ending within 12 hrs. Possible wind shift to the W, NW, or N.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Mostly cloudy and cooler. Precipitation possible within 24 hrs. Possible wind shift to the W, NW, or N.", +"Mostly cloudy with little temperature change. Precipitation ending within 12 hrs. Possible wind shift to the W, NW, or N.", +"Mostly cloudy with little temperature change. Precipitation possible within 24 hrs. Possible wind shift to the W, NW, or N.", +"clearing, cooler and windy. Precipitation ending within 6 hrs.", +"clearing, cooler and windy.", +"Mostly cloudy and cooler. Precipitation ending within 6 hrs. Windy with possible wind shift to the W, NW, or N.", +"Mostly cloudy and cooler. Windy with possible wind shift to the W, NW, or N.", +"clearing, cooler and windy.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Mostly cloudy with little temperature change. Precipitation possible within 12 hrs. Windy.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds and cooler. Precipitation possible within 12 hrs, possibly heavy at times. Windy.", +"Mostly cloudy and cooler. Precipitation ending within 6 hrs. Windy.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Mostly cloudy and cooler. Precipitation possible within 12 hrs. Windy.", +"Mostly cloudy and cooler. Precipitation ending in 12 to 24 hrs.", +"Mostly cloudy and cooler.", +"Mostly cloudy and cooler. Precipitation continuing, possible heavy at times. Windy.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Mostly cloudy and cooler. Precipitation possible within 6 to 12 hrs. Windy.", +"Mostly cloudy with little temperature change. Precipitation continuing, possibly heavy at times. Windy.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Mostly cloudy with little temperature change. Precipitation possible within 6 to 12 hrs. Windy.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds with little temperature change. Precipitation possible within 12 hrs, possibly heavy at times. Windy.", +"Mostly cloudy and cooler. Windy.", +"Mostly cloudy and cooler. Precipitation continuing, possibly heavy at times. Windy.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Mostly cloudy and cooler. Precipitation likely, possibly heavy at times. Windy.", +"Mostly cloudy with little temperature change. Precipitation continuing, possibly heavy at times. Windy.", +"Mostly cloudy with little temperature change. Precipitation likely, possibly heavy at times. Windy.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds and cooler. Precipitation possible within 6 hrs. Windy.", +"Increasing clouds with little temperature change. Precipitation possible within 6 hrs. windy", +"Increasing clouds and cooler. Precipitation continuing. Windy with possible wind shift to the W, NW, or N.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Mostly cloudy and cooler. Precipitation likely. Windy with possible wind shift to the W, NW, or N.", +"Mostly cloudy with little temperature change. Precipitation continuing. Windy with possible wind shift to the W, NW, or N.", +"Mostly cloudy with little temperature change. Precipitation likely. Windy with possible wind shift to the W, NW, or N.", +"Increasing clouds and cooler. Precipitation possible within 6 hrs. Windy with possible wind shift to the W, NW, or N.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds and cooler. Precipitation possible within 6 hrs. Possible wind shift to the W, NW, or N.", +"Increasing clouds with little temperature change. Precipitation possible within 6 hrs. Windy with possible wind shift to the W, NW, or N.", +"Increasing clouds with little temperature change. Precipitation possible within 6 hrs. Possible wind shift to the W, NW, or N.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds and cooler. Precipitation possible within 6 hrs. Windy with possible wind shift to the W, NW, or N.", +"Increasing clouds with little temperature change. Precipitation possible within 6 hrs. Windy with possible wind shift to the W, NW, or N.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Increasing clouds and cooler. Precipitation possible within 12 to 24 hrs. Windy with possible wind shift to the W, NW, or N.", +"Increasing clouds with little temperature change. Precipitation possible within 12 to 24 hrs. Windy with possible wind shift to the W, NW, or N.", +"Mostly cloudy and cooler. Precipitation possibly heavy at times and ending within 12 hrs. Windy with possible wind shift to the W, NW, or N.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Mostly cloudy and cooler. Precipitation possible within 6 to 12 hrs, possibly heavy at times. Windy with possible wind shift to the W, NW, or N.", +"Mostly cloudy with little temperature change. Precipitation ending within 12 hrs. Windy with possible wind shift to the W, NW, or N.", +"Mostly cloudy with little temperature change. Precipitation possible within 6 to 12 hrs, possibly heavy at times. Windy with possible wind shift to the W, NW, or N.", +"Mostly cloudy and cooler. Precipitation continuing.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Mostly cloudy and cooler. Precipitation likely, windy with possible wind shift to the W, NW, or N.", +"Mostly cloudy with little temperature change. Precipitation continuing.", +"Mostly cloudy with little temperature change. Precipitation likely.", +"Partly cloudy with little temperature change.", +"Mostly clear with little temperature change.", +"Mostly cloudy and cooler. Precipitation possible within 12 hours, possibly heavy at times. Windy.", +"FORECAST REQUIRES 3 HRS. OF RECENT DATA", +"Mostly clear and cooler." ] + +def convert_to_celcius(value: float) -> float: + return round((value - 32.0) * (5.0/9.0), 1) + +def convert_celcius_to_fahrenheit(value_c: float) -> float: + return round(value_c * 1.8 + 32, 1) + +def convert_to_kmh(value: float) -> float: + return round(value * 1.609344, 1) + +def convert_to_ms(value: float) -> float: + return convert_kmh_to_ms(convert_to_kmh(value)) + +def convert_to_mbar(value: float) -> float: + return round(value * 33.8637526, 1) + +def convert_to_mm(value: float) -> float: + return round(value * 20.0, 1) # Use metric tipping bucket modification + +def convert_kmh_to_ms(windspeed: float) -> float: + return round(windspeed / 3.6, 1) + +def convert_ms_to_bft(windspeed: float) -> int: + if windspeed < 0.2: + return 0 + elif windspeed < 1.6: + return 1 + elif windspeed < 3.4: + return 2 + elif windspeed < 5.5: + return 3 + elif windspeed < 8.0: + return 4 + elif windspeed < 10.8: + return 5 + elif windspeed < 13.9: + return 6 + elif windspeed < 17.2: + return 7 + elif windspeed < 20.8: + return 8 + elif windspeed < 24.5: + return 9 + elif windspeed < 28.5: + return 10 + elif windspeed < 32.7: + return 11 + else: + return 12 + +def convert_kmh_to_bft(windspeed_kmh: float) -> int: + return convert_ms_to_bft(convert_kmh_to_ms(windspeed_kmh)) + +def contains_correct_data(json_data: dict[str, Any]) -> None: + return json_data['OutsideTemp']['value'] < 60 \ + and json_data['RainRate']['value'] < 1000 \ + and json_data['WindSpeed']['value'] < 40 \ + and json_data['OutsideHum']['value'] < 100 \ + and json_data['WindAvgSpeed']['value'] < 250 + +def calc_heat_index(temperature_f: float, humidity: float) -> float: + if temperature_f < 80.0 or humidity < 40.0: + return temperature_f + else: + heat_index_f = \ + -42.379 \ + + (2.04901523 * temperature_f) \ + + (10.14333127 * humidity) \ + - (0.22475541 * temperature_f * humidity) \ + - (0.00683783 * pow(temperature_f, 2)) \ + - (0.05481717 * pow(humidity, 2)) \ + + (0.00122874 * pow(temperature_f, 2) * humidity) \ + + (0.00085282 * temperature_f * pow(humidity, 2)) \ + - (0.00000199 * pow(temperature_f, 2) * pow(humidity, 2)) + + if (heat_index_f < temperature_f): + heat_index_f = temperature_f + + return heat_index_f + +def calc_wind_chill(temperature_f: float, windspeed: float) -> float: + if (windspeed == 0): + wind_chill_f = temperature_f + else: + wind_chill_f = \ + 35.74 \ + + (0.6215 * temperature_f) \ + - (35.75 * pow(windspeed,0.16)) \ + + (0.4275 * temperature_f * pow(windspeed, 0.16)) + if (wind_chill_f > temperature_f): + wind_chill_f = temperature_f + + return wind_chill_f + +def calc_feels_like(temperature_f: float, humidity: float, windspeed_mph: float) -> float: + if windspeed_mph == 0: + windspeed_mph = 1 + feels_like_f = temperature_f + if temperature_f <= 50 and humidity >= 3: + feels_like_f = \ + 35.74 \ + + (0.6215 * temperature_f) \ + - (35.75 * pow(windspeed_mph, 0.16)) \ + + (0.4275 * temperature_f * pow(windspeed_mph, 0.16)) + + if feels_like_f == temperature_f and temperature_f >= 80: + feels_like_f = \ + 0.5 * (temperature_f + 61 + ((temperature_f - 68) * 1.2) \ + + (humidity * 0.094) ) + + if feels_like_f >= 80: + feels_like_f = \ + -42.379 \ + + (2.04901523 * temperature_f) \ + + (10.14333127 * humidity) \ + - (0.22475541 * temperature_f * humidity) \ + - (0.00683783 * pow(temperature_f, 2)) \ + - (0.05481717 * pow(humidity, 2)) \ + + (0.00122874 * pow(temperature_f, 2) * humidity) \ + + (0.00085282 * temperature_f * pow(humidity, 2)) \ + - (0.00000199 * pow(temperature_f, 2) * pow(humidity, 2)) + + if humidity < 13 and temperature_f >= 80 and temperature_f <= 112: + feels_like_f = feels_like_f - ((13 - humidity) / 4) * math.sqrt((17 - math.fabs(temperature_f - 95.0)) / 17) + + if humidity > 85 and temperature_f >= 80 and temperature_f <= 87: + feels_like_f = feels_like_f + ((humidity - 85) / 10) * ((87 - temperature_f) / 5) + return feels_like_f + +def convert_to_iso_datetime(value: datetime, tzinfo: ZoneInfo) -> datetime: + return value.replace(tzinfo=tzinfo) + +def get_wind_rose(bearing: int, windrose8: bool) -> str: + directions = [ 'N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', + 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW' ] + if windrose8: + index = (round(bearing / 45) % 8) * 2 + else: + index = round(bearing / 22.5) % 16 + return directions[index] + +def has_correct_value(value: float) -> bool: + return value != 255 and value != 32767 + +def round_to_one_decimal(value: float) -> float: + return round(value, 1) + +def get_baro_trend(trend: int) -> str: + if trend in [-60,196]: + return "Falling Rapidly" + elif trend in [-20,236]: + return "Falling Slowly" + elif trend == 0: + return "Steady" + elif trend == 20: + return "Rising Slowly" + elif trend == 60: + return "Rising Rapidly" + else: + return f"n/a ({trend})" + +def get_forecast_string(wrule: int) -> str: + if wrule > 194: + wrule = 194 + return ForecastStrings[wrule] + +def get_uv(value: int) -> float|bool: + if value == 255: + return False + else: + return round(value / 10, 1) + +def get_solar_rad(value: int) -> float|bool: + if value == 32767: + return False + else: + return value + +def calc_dew_point(temperature_f: float, humidity: float) -> float: + temperature_c = convert_to_celcius(temperature_f) + A = math.log(humidity / 100) + (17.62 * temperature_c / (243.12 + temperature_c)) + return convert_celcius_to_fahrenheit(243.12 * A / (17.62 - A)) diff --git a/hacs.json b/hacs.json new file mode 100755 index 0000000..1bc81f0 --- /dev/null +++ b/hacs.json @@ -0,0 +1,5 @@ +{ + "name": "Davis Vantage", + "homeassistant": "2022.12.0", + "render_readme": true + }