meteocat 2.2.7 → 2.3.0

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.
@@ -2,11 +2,23 @@ from __future__ import annotations
2
2
 
3
3
  import logging
4
4
  from datetime import datetime
5
+ from pathlib import Path
6
+ from homeassistant.core import HomeAssistant
5
7
  from homeassistant.util.dt import as_local, as_utc, start_of_local_day
6
8
  from homeassistant.helpers.sun import get_astral_event_date
7
9
 
8
10
  _LOGGER = logging.getLogger(__name__)
9
11
 
12
+ # Ruta base para guardar archivos persistentes que se descargan de la API y que son utilizados por los coordinadores
13
+ def get_storage_dir(hass: HomeAssistant, subdir: str | None = None) -> Path:
14
+ """Devuelve una ruta persistente en config/meteocat_files[/subdir]."""
15
+ base_dir = Path(hass.config.path("meteocat_files"))
16
+ if subdir:
17
+ base_dir = base_dir / subdir
18
+ base_dir.mkdir(parents=True, exist_ok=True)
19
+ return base_dir
20
+
21
+ # Cálculo de amanecer y atardecer para definir cuando es de noche
10
22
  def get_sun_times(hass, current_time=None):
11
23
  """Obtén las horas de amanecer y atardecer para el día actual."""
12
24
  if current_time is None:
@@ -1,13 +1,24 @@
1
1
  {
2
- "domain": "meteocat",
3
- "name": "Meteocat",
4
- "codeowners": ["@figorr"],
5
- "config_flow": true,
6
- "dependencies": ["persistent_notification", "http"],
7
- "documentation": "https://github.com/figorr/meteocat",
8
- "iot_class": "cloud_polling",
9
- "issue_tracker": "https://github.com/figorr/meteocat/issues",
10
- "loggers": ["meteocatpy"],
11
- "requirements": ["meteocatpy==1.0.1", "packaging>=20.3", "wrapt>=1.14.0"],
12
- "version": "2.2.7"
2
+ "domain": "meteocat",
3
+ "name": "Meteocat",
4
+ "codeowners": [
5
+ "@figorr"
6
+ ],
7
+ "config_flow": true,
8
+ "dependencies": [
9
+ "persistent_notification",
10
+ "http"
11
+ ],
12
+ "documentation": "https://github.com/figorr/meteocat",
13
+ "iot_class": "cloud_polling",
14
+ "issue_tracker": "https://github.com/figorr/meteocat/issues",
15
+ "loggers": [
16
+ "meteocatpy"
17
+ ],
18
+ "requirements": [
19
+ "meteocatpy==1.0.1",
20
+ "packaging>=20.3",
21
+ "wrapt>=1.14.0"
22
+ ],
23
+ "version": ""
13
24
  }
@@ -43,6 +43,8 @@ class MeteocatOptionsFlowHandler(OptionsFlow):
43
43
  return await self.async_step_update_api_and_limits()
44
44
  elif user_input["option"] == "update_limits_only":
45
45
  return await self.async_step_update_limits_only()
46
+ elif user_input["option"] == "regenerate_assets":
47
+ return await self.async_step_confirm_regenerate_assets()
46
48
 
47
49
  return self.async_show_form(
48
50
  step_id="init",
@@ -51,7 +53,8 @@ class MeteocatOptionsFlowHandler(OptionsFlow):
51
53
  SelectSelectorConfig(
52
54
  options=[
53
55
  "update_api_and_limits",
54
- "update_limits_only"
56
+ "update_limits_only",
57
+ "regenerate_assets"
55
58
  ],
56
59
  translation_key="option"
57
60
  )
@@ -173,4 +176,45 @@ class MeteocatOptionsFlowHandler(OptionsFlow):
173
176
  })
174
177
  return self.async_show_form(
175
178
  step_id="update_limits_only", data_schema=schema, errors=errors
176
- )
179
+ )
180
+
181
+ async def async_step_confirm_regenerate_assets(self, user_input: dict | None = None):
182
+ """Confirma si el usuario realmente quiere regenerar los assets."""
183
+ if user_input is not None:
184
+ if user_input.get("confirm") is True:
185
+ return await self.async_step_regenerate_assets()
186
+ else:
187
+ # Volver al menú inicial si el usuario cancela
188
+ return await self.async_step_init()
189
+
190
+ schema = vol.Schema({
191
+ vol.Required("confirm", default=False): bool
192
+ })
193
+ return self.async_show_form(
194
+ step_id="confirm_regenerate_assets",
195
+ data_schema=schema,
196
+ description_placeholders={
197
+ "warning": "Esto regenerará los archivos faltantes de towns.json, stations.json, variables.json, symbols.json y stations_<town_id>.json. ¿Desea continuar?"
198
+ }
199
+ )
200
+
201
+ async def async_step_regenerate_assets(self, user_input: dict | None = None):
202
+ """Regenera los archivos de assets."""
203
+ from . import ensure_assets_exist # importamos la función desde __init__.py
204
+
205
+ errors = {}
206
+ try:
207
+ # Llamar a la función que garantiza que los assets existan
208
+ await ensure_assets_exist(self.hass, self._config_entry.data)
209
+
210
+ _LOGGER.info("Archivos de assets regenerados correctamente.")
211
+ # Forzar recarga de la integración
212
+ await self.hass.config_entries.async_reload(self._config_entry.entry_id)
213
+
214
+ return self.async_create_entry(title="", data={})
215
+
216
+ except Exception as ex:
217
+ _LOGGER.error("Error al regenerar assets: %s", ex)
218
+ errors["base"] = "regenerate_failed"
219
+
220
+ return self.async_show_form(step_id="regenerate_assets", errors=errors)
@@ -36,7 +36,7 @@
36
36
  "options": {
37
37
  "step":{
38
38
  "init": {
39
- "description": "Setup the API Key and the API limits.",
39
+ "description": "Setup the API Key, the API limits and regenerate 'assets' files.",
40
40
  "title": "Setup options",
41
41
  "data": {
42
42
  "option": "Options"
@@ -49,6 +49,13 @@
49
49
  "update_limits_only": {
50
50
  "description": "Setup the API limits.",
51
51
  "title": "API limits"
52
+ },
53
+ "confirm_regenerate_assets": {
54
+ "description": "Regenerate missing assets files.",
55
+ "title": "Regenerate assets",
56
+ "data": {
57
+ "confirm": "Confirm"
58
+ }
52
59
  }
53
60
  },
54
61
  "error": {
@@ -61,7 +68,8 @@
61
68
  "option": {
62
69
  "options": {
63
70
  "update_api_and_limits": "Update API Key and limits.",
64
- "update_limits_only": "Update API limits."
71
+ "update_limits_only": "Update API limits.",
72
+ "regenerate_assets": "Regenerate 'assets' files."
65
73
  }
66
74
  }
67
75
  },
@@ -36,7 +36,7 @@
36
36
  "options": {
37
37
  "step":{
38
38
  "init": {
39
- "description": "Configura l'API Key i els límits de l'API.",
39
+ "description": "Configura l'API Key, els límits de l'API i regenera els arxius a 'assets'.",
40
40
  "title": "Opcions de configuració",
41
41
  "data": {
42
42
  "option": "Opcions"
@@ -49,6 +49,13 @@
49
49
  "update_limits_only": {
50
50
  "description": "Configura els límits de l'API.",
51
51
  "title": "Límits de l'API"
52
+ },
53
+ "confirm_regenerate_assets": {
54
+ "description": "Regenera els arxius a 'assets'.",
55
+ "title": "Regenera 'assets'",
56
+ "data": {
57
+ "confirm": "Confirmar"
58
+ }
52
59
  }
53
60
  },
54
61
  "error": {
@@ -61,7 +68,8 @@
61
68
  "option": {
62
69
  "options": {
63
70
  "update_api_and_limits": "Actualitzar API Key i limits.",
64
- "update_limits_only": "Actualitzar API limits."
71
+ "update_limits_only": "Actualitzar API limits.",
72
+ "regenerate_assets": "Regenera arxius a 'assets'."
65
73
  }
66
74
  }
67
75
  },
@@ -36,7 +36,7 @@
36
36
  "options": {
37
37
  "step":{
38
38
  "init": {
39
- "description": "Setup the API Key and the API limits.",
39
+ "description": "Setup the API Key, the API limits and regenerate 'assets' files.",
40
40
  "title": "Setup options",
41
41
  "data": {
42
42
  "option": "Options"
@@ -49,6 +49,13 @@
49
49
  "update_limits_only": {
50
50
  "description": "Setup the API limits.",
51
51
  "title": "API limits"
52
+ },
53
+ "confirm_regenerate_assets": {
54
+ "description": "Regenerate missing assets files.",
55
+ "title": "Regenerate assets",
56
+ "data": {
57
+ "confirm": "Confirm"
58
+ }
52
59
  }
53
60
  },
54
61
  "error": {
@@ -61,7 +68,8 @@
61
68
  "option": {
62
69
  "options": {
63
70
  "update_api_and_limits": "Update API Key and limits.",
64
- "update_limits_only": "Update API limits."
71
+ "update_limits_only": "Update API limits.",
72
+ "regenerate_assets": "Regenerate 'assets' files."
65
73
  }
66
74
  }
67
75
  },
@@ -36,7 +36,7 @@
36
36
  "options": {
37
37
  "step":{
38
38
  "init": {
39
- "description": "Configura el API Key y los límites de la API.",
39
+ "description": "Configura el API Key, los límites de la API y regenera los archivos en 'assets'.",
40
40
  "title": "Opciones de configuración",
41
41
  "data": {
42
42
  "option": "Opciones"
@@ -49,6 +49,13 @@
49
49
  "update_limits_only": {
50
50
  "description": "Configura los límites de la API.",
51
51
  "title": "Límites de la API"
52
+ },
53
+ "confirm_regenerate_assets": {
54
+ "description": "Regenera los archivos de 'assets'.",
55
+ "title": "Regenera 'assets'",
56
+ "data": {
57
+ "confirm": "Confirmar"
58
+ }
52
59
  }
53
60
  },
54
61
  "error": {
@@ -61,7 +68,8 @@
61
68
  "option": {
62
69
  "options": {
63
70
  "update_api_and_limits": "Actualizar API Key y límites.",
64
- "update_limits_only": "Actualizar API límites."
71
+ "update_limits_only": "Actualizar API límites.",
72
+ "regenerate_assets": "Regenerar archivos de 'assets'."
65
73
  }
66
74
  }
67
75
  },
@@ -1,2 +1 @@
1
- # version.py
2
- __version__ = "2.2.7"
1
+ __version__ = ""
package/filetree.txt CHANGED
@@ -1,7 +1,15 @@
1
1
  └── .github/
2
+ └── ISSUE_TEMPLATE/
3
+ ├── bug_report.md
4
+ ├── config.yml
2
5
  └── workflows/
6
+ ├── autocloser.yaml
7
+ ├── close-duplicates.yml
3
8
  ├── hassfest.yaml
9
+ ├── publish-zip.yml
4
10
  ├── release.yml
11
+ ├── stale.yml
12
+ ├── sync-gitlab.yml
5
13
  ├── validate.yaml
6
14
  ├── .gitignore
7
15
  ├── .gitlab-ci.yml
@@ -42,6 +50,7 @@
42
50
  ├── diagnostic_sensors.png
43
51
  ├── dynamic_sensors.png
44
52
  ├── login.png
53
+ ├── options.png
45
54
  ├── pick_area.png
46
55
  ├── pick_station.png
47
56
  ├── pick_town.png
package/hacs.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "Meteocat",
3
- "homeassistant": "2025.3.0",
3
+ "homeassistant": "2025.8.3",
4
4
  "hide_default_branch": true,
5
5
  "render_readme": true,
6
6
  "zip_release": true,
7
7
  "filename": "meteocat.zip"
8
- }
8
+ }
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "meteocat",
3
- "version": "2.2.7",
3
+ "version": "2.3.0",
4
4
  "description": "[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\r [![Python version compatibility](https://img.shields.io/pypi/pyversions/meteocat)](https://pypi.org/project/meteocat)\r [![pipeline status](https://gitlab.com/figorr/meteocat/badges/master/pipeline.svg)](https://gitlab.com/figorr/meteocat/commits/master)",
5
5
  "main": "index.js",
6
6
  "directories": {
package/pyproject.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "meteocat"
3
- version = "2.2.7"
3
+ version = ""
4
4
  description = "Script para obtener datos meteorológicos de la API de Meteocat"
5
5
  authors = ["figorr <jdcuartero@yahoo.es>"]
6
6
  license = "Apache-2.0"
package/.releaserc.toml DELETED
@@ -1,14 +0,0 @@
1
- branches = ["master"]
2
-
3
- [plugins]
4
- "@semantic-release/gitlab" = {}
5
- "@semantic-release/github" = {}
6
- "@semantic-release/changelog" = {}
7
- "@semantic-release/commit-analyzer" = { preset = "conventional" }
8
- "@semantic-release/release-notes-generator" = {}
9
- "@semantic-release/git" = {}
10
-
11
- [[plugins]]
12
- path = "@semantic-release/git"
13
- assets = ["meteocat/version.py"]
14
- message = "chore(release): update version to ${nextRelease.version}"
package/releaserc.json DELETED
@@ -1,18 +0,0 @@
1
- {
2
- "branches": ["master"],
3
- "plugins": [
4
- "@semantic-release/commit-analyzer",
5
- "@semantic-release/release-notes-generator",
6
- "@semantic-release/changelog",
7
- [
8
- "@semantic-release/exec",
9
- {
10
- "prepareCmd": "python setup.py sdist bdist_wheel",
11
- "publishCmd": "twine upload dist/* -u ${PYPI_USERNAME} -p ${PYPI_PASSWORD}"
12
- }
13
- ],
14
- "@semantic-release/github",
15
- "@semantic-release/git"
16
- ]
17
- }
18
-