diff --git a/README.md b/README.md index 090a392..4f4f25d 100755 --- a/README.md +++ b/README.md @@ -19,16 +19,133 @@ During the setup of the integration the serial port or the hostname of the weath Example network host: 192.168.0.18:1111 -![Setup](/assets/setup.png) - ## What to expect -The following sensors will be registered: +The following entities will be created: + +- Barometric Pressure: + - Current barometric pressure +- Barometric Pressure High (Day): + - Today's highest barometric pressure +- Barometric Pressure Low (Day): + - Today's lowest barometric pressure +- Barometric Trend: + - Current barometric trend, being Stable, Rising Slowly, Rising Rapidly, Falling Slowly, Falling Rapidly +- Dew Point: + - Current dev point +- Feels Like: + - Current feels like temperature +- Forecast Rule: + - Current forecast rule +- Heat Index: + - Current heat index +- Humidity: + - Current outside relative humidify +- Humidity High (Day): + - Today's highest outside relative humididy +- Humidity Low (Day): + - Today's lowest outside relative humidity +- Is Raining: + - True if it's currently raining (based on rain rate) +- Rain (Day): + - Today's total precipitation +- Rain (Month): + - This months total precipitation +- Rain (Year): + - This year total precipitation +- Rain Rate: + - Current rain rate +- Rain Rate (Day): + - Today's highest rain rate +- Solar Radiation: + - Current solar radiation +- Solar Radiation (Day): + - Today's highest solar radiation +- Temperature: + - Current outside temperature +- Temperature High (Day): + - Today's highest outside temperature +- Temperature Low (Day): + - Today's lowest outside temperature +- UV Level: + - Current UV level +- UV Level (Day): + - Today's highest UV level +- Wind Chill: + - Current wind chill +- Wind Direction: + - Current wind direction in degrees +- Wind Direction Rose: + - Current wind direction in cardinal directions (N, NE, E, etc.) +- Wind Gust: + - Current wind gust, based on the highest value within an Archive Interval +- Wind Gust (Day): + - Today's highest wind gust +- Wind Speed: + - Current wind speed +- Wind Speed (Avarage): + - 10 minutes average wind speed +- Wind Speed (Bft): + - 10 minutes average wind speed in Beaufort +- Extra Humidity 1: + - Current humidity extra sensor 1 +- Extra Humidity 2: + - Current humidity extra sensor 2 +- Extra Humidity 3: + - Current humidity extra sensor 3 +- Extra Humidity 4: + - Current humidity extra sensor 4 +- Extra Humidity 5: + - Current humidity extra sensor 5 +- Extra Humidity 6: + - Current humidity extra sensor 6 +- Extra Humidity 7: + - Current humidity extra sensor 7 +- Extra Temperature 1: + - Current temperature extra sensor 1 +- Extra Temperature 2: + - Current temperature extra sensor 2 +- Extra Temperature 3: + - Current temperature extra sensor 3 +- Extra Temperature 4: + - Current temperature extra sensor 4 +- Extra Temperature 5: + - Current temperature extra sensor 5 +- Extra Temperature 6: + - Current temperature extra sensor 6 +- Extra Temperature 7: + - Current temperature extra sensor 7 +- Forecast Icon: + - Current forecast icon +- Humidity (Inside): + - Current inside relative humidity +- Temperature (Inside): + - Current inside temperature -![Sensors](/assets/sensors.png) +Diagnostic entities: +- Archive Interval: + - Archive data interval (usual around 10 minutes) +- High/Low Values Up-to-Date: + - Boolean sensor indicating if the last fetch of the high/low values succeeded +- Last Error Message: + - Last error message, if no error then empty +- Last Fetch Time: + - Last fetch time +- Battery Voltage: + - Current battery voltage +- Cardinal Directions: + - Number of cardinal direction 8 or 16 (set during setup) +- Last Error Time: + - Last error time +- Last Success Time: + - Last success time +- Rain Collector: + - Current rain collector setup (0.01" or 0.2 mm) -The sensor information is updated every 30 seconds. +The entity information is updated every 30 seconds (default or other value is choosen otherwise during setup). ## Known problems During first setup the communication to the weather station can be a bit tricky, resulting in an error saying the device didn't communicate. Please try again to set it up (can take up to 5 times). + +Determining Wind Gust and High/Low values are done by reading archive data of the weather station. Unfortunately this part of the library function is a bit unstable. If the integration was not able to read the archive data the sensor "High/Low Value Up-to-Date" becomes false. \ No newline at end of file diff --git a/custom_components/davis_vantage/binary_sensor.py b/custom_components/davis_vantage/binary_sensor.py index 7df12c3..b1002f2 100755 --- a/custom_components/davis_vantage/binary_sensor.py +++ b/custom_components/davis_vantage/binary_sensor.py @@ -7,12 +7,16 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.update_coordinator import CoordinatorEntity +from homeassistant.helpers.entity import EntityCategory from .const import DEFAULT_NAME, DOMAIN from .coordinator import DavisVantageDataUpdateCoordinator DESCRIPTIONS: list[BinarySensorEntityDescription] = [ - BinarySensorEntityDescription(key="IsRaining", name="Is Raining") + BinarySensorEntityDescription( + key="IsRaining", + name="Is Raining" + ) ] diff --git a/custom_components/davis_vantage/client.py b/custom_components/davis_vantage/client.py index 6f87fff..e4e926c 100755 --- a/custom_components/davis_vantage/client.py +++ b/custom_components/davis_vantage/client.py @@ -1,13 +1,18 @@ """All client function""" from typing import Any -from datetime import datetime +from datetime import datetime, timedelta, time from zoneinfo import ZoneInfo import logging import asyncio import struct import re from pyvantagepro import VantagePro2 -from pyvantagepro.parser import LoopDataParserRevB, DataParser +from pyvantagepro.parser import ( + HighLowParserRevB, + LoopDataParserRevB, + DataParser +) +from pyvantagepro.utils import ListDict from homeassistant.core import HomeAssistant from .utils import ( @@ -25,14 +30,16 @@ get_uv, get_wind_rose, ) -from .const import RAIN_COLLECTOR_METRIC, PROTOCOL_NETWORK +from .const import RAIN_COLLECTOR_IMPERIAL, PROTOCOL_NETWORK _LOGGER: logging.Logger = logging.getLogger(__package__) class DavisVantageClient: """Davis Vantage Client class""" + _vantagepro2: VantagePro2 = None + def __init__( self, hass: HomeAssistant, @@ -46,8 +53,8 @@ def __init__( self._link = link self._windrose8 = windrose8 self._rain_collector = rain_collector - self._last_data: LoopDataParserRevB = {} # type: ignore - self._last_raw_data: DataParser = {} # type: ignore + self._last_data: LoopDataParserRevB = {} # type: ignore + self._last_raw_data: DataParser = {} # type: ignore def get_vantagepro2fromurl(self, url: str) -> VantagePro2 | None: try: @@ -58,69 +65,93 @@ def get_vantagepro2fromurl(self, url: str) -> VantagePro2 | None: raise e async def async_get_vantagepro2fromurl(self, url: str) -> VantagePro2 | None: - _LOGGER.debug('async_get_vantagepro2fromurl with url=%s', url) + _LOGGER.debug("async_get_vantagepro2fromurl with url=%s", url) vp = None try: loop = asyncio.get_event_loop() vp = await loop.run_in_executor(None, self.get_vantagepro2fromurl, url) except Exception as e: - _LOGGER.error('Error on opening device from url: %s: %s', url, e) + _LOGGER.error("Error on opening device from url: %s: %s", url, e) return vp async def connect_to_station(self): self._vantagepro2 = await self.async_get_vantagepro2fromurl(self.get_link()) - def get_current_data(self) -> LoopDataParserRevB | None: + def get_current_data(self) -> tuple[LoopDataParserRevB | None, ListDict | None, HighLowParserRevB|None]: """Get current date from weather station.""" + data = None + archives = None + hilows = None + try: self._vantagepro2.link.open() data = self._vantagepro2.get_current_data() except Exception as e: + self._vantagepro2.link.close() raise e + + try: + hilows = self._vantagepro2.get_hilows() + except Exception: + pass + + try: + end_datetime = datetime.now() + start_datetime = end_datetime - timedelta(minutes=(self._vantagepro2.archive_period * 2)) # type: ignore + # start_datetime = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) + # end_datetime = start_datetime + timedelta(hours=24) + archives = self._vantagepro2.get_archives(start_datetime, end_datetime) + except Exception: + pass finally: self._vantagepro2.link.close() - return data + + return data, archives, hilows async def async_get_current_data(self) -> LoopDataParserRevB | None: """Get current date from weather station async.""" data = self._last_data - now = convert_to_iso_datetime(datetime.now(), ZoneInfo(self._hass.config.time_zone)) + now = convert_to_iso_datetime( + datetime.now(), ZoneInfo(self._hass.config.time_zone) + ) try: loop = asyncio.get_event_loop() - new_data = await loop.run_in_executor(None, self.get_current_data) + new_data, archives, hilows = await loop.run_in_executor(None, self.get_current_data) if new_data: new_raw_data = self.__get_full_raw_data(new_data) self._last_raw_data = new_raw_data self.remove_all_incorrect_data(new_raw_data, new_data) self.add_additional_info(new_data) + self.add_wind_gust(archives, new_data) + self.add_hilows(hilows, new_data) self.convert_values(new_data) data = new_data - data['Datetime'] = now + data["Datetime"] = now if contains_correct_raw_data(new_raw_data): - data['LastError'] = "" - data['LastSuccessTime'] = now + data["LastError"] = "" + data["LastSuccessTime"] = now else: - data['LastError'] = "Received partly incorrect data" + data["LastError"] = "Received partly incorrect data" else: data["LastError"] = "Couldn't acquire data, no data received" except Exception as e: - _LOGGER.warning(f"Couldn't acquire data from {self.get_link()}") - data['LastError'] = f"Couldn't acquire data: {e}" + _LOGGER.warning(f"Couldn't acquire data from {self.get_link()}: {e}") + data["LastError"] = f"Couldn't acquire data: {e}" - if data['LastError']: - data['LastErrorTime'] = now + if data["LastError"]: + data["LastErrorTime"] = now self._last_data = data return data def __get_full_raw_data(self, data: LoopDataParserRevB) -> DataParser: raw_data = DataParser(data.raw_bytes, LoopDataParserRevB.LOOP_FORMAT) - raw_data['HumExtra'] = struct.unpack(b'7B', raw_data['HumExtra']) # type: ignore - raw_data['ExtraTemps'] = struct.unpack(b'7B', raw_data['ExtraTemps']) # type: ignore - raw_data['SoilMoist'] = struct.unpack(b'4B', raw_data['SoilMoist']) # type: ignore - raw_data['SoilTemps'] = struct.unpack(b'4B', raw_data['SoilTemps']) # type: ignore - raw_data['LeafWetness'] = struct.unpack(b'4B', raw_data['LeafWetness']) # type: ignore - raw_data['LeafTemps'] = struct.unpack(b'4B', raw_data['LeafTemps']) # type: ignore + raw_data["HumExtra"] = struct.unpack(b"7B", raw_data["HumExtra"]) # type: ignore + raw_data["ExtraTemps"] = struct.unpack(b"7B", raw_data["ExtraTemps"]) # type: ignore + raw_data["SoilMoist"] = struct.unpack(b"4B", raw_data["SoilMoist"]) # type: ignore + raw_data["SoilTemps"] = struct.unpack(b"4B", raw_data["SoilTemps"]) # type: ignore + raw_data["LeafWetness"] = struct.unpack(b"4B", raw_data["LeafWetness"]) # type: ignore + raw_data["LeafTemps"] = struct.unpack(b"4B", raw_data["LeafTemps"]) # type: ignore raw_data.tuple_to_dict("ExtraTemps") raw_data.tuple_to_dict("LeafTemps") raw_data.tuple_to_dict("SoilTemps") @@ -172,14 +203,18 @@ async def async_set_davis_time(self) -> None: def get_info(self) -> dict[str, Any] | None: try: self._vantagepro2.link.open() - firmware_version = self._vantagepro2.firmware_version # type: ignore - firmware_date = self._vantagepro2.firmware_date # type: ignore - diagnostics = self._vantagepro2.diagnostics # type: ignore + firmware_version = self._vantagepro2.firmware_version # type: ignore + firmware_date = self._vantagepro2.firmware_date # type: ignore + diagnostics = self._vantagepro2.diagnostics # type: ignore except Exception as e: raise e finally: self._vantagepro2.link.close() - return { "version": firmware_version, "date": firmware_date, "diagnostics": diagnostics } + return { + "version": firmware_version, + "date": firmware_date, + "diagnostics": diagnostics, + } async def async_get_info(self) -> dict[str, Any] | None: info = None @@ -191,56 +226,99 @@ async def async_get_info(self) -> dict[str, Any] | None: return info def add_additional_info(self, data: dict[str, Any]) -> None: - if data['TempOut'] is not None: - if data['HumOut'] is not None: - data['HeatIndex'] = calc_heat_index(data['TempOut'], data['HumOut']) - data['DewPoint'] = calc_dew_point(data['TempOut'], data['HumOut']) - if data['WindSpeed'] is not None: - data['WindChill'] = calc_wind_chill(data['TempOut'], data['WindSpeed']) - if data['HumOut'] is not None: - data['FeelsLike'] = calc_feels_like(data['TempOut'], data['HumOut'], data['WindSpeed']) - if data['WindDir'] is not None: - data['WindDirRose'] = get_wind_rose(data['WindDir'], self._windrose8) - if data['WindSpeed10Min'] is not None: - data['WindSpeedBft'] = convert_kmh_to_bft(convert_to_kmh(data['WindSpeed10Min'])) - if data['RainRate'] is not None: - data['IsRaining'] = data['RainRate'] > 0 + if data["TempOut"] is not None: + if data["HumOut"] is not None: + data["HeatIndex"] = calc_heat_index(data["TempOut"], data["HumOut"]) + data["DewPoint"] = calc_dew_point(data["TempOut"], data["HumOut"]) + if data["WindSpeed"] is not None: + data["WindChill"] = calc_wind_chill(data["TempOut"], data["WindSpeed"]) + if data["HumOut"] is not None: + data["FeelsLike"] = calc_feels_like( + data["TempOut"], data["HumOut"], data["WindSpeed"] + ) + if data["WindDir"] is not None: + data["WindDirRose"] = get_wind_rose(data["WindDir"], self._windrose8) + if data["WindSpeed10Min"] is not None: + data["WindSpeedBft"] = convert_kmh_to_bft( + convert_to_kmh(data["WindSpeed10Min"]) + ) + if data["RainRate"] is not None: + data["IsRaining"] = data["RainRate"] > 0 + data["ArchiveInterval"] = self._vantagepro2.archive_period def convert_values(self, data: dict[str, Any]) -> None: - del data['Datetime'] - if data['BarTrend'] is not None: - data['BarTrend'] = get_baro_trend(data['BarTrend']) - if data['UV'] is not None: - data['UV'] = get_uv(data['UV']) - if data['SolarRad'] is not None: - data['SolarRad'] = get_solar_rad(data['SolarRad']) - if data['ForecastRuleNo'] is not None: - 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: + del data["Datetime"] + if data["BarTrend"] is not None: + data["BarTrend"] = get_baro_trend(data["BarTrend"]) + if data["UV"] is not None: + data["UV"] = get_uv(data["UV"]) + if data["SolarRad"] is not None: + data["SolarRad"] = get_solar_rad(data["SolarRad"]) + if data["ForecastRuleNo"] is not None: + 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_IMPERIAL: self.correct_rain_values(data) def correct_rain_values(self, data: dict[str, Any]): - if data['RainDay'] is not None: - data['RainDay'] *= 2/2.54 - if data['RainMonth'] is not None: - data['RainMonth'] *= 2/2.54 - if data['RainYear'] is not None: - data['RainYear'] *= 2/2.54 - if data['RainRate'] is not None: - data['RainRate'] *= 2/2.54 + if data["RainDay"] is not None: + data["RainDay"] *= 2 / 2.54 + if data["RainMonth"] is not None: + data["RainMonth"] *= 2 / 2.54 + if data["RainYear"] is not None: + data["RainYear"] *= 2 / 2.54 + if data["RainRate"] is not None: + data["RainRate"] *= 2 / 2.54 + if "RainRateDay" in data: + if data["RainRateDay"] is not None: + data["RainRateDay"] *= 2 / 2.54 def remove_all_incorrect_data(self, raw_data: DataParser, data: LoopDataParserRevB): - data_info = { key: value for key, value in LoopDataParserRevB.LOOP_FORMAT } - for key in data.keys(): # type: ignore - info_key = re.sub(r'\d+$', '', key) # type: ignore - if data_info.get(info_key, '') in ["B", "7s"]: - if raw_data.get(key, 0) == 255: # type: ignore - data[key] = None # type: ignore - if data_info.get(key, '') == 'H': # type: ignore - if raw_data.get(key, '') == 32767 or raw_data.get(key, '') == 65535: # type: ignore - data[key] = None # type: ignore + data_info = {key: value for key, value in LoopDataParserRevB.LOOP_FORMAT} + for key in data.keys(): # type: ignore + info_key = re.sub(r"\d+$", "", key) # type: ignore + if data_info.get(info_key, "") in ["B", "7s"]: + if raw_data.get(key, 0) == 255: # type: ignore + data[key] = None # type: ignore + if data_info.get(key, "") == "H": # type: ignore + if raw_data.get(key, "") == 32767 or raw_data.get(key, "") == 65535: # type: ignore + data[key] = None # type: ignore + + def add_wind_gust(self, archives: ListDict | None, data: dict[str, Any]): + if not archives: + return + data["WindGust"] = archives[-1]["WindHi"] + + def add_hilows(self, hilows: HighLowParserRevB | None, data: dict[str, Any]): + if not hilows: + return + data['TempOutHiDay'] = hilows['TempHiDay'] + data['TempOutHiTime'] = self.strtotime(hilows['TempHiTime']) + data['TempOutLowDay'] = hilows['TempLoDay'] + data['TempOutLowTime'] = self.strtotime(hilows['TempLoTime']) + + data['DewPointHiDay'] = hilows['DewHiDay'] + data['DewPointHiTime'] = self.strtotime(hilows['DewHiTime']) + data['DewPointLowDay'] = hilows['DewLoDay'] + data['DewPointLowTime'] = self.strtotime(hilows['DewLoTime']) + + data['RainRateDay'] = hilows['RainHiDay'] + data['RainRateTime'] = self.strtotime(hilows['RainHiTime']) + + data['BarometerHiDay'] = hilows['BaroHiDay'] + data['BarometerHiTime'] = self.strtotime(hilows['BaroHiTime']) + data['BarometerLowDay'] = hilows['BaroLoDay'] + data['BarometerLoTime'] = self.strtotime(hilows['BaroLoTime']) + + data['SolarRadDay'] = hilows['SolarHiDay'] + data['SolarRadTime'] = self.strtotime(hilows['SolarHiTime']) + + data['UVDay'] = hilows['UVHiDay'] + data['UVTime'] = self.strtotime(hilows['UVHiTime']) + + data['WindGustDay'] = hilows['WindHiDay'] + data['WindGustTime'] =self.strtotime( hilows['WindHiTime']) def get_link(self) -> str | None: """Get device link for use with vproweather.""" @@ -250,3 +328,9 @@ def get_link(self) -> str | None: def get_raw_data(self) -> DataParser: return self._last_raw_data + + def strtotime(self, time_str: str) -> time | None: + if time_str == '655:35': + return None + else: + return datetime.strptime(time_str, '%H:%M').time() diff --git a/custom_components/davis_vantage/const.py b/custom_components/davis_vantage/const.py index ea5143f..700aab6 100755 --- a/custom_components/davis_vantage/const.py +++ b/custom_components/davis_vantage/const.py @@ -4,7 +4,7 @@ DOMAIN = "davis_vantage" MANUFACTURER = "Davis" MODEL = "Vantage Pro2/Vue" -VERSION = "1.0.11" +VERSION = "1.1.0" DEFAULT_SYNC_INTERVAL = 30 # seconds DEFAULT_NAME = NAME diff --git a/custom_components/davis_vantage/manifest.json b/custom_components/davis_vantage/manifest.json index 66d3914..ce5e771 100755 --- a/custom_components/davis_vantage/manifest.json +++ b/custom_components/davis_vantage/manifest.json @@ -4,7 +4,7 @@ "version": "1.0.0", "config_flow": true, "documentation": "https://github.com/MarcoGos/davis_vantage", - "requirements": ["git+https://github.com/MarcoGos/PyVantagePro.git#PyVantagePro==0.3.3"], + "requirements": ["git+https://github.com/MarcoGos/PyVantagePro.git#PyVantagePro==0.3.8"], "ssdp": [], "zeroconf": [], "homekit": {}, diff --git a/custom_components/davis_vantage/sensor.py b/custom_components/davis_vantage/sensor.py index 77fff41..bbba1c0 100755 --- a/custom_components/davis_vantage/sensor.py +++ b/custom_components/davis_vantage/sensor.py @@ -15,7 +15,8 @@ UnitOfElectricPotential, UnitOfTemperature, UnitOfPressure, - UnitOfIrradiance + UnitOfIrradiance, + UnitOfTime ) from homeassistant.core import HomeAssistant from homeassistant.helpers.entity import EntityCategory @@ -64,6 +65,14 @@ entity_category=EntityCategory.DIAGNOSTIC, entity_registry_enabled_default=False ), + SensorEntityDescription( + key="ArchiveInterval", + name="Archive Interval", + icon="mdi:archive-clock-outline", + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + native_unit_of_measurement=UnitOfTime.MINUTES + ), SensorEntityDescription( key="TempOut", name="Temperature", @@ -72,6 +81,34 @@ native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, suggested_display_precision=1 ), + SensorEntityDescription( + key="TempOutHiDay", + name="Temperature High (Day)", + device_class=SensorDeviceClass.TEMPERATURE, + state_class="measurement", + native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, + suggested_display_precision=1, + icon="mdi:thermometer-chevron-up" + ), + SensorEntityDescription( + key="TempOutHiTime", + name="Temperature High Time", + icon="mdi:clock-in" + ), + SensorEntityDescription( + key="TempOutLowDay", + name="Temperature Low (Day)", + device_class=SensorDeviceClass.TEMPERATURE, + state_class="measurement", + native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, + suggested_display_precision=1, + icon="mdi:thermometer-chevron-down" + ), + SensorEntityDescription( + key="TempOutLowTime", + name="Temperature Low Time", + icon="mdi:clock-in" + ), SensorEntityDescription( key="TempIn", name="Temperature (Inside)", @@ -116,6 +153,34 @@ native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, suggested_display_precision=1 ), + SensorEntityDescription( + key="DewPointHiDay", + name="Dew Point High (Day)", + icon="mdi:water-thermometer-outline", + device_class=SensorDeviceClass.TEMPERATURE, + state_class="measurement", + native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, + suggested_display_precision=1 + ), + SensorEntityDescription( + key="DewPointHiTime", + name="Dew Point High Time", + icon="mdi:clock-in" + ), + SensorEntityDescription( + key="DewPointLowDay", + name="Dew Point Low (Day)", + icon="mdi:water-thermometer-outline", + device_class=SensorDeviceClass.TEMPERATURE, + state_class="measurement", + native_unit_of_measurement=UnitOfTemperature.FAHRENHEIT, + suggested_display_precision=1 + ), + SensorEntityDescription( + key="DewPointLowTime", + name="Dew Point Low Time", + icon="mdi:clock-in" + ), SensorEntityDescription( key="Barometer", name="Barometric Pressure", @@ -124,6 +189,32 @@ native_unit_of_measurement=UnitOfPressure.INHG, suggested_display_precision=2 ), + SensorEntityDescription( + key="BarometerHiDay", + name="Barometric Pressure High (Day)", + device_class=SensorDeviceClass.PRESSURE, + state_class="measurement", + native_unit_of_measurement=UnitOfPressure.INHG, + suggested_display_precision=2 + ), + SensorEntityDescription( + key="BarometerHiTime", + name="Barometric Pressure High Time", + icon="mdi:clock-in" + ), + SensorEntityDescription( + key="BarometerLowDay", + name="Barometric Pressure Low (Day)", + device_class=SensorDeviceClass.PRESSURE, + state_class="measurement", + native_unit_of_measurement=UnitOfPressure.INHG, + suggested_display_precision=2 + ), + SensorEntityDescription( + key="BarometerLoTime", + name="Barometric Pressure Low Time", + icon="mdi:clock-in" + ), SensorEntityDescription( key="BarTrend", name="Barometric Trend", @@ -163,6 +254,29 @@ native_unit_of_measurement=UnitOfSpeed.MILES_PER_HOUR, suggested_display_precision=1 ), + SensorEntityDescription( + key="WindGust", + name="Wind Gust", + icon="mdi:windsock", + device_class=SensorDeviceClass.WIND_SPEED, + state_class="measurement", + native_unit_of_measurement=UnitOfSpeed.MILES_PER_HOUR, + suggested_display_precision=1 + ), + SensorEntityDescription( + key="WindGustDay", + name="Wind Gust (Day)", + icon="mdi:windsock", + device_class=SensorDeviceClass.WIND_SPEED, + state_class="measurement", + native_unit_of_measurement=UnitOfSpeed.MILES_PER_HOUR, + suggested_display_precision=1 + ), + SensorEntityDescription( + key="WindGustTime", + name="Wind Gust Time", + icon="mdi:clock-in" + ), SensorEntityDescription( key="WindDir", name="Wind Direction", @@ -219,6 +333,20 @@ native_unit_of_measurement=UnitOfVolumetricFlux.INCHES_PER_HOUR, suggested_display_precision=1 ), + SensorEntityDescription( + key="RainRateDay", + name="Rain Rate (Day)", + icon="mdi:water-outline", + device_class=SensorDeviceClass.PRECIPITATION_INTENSITY, + state_class="measurement", + native_unit_of_measurement=UnitOfVolumetricFlux.INCHES_PER_HOUR, + suggested_display_precision=1 + ), + SensorEntityDescription( + key="RainRateTime", + name="Rain Rate Time", + icon="mdi:clock-in" + ), SensorEntityDescription( key="UV", name="UV Level", @@ -226,6 +354,19 @@ state_class="measurement", entity_registry_enabled_default=False ), + SensorEntityDescription( + key="UVDay", + name="UV Level (Day)", + icon="mdi:sun-wireless-outline", + state_class="measurement", + entity_registry_enabled_default=False + ), + SensorEntityDescription( + key="UVTime", + name="UV Level Time", + icon="mdi:clock-in", + entity_registry_enabled_default=False + ), SensorEntityDescription( key="SolarRad", name="Solar Radiation", @@ -234,6 +375,20 @@ entity_registry_enabled_default=False, native_unit_of_measurement=UnitOfIrradiance.WATTS_PER_SQUARE_METER ), + SensorEntityDescription( + key="SolarRadDay", + name="Solar Radiation (Day)", + icon="mdi:sun-wireless-outline", + state_class="measurement", + entity_registry_enabled_default=False, + native_unit_of_measurement=UnitOfIrradiance.WATTS_PER_SQUARE_METER + ), + SensorEntityDescription( + key="SolarRadTime", + name="Solar Radiation Time", + icon="mdi:clock-in", + entity_registry_enabled_default=False + ), SensorEntityDescription( key="BatteryVolts", name="Battery Voltage",