meteocat 3.2.0 → 4.0.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.
- package/.github/ISSUE_TEMPLATE/bug_report.md +45 -45
- package/.github/ISSUE_TEMPLATE/config.yml +8 -8
- package/.github/ISSUE_TEMPLATE/improvement.md +39 -39
- package/.github/ISSUE_TEMPLATE/new_function.md +41 -41
- package/.github/labels.yml +63 -63
- package/.github/workflows/autocloser.yaml +27 -27
- package/.github/workflows/close-on-label.yml +48 -48
- package/.github/workflows/force-sync-labels.yml +18 -18
- package/.github/workflows/hassfest.yaml +13 -13
- package/.github/workflows/publish-zip.yml +67 -67
- package/.github/workflows/release.yml +41 -41
- package/.github/workflows/stale.yml +63 -63
- package/.github/workflows/sync-gitlab.yml +107 -107
- package/.github/workflows/sync-labels.yml +21 -21
- package/.github/workflows/validate.yaml +16 -16
- package/.pre-commit-config.yaml +37 -37
- package/.releaserc +37 -37
- package/AUTHORS.md +13 -13
- package/CHANGELOG.md +954 -932
- package/README.md +207 -207
- package/conftest.py +11 -11
- package/custom_components/meteocat/__init__.py +298 -298
- package/custom_components/meteocat/condition.py +63 -63
- package/custom_components/meteocat/config_flow.py +613 -613
- package/custom_components/meteocat/const.py +132 -132
- package/custom_components/meteocat/helpers.py +58 -58
- package/custom_components/meteocat/manifest.json +25 -25
- package/custom_components/meteocat/options_flow.py +287 -287
- package/custom_components/meteocat/strings.json +1058 -1058
- package/custom_components/meteocat/translations/ca.json +1058 -1058
- package/custom_components/meteocat/translations/en.json +1058 -1058
- package/custom_components/meteocat/translations/es.json +1058 -1058
- package/custom_components/meteocat/version.py +1 -1
- package/custom_components/meteocat/weather.py +218 -218
- package/filetree.py +48 -48
- package/filetree.txt +79 -79
- package/hacs.json +8 -8
- package/info.md +11 -11
- package/package.json +22 -22
- package/poetry.lock +3222 -3222
- package/pyproject.toml +68 -68
- package/requirements.test.txt +3 -3
- package/setup.cfg +64 -64
- package/setup.py +10 -10
- package/tests/bandit.yaml +17 -17
- package/tests/conftest.py +19 -19
- package/tests/test_init.py +9 -9
|
@@ -1,132 +1,132 @@
|
|
|
1
|
-
# Constantes generales
|
|
2
|
-
DOMAIN = "meteocat"
|
|
3
|
-
BASE_URL = "https://api.meteo.cat"
|
|
4
|
-
CONF_API_KEY = "api_key"
|
|
5
|
-
TOWN_NAME = "town_name"
|
|
6
|
-
TOWN_ID = "town_id"
|
|
7
|
-
VARIABLE_NAME = "variable_name"
|
|
8
|
-
VARIABLE_ID = "variable_id"
|
|
9
|
-
STATION_NAME = "station_name"
|
|
10
|
-
STATION_ID = "station_id"
|
|
11
|
-
STATION_TYPE = "station_type"
|
|
12
|
-
LATITUDE = "latitude"
|
|
13
|
-
LONGITUDE = "longitude"
|
|
14
|
-
ALTITUDE = "altitude"
|
|
15
|
-
REGION_ID = "region_id"
|
|
16
|
-
REGION_NAME = "region_name"
|
|
17
|
-
PROVINCE_ID = "province_id"
|
|
18
|
-
PROVINCE_NAME = "province_name"
|
|
19
|
-
LIMIT_XEMA = "limit_xema"
|
|
20
|
-
LIMIT_PREDICCIO = "limit_prediccio"
|
|
21
|
-
LIMIT_XDDE = "limit_xdde"
|
|
22
|
-
LIMIT_BASIC = "limit_basic"
|
|
23
|
-
LIMIT_QUOTA = "limit_quota"
|
|
24
|
-
STATION_STATUS = "station_status"
|
|
25
|
-
HOURLY_FORECAST_FILE_STATUS = "hourly_forecast_file_status"
|
|
26
|
-
DAILY_FORECAST_FILE_STATUS = "daily_forecast_file_status"
|
|
27
|
-
UVI_FILE_STATUS = "uvi_file_status"
|
|
28
|
-
ALERTS = "alerts"
|
|
29
|
-
ALERT_FILE_STATUS = "alert_file_status"
|
|
30
|
-
ALERT_WIND = "alert_wind"
|
|
31
|
-
ALERT_RAIN_INTENSITY = "alert_rain_intensity"
|
|
32
|
-
ALERT_RAIN = "alert_rain"
|
|
33
|
-
ALERT_SEA = "alert_sea"
|
|
34
|
-
ALERT_COLD = "alert_cold"
|
|
35
|
-
ALERT_WARM = "alert_warm"
|
|
36
|
-
ALERT_WARM_NIGHT = "alert_warm_night"
|
|
37
|
-
ALERT_SNOW = "alert_snow"
|
|
38
|
-
QUOTA_FILE_STATUS = "quota_file_status"
|
|
39
|
-
QUOTA_XDDE = "quota_xdde"
|
|
40
|
-
QUOTA_PREDICCIO = "quota_prediccio"
|
|
41
|
-
QUOTA_BASIC = "quota_basic"
|
|
42
|
-
QUOTA_XEMA = "quota_xema"
|
|
43
|
-
QUOTA_QUERIES = "quota_queries"
|
|
44
|
-
LIGHTNING_FILE_STATUS = "lightning_file_status"
|
|
45
|
-
SUN = "sun"
|
|
46
|
-
SUNRISE = "sunrise"
|
|
47
|
-
SUNSET = "sunset"
|
|
48
|
-
SUN_FILE_STATUS = "sun_file_status"
|
|
49
|
-
MOON_PHASE = "moon_phase"
|
|
50
|
-
MOON_FILE_STATUS = "moon_file_status"
|
|
51
|
-
MOONRISE = "moonrise"
|
|
52
|
-
MOONSET = "moonset"
|
|
53
|
-
|
|
54
|
-
from homeassistant.const import Platform
|
|
55
|
-
|
|
56
|
-
ATTRIBUTION = "Powered by Meteocatpy & Solarmoonpy"
|
|
57
|
-
PLATFORMS = [Platform.SENSOR, Platform.WEATHER]
|
|
58
|
-
DEFAULT_NAME = "METEOCAT"
|
|
59
|
-
|
|
60
|
-
# Tiempos para validación de API
|
|
61
|
-
DEFAULT_VALIDITY_DAYS = 1 # Número de días a partir de los cuales se considera que el archivo de información está obsoleto
|
|
62
|
-
DEFAULT_VALIDITY_HOURS = 6 # Hora a partir de la cual la API tiene la información actualizada de predicciones disponible para descarga
|
|
63
|
-
DEFAULT_VALIDITY_MINUTES = 0 # Minutos a partir de los cuales la API tiene la información actualizada de predicciones disponible para descarga
|
|
64
|
-
DEFAULT_UVI_LOW_VALIDITY_HOURS = 5 # Hora a partir de la cual la API tiene la información actualizada de datos UVI disponible para descarga con límite bajo de cuota
|
|
65
|
-
DEFAULT_UVI_LOW_VALIDITY_MINUTES = 0 # Minutos a partir de los cuales la API tiene la información actualizada de datos UVI disponible para descarga con límite bajo de cuota
|
|
66
|
-
DEFAULT_UVI_HIGH_VALIDITY_HOURS = 9 # Hora a partir de la cual la API tiene la información actualizada de datos UVI disponible para descarga con límite alto de cuota
|
|
67
|
-
DEFAULT_UVI_HIGH_VALIDITY_MINUTES = 0 # Minutos a partir de los cuales la API tiene la información actualizada de datos UVI disponible para descarga con límite alto de cuota
|
|
68
|
-
DEFAULT_ALERT_VALIDITY_TIME = 120 # Minutos a partir de los cuales las alertas están obsoletas y se se debe proceder a una nueva llamada a la API
|
|
69
|
-
DEFAULT_QUOTES_VALIDITY_TIME = 240 # Minutos a partir de los cuales los datos de cuotas están obsoletos y se se debe proceder a una nueva llamada a la API
|
|
70
|
-
DEFAULT_LIGHTNING_VALIDITY_TIME = 240 # Minutos a partir de los cuales los datos de rayos están obsoletos y se se debe proceder a una nueva llamada a la API
|
|
71
|
-
DEFAULT_LIGHTNING_VALIDITY_HOURS = 1 # Hora a partir de la cual la API tiene la información actualizada de rayos disponible para descarga
|
|
72
|
-
DEFAULT_LIGHTNING_VALIDITY_MINUTES = 0 # Minutos a partir de los cuales la API tiene la información actualizada de rayos disponible para descarga
|
|
73
|
-
|
|
74
|
-
# Multiplicadores para la duración de validez basada en limit_prediccio
|
|
75
|
-
ALERT_VALIDITY_MULTIPLIER_100 = 12 # para limit_prediccio <= 100
|
|
76
|
-
ALERT_VALIDITY_MULTIPLIER_200 = 6 # para 100 < limit_prediccio <= 200
|
|
77
|
-
ALERT_VALIDITY_MULTIPLIER_500 = 3 # para 200 < limit_prediccio <= 500
|
|
78
|
-
ALERT_VALIDITY_MULTIPLIER_DEFAULT = 1 # para limit_prediccio > 500
|
|
79
|
-
|
|
80
|
-
# CUOTA ALTA PARA FAVORECER ACTUALIZACIONES DIARIAS DE LAS PREDICCIONES
|
|
81
|
-
PREDICCIO_HIGH_QUOTA_LIMIT = 550
|
|
82
|
-
|
|
83
|
-
# Códigos de sensores de la API
|
|
84
|
-
WIND_SPEED = "wind_speed" # Velocidad del viento
|
|
85
|
-
WIND_DIRECTION = "wind_direction" # Dirección del viento
|
|
86
|
-
WIND_DIRECTION_CARDINAL = "wind_direction_cardinal" # Dirección del viento en cardinal
|
|
87
|
-
TEMPERATURE = "temperature" # Temperatura
|
|
88
|
-
HUMIDITY = "humidity" # Humedad relativa
|
|
89
|
-
PRESSURE = "pressure" # Presión atmosférica
|
|
90
|
-
PRECIPITATION = "precipitation" # Precipitación
|
|
91
|
-
PRECIPITATION_ACCUMULATED = "precipitation_accumulated" #Precipitación acumulada
|
|
92
|
-
PRECIPITATION_PROBABILITY = "precipitation_probability" #Precipitación probabilidad
|
|
93
|
-
SOLAR_GLOBAL_IRRADIANCE = "solar_global_irradiance" # Irradiación solar global
|
|
94
|
-
UV_INDEX = "uv_index" # UV
|
|
95
|
-
MAX_TEMPERATURE = "max_temperature" # Temperatura máxima
|
|
96
|
-
MIN_TEMPERATURE = "min_temperature" # Temperatura mínima
|
|
97
|
-
FEELS_LIKE = "feels_like" # Sensación térmica
|
|
98
|
-
WIND_GUST = "wind_gust" # Racha de viento
|
|
99
|
-
STATION_TIMESTAMP = "station_timestamp" # Código de tiempo de la estación
|
|
100
|
-
CONDITION = "condition" # Estado del cielo
|
|
101
|
-
MAX_TEMPERATURE_FORECAST = "max_temperature_forecast" # Temperatura máxima prevista
|
|
102
|
-
MIN_TEMPERATURE_FORECAST = "min_temperature_forecast" # Temperatura mínima prevista
|
|
103
|
-
LIGHTNING_REGION = "lightning_region" # Rayos de la comarca
|
|
104
|
-
LIGHTNING_TOWN = "lightning_town" # Rayos de la población
|
|
105
|
-
|
|
106
|
-
# Definición de códigos para variables
|
|
107
|
-
WIND_SPEED_CODE = 30
|
|
108
|
-
WIND_DIRECTION_CODE = 31
|
|
109
|
-
TEMPERATURE_CODE = 32
|
|
110
|
-
HUMIDITY_CODE = 33
|
|
111
|
-
PRESSURE_CODE = 34
|
|
112
|
-
PRECIPITATION_CODE = 35
|
|
113
|
-
SOLAR_GLOBAL_IRRADIANCE_CODE = 36
|
|
114
|
-
UV_INDEX_CODE = 39
|
|
115
|
-
MAX_TEMPERATURE_CODE = 40
|
|
116
|
-
MIN_TEMPERATURE_CODE = 42
|
|
117
|
-
WIND_GUST_CODE = 50
|
|
118
|
-
|
|
119
|
-
# Mapeo de códigos 'estatCel' a condiciones de Home Assistant
|
|
120
|
-
CONDITION_MAPPING = {
|
|
121
|
-
"sunny": [1],
|
|
122
|
-
# "clear-night": [1],
|
|
123
|
-
"partlycloudy": [2, 3],
|
|
124
|
-
"cloudy": [4, 20, 21, 22],
|
|
125
|
-
"rainy": [5, 6, 23],
|
|
126
|
-
"pouring": [7, 8, 25],
|
|
127
|
-
"lightning-rainy": [8, 24],
|
|
128
|
-
"hail": [9],
|
|
129
|
-
"snowy": [10, 26, 27, 28],
|
|
130
|
-
"fog": [11, 12],
|
|
131
|
-
"snow-rainy": [27, 29, 30],
|
|
132
|
-
}
|
|
1
|
+
# Constantes generales
|
|
2
|
+
DOMAIN = "meteocat"
|
|
3
|
+
BASE_URL = "https://api.meteo.cat"
|
|
4
|
+
CONF_API_KEY = "api_key"
|
|
5
|
+
TOWN_NAME = "town_name"
|
|
6
|
+
TOWN_ID = "town_id"
|
|
7
|
+
VARIABLE_NAME = "variable_name"
|
|
8
|
+
VARIABLE_ID = "variable_id"
|
|
9
|
+
STATION_NAME = "station_name"
|
|
10
|
+
STATION_ID = "station_id"
|
|
11
|
+
STATION_TYPE = "station_type"
|
|
12
|
+
LATITUDE = "latitude"
|
|
13
|
+
LONGITUDE = "longitude"
|
|
14
|
+
ALTITUDE = "altitude"
|
|
15
|
+
REGION_ID = "region_id"
|
|
16
|
+
REGION_NAME = "region_name"
|
|
17
|
+
PROVINCE_ID = "province_id"
|
|
18
|
+
PROVINCE_NAME = "province_name"
|
|
19
|
+
LIMIT_XEMA = "limit_xema"
|
|
20
|
+
LIMIT_PREDICCIO = "limit_prediccio"
|
|
21
|
+
LIMIT_XDDE = "limit_xdde"
|
|
22
|
+
LIMIT_BASIC = "limit_basic"
|
|
23
|
+
LIMIT_QUOTA = "limit_quota"
|
|
24
|
+
STATION_STATUS = "station_status"
|
|
25
|
+
HOURLY_FORECAST_FILE_STATUS = "hourly_forecast_file_status"
|
|
26
|
+
DAILY_FORECAST_FILE_STATUS = "daily_forecast_file_status"
|
|
27
|
+
UVI_FILE_STATUS = "uvi_file_status"
|
|
28
|
+
ALERTS = "alerts"
|
|
29
|
+
ALERT_FILE_STATUS = "alert_file_status"
|
|
30
|
+
ALERT_WIND = "alert_wind"
|
|
31
|
+
ALERT_RAIN_INTENSITY = "alert_rain_intensity"
|
|
32
|
+
ALERT_RAIN = "alert_rain"
|
|
33
|
+
ALERT_SEA = "alert_sea"
|
|
34
|
+
ALERT_COLD = "alert_cold"
|
|
35
|
+
ALERT_WARM = "alert_warm"
|
|
36
|
+
ALERT_WARM_NIGHT = "alert_warm_night"
|
|
37
|
+
ALERT_SNOW = "alert_snow"
|
|
38
|
+
QUOTA_FILE_STATUS = "quota_file_status"
|
|
39
|
+
QUOTA_XDDE = "quota_xdde"
|
|
40
|
+
QUOTA_PREDICCIO = "quota_prediccio"
|
|
41
|
+
QUOTA_BASIC = "quota_basic"
|
|
42
|
+
QUOTA_XEMA = "quota_xema"
|
|
43
|
+
QUOTA_QUERIES = "quota_queries"
|
|
44
|
+
LIGHTNING_FILE_STATUS = "lightning_file_status"
|
|
45
|
+
SUN = "sun"
|
|
46
|
+
SUNRISE = "sunrise"
|
|
47
|
+
SUNSET = "sunset"
|
|
48
|
+
SUN_FILE_STATUS = "sun_file_status"
|
|
49
|
+
MOON_PHASE = "moon_phase"
|
|
50
|
+
MOON_FILE_STATUS = "moon_file_status"
|
|
51
|
+
MOONRISE = "moonrise"
|
|
52
|
+
MOONSET = "moonset"
|
|
53
|
+
|
|
54
|
+
from homeassistant.const import Platform
|
|
55
|
+
|
|
56
|
+
ATTRIBUTION = "Powered by Meteocatpy & Solarmoonpy"
|
|
57
|
+
PLATFORMS = [Platform.SENSOR, Platform.WEATHER]
|
|
58
|
+
DEFAULT_NAME = "METEOCAT"
|
|
59
|
+
|
|
60
|
+
# Tiempos para validación de API
|
|
61
|
+
DEFAULT_VALIDITY_DAYS = 1 # Número de días a partir de los cuales se considera que el archivo de información está obsoleto
|
|
62
|
+
DEFAULT_VALIDITY_HOURS = 6 # Hora a partir de la cual la API tiene la información actualizada de predicciones disponible para descarga
|
|
63
|
+
DEFAULT_VALIDITY_MINUTES = 0 # Minutos a partir de los cuales la API tiene la información actualizada de predicciones disponible para descarga
|
|
64
|
+
DEFAULT_UVI_LOW_VALIDITY_HOURS = 5 # Hora a partir de la cual la API tiene la información actualizada de datos UVI disponible para descarga con límite bajo de cuota
|
|
65
|
+
DEFAULT_UVI_LOW_VALIDITY_MINUTES = 0 # Minutos a partir de los cuales la API tiene la información actualizada de datos UVI disponible para descarga con límite bajo de cuota
|
|
66
|
+
DEFAULT_UVI_HIGH_VALIDITY_HOURS = 9 # Hora a partir de la cual la API tiene la información actualizada de datos UVI disponible para descarga con límite alto de cuota
|
|
67
|
+
DEFAULT_UVI_HIGH_VALIDITY_MINUTES = 0 # Minutos a partir de los cuales la API tiene la información actualizada de datos UVI disponible para descarga con límite alto de cuota
|
|
68
|
+
DEFAULT_ALERT_VALIDITY_TIME = 120 # Minutos a partir de los cuales las alertas están obsoletas y se se debe proceder a una nueva llamada a la API
|
|
69
|
+
DEFAULT_QUOTES_VALIDITY_TIME = 240 # Minutos a partir de los cuales los datos de cuotas están obsoletos y se se debe proceder a una nueva llamada a la API
|
|
70
|
+
DEFAULT_LIGHTNING_VALIDITY_TIME = 240 # Minutos a partir de los cuales los datos de rayos están obsoletos y se se debe proceder a una nueva llamada a la API
|
|
71
|
+
DEFAULT_LIGHTNING_VALIDITY_HOURS = 1 # Hora a partir de la cual la API tiene la información actualizada de rayos disponible para descarga
|
|
72
|
+
DEFAULT_LIGHTNING_VALIDITY_MINUTES = 0 # Minutos a partir de los cuales la API tiene la información actualizada de rayos disponible para descarga
|
|
73
|
+
|
|
74
|
+
# Multiplicadores para la duración de validez basada en limit_prediccio
|
|
75
|
+
ALERT_VALIDITY_MULTIPLIER_100 = 12 # para limit_prediccio <= 100
|
|
76
|
+
ALERT_VALIDITY_MULTIPLIER_200 = 6 # para 100 < limit_prediccio <= 200
|
|
77
|
+
ALERT_VALIDITY_MULTIPLIER_500 = 3 # para 200 < limit_prediccio <= 500
|
|
78
|
+
ALERT_VALIDITY_MULTIPLIER_DEFAULT = 1 # para limit_prediccio > 500
|
|
79
|
+
|
|
80
|
+
# CUOTA ALTA PARA FAVORECER ACTUALIZACIONES DIARIAS DE LAS PREDICCIONES
|
|
81
|
+
PREDICCIO_HIGH_QUOTA_LIMIT = 550
|
|
82
|
+
|
|
83
|
+
# Códigos de sensores de la API
|
|
84
|
+
WIND_SPEED = "wind_speed" # Velocidad del viento
|
|
85
|
+
WIND_DIRECTION = "wind_direction" # Dirección del viento
|
|
86
|
+
WIND_DIRECTION_CARDINAL = "wind_direction_cardinal" # Dirección del viento en cardinal
|
|
87
|
+
TEMPERATURE = "temperature" # Temperatura
|
|
88
|
+
HUMIDITY = "humidity" # Humedad relativa
|
|
89
|
+
PRESSURE = "pressure" # Presión atmosférica
|
|
90
|
+
PRECIPITATION = "precipitation" # Precipitación
|
|
91
|
+
PRECIPITATION_ACCUMULATED = "precipitation_accumulated" #Precipitación acumulada
|
|
92
|
+
PRECIPITATION_PROBABILITY = "precipitation_probability" #Precipitación probabilidad
|
|
93
|
+
SOLAR_GLOBAL_IRRADIANCE = "solar_global_irradiance" # Irradiación solar global
|
|
94
|
+
UV_INDEX = "uv_index" # UV
|
|
95
|
+
MAX_TEMPERATURE = "max_temperature" # Temperatura máxima
|
|
96
|
+
MIN_TEMPERATURE = "min_temperature" # Temperatura mínima
|
|
97
|
+
FEELS_LIKE = "feels_like" # Sensación térmica
|
|
98
|
+
WIND_GUST = "wind_gust" # Racha de viento
|
|
99
|
+
STATION_TIMESTAMP = "station_timestamp" # Código de tiempo de la estación
|
|
100
|
+
CONDITION = "condition" # Estado del cielo
|
|
101
|
+
MAX_TEMPERATURE_FORECAST = "max_temperature_forecast" # Temperatura máxima prevista
|
|
102
|
+
MIN_TEMPERATURE_FORECAST = "min_temperature_forecast" # Temperatura mínima prevista
|
|
103
|
+
LIGHTNING_REGION = "lightning_region" # Rayos de la comarca
|
|
104
|
+
LIGHTNING_TOWN = "lightning_town" # Rayos de la población
|
|
105
|
+
|
|
106
|
+
# Definición de códigos para variables
|
|
107
|
+
WIND_SPEED_CODE = 30
|
|
108
|
+
WIND_DIRECTION_CODE = 31
|
|
109
|
+
TEMPERATURE_CODE = 32
|
|
110
|
+
HUMIDITY_CODE = 33
|
|
111
|
+
PRESSURE_CODE = 34
|
|
112
|
+
PRECIPITATION_CODE = 35
|
|
113
|
+
SOLAR_GLOBAL_IRRADIANCE_CODE = 36
|
|
114
|
+
UV_INDEX_CODE = 39
|
|
115
|
+
MAX_TEMPERATURE_CODE = 40
|
|
116
|
+
MIN_TEMPERATURE_CODE = 42
|
|
117
|
+
WIND_GUST_CODE = 50
|
|
118
|
+
|
|
119
|
+
# Mapeo de códigos 'estatCel' a condiciones de Home Assistant
|
|
120
|
+
CONDITION_MAPPING = {
|
|
121
|
+
"sunny": [1],
|
|
122
|
+
# "clear-night": [1],
|
|
123
|
+
"partlycloudy": [2, 3],
|
|
124
|
+
"cloudy": [4, 20, 21, 22],
|
|
125
|
+
"rainy": [5, 6, 23],
|
|
126
|
+
"pouring": [7, 8, 25],
|
|
127
|
+
"lightning-rainy": [8, 24],
|
|
128
|
+
"hail": [9],
|
|
129
|
+
"snowy": [10, 26, 27, 28],
|
|
130
|
+
"fog": [11, 12],
|
|
131
|
+
"snow-rainy": [27, 29, 30],
|
|
132
|
+
}
|
|
@@ -1,58 +1,58 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import logging
|
|
4
|
-
from datetime import datetime
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
from homeassistant.core import HomeAssistant
|
|
7
|
-
from homeassistant.util import dt as dt_util
|
|
8
|
-
from solarmoonpy.location import Location
|
|
9
|
-
|
|
10
|
-
_LOGGER = logging.getLogger(__name__)
|
|
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
|
|
22
|
-
def get_sun_times(location: Location, current_time: datetime | None = None) -> tuple[datetime, datetime]:
|
|
23
|
-
"""Obtiene las horas de amanecer y atardecer para una ubicación usando solarmoonpy."""
|
|
24
|
-
now = dt_util.as_local(current_time or dt_util.now())
|
|
25
|
-
today = now.date()
|
|
26
|
-
sunrise = location.sunrise(date=today, local=True)
|
|
27
|
-
sunset = location.sunset(date=today, local=True)
|
|
28
|
-
|
|
29
|
-
if not sunrise or not sunset:
|
|
30
|
-
raise ValueError("No se pudieron calcular amanecer o atardecer.")
|
|
31
|
-
|
|
32
|
-
_LOGGER.debug(
|
|
33
|
-
"[solarmoonpy] Amanecer: %s, Atardecer: %s, Hora actual: %s",
|
|
34
|
-
sunrise, sunset, now
|
|
35
|
-
)
|
|
36
|
-
return sunrise, sunset
|
|
37
|
-
|
|
38
|
-
def is_night(current_time, location: Location) -> bool:
|
|
39
|
-
"""Determina si actualmente es de noche usando una instancia de Location."""
|
|
40
|
-
# Asegurarse de que current_time sea aware y en zona local
|
|
41
|
-
if current_time.tzinfo is None:
|
|
42
|
-
_LOGGER.warning("current_time sin zona horaria, asumiendo UTC")
|
|
43
|
-
current_time = dt_util.as_local(dt_util.utc_to_local(current_time))
|
|
44
|
-
else:
|
|
45
|
-
current_time = dt_util.as_local(current_time)
|
|
46
|
-
|
|
47
|
-
try:
|
|
48
|
-
sunrise, sunset = get_sun_times(location, current_time)
|
|
49
|
-
except Exception as e:
|
|
50
|
-
_LOGGER.warning("Fallo al calcular amanecer/atardecer con solarmoonpy: %s", e)
|
|
51
|
-
return False # fallback seguro
|
|
52
|
-
|
|
53
|
-
is_night_now = current_time < sunrise or current_time > sunset
|
|
54
|
-
_LOGGER.debug(
|
|
55
|
-
"[solarmoonpy] Hora actual: %s | Amanecer: %s | Atardecer: %s → Noche: %s",
|
|
56
|
-
current_time, sunrise, sunset, is_night_now
|
|
57
|
-
)
|
|
58
|
-
return is_night_now
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from homeassistant.core import HomeAssistant
|
|
7
|
+
from homeassistant.util import dt as dt_util
|
|
8
|
+
from solarmoonpy.location import Location
|
|
9
|
+
|
|
10
|
+
_LOGGER = logging.getLogger(__name__)
|
|
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
|
|
22
|
+
def get_sun_times(location: Location, current_time: datetime | None = None) -> tuple[datetime, datetime]:
|
|
23
|
+
"""Obtiene las horas de amanecer y atardecer para una ubicación usando solarmoonpy."""
|
|
24
|
+
now = dt_util.as_local(current_time or dt_util.now())
|
|
25
|
+
today = now.date()
|
|
26
|
+
sunrise = location.sunrise(date=today, local=True)
|
|
27
|
+
sunset = location.sunset(date=today, local=True)
|
|
28
|
+
|
|
29
|
+
if not sunrise or not sunset:
|
|
30
|
+
raise ValueError("No se pudieron calcular amanecer o atardecer.")
|
|
31
|
+
|
|
32
|
+
_LOGGER.debug(
|
|
33
|
+
"[solarmoonpy] Amanecer: %s, Atardecer: %s, Hora actual: %s",
|
|
34
|
+
sunrise, sunset, now
|
|
35
|
+
)
|
|
36
|
+
return sunrise, sunset
|
|
37
|
+
|
|
38
|
+
def is_night(current_time, location: Location) -> bool:
|
|
39
|
+
"""Determina si actualmente es de noche usando una instancia de Location."""
|
|
40
|
+
# Asegurarse de que current_time sea aware y en zona local
|
|
41
|
+
if current_time.tzinfo is None:
|
|
42
|
+
_LOGGER.warning("current_time sin zona horaria, asumiendo UTC")
|
|
43
|
+
current_time = dt_util.as_local(dt_util.utc_to_local(current_time))
|
|
44
|
+
else:
|
|
45
|
+
current_time = dt_util.as_local(current_time)
|
|
46
|
+
|
|
47
|
+
try:
|
|
48
|
+
sunrise, sunset = get_sun_times(location, current_time)
|
|
49
|
+
except Exception as e:
|
|
50
|
+
_LOGGER.warning("Fallo al calcular amanecer/atardecer con solarmoonpy: %s", e)
|
|
51
|
+
return False # fallback seguro
|
|
52
|
+
|
|
53
|
+
is_night_now = current_time < sunrise or current_time > sunset
|
|
54
|
+
_LOGGER.debug(
|
|
55
|
+
"[solarmoonpy] Hora actual: %s | Amanecer: %s | Atardecer: %s → Noche: %s",
|
|
56
|
+
current_time, sunrise, sunset, is_night_now
|
|
57
|
+
)
|
|
58
|
+
return is_night_now
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
{
|
|
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.2",
|
|
20
|
-
"solarmoonpy==1.0.8",
|
|
21
|
-
"packaging>=20.3",
|
|
22
|
-
"wrapt>=1.14.0"
|
|
23
|
-
],
|
|
24
|
-
"version": "
|
|
25
|
-
}
|
|
1
|
+
{
|
|
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.2",
|
|
20
|
+
"solarmoonpy==1.0.8",
|
|
21
|
+
"packaging>=20.3",
|
|
22
|
+
"wrapt>=1.14.0"
|
|
23
|
+
],
|
|
24
|
+
"version": "4.0.0"
|
|
25
|
+
}
|