Skip to content

Commit

Permalink
Merge pull request #120 from golles/api-v2
Browse files Browse the repository at this point in the history
Update to Weerlive API v2
  • Loading branch information
golles authored Feb 25, 2024
2 parents 30748e8 + ec9d04f commit dd08339
Show file tree
Hide file tree
Showing 22 changed files with 1,646 additions and 633 deletions.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/issue.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ body:
required: true
attributes:
label: Integration version
placeholder: "1.7.1"
placeholder: "2.0.0"
description: >
Can be found in the Configuration panel -> Integrations -> KNMI
Expand Down
163 changes: 117 additions & 46 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,81 +15,152 @@ Weather data provided by KNMI, https://weerlive.nl.

## Installation

### HACS

This component can be installed in your Home Assistant with HACS.


### Manual

1. Using the tool of choice open the directory (folder) for your HA configuration (where you find `configuration.yaml`).
2. If you do not have a `custom_components` directory (folder) there, you need to create it.
3. In the `custom_components` directory (folder) create a new folder called `knmi`.
4. Download _all_ the files from the `custom_components/knmi/` directory (folder) in this repository.
5. Place the files you downloaded in the new directory (folder) you created.
6. Restart Home Assistant
7. In the HA UI go to "Configuration" -> "Integrations" click "+" and search for "knmi"

Using your HA configuration directory (folder) as a starting point you should now also have this:

```text
custom_components/knmi/translations/en.json
custom_components/knmi/translations/nl.json
custom_components/knmi/__init__.py
custom_components/knmi/api.py
custom_components/knmi/binary_sensor.py
custom_components/knmi/config_flow.py
custom_components/knmi/const.py
custom_components/knmi/coordinator.py
custom_components/knmi/diagnostics.py
custom_components/knmi/manifest.json
custom_components/knmi/sensor.py
custom_components/knmi/weather.py
```
### HACS installation

The most convenient method for installing this custom component is via HACS. Simply search for the name, and you should be able to locate and install it seamlessly.

### Manual installation guide:

1. Utilize your preferred tool to access the directory in your Home Assistant (HA) configuration, where you can locate the `configuration.yaml` file.
2. Should there be no existing `custom_components` directory, you must create one.
3. Inside the newly created `custom_components` directory, generate a new directory named `knmi`.
4. Retrieve and download all files from the `custom_components/knmi/` directory in this repository.
5. Place the downloaded files into the newly created `knmi` directory.
6. Restart Home Assistant.

## Configuration is done in the UI

You can configure and setup the KNMI integration in your integrations page, look for KNMI in the add integrations dialog.
Within the HA user interface, navigate to "Configuration" -> "Integrations", click the "+" button, and search for "KNMI" to add the integration.

## Known limitations

- This integration is translated into English and Dutch, the entity names and the data (from the API) are only available in Dutch.
- The free API only provides a forecast for 2 days ahead. To make the weather card aesthetically not look too bad, the forecast for today is also shown, resulting in showing only 3 days (see example below).
This integration is translated into English and Dutch, including entity names and attributes, the data (from the API) is only available in Dutch.
Feel free to create a pull request with your language, see [translations](custom_components/knmi/translations/). Non-numerical values are only available in Dutch

## Entities

This integration comes with multiple pre-built entities, most of which are initially deactivated. To enable additional entities, follow these steps:

1. Navigate to "Configuration" -> "Integrations" -> "KNMI" in the Home Assistant interface.
2. Click on the specific integration with "1 service" that you desire.
3. Click on "X entities hidden", and a summary of all entities in this integration will be displayed.
4. Choose the desired entity, click on the cogwheel icon, and access its settings.
5. Toggle the "Enabled" switch to activate the entity.
6. Click "Update" to save the changes. Repeat these steps for each entity you wish to enable.

After completing this process, the newly enabled entities will receive values during the next update.

### Binary sensors

| Name (EN) | Name (NL) | Attributes | Notes |
| --------- | ------------ | ------------------------------------------------------------------ | ----------------------------------------------------------------------- |
| Sun | Zon | Sunrise, Sunset, Sun chance today, tomorrow and day after tomorrow | Times of today, in UTC, frontend will convert this into your local time |
| Warning | Waarschuwing | Title, Description, Code, Next code, Next warning | Code has its own entity, see Weather code below |

### Sensors

Normal sensors:

| Name (EN) | Name (NL) | Attributes | Notes |
| ------------------------ | ---------------------------- | ----------------------------------- | --------------------- |
| Dew point | Dauwpunt | | Unit configurable |
| Solar irradiance | Globale stralingsintensiteit | | |
| Wind chill | Gevoelstemperatuur | | Unit configurable |
| Air pressure | Luchtdruk | | Unit configurable |
| Humidity | Luchtvochtigheid | | |
| Max temperature today | Max temperatuur vandaag | | Unit configurable |
| Max temperature tomorrow | Max temperatuur morgen | | Unit configurable |
| Min temperature today | Min temperatuur vandaag | | Unit configurable |
| Min temperature tomorrow | Min temperatuur morgen | | Unit configurable |
| Precipitation today | Neerslag vandaag | | |
| Precipitation tomorrow | Neerslag morgen | | |
| Description | Omschrijving | | State is in Dutch |
| Temperature | Temperatuur | | Unit configurable |
| Weather forecast | Weersverwachting | | State is in Dutch |
| Wind speed | Windsnelheid | Bearing, Degree, Beaufort and Knots | Unit configurable |
| Weather code | Weercode | | Raw state is in Dutch |
| Visibility | Zicht | | Unit configurable |

Diagnostic sensors:

| Name (EN) | Name (NL) | Notes |
| ---------------------- | ------------------------ | ----------------------- |
| Location | Plaats | |
| Remaining API requests | Resterende API verzoeken | |
| Latest update | Laatste update | Server side update time |

### Weather

The weather entity contains all the weather information, ideal for displaying a comprehensive overview in the Home Assistant frontend. It includes both a daily forecast spanning up to 5 days and an hourly forecast covering up to 24 hours.

Daily forecast attributes:

| Attribute | Notes |
| ------------------------- | ------------------------------------------------------------- |
| datetime | Times in UTC, frontend will convert this into your local time |
| condition | |
| templow | |
| temperature | |
| precipitation_probability | in a percentage |
| wind_bearing | |
| wind_speed | |
| wind_speed_bft | Not officially supported, but nice addition |
| sun_chance | Not officially supported, but nice addition |

Hourly forecast attributes:

| Attribute | Notes |
| ------------------------- | ------------------------------------------------------------- |
| datetime | Times in UTC, frontend will convert this into your local time |
| condition | |
| temperature | |
| precipitation_probability | in millimeters |
| wind_bearing | |
| wind_speed | |
| wind_speed_bft | Not officially supported, but nice addition |
| solar_irradiance | Not officially supported, but nice addition |

## Examples
Integration with all entities: <br>
<img width="662" alt="Integration" src="https://user-images.githubusercontent.com/2211503/179353840-009a710e-94b9-41a7-9efd-b9dd98ae5b66.png">

Weather card: <br>
<img width="472" alt="Weather card" src="https://user-images.githubusercontent.com/2211503/179353837-a535059b-b5b6-462a-8519-3bb15dd3fdab.png">
Integration with entities, notice the hidden ones: <br>
<img width="674" alt="Integration" src="https://github.com/golles/ha-knmi/assets/2211503/2924375b-5a07-43e4-96c5-fa0caa476053">

Weather cards (hourly and daily forecast): <br>
<img width="500" alt="Weather cards" src="https://github.com/golles/ha-knmi/assets/2211503/23417918-8b08-4005-9c36-5da9ff3e9122">

Weather entity: <br>
<img width="396" alt="Weather entity" src="https://user-images.githubusercontent.com/2211503/179353844-32d9c826-5701-4264-91e4-894c797b4e0d.png">
Weather entity (with daily and hourly forecast tabs): <br>
<img width="543" alt="Weather entity" src="https://github.com/golles/ha-knmi/assets/2211503/8d2b2ad5-c0f8-4890-b1d2-034fd1e7a1e9">

Sun entity: <br>
<img width="392" alt="Sun entity" src="https://user-images.githubusercontent.com/2211503/179353841-8376e62f-1bd8-4ee2-ae16-14e1dde41c9f.png">
<img width="551" alt="Sun entity" src="https://github.com/golles/ha-knmi/assets/2211503/a7eb3045-dfb5-42e3-a1b6-ce2b396119a4">

Warning entity: <br>
<img width="370" alt="Warning entity" src="https://user-images.githubusercontent.com/2211503/179353843-fee87e24-eabd-4d44-a58c-b933cfe4625c.png">

<img width="552" alt="Warning entity" src="https://github.com/golles/ha-knmi/assets/2211503/66aecc7a-2e84-453e-8669-59db34cf6cb1">

## Collect logs

When you want to report an issue, please add logs from this component. You can enable logging for this component by configuring the logger in Home Assistant as follows:
To activate the debug log necessary for issue reporting, follow these steps:

1. Go to "Configuration" -> "Integrations" -> "KNMI" within the Home Assistant interface.
2. On the left side, locate the "Enable debug logging" button and click on it.
3. Once you collected enough information, Stop debug logging, this will download the log file as well.
4. Share the log file in an issue.

Additionally, logging for this component can be enabled by configuring the logger in Home Assistant with the following steps:

```yaml
logger:
default: warn
logs:
custom_components.knmi: debug
```
More info can be found on the [Home Assistant logger integration page](https://www.home-assistant.io/integrations/logger)
More info can be found on the [Home Assistant logger integration page](https://www.home-assistant.io/integrations/logger)
## Contributions are welcome!
If you want to contribute to this please read the [Contribution guidelines](CONTRIBUTING.md)
[buymecoffee]: https://www.buymeacoffee.com/golles
[buymecoffeebadge]: https://img.shields.io/badge/buy%20me%20a%20coffee-donate-yellow.svg?style=for-the-badge
[codecov]: https://app.codecov.io/gh/golles/ha-knmi
Expand Down
34 changes: 30 additions & 4 deletions custom_components/knmi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@
Platform,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.device_registry import DeviceEntryType
from homeassistant.helpers.entity import DeviceInfo

from .api import KnmiApiClient
from .const import API_CONF_URL, DEFAULT_SCAN_INTERVAL, DOMAIN, NAME, VERSION
from .const import API_CONF_URL, DEFAULT_SCAN_INTERVAL, DOMAIN, NAME, SUPPLIER, VERSION
from .coordinator import KnmiDataUpdateCoordinator

PLATFORMS: list[Platform] = [
Expand Down Expand Up @@ -53,12 +54,13 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
)

device_info = DeviceInfo(
configuration_url=API_CONF_URL,
entry_type=DeviceEntryType.SERVICE,
identifiers={(DOMAIN, entry.entry_id)},
manufacturer=NAME,
model=NAME,
manufacturer=SUPPLIER,
name=NAME,
model=VERSION,
configuration_url=API_CONF_URL,
sw_version=VERSION,
)

hass.data[DOMAIN][entry.entry_id] = coordinator = KnmiDataUpdateCoordinator(
Expand Down Expand Up @@ -87,3 +89,27 @@ 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)


async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
"""Migrate old entry."""
_LOGGER.debug("Migrating from version %s", config_entry.version)

if config_entry.version == 1:
# Replace with the following line after 2024.3.
# hass.config_entries.async_update_entry(config_entry, version=2)
# See https://developers.home-assistant.io/blog/2024/02/12/async_update_entry/
config_entry.version = 2

entity_registry = er.async_get(hass)
existing_entries = er.async_entries_for_config_entry(
entity_registry, config_entry.entry_id
)

for entry in list(existing_entries):
_LOGGER.debug("Deleting version 1 entity: %s", entry.entity_id)
entity_registry.async_remove(entry.entity_id)

_LOGGER.debug("Migration to version %s successful", config_entry.version)

return True
38 changes: 17 additions & 21 deletions custom_components/knmi/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,29 +42,25 @@ def __init__(

async def async_get_data(self) -> dict:
"""Get data from the API."""
url = API_ENDPOINT.format(self.api_key, self.latitude, self.longitude)
return await self.api_wrapper("get", url)

async def api_wrapper(self, method: str, url: str) -> dict:
"""Get information from the API."""
try:
async with asyncio.timeout(API_TIMEOUT):
if method == "get":
response = await self._session.get(url)
response_text = await response.text()

# The API has no proper error handling for a wrong API key or rate limit.
# Instead a 200 with a message is returned, try to detect that here.
if "Vraag eerst een API-key op" in response_text:
raise KnmiApiClientApiKeyError("The given API key is invalid")

if "Dagelijkse limiet" in response_text:
raise KnmiApiRateLimitError(
"API key daily limit exceeded, try again tomorrow"
)

data = await response.json()
return data.get("liveweer")[0]
response = await self._session.get(
API_ENDPOINT.format(self.api_key, self.latitude, self.longitude)
)

response_text = await response.text()

# The API has no proper error handling for a wrong API key or rate limit.
# Instead a 200 with a message is returned, try to detect that here.
if "Vraag eerst een API-key op" in response_text:
raise KnmiApiClientApiKeyError("The given API key is invalid")

if "Dagelijkse limiet" in response_text:
raise KnmiApiRateLimitError(
"API key daily limit exceeded, try again tomorrow"
)

return await response.json()

except asyncio.TimeoutError as exception:
raise KnmiApiClientCommunicationError(
Expand Down
Loading

0 comments on commit dd08339

Please sign in to comment.