meteocat 0.1.22 → 0.1.25

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.
Files changed (35) hide show
  1. package/.github/workflows/release.yml +33 -33
  2. package/.pre-commit-config.yaml +37 -37
  3. package/.releaserc +23 -23
  4. package/.releaserc.toml +14 -14
  5. package/AUTHORS.md +12 -12
  6. package/CHANGELOG.md +401 -372
  7. package/README.md +40 -40
  8. package/custom_components/meteocat/__init__.py +107 -107
  9. package/custom_components/meteocat/condition.py +28 -28
  10. package/custom_components/meteocat/config_flow.py +192 -192
  11. package/custom_components/meteocat/const.py +55 -52
  12. package/custom_components/meteocat/coordinator.py +195 -171
  13. package/custom_components/meteocat/entity.py +98 -91
  14. package/custom_components/meteocat/helpers.py +42 -42
  15. package/custom_components/meteocat/manifest.json +12 -12
  16. package/custom_components/meteocat/options_flow.py +71 -71
  17. package/custom_components/meteocat/sensor.py +303 -185
  18. package/custom_components/meteocat/strings.json +25 -25
  19. package/custom_components/meteocat/translations/ca.json +25 -25
  20. package/custom_components/meteocat/translations/en.json +25 -25
  21. package/custom_components/meteocat/translations/es.json +25 -25
  22. package/custom_components/meteocat/version.py +2 -2
  23. package/filetree.py +48 -48
  24. package/filetree.txt +46 -46
  25. package/hacs.json +5 -5
  26. package/package.json +22 -22
  27. package/poetry.lock +3216 -3216
  28. package/pyproject.toml +64 -64
  29. package/releaserc.json +17 -17
  30. package/requirements.test.txt +3 -3
  31. package/setup.cfg +64 -64
  32. package/setup.py +10 -10
  33. package/tests/bandit.yaml +17 -17
  34. package/tests/conftest.py +19 -19
  35. package/tests/test_init.py +9 -9
package/README.md CHANGED
@@ -1,41 +1,41 @@
1
- # Meteocat for Home Assistant
2
-
3
- [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
4
- [![Python version compatibility](https://img.shields.io/pypi/pyversions/meteocat)](https://pypi.org/project/meteocat)
5
- [![pipeline status](https://gitlab.com/figorr/meteocat/badges/master/pipeline.svg)](https://gitlab.com/figorr/meteocat/commits/master)
6
-
7
-
8
- This is a project to obtain meteorological data from the Meteocat API.
9
-
10
- **NOTE:** Meteocat API requires to use an API_KEY, you should ask to (https://apidocs.meteocat.gencat.cat/documentacio/acces-ciutada-i-administracio/)
11
-
12
- # Credits
13
-
14
- This is a personal project.
15
-
16
- Authors:
17
- - Figorr
18
-
19
- # Contributing
20
-
21
- 1. [Check for open features/bugs](https://gitlab.com/figorr/meteocat/issues)
22
- or [initiate a discussion on one](https://gitlab.com/figorr/meteocat/issues/new).
23
- 2. [Fork the repository](https://gitlab.com/figorr/meteocat/forks/new).
24
- 3. Install the dev environment: `make init`.
25
- 4. Enter the virtual environment: `pipenv shell`
26
- 5. Code your new feature or bug fix.
27
- 6. Write a test that covers your new functionality.
28
- 7. Update `README.md` with any new documentation.
29
- 8. Run tests and ensure 100% code coverage for your contribution: `make coverage`
30
- 9. Ensure you have no linting errors: `make lint`
31
- 10. Ensure you have typed your code correctly: `make typing`
32
- 11. Add yourself to `AUTHORS.md`.
33
- 12. Submit a pull request!
34
-
35
- # License
36
-
37
- [Apache-2.0](LICENSE). By providing a contribution, you agree the contribution is licensed under Apache-2.0.
38
-
39
- # API Reference
40
-
1
+ # Meteocat for Home Assistant
2
+
3
+ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
4
+ [![Python version compatibility](https://img.shields.io/pypi/pyversions/meteocat)](https://pypi.org/project/meteocat)
5
+ [![pipeline status](https://gitlab.com/figorr/meteocat/badges/master/pipeline.svg)](https://gitlab.com/figorr/meteocat/commits/master)
6
+
7
+
8
+ This is a project to obtain meteorological data from the Meteocat API.
9
+
10
+ **NOTE:** Meteocat API requires to use an API_KEY, you should ask to (https://apidocs.meteocat.gencat.cat/documentacio/acces-ciutada-i-administracio/)
11
+
12
+ # Credits
13
+
14
+ This is a personal project.
15
+
16
+ Authors:
17
+ - Figorr
18
+
19
+ # Contributing
20
+
21
+ 1. [Check for open features/bugs](https://gitlab.com/figorr/meteocat/issues)
22
+ or [initiate a discussion on one](https://gitlab.com/figorr/meteocat/issues/new).
23
+ 2. [Fork the repository](https://gitlab.com/figorr/meteocat/forks/new).
24
+ 3. Install the dev environment: `make init`.
25
+ 4. Enter the virtual environment: `pipenv shell`
26
+ 5. Code your new feature or bug fix.
27
+ 6. Write a test that covers your new functionality.
28
+ 7. Update `README.md` with any new documentation.
29
+ 8. Run tests and ensure 100% code coverage for your contribution: `make coverage`
30
+ 9. Ensure you have no linting errors: `make lint`
31
+ 10. Ensure you have typed your code correctly: `make typing`
32
+ 11. Add yourself to `AUTHORS.md`.
33
+ 12. Submit a pull request!
34
+
35
+ # License
36
+
37
+ [Apache-2.0](LICENSE). By providing a contribution, you agree the contribution is licensed under Apache-2.0.
38
+
39
+ # API Reference
40
+
41
41
  [See the docs 📚](https://apidocs.meteocat.gencat.cat/section/informacio-general/).
@@ -1,107 +1,107 @@
1
- from __future__ import annotations
2
-
3
- import os
4
- import logging
5
- from homeassistant import core
6
- from homeassistant.config_entries import ConfigEntry
7
- from homeassistant.core import HomeAssistant
8
- from homeassistant.exceptions import HomeAssistantError
9
- from .coordinator import MeteocatSensorCoordinator, MeteocatEntityCoordinator
10
- from .const import DOMAIN, PLATFORMS
11
-
12
- _LOGGER = logging.getLogger(__name__)
13
-
14
- # Versión
15
- __version__ = "0.1.22"
16
-
17
-
18
- async def async_setup(hass: core.HomeAssistant, config: dict) -> bool:
19
- """Configuración inicial del componente Meteocat."""
20
- return True
21
-
22
-
23
- async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
24
- """Configura una entrada de configuración para Meteocat."""
25
- _LOGGER.info("Configurando la integración de Meteocat...")
26
-
27
- # Extraer los datos necesarios de la entrada de configuración
28
- entry_data = entry.data
29
-
30
- # Validar que todos los campos requeridos estén presentes
31
- required_fields = [
32
- "api_key", "town_name", "town_id", "variable_name",
33
- "variable_id", "station_name", "station_id"
34
- ]
35
- if not all(field in entry_data for field in required_fields):
36
- _LOGGER.error("Faltan datos en la configuración. Por favor, reconfigura la integración.")
37
- return False
38
-
39
- _LOGGER.info(
40
- f"Integración configurada para el municipio '{entry_data['town_name']}' "
41
- f"(ID: {entry_data['town_id']}), variable '{entry_data['variable_name']}' "
42
- f"(ID: {entry_data['variable_id']}), estación '{entry_data['station_name']}' "
43
- f"(ID: {entry_data['station_id']})."
44
- )
45
-
46
- # Inicializa y refresca los coordinadores
47
- try:
48
- # Crear el coordinador para sensores
49
- sensor_coordinator = MeteocatSensorCoordinator(
50
- hass=hass,
51
- entry_data=entry_data, # Pasa los datos como un diccionario
52
- )
53
-
54
- # Crear el coordinador para entidades de predicción
55
- entity_coordinator = MeteocatEntityCoordinator(
56
- hass=hass,
57
- entry_data=entry_data, # Pasa los mismos datos
58
- )
59
-
60
- # Ejecutar la primera actualización
61
- await sensor_coordinator.async_config_entry_first_refresh()
62
- await entity_coordinator.async_config_entry_first_refresh()
63
- except HomeAssistantError as err:
64
- _LOGGER.error(f"Error al inicializar los coordinadores: {err}")
65
- return False
66
-
67
- # Guardar los coordinadores en hass.data
68
- hass.data.setdefault(DOMAIN, {})
69
- hass.data[DOMAIN][entry.entry_id] = {
70
- "sensor_coordinator": sensor_coordinator,
71
- "entity_coordinator": entity_coordinator,
72
- **entry_data,
73
- }
74
-
75
- # Configurar las plataformas
76
- await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
77
-
78
- return True
79
-
80
-
81
- async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
82
- """Desactiva una entrada de configuración para Meteocat."""
83
- if entry.entry_id in hass.data.get(DOMAIN, {}):
84
- hass.data[DOMAIN].pop(entry.entry_id, None)
85
- if not hass.data[DOMAIN]: # Si no quedan entradas, elimina el dominio
86
- hass.data.pop(DOMAIN)
87
-
88
- # Desinstalar las plataformas
89
- return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
90
-
91
-
92
- async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
93
- """Limpia cualquier dato adicional al desinstalar la integración."""
94
- _LOGGER.info(f"Eliminando datos residuales de la integración: {entry.entry_id}")
95
-
96
- # Definir la ruta del archivo de símbolos
97
- assets_folder = hass.config.path("custom_components", DOMAIN, "assets")
98
- symbols_file = os.path.join(assets_folder, "symbols.json")
99
-
100
- try:
101
- if os.path.exists(symbols_file):
102
- os.remove(symbols_file)
103
- _LOGGER.info("Archivo symbols.json eliminado correctamente.")
104
- else:
105
- _LOGGER.info("El archivo symbols.json no se encontró.")
106
- except OSError as e:
107
- _LOGGER.error(f"Error al intentar eliminar el archivo symbols.json: {e}")
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import logging
5
+ from homeassistant import core
6
+ from homeassistant.config_entries import ConfigEntry
7
+ from homeassistant.core import HomeAssistant
8
+ from homeassistant.exceptions import HomeAssistantError
9
+ from .coordinator import MeteocatSensorCoordinator, MeteocatEntityCoordinator
10
+ from .const import DOMAIN, PLATFORMS
11
+
12
+ _LOGGER = logging.getLogger(__name__)
13
+
14
+ # Versión
15
+ __version__ = "0.1.25"
16
+
17
+
18
+ async def async_setup(hass: core.HomeAssistant, config: dict) -> bool:
19
+ """Configuración inicial del componente Meteocat."""
20
+ return True
21
+
22
+
23
+ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
24
+ """Configura una entrada de configuración para Meteocat."""
25
+ _LOGGER.info("Configurando la integración de Meteocat...")
26
+
27
+ # Extraer los datos necesarios de la entrada de configuración
28
+ entry_data = entry.data
29
+
30
+ # Validar que todos los campos requeridos estén presentes
31
+ required_fields = [
32
+ "api_key", "town_name", "town_id", "variable_name",
33
+ "variable_id", "station_name", "station_id"
34
+ ]
35
+ if not all(field in entry_data for field in required_fields):
36
+ _LOGGER.error("Faltan datos en la configuración. Por favor, reconfigura la integración.")
37
+ return False
38
+
39
+ _LOGGER.info(
40
+ f"Integración configurada para el municipio '{entry_data['town_name']}' "
41
+ f"(ID: {entry_data['town_id']}), variable '{entry_data['variable_name']}' "
42
+ f"(ID: {entry_data['variable_id']}), estación '{entry_data['station_name']}' "
43
+ f"(ID: {entry_data['station_id']})."
44
+ )
45
+
46
+ # Inicializa y refresca los coordinadores
47
+ try:
48
+ # Crear el coordinador para sensores
49
+ sensor_coordinator = MeteocatSensorCoordinator(
50
+ hass=hass,
51
+ entry_data=entry_data, # Pasa los datos como un diccionario
52
+ )
53
+
54
+ # Crear el coordinador para entidades de predicción
55
+ entity_coordinator = MeteocatEntityCoordinator(
56
+ hass=hass,
57
+ entry_data=entry_data, # Pasa los mismos datos
58
+ )
59
+
60
+ # Ejecutar la primera actualización
61
+ await sensor_coordinator.async_config_entry_first_refresh()
62
+ await entity_coordinator.async_config_entry_first_refresh()
63
+ except HomeAssistantError as err:
64
+ _LOGGER.error(f"Error al inicializar los coordinadores: {err}")
65
+ return False
66
+
67
+ # Guardar los coordinadores en hass.data
68
+ hass.data.setdefault(DOMAIN, {})
69
+ hass.data[DOMAIN][entry.entry_id] = {
70
+ "sensor_coordinator": sensor_coordinator,
71
+ "entity_coordinator": entity_coordinator,
72
+ **entry_data,
73
+ }
74
+
75
+ # Configurar las plataformas
76
+ await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
77
+
78
+ return True
79
+
80
+
81
+ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
82
+ """Desactiva una entrada de configuración para Meteocat."""
83
+ if entry.entry_id in hass.data.get(DOMAIN, {}):
84
+ hass.data[DOMAIN].pop(entry.entry_id, None)
85
+ if not hass.data[DOMAIN]: # Si no quedan entradas, elimina el dominio
86
+ hass.data.pop(DOMAIN)
87
+
88
+ # Desinstalar las plataformas
89
+ return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
90
+
91
+
92
+ async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
93
+ """Limpia cualquier dato adicional al desinstalar la integración."""
94
+ _LOGGER.info(f"Eliminando datos residuales de la integración: {entry.entry_id}")
95
+
96
+ # Definir la ruta del archivo de símbolos
97
+ assets_folder = hass.config.path("custom_components", DOMAIN, "assets")
98
+ symbols_file = os.path.join(assets_folder, "symbols.json")
99
+
100
+ try:
101
+ if os.path.exists(symbols_file):
102
+ os.remove(symbols_file)
103
+ _LOGGER.info("Archivo symbols.json eliminado correctamente.")
104
+ else:
105
+ _LOGGER.info("El archivo symbols.json no se encontró.")
106
+ except OSError as e:
107
+ _LOGGER.error(f"Error al intentar eliminar el archivo symbols.json: {e}")
@@ -1,28 +1,28 @@
1
- from __future__ import annotations
2
-
3
- from datetime import datetime
4
- from .const import CONDITION_MAPPING
5
- from .helpers import is_night # Importar la función is_night de helpers.py
6
-
7
- def get_condition_from_statcel(codi_estatcel, current_time: datetime, hass) -> dict:
8
- """
9
- Convierte el código 'estatCel' en condición de Home Assistant.
10
-
11
- :param codi_estatcel: Código del estado del cielo (celestial state code).
12
- :param current_time: Fecha y hora actual (datetime).
13
- :param hass: Instancia de Home Assistant.
14
- :return: Diccionario con la condición y el icono.
15
- """
16
- # Determinar si es de noche usando la lógica centralizada en helpers.py
17
- is_night_flag = is_night(current_time, hass)
18
-
19
- # Identificar la condición basada en el código
20
- for condition, codes in CONDITION_MAPPING.items():
21
- if codi_estatcel in codes:
22
- # Ajustar para condiciones nocturnas si aplica
23
- if condition == "sunny" and is_night_flag:
24
- return {"condition": "clear-night", "icon": None}
25
- return {"condition": condition, "icon": None}
26
-
27
- # Si no coincide ningún código, devolver condición desconocida
28
- return {"condition": "unknown", "icon": None}
1
+ from __future__ import annotations
2
+
3
+ from datetime import datetime
4
+ from .const import CONDITION_MAPPING
5
+ from .helpers import is_night # Importar la función is_night de helpers.py
6
+
7
+ def get_condition_from_statcel(codi_estatcel, current_time: datetime, hass) -> dict:
8
+ """
9
+ Convierte el código 'estatCel' en condición de Home Assistant.
10
+
11
+ :param codi_estatcel: Código del estado del cielo (celestial state code).
12
+ :param current_time: Fecha y hora actual (datetime).
13
+ :param hass: Instancia de Home Assistant.
14
+ :return: Diccionario con la condición y el icono.
15
+ """
16
+ # Determinar si es de noche usando la lógica centralizada en helpers.py
17
+ is_night_flag = is_night(current_time, hass)
18
+
19
+ # Identificar la condición basada en el código
20
+ for condition, codes in CONDITION_MAPPING.items():
21
+ if codi_estatcel in codes:
22
+ # Ajustar para condiciones nocturnas si aplica
23
+ if condition == "sunny" and is_night_flag:
24
+ return {"condition": "clear-night", "icon": None}
25
+ return {"condition": condition, "icon": None}
26
+
27
+ # Si no coincide ningún código, devolver condición desconocida
28
+ return {"condition": "unknown", "icon": None}