Skip to content

Commit

Permalink
Add UV Sensors (#41)
Browse files Browse the repository at this point in the history
* Add UV Sensors

* Fix adding UV sensors

* Fix UV Sensors

* Fix

* Fix
  • Loading branch information
GuyKh authored May 17, 2023
1 parent 67e4df6 commit 94bb8a5
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 56 deletions.
47 changes: 42 additions & 5 deletions custom_components/ims/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@

import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_registry import EntityRegistry

from datetime import timedelta

from homeassistant.core import HomeAssistant, callback
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.helpers.entity import EntityDescription
from homeassistant.helpers.entity_registry import EntityRegistry
from homeassistant.helpers.update_coordinator import CoordinatorEntity


from homeassistant.const import (
CONF_MODE,
CONF_NAME,
Platform,
)
from homeassistant.core import HomeAssistant

from .const import (
CONF_CITY,
Expand Down Expand Up @@ -90,7 +92,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:

# If both platforms
if (IMS_PLATFORMS[0] in ims_entity_platform) and (
IMS_PLATFORMS[1] in ims_entity_platform
IMS_PLATFORMS[1] in ims_entity_platform
):
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
# If only sensor
Expand All @@ -116,7 +118,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:

# If both
if (IMS_PLATFORMS[0] in ims_entity_prevplatform) and (
IMS_PLATFORMS[1] in ims_entity_prevplatform
IMS_PLATFORMS[1] in ims_entity_prevplatform
):
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
# If only sensor
Expand Down Expand Up @@ -149,3 +151,38 @@ def _get_config_value(config_entry: ConfigEntry, key: str) -> Any:

def _filter_domain_configs(elements, domain):
return list(filter(lambda elem: elem["platform"] == domain, elements))


class ImsEntity(CoordinatorEntity):
"""Define a generic Ims entity."""

_attr_has_entity_name = True

def __init__(
self, coordinator: WeatherUpdateCoordinator, description: EntityDescription
) -> None:
"""Initialize."""
super().__init__(coordinator)

self._attr_extra_state_attributes = {}
self._attr_unique_id = (
f"{description.key}_{coordinator.city}_{coordinator.language}"
)
self._attr_translation_key = f"{description.key}_{coordinator.city}"
self.entity_description = description

@callback
def _handle_coordinator_update(self) -> None:
"""Respond to a DataUpdateCoordinator update."""
self._update_from_latest_data()
self.async_write_ha_state()

@callback
def _update_from_latest_data(self) -> None:
"""Update the entity from the latest data."""
raise NotImplementedError

async def async_added_to_hass(self) -> None:
"""Handle entity which will be added."""
await super().async_added_to_hass()
self._update_from_latest_data()
4 changes: 4 additions & 0 deletions custom_components/ims/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@
DEFAULT_FORECAST_MODE = FORECAST_MODE_DAILY
FORECAST_MODES = [FORECAST_MODE_HOURLY, FORECAST_MODE_DAILY]

TYPE_CURRENT_UV_INDEX = "current_uv_index"
TYPE_CURRENT_UV_LEVEL = "current_uv_level"
TYPE_MAX_UV_INDEX = "max_uv_index"

LANGUAGES = ["en", "he"]

# Based on https://ims.gov.il/en/wind_directions
Expand Down
2 changes: 1 addition & 1 deletion custom_components/ims/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
"documentation": "https://github.com/t0mer/ims-custom-component",
"iot_class": "cloud_polling",
"issue_tracker": "https://github.com/t0mer/ims-custom-component/issues",
"requirements": ["weatheril>=0.29.1"],
"requirements": ["weatheril>=0.30.0"],
"version": "0.1.12"
}
104 changes: 93 additions & 11 deletions custom_components/ims/sensor.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
import asyncio
import json
import logging
import asyncio
import types

from datetime import date
from weatheril import WeatherIL
import voluptuous as vol
from homeassistant.helpers.entity import Entity
import homeassistant.helpers.config_validation as cv
from types import SimpleNamespace
from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.core import HomeAssistant
from homeassistant.components.sensor import (
PLATFORM_SCHEMA,
SensorEntity,
SensorEntityDescription,
SensorStateClass,
)

from homeassistant.const import UV_INDEX, UnitOfTime
from homeassistant.core import HomeAssistant, callback
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from homeassistant.const import CONF_NAME, TEMP_CELSIUS

from . import ImsEntity
from .const import (
CONFIG_FLOW_VERSION,
DEFAULT_FORECAST_MODE,
Expand Down Expand Up @@ -41,11 +50,26 @@
ENTRY_WEATHER_COORDINATOR,
WEATHER_CODE_TO_CONDITION,
WIND_DIRECTIONS,
TYPE_CURRENT_UV_INDEX,
TYPE_CURRENT_UV_LEVEL,
TYPE_MAX_UV_INDEX,
)

IMS_SENSOR_KEY_PREFIX = "ims_"

sensor_keys = types.SimpleNamespace()
sensor_keys.TYPE_CURRENT_UV_INDEX = IMS_SENSOR_KEY_PREFIX + TYPE_CURRENT_UV_INDEX
sensor_keys.TYPE_CURRENT_UV_LEVEL = IMS_SENSOR_KEY_PREFIX + TYPE_CURRENT_UV_LEVEL
sensor_keys.TYPE_MAX_UV_INDEX = IMS_SENSOR_KEY_PREFIX + TYPE_MAX_UV_INDEX

_LOGGER = logging.getLogger(__name__)

UV_LEVEL_EXTREME = "Extreme"
UV_LEVEL_VHIGH = "Very High"
UV_LEVEL_HIGH = "High"
UV_LEVEL_MODERATE = "Moderate"
UV_LEVEL_LOW = "Low"

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_CITY): cv.positive_int,
Expand All @@ -61,6 +85,28 @@

weather = None

SENSOR_DESCRIPTIONS = (
SensorEntityDescription(
key=IMS_SENSOR_KEY_PREFIX + TYPE_CURRENT_UV_INDEX,
name="IMS Current UV Index",
icon="mdi:weather-sunny",
native_unit_of_measurement=UV_INDEX,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key=IMS_SENSOR_KEY_PREFIX + TYPE_CURRENT_UV_LEVEL,
name="IMS Current UV Level",
icon="mdi:weather-sunny",
),
SensorEntityDescription(
key=IMS_SENSOR_KEY_PREFIX + TYPE_MAX_UV_INDEX,
name="IMS Max UV Index",
icon="mdi:weather-sunny",
native_unit_of_measurement=UV_INDEX,
state_class=SensorStateClass.MEASUREMENT,
),
)


async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
_LOGGER.warning(
Expand All @@ -83,9 +129,9 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=


async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up IMS Weather sensor entities based on a config entry."""

Expand All @@ -101,7 +147,7 @@ async def async_setup_entry(
# Add IMS Sensors
sensors: list[Entity] = []
sensors.append(ImsCity(hass, city, language, weather_coordinator))
sensors.append(ImsTemprature(hass, city, language, weather_coordinator))
sensors.append(ImsTemperature(hass, city, language, weather_coordinator))
sensors.append(ImsRealFeel(hass, city, language, weather_coordinator))
sensors.append(ImsHumidity(hass, city, language, weather_coordinator))
sensors.append(ImsWindSpeed(hass, city, language, weather_coordinator))
Expand All @@ -124,11 +170,47 @@ async def async_setup_entry(
)
)

for description in SENSOR_DESCRIPTIONS:
sensors.append(ImsSensor(weather_coordinator, description))

async_add_entities(sensors, update_before_add=True)

return True


class ImsSensor(ImsEntity, SensorEntity):
"""Representation of an IMS sensor."""

@callback
def _update_from_latest_data(self) -> None:
"""Update the state."""
data = self.coordinator.data

match self.entity_description.key:
case sensor_keys.TYPE_CURRENT_UV_LEVEL:
match data.current_weather.u_v_level:
case "E":
self._attr_native_value = UV_LEVEL_EXTREME
case "V":
self._attr_native_value = UV_LEVEL_VHIGH
case "H":
self._attr_native_value = UV_LEVEL_HIGH
case "M":
self._attr_native_value = UV_LEVEL_MODERATE
case _:
self._attr_native_value = UV_LEVEL_LOW

case sensor_keys.TYPE_CURRENT_UV_INDEX:
self._attr_native_value = data.current_weather.u_v_index

case sensor_keys.TYPE_MAX_UV_INDEX:
self._attr_native_value = data.current_weather.u_v_i_max

case _:
self._attr_native_value = None



class ImsCity(Entity):
def __init__(self, hass, city, language, weather_coordinator):
self._hass = hass
Expand Down Expand Up @@ -159,19 +241,19 @@ def update(self):
self._state = self._weather_coordinator.data.current_weather.location if self._weather_coordinator and self._weather_coordinator.data and self._weather_coordinator.data.current_weather else None


class ImsTemprature(Entity):
class ImsTemperature(Entity):
def __init__(self, hass, city, language, weather_coordinator):
self._hass = hass
self._language = language
self.entity_id = f"sensor.ims_temprature"
self.entity_id = f"sensor.ims_temperature"
self._weather_coordinator = weather_coordinator

@property
def name(self):
if self._language == "he":
return "טמפרטורה"
else:
return "Temprature"
return "Temperature"

@property
def state(self):
Expand Down
Loading

0 comments on commit 94bb8a5

Please sign in to comment.