meteocat 0.1.28 → 0.1.30
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 +21 -0
- package/custom_components/meteocat/__init__.py +2 -13
- package/custom_components/meteocat/config_flow.py +28 -25
- package/custom_components/meteocat/const.py +1 -0
- package/custom_components/meteocat/manifest.json +2 -2
- package/custom_components/meteocat/sensor.py +37 -0
- package/custom_components/meteocat/version.py +1 -1
- package/package.json +1 -1
- package/pyproject.toml +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
## [0.1.30](https://github.com/figorr/meteocat/compare/v0.1.29...v0.1.30) (2024-12-12)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* 0.1.30 ([2095760](https://github.com/figorr/meteocat/commit/20957606eae28a97e82607136f97fde1abe38f81))
|
|
7
|
+
* add precipitation accumulated sensor ([b05090a](https://github.com/figorr/meteocat/commit/b05090a563656123464d95b17b01ba2d7cada20f))
|
|
8
|
+
* add precipitation_accumulated ([261d877](https://github.com/figorr/meteocat/commit/261d877cf9f68a2106687900951731ba6a4539eb))
|
|
9
|
+
* delete precipitation test ([845d721](https://github.com/figorr/meteocat/commit/845d721ff4e49a2fe79c5cdcf92698d52a6cff36))
|
|
10
|
+
* fix variables json ([df403b1](https://github.com/figorr/meteocat/commit/df403b12ab12cd357f087dc1dceda30c51e4c8f0))
|
|
11
|
+
|
|
12
|
+
## [0.1.29](https://github.com/figorr/meteocat/compare/v0.1.28...v0.1.29) (2024-12-12)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* 0.1.29 ([f80cb9e](https://github.com/figorr/meteocat/commit/f80cb9eda9bd7d731489b51c161bc16a00ac57f0))
|
|
18
|
+
* bump meteocatpy to 0.0.14 ([74cc591](https://github.com/figorr/meteocat/commit/74cc591ac7e9911c77649a20088af15d3af2d350))
|
|
19
|
+
* remove cache ([8c4f29b](https://github.com/figorr/meteocat/commit/8c4f29b0b2c2cfa33f2b45f72bed57bf45b9a3dd))
|
|
20
|
+
* remove cache tests ([6082096](https://github.com/figorr/meteocat/commit/6082096a92ade5a033e0493a819b20e950aff7a3))
|
|
21
|
+
|
|
1
22
|
## [0.1.28](https://github.com/figorr/meteocat/compare/v0.1.27...v0.1.28) (2024-12-11)
|
|
2
23
|
|
|
3
24
|
|
|
@@ -8,13 +8,13 @@ from homeassistant.core import HomeAssistant
|
|
|
8
8
|
from homeassistant.exceptions import HomeAssistantError
|
|
9
9
|
from homeassistant.helpers.entity_platform import async_get_platforms
|
|
10
10
|
|
|
11
|
-
from .coordinator import MeteocatSensorCoordinator
|
|
11
|
+
from .coordinator import MeteocatSensorCoordinator # , MeteocatEntityCoordinator
|
|
12
12
|
from .const import DOMAIN, PLATFORMS
|
|
13
13
|
|
|
14
14
|
_LOGGER = logging.getLogger(__name__)
|
|
15
15
|
|
|
16
16
|
# Versión
|
|
17
|
-
__version__ = "0.1.
|
|
17
|
+
__version__ = "0.1.30"
|
|
18
18
|
|
|
19
19
|
def safe_remove(path: Path, is_folder: bool = False):
|
|
20
20
|
"""Elimina de forma segura un archivo o carpeta si existe."""
|
|
@@ -28,12 +28,10 @@ def safe_remove(path: Path, is_folder: bool = False):
|
|
|
28
28
|
except OSError as e:
|
|
29
29
|
_LOGGER.error(f"Error al intentar eliminar {path.name}: {e}")
|
|
30
30
|
|
|
31
|
-
|
|
32
31
|
async def async_setup(hass: core.HomeAssistant, config: dict) -> bool:
|
|
33
32
|
"""Configuración inicial del componente Meteocat."""
|
|
34
33
|
return True
|
|
35
34
|
|
|
36
|
-
|
|
37
35
|
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|
38
36
|
"""Configura una entrada de configuración para Meteocat."""
|
|
39
37
|
_LOGGER.info("Configurando la integración de Meteocat...")
|
|
@@ -57,11 +55,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|
|
57
55
|
f"Estación '{entry_data['station_name']}' (ID: {entry_data['station_id']})."
|
|
58
56
|
)
|
|
59
57
|
|
|
60
|
-
# Configurar ruta de la caché
|
|
61
|
-
cache_dir = Path(hass.config.path("custom_components", DOMAIN, ".meteocat_cache"))
|
|
62
|
-
cache_dir.mkdir(parents=True, exist_ok=True)
|
|
63
|
-
_LOGGER.debug(f"Directorio de caché configurado en: {cache_dir}")
|
|
64
|
-
|
|
65
58
|
# Inicializar coordinadores
|
|
66
59
|
try:
|
|
67
60
|
sensor_coordinator = MeteocatSensorCoordinator(hass=hass, entry_data=entry_data)
|
|
@@ -87,7 +80,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|
|
87
80
|
|
|
88
81
|
return True
|
|
89
82
|
|
|
90
|
-
|
|
91
83
|
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|
92
84
|
"""Desactiva una entrada de configuración para Meteocat."""
|
|
93
85
|
platforms = async_get_platforms(hass, DOMAIN)
|
|
@@ -100,7 +92,6 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|
|
100
92
|
|
|
101
93
|
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
|
102
94
|
|
|
103
|
-
|
|
104
95
|
async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
|
105
96
|
"""Limpia cualquier dato adicional al desinstalar la integración."""
|
|
106
97
|
_LOGGER.info(f"Eliminando datos residuales de la integración: {entry.entry_id}")
|
|
@@ -109,7 +100,6 @@ async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
|
|
109
100
|
custom_components_path = Path(hass.config.path("custom_components")) / DOMAIN
|
|
110
101
|
assets_folder = custom_components_path / "assets"
|
|
111
102
|
files_folder = custom_components_path / "files"
|
|
112
|
-
cache_folder = custom_components_path / ".meteocat_cache"
|
|
113
103
|
symbols_file = assets_folder / "symbols.json"
|
|
114
104
|
variables_file = assets_folder / "variables.json"
|
|
115
105
|
station_data_file = files_folder / "station_data.json"
|
|
@@ -125,4 +115,3 @@ async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
|
|
125
115
|
safe_remove(station_data_file)
|
|
126
116
|
safe_remove(assets_folder, is_folder=True)
|
|
127
117
|
safe_remove(files_folder, is_folder=True)
|
|
128
|
-
safe_remove(cache_folder, is_folder=True)
|
|
@@ -47,6 +47,7 @@ class MeteocatConfigFlow(ConfigFlow, domain=DOMAIN):
|
|
|
47
47
|
self.variable_id: str | None = None
|
|
48
48
|
self.station_id: str | None = None
|
|
49
49
|
self.station_name: str | None = None
|
|
50
|
+
self._cache = {}
|
|
50
51
|
|
|
51
52
|
async def async_step_user(
|
|
52
53
|
self, user_input: dict[str, Any] | None = None
|
|
@@ -97,46 +98,48 @@ class MeteocatConfigFlow(ConfigFlow, domain=DOMAIN):
|
|
|
97
98
|
return self.async_show_form(step_id="select_municipi", data_schema=schema, errors=errors)
|
|
98
99
|
|
|
99
100
|
async def fetch_symbols_and_variables(self):
|
|
100
|
-
"""Descarga los símbolos y
|
|
101
|
+
"""Descarga y guarda los símbolos y variables después de seleccionar el municipio."""
|
|
101
102
|
|
|
102
103
|
errors = {}
|
|
103
104
|
|
|
104
|
-
#
|
|
105
|
+
# Crear directorio de activos (assets) si no existe
|
|
105
106
|
assets_dir = Path(__file__).parent / "assets"
|
|
106
107
|
assets_dir.mkdir(parents=True, exist_ok=True)
|
|
107
108
|
symbols_file = assets_dir / "symbols.json"
|
|
108
109
|
variables_file = assets_dir / "variables.json"
|
|
109
|
-
symbols_client = MeteocatSymbols(self.api_key)
|
|
110
110
|
|
|
111
111
|
try:
|
|
112
|
+
# Descargar y guardar los símbolos
|
|
113
|
+
symbols_client = MeteocatSymbols(self.api_key)
|
|
112
114
|
symbols_data = await symbols_client.fetch_symbols()
|
|
115
|
+
|
|
113
116
|
async with aiofiles.open(symbols_file, "w", encoding="utf-8") as file:
|
|
114
117
|
await file.write(json.dumps({"symbols": symbols_data}, ensure_ascii=False, indent=4))
|
|
115
|
-
|
|
116
|
-
_LOGGER.
|
|
117
|
-
errors["base"] = "symbols_download_failed"
|
|
118
|
+
|
|
119
|
+
_LOGGER.info(f"Símbolos guardados en {symbols_file}")
|
|
118
120
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
121
|
+
# Descargar y guardar las variables
|
|
122
|
+
variables_client = MeteocatVariables(self.api_key)
|
|
123
|
+
variables_data = await variables_client.get_variables()
|
|
122
124
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
+
async with aiofiles.open(variables_file, "w", encoding="utf-8") as file:
|
|
126
|
+
await file.write(json.dumps({"variables": variables_data}, ensure_ascii=False, indent=4))
|
|
125
127
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
128
|
+
_LOGGER.info(f"Variables guardadas en {variables_file}")
|
|
129
|
+
|
|
130
|
+
# Buscar la variable de temperatura
|
|
131
|
+
self.variable_id = next(
|
|
132
|
+
(v["codi"] for v in variables_data if v["nom"].lower() == "temperatura"), None
|
|
133
|
+
)
|
|
134
|
+
if not self.variable_id:
|
|
135
|
+
_LOGGER.error("No se encontró la variable 'Temperatura'")
|
|
136
|
+
errors["base"] = "variable_not_found"
|
|
137
|
+
except (BadRequestError, ForbiddenError, TooManyRequestsError, InternalServerError, UnknownAPIError) as ex:
|
|
138
|
+
_LOGGER.error("Error al conectar con la API de Meteocat: %s", ex)
|
|
139
|
+
errors["base"] = "cannot_connect"
|
|
140
|
+
except Exception as ex:
|
|
141
|
+
_LOGGER.error("Error inesperado al descargar los datos: %s", ex)
|
|
142
|
+
errors["base"] = "unknown"
|
|
140
143
|
|
|
141
144
|
if errors:
|
|
142
145
|
raise HomeAssistantError(errors)
|
|
@@ -16,6 +16,7 @@ TEMPERATURE = "temperature" # Temperatura
|
|
|
16
16
|
HUMIDITY = "humidity" # Humedad relativa
|
|
17
17
|
PRESSURE = "pressure" # Presión atmosférica
|
|
18
18
|
PRECIPITATION = "precipitation" # Precipitación
|
|
19
|
+
PRECIPITATION_ACCUMULATED = "precipitation_accumulated" #Precipitación acumulada
|
|
19
20
|
SOLAR_GLOBAL_IRRADIANCE = "solar_global_irradiance" # Irradiación solar global
|
|
20
21
|
UV_INDEX = "uv_index" # UV
|
|
21
22
|
MAX_TEMPERATURE = "max_temperature" # Temperatura máxima
|
|
@@ -7,6 +7,6 @@
|
|
|
7
7
|
"iot_class": "cloud_polling",
|
|
8
8
|
"documentation": "https://gitlab.com/figorr/meteocat",
|
|
9
9
|
"loggers": ["meteocatpy"],
|
|
10
|
-
"requirements": ["meteocatpy==0.0.
|
|
11
|
-
"version": "0.1.
|
|
10
|
+
"requirements": ["meteocatpy==0.0.14", "packaging>=20.3", "wrapt>=1.14.0"],
|
|
11
|
+
"version": "0.1.30"
|
|
12
12
|
}
|
|
@@ -38,6 +38,7 @@ from .const import (
|
|
|
38
38
|
HUMIDITY,
|
|
39
39
|
PRESSURE,
|
|
40
40
|
PRECIPITATION,
|
|
41
|
+
PRECIPITATION_ACCUMULATED,
|
|
41
42
|
SOLAR_GLOBAL_IRRADIANCE,
|
|
42
43
|
UV_INDEX,
|
|
43
44
|
MAX_TEMPERATURE,
|
|
@@ -113,6 +114,14 @@ SENSOR_TYPES: tuple[MeteocatSensorEntityDescription, ...] = (
|
|
|
113
114
|
state_class=SensorStateClass.MEASUREMENT,
|
|
114
115
|
native_unit_of_measurement=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
|
|
115
116
|
),
|
|
117
|
+
MeteocatSensorEntityDescription(
|
|
118
|
+
key=PRECIPITATION_ACCUMULATED,
|
|
119
|
+
name="Precipitation Accumulated",
|
|
120
|
+
icon="mdi:weather-rainy",
|
|
121
|
+
device_class=SensorDeviceClass.PRECIPITATION,
|
|
122
|
+
state_class=SensorStateClass.MEASUREMENT,
|
|
123
|
+
native_unit_of_measurement="mm",
|
|
124
|
+
),
|
|
116
125
|
MeteocatSensorEntityDescription(
|
|
117
126
|
key=SOLAR_GLOBAL_IRRADIANCE,
|
|
118
127
|
name="Solar Global Irradiance",
|
|
@@ -299,8 +308,36 @@ class MeteocatSensor(CoordinatorEntity[MeteocatSensorCoordinator], SensorEntity)
|
|
|
299
308
|
# Manejo de errores si el formato no es válido
|
|
300
309
|
return None
|
|
301
310
|
|
|
311
|
+
# Nuevo sensor para la precipitación acumulada
|
|
312
|
+
if self.entity_description.key == "precipitation_accumulated":
|
|
313
|
+
stations = self.coordinator.data or []
|
|
314
|
+
total_precipitation = 0.0 # Usa float para permitir acumulación de decimales
|
|
315
|
+
|
|
316
|
+
for station in stations:
|
|
317
|
+
variables = station.get("variables", [])
|
|
318
|
+
|
|
319
|
+
# Filtramos por código de precipitación
|
|
320
|
+
variable_data = next(
|
|
321
|
+
(var for var in variables if var.get("codi") == PRECIPITATION_CODE),
|
|
322
|
+
None,
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
if variable_data:
|
|
326
|
+
# Sumamos las lecturas de precipitación
|
|
327
|
+
lectures = variable_data.get("lectures", [])
|
|
328
|
+
for lecture in lectures:
|
|
329
|
+
total_precipitation += float(lecture.get("valor", 0.0)) # Convertimos a float
|
|
330
|
+
|
|
331
|
+
_LOGGER.debug(f"Total precipitación acumulada: {total_precipitation} mm")
|
|
332
|
+
return total_precipitation
|
|
333
|
+
|
|
302
334
|
return None
|
|
303
335
|
|
|
336
|
+
@property
|
|
337
|
+
def precipitation_accumulated(self):
|
|
338
|
+
"""Return the accumulated precipitation state of the sensor."""
|
|
339
|
+
|
|
340
|
+
|
|
304
341
|
@staticmethod
|
|
305
342
|
def _convert_degrees_to_cardinal(degree: float) -> str:
|
|
306
343
|
"""Convert degrees to cardinal direction."""
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# version.py
|
|
2
|
-
__version__ = "0.1.
|
|
2
|
+
__version__ = "0.1.30"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "meteocat",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.30",
|
|
4
4
|
"description": "[](https://opensource.org/licenses/Apache-2.0)\r [](https://pypi.org/project/meteocat)\r [](https://gitlab.com/figorr/meteocat/commits/master)",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"directories": {
|