mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 00:37:53 +00:00
Add Stookwijzer (#84435)
Co-authored-by: Franck Nijhof <frenck@frenck.nl> Co-authored-by: Franck Nijhof <git@frenck.dev>
This commit is contained in:
parent
658db7ff05
commit
29b2b6727e
@ -1249,6 +1249,9 @@ omit =
|
||||
homeassistant/components/stookalert/__init__.py
|
||||
homeassistant/components/stookalert/binary_sensor.py
|
||||
homeassistant/components/stookalert/diagnostics.py
|
||||
homeassistant/components/stookwijzer/__init__.py
|
||||
homeassistant/components/stookwijzer/diagnostics.py
|
||||
homeassistant/components/stookwijzer/sensor.py
|
||||
homeassistant/components/stream/*
|
||||
homeassistant/components/streamlabswater/*
|
||||
homeassistant/components/suez_water/*
|
||||
|
@ -1139,6 +1139,8 @@ build.json @home-assistant/supervisor
|
||||
/homeassistant/components/stiebel_eltron/ @fucm
|
||||
/homeassistant/components/stookalert/ @fwestenberg @frenck
|
||||
/tests/components/stookalert/ @fwestenberg @frenck
|
||||
/homeassistant/components/stookwijzer/ @fwestenberg
|
||||
/tests/components/stookwijzer/ @fwestenberg
|
||||
/homeassistant/components/stream/ @hunterjm @uvjustin @allenporter
|
||||
/tests/components/stream/ @hunterjm @uvjustin @allenporter
|
||||
/homeassistant/components/stt/ @pvizeli
|
||||
|
29
homeassistant/components/stookwijzer/__init__.py
Normal file
29
homeassistant/components/stookwijzer/__init__.py
Normal file
@ -0,0 +1,29 @@
|
||||
"""The Stookwijzer integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
from stookwijzer import Stookwijzer
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_LATITUDE, CONF_LOCATION, CONF_LONGITUDE, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .const import DOMAIN
|
||||
|
||||
PLATFORMS = [Platform.SENSOR]
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Set up Stookwijzer from a config entry."""
|
||||
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = Stookwijzer(
|
||||
entry.data[CONF_LOCATION][CONF_LATITUDE],
|
||||
entry.data[CONF_LOCATION][CONF_LONGITUDE],
|
||||
)
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Unload Stookwijzer config entry."""
|
||||
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
|
||||
del hass.data[DOMAIN][entry.entry_id]
|
||||
return unload_ok
|
45
homeassistant/components/stookwijzer/config_flow.py
Normal file
45
homeassistant/components/stookwijzer/config_flow.py
Normal file
@ -0,0 +1,45 @@
|
||||
"""Config flow to configure the Stookwijzer integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import ConfigFlow
|
||||
from homeassistant.const import CONF_LATITUDE, CONF_LOCATION, CONF_LONGITUDE
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.helpers.selector import LocationSelector
|
||||
|
||||
from .const import DOMAIN
|
||||
|
||||
|
||||
class StookwijzerFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
"""Config flow for Stookwijzer."""
|
||||
|
||||
VERSION = 1
|
||||
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Handle a flow initialized by the user."""
|
||||
|
||||
if user_input is not None:
|
||||
return self.async_create_entry(
|
||||
title="Stookwijzer",
|
||||
data=user_input,
|
||||
)
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="user",
|
||||
data_schema=vol.Schema(
|
||||
{
|
||||
vol.Required(
|
||||
CONF_LOCATION,
|
||||
default={
|
||||
CONF_LATITUDE: self.hass.config.latitude,
|
||||
CONF_LONGITUDE: self.hass.config.longitude,
|
||||
},
|
||||
): LocationSelector()
|
||||
}
|
||||
),
|
||||
)
|
16
homeassistant/components/stookwijzer/const.py
Normal file
16
homeassistant/components/stookwijzer/const.py
Normal file
@ -0,0 +1,16 @@
|
||||
"""Constants for the Stookwijzer integration."""
|
||||
import logging
|
||||
from typing import Final
|
||||
|
||||
from homeassistant.backports.enum import StrEnum
|
||||
|
||||
DOMAIN: Final = "stookwijzer"
|
||||
LOGGER = logging.getLogger(__package__)
|
||||
|
||||
|
||||
class StookwijzerState(StrEnum):
|
||||
"""Stookwijzer states for sensor entity."""
|
||||
|
||||
BLUE = "blauw"
|
||||
ORANGE = "oranje"
|
||||
RED = "rood"
|
31
homeassistant/components/stookwijzer/diagnostics.py
Normal file
31
homeassistant/components/stookwijzer/diagnostics.py
Normal file
@ -0,0 +1,31 @@
|
||||
"""Diagnostics support for Stookwijzer."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from stookwijzer import Stookwijzer
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .const import DOMAIN
|
||||
|
||||
|
||||
async def async_get_config_entry_diagnostics(
|
||||
hass: HomeAssistant, entry: ConfigEntry
|
||||
) -> dict[str, Any]:
|
||||
"""Return diagnostics for a config entry."""
|
||||
client: Stookwijzer = hass.data[DOMAIN][entry.entry_id]
|
||||
|
||||
last_updated = None
|
||||
if client.last_updated:
|
||||
last_updated = client.last_updated.isoformat()
|
||||
|
||||
return {
|
||||
"state": client.state,
|
||||
"last_updated": last_updated,
|
||||
"lqi": client.lqi,
|
||||
"windspeed": client.windspeed,
|
||||
"weather": client.weather,
|
||||
"concentrations": client.concentrations,
|
||||
}
|
10
homeassistant/components/stookwijzer/manifest.json
Normal file
10
homeassistant/components/stookwijzer/manifest.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"domain": "stookwijzer",
|
||||
"name": "Stookwijzer",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/stookwijzer",
|
||||
"codeowners": ["@fwestenberg"],
|
||||
"requirements": ["stookwijzer==1.3.0"],
|
||||
"integration_type": "service",
|
||||
"iot_class": "cloud_polling"
|
||||
}
|
65
homeassistant/components/stookwijzer/sensor.py
Normal file
65
homeassistant/components/stookwijzer/sensor.py
Normal file
@ -0,0 +1,65 @@
|
||||
"""This integration provides support for Stookwijzer Sensor."""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import timedelta
|
||||
|
||||
from stookwijzer import Stookwijzer
|
||||
|
||||
from homeassistant.components.sensor import SensorDeviceClass, SensorEntity
|
||||
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.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import DOMAIN, StookwijzerState
|
||||
|
||||
SCAN_INTERVAL = timedelta(minutes=60)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Stookwijzer sensor from a config entry."""
|
||||
client = hass.data[DOMAIN][entry.entry_id]
|
||||
async_add_entities([StookwijzerSensor(client, entry)], update_before_add=True)
|
||||
|
||||
|
||||
class StookwijzerSensor(SensorEntity):
|
||||
"""Defines a Stookwijzer binary sensor."""
|
||||
|
||||
_attr_attribution = "Data provided by stookwijzer.nu"
|
||||
_attr_device_class = SensorDeviceClass.ENUM
|
||||
_attr_has_entity_name = True
|
||||
_attr_translation_key = "stookwijzer"
|
||||
|
||||
def __init__(self, client: Stookwijzer, entry: ConfigEntry) -> None:
|
||||
"""Initialize a Stookwijzer device."""
|
||||
self._client = client
|
||||
self._attr_options = [cls.value for cls in StookwijzerState]
|
||||
self._attr_unique_id = entry.entry_id
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={(DOMAIN, f"{entry.entry_id}")},
|
||||
name="Stookwijzer",
|
||||
manufacturer="stookwijzer.nu",
|
||||
entry_type=DeviceEntryType.SERVICE,
|
||||
configuration_url="https://www.stookwijzer.nu",
|
||||
)
|
||||
|
||||
def update(self) -> None:
|
||||
"""Update the data from the Stookwijzer handler."""
|
||||
self._client.update()
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
"""Return if entity is available."""
|
||||
return self._client.state is not None
|
||||
|
||||
@property
|
||||
def native_value(self) -> str | None:
|
||||
"""Return the state of the device."""
|
||||
if self._client.state is None:
|
||||
return None
|
||||
return StookwijzerState(self._client.state).value
|
23
homeassistant/components/stookwijzer/strings.json
Normal file
23
homeassistant/components/stookwijzer/strings.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"config": {
|
||||
"step": {
|
||||
"user": {
|
||||
"description": "Select the location you want to recieve the Stookwijzer information for.",
|
||||
"data": {
|
||||
"location": "[%key:common::config_flow::data::location%]"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"entity": {
|
||||
"sensor": {
|
||||
"stookwijzer": {
|
||||
"state": {
|
||||
"blauw": "Blue",
|
||||
"oranje": "Orange",
|
||||
"rood": "Red"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
23
homeassistant/components/stookwijzer/translations/en.json
Normal file
23
homeassistant/components/stookwijzer/translations/en.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"config": {
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"location": "Location"
|
||||
},
|
||||
"description": "Select the location you want to recieve the Stookwijzer information for."
|
||||
}
|
||||
}
|
||||
},
|
||||
"entity": {
|
||||
"sensor": {
|
||||
"stookwijzer": {
|
||||
"state": {
|
||||
"blauw": "Blue",
|
||||
"oranje": "Orange",
|
||||
"rood": "Red"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -411,6 +411,7 @@ FLOWS = {
|
||||
"steam_online",
|
||||
"steamist",
|
||||
"stookalert",
|
||||
"stookwijzer",
|
||||
"subaru",
|
||||
"sun",
|
||||
"surepetcare",
|
||||
|
@ -5243,6 +5243,12 @@
|
||||
"config_flow": true,
|
||||
"iot_class": "cloud_polling"
|
||||
},
|
||||
"stookwijzer": {
|
||||
"name": "Stookwijzer",
|
||||
"integration_type": "service",
|
||||
"config_flow": true,
|
||||
"iot_class": "cloud_polling"
|
||||
},
|
||||
"streamlabswater": {
|
||||
"name": "StreamLabs",
|
||||
"integration_type": "hub",
|
||||
|
@ -2405,6 +2405,9 @@ steamodd==4.21
|
||||
# homeassistant.components.stookalert
|
||||
stookalert==0.1.4
|
||||
|
||||
# homeassistant.components.stookwijzer
|
||||
stookwijzer==1.3.0
|
||||
|
||||
# homeassistant.components.streamlabswater
|
||||
streamlabswater==1.0.1
|
||||
|
||||
|
@ -1699,6 +1699,9 @@ steamodd==4.21
|
||||
# homeassistant.components.stookalert
|
||||
stookalert==0.1.4
|
||||
|
||||
# homeassistant.components.stookwijzer
|
||||
stookwijzer==1.3.0
|
||||
|
||||
# homeassistant.components.huawei_lte
|
||||
# homeassistant.components.solaredge
|
||||
# homeassistant.components.thermoworks_smoke
|
||||
|
1
tests/components/stookwijzer/__init__.py
Normal file
1
tests/components/stookwijzer/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""Tests for the Stookwijzer integration."""
|
42
tests/components/stookwijzer/test_config_flow.py
Normal file
42
tests/components/stookwijzer/test_config_flow.py
Normal file
@ -0,0 +1,42 @@
|
||||
"""Tests for the Stookwijzer config flow."""
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.components.stookwijzer.const import DOMAIN
|
||||
from homeassistant.config_entries import SOURCE_USER
|
||||
from homeassistant.const import CONF_LATITUDE, CONF_LOCATION, CONF_LONGITUDE
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.data_entry_flow import FlowResultType
|
||||
|
||||
|
||||
async def test_full_user_flow(hass: HomeAssistant) -> None:
|
||||
"""Test the full user configuration flow."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}
|
||||
)
|
||||
|
||||
assert result.get("type") == FlowResultType.FORM
|
||||
assert result.get("step_id") == SOURCE_USER
|
||||
assert "flow_id" in result
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.stookwijzer.async_setup_entry", return_value=True
|
||||
) as mock_setup_entry:
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={
|
||||
CONF_LOCATION: {
|
||||
CONF_LATITUDE: 1.0,
|
||||
CONF_LONGITUDE: 1.1,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
assert result2.get("type") == FlowResultType.CREATE_ENTRY
|
||||
assert result2.get("data") == {
|
||||
"location": {
|
||||
"latitude": 1.0,
|
||||
"longitude": 1.1,
|
||||
},
|
||||
}
|
||||
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
Loading…
x
Reference in New Issue
Block a user