meteocat 0.1.38 → 0.1.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/conftest.py +11 -0
- package/custom_components/meteocat/__init__.py +31 -5
- package/custom_components/meteocat/condition.py +15 -5
- package/custom_components/meteocat/const.py +9 -4
- package/custom_components/meteocat/coordinator.py +593 -127
- package/custom_components/meteocat/helpers.py +39 -40
- package/custom_components/meteocat/manifest.json +1 -1
- package/custom_components/meteocat/sensor.py +136 -19
- package/custom_components/meteocat/strings.json +20 -0
- package/custom_components/meteocat/translations/ca.json +20 -0
- package/custom_components/meteocat/translations/en.json +20 -0
- package/custom_components/meteocat/translations/es.json +20 -0
- package/custom_components/meteocat/version.py +1 -1
- package/custom_components/meteocat/weather.py +214 -0
- package/filetree.txt +2 -1
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/custom_components/meteocat/entity.py +0 -98
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
## [0.1.40](https://github.com/figorr/meteocat/compare/v0.1.39...v0.1.40) (2024-12-26)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* 0.1.40 ([011f139](https://github.com/figorr/meteocat/commit/011f1391874a78d16c1ad1eebbd8f84e6b053b5b))
|
|
7
|
+
* fix hourly forecasts ([bc1aa17](https://github.com/figorr/meteocat/commit/bc1aa178222a7158590b32af442427def4187e38))
|
|
8
|
+
|
|
9
|
+
## [0.1.39](https://github.com/figorr/meteocat/compare/v0.1.38...v0.1.39) (2024-12-25)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
* 0.1.39 ([be7e9f3](https://github.com/figorr/meteocat/commit/be7e9f394a02be59521fce9a20100d3091092358))
|
|
15
|
+
* add conditions constants ([95fa3bb](https://github.com/figorr/meteocat/commit/95fa3bba33722d2d976e1545bb58a7f97636ab7b))
|
|
16
|
+
* add MeteocatEntityCoordinator and def json to save files ([f5816cc](https://github.com/figorr/meteocat/commit/f5816cc71dd2d7f4900c796d482969742a67ca05))
|
|
17
|
+
* add MeteocatyEntityCoordinator and update async_remove_entry ([99a9883](https://github.com/figorr/meteocat/commit/99a98837de9923ba4a8604b5ff5ea6e628a51097))
|
|
18
|
+
* add translations to new condition sensor ([92d757c](https://github.com/figorr/meteocat/commit/92d757c82bf9c33bd392d16f74d666f806fc27cb))
|
|
19
|
+
* add weather entity ([914c407](https://github.com/figorr/meteocat/commit/914c4076457c8dd2ff1527ef83e5f62b911112a1))
|
|
20
|
+
* fix condition code ([04c6ea3](https://github.com/figorr/meteocat/commit/04c6ea3e668b19bad95141154ffa6910d4aa8f3a))
|
|
21
|
+
* fix is night code ([d50d587](https://github.com/figorr/meteocat/commit/d50d5871d89eb3ae20217e2070db61dcfc6c2503))
|
|
22
|
+
* fix uvi icon ([d16d452](https://github.com/figorr/meteocat/commit/d16d45282f5eae83f5a337a58d34d5c5e62bee6f))
|
|
23
|
+
* new condition sensor ([8f352fc](https://github.com/figorr/meteocat/commit/8f352fcff6f97e1bfe9ea49d22f03837b177f680))
|
|
24
|
+
* new repo file structure ([ac61261](https://github.com/figorr/meteocat/commit/ac612613e386f926eed526e2796cadd325a3fabc))
|
|
25
|
+
* new weather and condition coordinators ([f8307d8](https://github.com/figorr/meteocat/commit/f8307d8d8de915592c3a285e91dc8c79164953b5))
|
|
26
|
+
* new weather and condition coordinators ([4c457e8](https://github.com/figorr/meteocat/commit/4c457e87f17564fa50743064dfbdd922e4babc17))
|
|
27
|
+
* use await to save json files ([0945320](https://github.com/figorr/meteocat/commit/09453205bf891dcfef811c2628e72bf921aac8bb))
|
|
28
|
+
|
|
1
29
|
## [0.1.38](https://github.com/figorr/meteocat/compare/v0.1.37...v0.1.38) (2024-12-18)
|
|
2
30
|
|
|
3
31
|
|
package/conftest.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from homeassistant.core import HomeAssistant
|
|
3
|
+
from pytest_homeassistant_custom_component.common import mock_component
|
|
4
|
+
from homeassistant.setup import async_setup_component
|
|
5
|
+
|
|
6
|
+
@pytest.fixture(autouse=True)
|
|
7
|
+
async def auto_enable_custom_integrations(hass: HomeAssistant):
|
|
8
|
+
"""Enable custom integrations."""
|
|
9
|
+
mock_component(hass, "meteocat")
|
|
10
|
+
await async_setup_component(hass, 'meteocat', {})
|
|
11
|
+
yield
|
|
@@ -10,9 +10,13 @@ from homeassistant.helpers.entity_platform import async_get_platforms
|
|
|
10
10
|
|
|
11
11
|
from .coordinator import (
|
|
12
12
|
MeteocatSensorCoordinator,
|
|
13
|
-
|
|
13
|
+
MeteocatStaticSensorCoordinator,
|
|
14
|
+
MeteocatEntityCoordinator,
|
|
14
15
|
MeteocatUviCoordinator,
|
|
15
16
|
MeteocatUviFileCoordinator,
|
|
17
|
+
HourlyForecastCoordinator,
|
|
18
|
+
DailyForecastCoordinator,
|
|
19
|
+
MeteocatConditionCoordinator,
|
|
16
20
|
)
|
|
17
21
|
|
|
18
22
|
from .const import DOMAIN, PLATFORMS
|
|
@@ -20,7 +24,7 @@ from .const import DOMAIN, PLATFORMS
|
|
|
20
24
|
_LOGGER = logging.getLogger(__name__)
|
|
21
25
|
|
|
22
26
|
# Versión
|
|
23
|
-
__version__ = "0.1.
|
|
27
|
+
__version__ = "0.1.40"
|
|
24
28
|
|
|
25
29
|
def safe_remove(path: Path, is_folder: bool = False):
|
|
26
30
|
"""Elimina de forma segura un archivo o carpeta si existe."""
|
|
@@ -65,9 +69,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|
|
65
69
|
try:
|
|
66
70
|
sensor_coordinator = MeteocatSensorCoordinator(hass=hass, entry_data=entry_data)
|
|
67
71
|
await sensor_coordinator.async_config_entry_first_refresh()
|
|
72
|
+
|
|
73
|
+
static_sensor_coordinator = MeteocatStaticSensorCoordinator(hass=hass, entry_data=entry_data)
|
|
74
|
+
await sensor_coordinator.async_config_entry_first_refresh()
|
|
68
75
|
|
|
69
|
-
|
|
70
|
-
|
|
76
|
+
entity_coordinator = MeteocatEntityCoordinator(hass=hass, entry_data=entry_data)
|
|
77
|
+
await entity_coordinator.async_config_entry_first_refresh()
|
|
71
78
|
|
|
72
79
|
uvi_coordinator = MeteocatUviCoordinator(hass=hass, entry_data=entry_data)
|
|
73
80
|
await uvi_coordinator.async_config_entry_first_refresh()
|
|
@@ -75,6 +82,15 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|
|
75
82
|
uvi_file_coordinator = MeteocatUviFileCoordinator(hass=hass, entry_data=entry_data)
|
|
76
83
|
await uvi_file_coordinator.async_config_entry_first_refresh()
|
|
77
84
|
|
|
85
|
+
hourly_forecast_coordinator = HourlyForecastCoordinator(hass=hass, entry_data=entry_data)
|
|
86
|
+
await hourly_forecast_coordinator.async_config_entry_first_refresh()
|
|
87
|
+
|
|
88
|
+
daily_forecast_coordinator = DailyForecastCoordinator(hass=hass, entry_data=entry_data)
|
|
89
|
+
await daily_forecast_coordinator.async_config_entry_first_refresh()
|
|
90
|
+
|
|
91
|
+
condition_coordinator = MeteocatConditionCoordinator(hass=hass, entry_data=entry_data)
|
|
92
|
+
await condition_coordinator.async_config_entry_first_refresh()
|
|
93
|
+
|
|
78
94
|
except Exception as err: # Capturar todos los errores
|
|
79
95
|
_LOGGER.exception(f"Error al inicializar los coordinadores: {err}")
|
|
80
96
|
return False
|
|
@@ -83,9 +99,13 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|
|
83
99
|
hass.data.setdefault(DOMAIN, {})
|
|
84
100
|
hass.data[DOMAIN][entry.entry_id] = {
|
|
85
101
|
"sensor_coordinator": sensor_coordinator,
|
|
86
|
-
|
|
102
|
+
"static_sensor_coordinator": static_sensor_coordinator,
|
|
103
|
+
"entity_coordinator": entity_coordinator,
|
|
87
104
|
"uvi_coordinator": uvi_coordinator,
|
|
88
105
|
"uvi_file_coordinator": uvi_file_coordinator,
|
|
106
|
+
"hourly_forecast_coordinator": hourly_forecast_coordinator,
|
|
107
|
+
"daily_forecast_coordinator": daily_forecast_coordinator,
|
|
108
|
+
"condition_coordinator": condition_coordinator,
|
|
89
109
|
**entry_data,
|
|
90
110
|
}
|
|
91
111
|
|
|
@@ -138,6 +158,10 @@ async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
|
|
138
158
|
# Archivo JSON UVI del municipio
|
|
139
159
|
town_data_file = files_folder / f"uvi_{town_id.lower()}_data.json"
|
|
140
160
|
|
|
161
|
+
# Arhivos JSON de las predicciones del municipio a eliminar
|
|
162
|
+
forecast_hourly_data_file = files_folder / f"forecast_{town_id.lower()}_hourly_data.json"
|
|
163
|
+
forecast_daily_data_file = files_folder / f"forecast_{town_id.lower()}_daily_data.json"
|
|
164
|
+
|
|
141
165
|
# Validar la ruta base
|
|
142
166
|
if not custom_components_path.exists():
|
|
143
167
|
_LOGGER.warning(f"La ruta {custom_components_path} no existe. No se realizará la limpieza.")
|
|
@@ -148,5 +172,7 @@ async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
|
|
148
172
|
safe_remove(variables_file)
|
|
149
173
|
safe_remove(station_data_file)
|
|
150
174
|
safe_remove(town_data_file)
|
|
175
|
+
safe_remove(forecast_hourly_data_file)
|
|
176
|
+
safe_remove(forecast_daily_data_file)
|
|
151
177
|
safe_remove(assets_folder, is_folder=True)
|
|
152
178
|
safe_remove(files_folder, is_folder=True)
|
|
@@ -2,23 +2,33 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from datetime import datetime
|
|
4
4
|
from .const import CONDITION_MAPPING
|
|
5
|
-
from .helpers import is_night
|
|
5
|
+
from .helpers import is_night
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
def get_condition_from_statcel(
|
|
9
|
+
codi_estatcel, current_time: datetime, hass, is_hourly: bool = True
|
|
10
|
+
) -> dict:
|
|
8
11
|
"""
|
|
9
12
|
Convierte el código 'estatCel' en condición de Home Assistant.
|
|
10
13
|
|
|
11
|
-
:param codi_estatcel: Código del estado del cielo
|
|
14
|
+
:param codi_estatcel: Código o lista de códigos del estado del cielo.
|
|
12
15
|
:param current_time: Fecha y hora actual (datetime).
|
|
13
16
|
:param hass: Instancia de Home Assistant.
|
|
17
|
+
:param is_hourly: Indica si los datos son de predicción horaria (True) o diaria (False).
|
|
14
18
|
:return: Diccionario con la condición y el icono.
|
|
15
19
|
"""
|
|
16
|
-
#
|
|
20
|
+
# Asegurarse de que codi_estatcel sea una lista válida
|
|
21
|
+
if codi_estatcel is None:
|
|
22
|
+
codi_estatcel = []
|
|
23
|
+
elif isinstance(codi_estatcel, int): # Convertir enteros en lista
|
|
24
|
+
codi_estatcel = [codi_estatcel]
|
|
25
|
+
|
|
26
|
+
# Determinar si es de noche
|
|
17
27
|
is_night_flag = is_night(current_time, hass)
|
|
18
28
|
|
|
19
29
|
# Identificar la condición basada en el código
|
|
20
30
|
for condition, codes in CONDITION_MAPPING.items():
|
|
21
|
-
if
|
|
31
|
+
if any(code in codes for code in codi_estatcel):
|
|
22
32
|
# Ajustar para condiciones nocturnas si aplica
|
|
23
33
|
if condition == "sunny" and is_night_flag:
|
|
24
34
|
return {"condition": "clear-night", "icon": None}
|
|
@@ -9,6 +9,13 @@ VARIABLE_ID = "variable_id"
|
|
|
9
9
|
STATION_NAME = "station_name"
|
|
10
10
|
STATION_ID = "station_id"
|
|
11
11
|
|
|
12
|
+
from homeassistant.const import Platform
|
|
13
|
+
|
|
14
|
+
ATTRIBUTION = "Powered by Meteocatpy"
|
|
15
|
+
PLATFORMS = [Platform.SENSOR, Platform.WEATHER]
|
|
16
|
+
DEFAULT_NAME = "METEOCAT"
|
|
17
|
+
|
|
18
|
+
|
|
12
19
|
# Códigos de sensores de la API
|
|
13
20
|
WIND_SPEED = "wind_speed" # Velocidad del viento
|
|
14
21
|
WIND_DIRECTION = "wind_direction" # Dirección del viento
|
|
@@ -24,6 +31,7 @@ MIN_TEMPERATURE = "min_temperature" # Temperatura mínima
|
|
|
24
31
|
FEELS_LIKE = "feels_like" # Sensación térmica
|
|
25
32
|
WIND_GUST = "wind_gust" # Racha de viento
|
|
26
33
|
STATION_TIMESTAMP = "station_timestamp" # Código de tiempo de la estación
|
|
34
|
+
CONDITION = "condition" # Estado del cielo
|
|
27
35
|
|
|
28
36
|
# Definición de códigos para variables
|
|
29
37
|
WIND_SPEED_CODE = 30
|
|
@@ -41,7 +49,7 @@ WIND_GUST_CODE = 50
|
|
|
41
49
|
# Mapeo de códigos 'estatCel' a condiciones de Home Assistant
|
|
42
50
|
CONDITION_MAPPING = {
|
|
43
51
|
"sunny": [1],
|
|
44
|
-
"clear-night": [1],
|
|
52
|
+
# "clear-night": [1],
|
|
45
53
|
"partlycloudy": [2, 3],
|
|
46
54
|
"cloudy": [4, 20, 21, 22],
|
|
47
55
|
"rainy": [5, 6, 23],
|
|
@@ -52,6 +60,3 @@ CONDITION_MAPPING = {
|
|
|
52
60
|
"fog": [11, 12],
|
|
53
61
|
"snow-rainy": [27, 29, 30],
|
|
54
62
|
}
|
|
55
|
-
|
|
56
|
-
# Platforms
|
|
57
|
-
PLATFORMS = ["sensor"]
|