meteocat 0.1.43 → 0.1.45

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 CHANGED
@@ -1,3 +1,24 @@
1
+ ## [0.1.45](https://github.com/figorr/meteocat/compare/v0.1.44...v0.1.45) (2024-12-31)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * 0.1.45 ([ab522cf](https://github.com/figorr/meteocat/commit/ab522cf4d94687c64dc84480f8f5507645a79557))
7
+ * change icon for status sensors ([7415646](https://github.com/figorr/meteocat/commit/741564698b09b6e29b774bb388b6c96f718a573a))
8
+ * fix async_add_entities for generic dynamic sensors ([2192214](https://github.com/figorr/meteocat/commit/2192214ebb767e74c187df98e7c811225c21ca33))
9
+ * fix name and comments for Temp Forecast Coordinator ([e65e476](https://github.com/figorr/meteocat/commit/e65e476f03b0de062ab14a9563eaa71b6d80301f))
10
+ * fix name sensor coordinator ([e93d01f](https://github.com/figorr/meteocat/commit/e93d01f359158ee63494e697059550fcea37806f))
11
+
12
+ ## [0.1.44](https://github.com/figorr/meteocat/compare/v0.1.43...v0.1.44) (2024-12-30)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * 0.1.44 ([7a506ea](https://github.com/figorr/meteocat/commit/7a506eab7e1fa1c0975561d71520ec3e146019dd))
18
+ * add date attribute for status sensors ([5663be5](https://github.com/figorr/meteocat/commit/5663be50ba007debe349aa730a7e735f8d448a8b))
19
+ * add state translations for file status ([32bcd61](https://github.com/figorr/meteocat/commit/32bcd611cddf773046ee07043a8578a6cbc52f94))
20
+ * add translations for status sensors date attribute ([9504a58](https://github.com/figorr/meteocat/commit/9504a5809fbc83ed2bba0b507354260d6606b7c5))
21
+
1
22
  ## [0.1.43](https://github.com/figorr/meteocat/compare/v0.1.42...v0.1.43) (2024-12-30)
2
23
 
3
24
 
@@ -25,7 +25,7 @@ from .const import DOMAIN, PLATFORMS
25
25
  _LOGGER = logging.getLogger(__name__)
26
26
 
27
27
  # Versión
28
- __version__ = "0.1.43"
28
+ __version__ = "0.1.45"
29
29
 
30
30
  def safe_remove(path: Path, is_folder: bool = False):
31
31
  """Elimina de forma segura un archivo o carpeta si existe."""
@@ -940,14 +940,14 @@ class MeteocatConditionCoordinator(DataUpdateCoordinator):
940
940
  return {"condition": "unknown", "hour": current_hour, "icon": None, "date": current_date}
941
941
 
942
942
  class MeteocatTempForecastCoordinator(DataUpdateCoordinator):
943
- """Coordinator para manejar las predicciones diarias desde archivos locales."""
943
+ """Coordinator para manejar la temperatura máxima y mínima de las predicciones diarias desde archivos locales."""
944
944
 
945
945
  def __init__(
946
946
  self,
947
947
  hass: HomeAssistant,
948
948
  entry_data: dict,
949
949
  ):
950
- """Inicializa el coordinador para predicciones diarias."""
950
+ """Inicializa el coordinador para las temperaturas máximas y mínimas de predicciones diarias."""
951
951
  self.town_name = entry_data["town_name"]
952
952
  self.town_id = entry_data["town_id"]
953
953
  self.station_name = entry_data["station_name"]
@@ -962,7 +962,7 @@ class MeteocatTempForecastCoordinator(DataUpdateCoordinator):
962
962
  super().__init__(
963
963
  hass,
964
964
  _LOGGER,
965
- name=f"{DOMAIN} Daily Forecast Coordinator",
965
+ name=f"{DOMAIN} Daily Temperature Forecast Coordinator",
966
966
  update_interval=DEFAULT_TEMP_FORECAST_UPDATE_INTERVAL,
967
967
  )
968
968
 
@@ -1005,18 +1005,18 @@ class MeteocatTempForecastCoordinator(DataUpdateCoordinator):
1005
1005
  if datetime.fromisoformat(dia["data"].rstrip("Z")).date() >= today
1006
1006
  ]
1007
1007
 
1008
- # Usar datos del día actual si están disponibles
1008
+ # Usar datos de temperatura del día actual si están disponibles
1009
1009
  today_temp_forecast = self.get_temp_forecast_for_today(data)
1010
1010
  if today_temp_forecast:
1011
1011
  parsed_data = self.parse_temp_forecast(today_temp_forecast)
1012
1012
  return parsed_data
1013
1013
  except Exception as e:
1014
- _LOGGER.warning("Error leyendo archivo de predicción diaria: %s", e)
1014
+ _LOGGER.warning("Error leyendo temperaturas del archivo de predicción diaria: %s", e)
1015
1015
 
1016
1016
  return {}
1017
1017
 
1018
1018
  def get_temp_forecast_for_today(self, data: dict) -> dict | None:
1019
- """Obtiene los datos diarios para el día actual."""
1019
+ """Obtiene los datos de temperaturas diarios para el día actual."""
1020
1020
  if not data or "dies" not in data or not data["dies"]:
1021
1021
  return None
1022
1022
 
@@ -1028,7 +1028,7 @@ class MeteocatTempForecastCoordinator(DataUpdateCoordinator):
1028
1028
  return None
1029
1029
 
1030
1030
  def parse_temp_forecast(self, dia: dict) -> dict:
1031
- """Convierte un día de predicción en un diccionario con los datos necesarios."""
1031
+ """Convierte la temperatura de un día de predicción en un diccionario con los datos necesarios."""
1032
1032
  variables = dia.get("variables", {})
1033
1033
 
1034
1034
  temp_forecast_data = {
@@ -8,5 +8,5 @@
8
8
  "documentation": "https://gitlab.com/figorr/meteocat",
9
9
  "loggers": ["meteocatpy"],
10
10
  "requirements": ["meteocatpy==0.0.17", "packaging>=20.3", "wrapt>=1.14.0"],
11
- "version": "0.1.43"
11
+ "version": "0.1.45"
12
12
  }
@@ -237,19 +237,19 @@ SENSOR_TYPES: tuple[MeteocatSensorEntityDescription, ...] = (
237
237
  MeteocatSensorEntityDescription(
238
238
  key=HOURLY_FORECAST_FILE_STATUS,
239
239
  translation_key="hourly_forecast_file_status",
240
- icon="mdi:clock",
240
+ icon="mdi:update",
241
241
  entity_category=EntityCategory.DIAGNOSTIC,
242
242
  ),
243
243
  MeteocatSensorEntityDescription(
244
244
  key=DAILY_FORECAST_FILE_STATUS,
245
245
  translation_key="daily_forecast_file_status",
246
- icon="mdi:clock",
246
+ icon="mdi:update",
247
247
  entity_category=EntityCategory.DIAGNOSTIC,
248
248
  ),
249
249
  MeteocatSensorEntityDescription(
250
250
  key=UVI_FILE_STATUS,
251
251
  translation_key="uvi_file_status",
252
- icon="mdi:clock",
252
+ icon="mdi:update",
253
253
  entity_category=EntityCategory.DIAGNOSTIC,
254
254
  )
255
255
  )
@@ -260,7 +260,7 @@ async def async_setup_entry(hass, entry, async_add_entities: AddEntitiesCallback
260
260
  entry_data = hass.data[DOMAIN][entry.entry_id]
261
261
 
262
262
  # Coordinadores para sensores
263
- coordinator = entry_data.get("sensor_coordinator")
263
+ sensor_coordinator = entry_data.get("sensor_coordinator")
264
264
  uvi_file_coordinator = entry_data.get("uvi_file_coordinator")
265
265
  static_sensor_coordinator = entry_data.get("static_sensor_coordinator")
266
266
  condition_coordinator = entry_data.get("condition_coordinator")
@@ -270,9 +270,9 @@ async def async_setup_entry(hass, entry, async_add_entities: AddEntitiesCallback
270
270
 
271
271
  # Sensores generales
272
272
  async_add_entities(
273
- MeteocatSensor(coordinator, description, entry_data)
273
+ MeteocatSensor(sensor_coordinator, description, entry_data)
274
274
  for description in SENSOR_TYPES
275
- if description.key not in {TOWN_NAME, TOWN_ID, STATION_NAME, STATION_ID, UV_INDEX, CONDITION, MAX_TEMPERATURE_FORECAST, MIN_TEMPERATURE_FORECAST, HOURLY_FORECAST_FILE_STATUS, DAILY_FORECAST_FILE_STATUS, UVI_FILE_STATUS} # Excluir estáticos y UVI
275
+ if description.key in {WIND_SPEED, WIND_DIRECTION, TEMPERATURE, HUMIDITY, PRESSURE, PRECIPITATION, PRECIPITATION_ACCUMULATED, SOLAR_GLOBAL_IRRADIANCE, MAX_TEMPERATURE, MIN_TEMPERATURE, FEELS_LIKE, WIND_GUST, STATION_TIMESTAMP} # Incluir sensores generales en el coordinador SENSOR COORDINATOR
276
276
  )
277
277
 
278
278
  # Sensores estáticos
@@ -502,9 +502,9 @@ class MeteocatSensor(CoordinatorEntity[MeteocatSensorCoordinator], SensorEntity)
502
502
 
503
503
  _attr_has_entity_name = True # Activa el uso de nombres basados en el dispositivo
504
504
 
505
- def __init__(self, coordinator, description, entry_data):
505
+ def __init__(self, sensor_coordinator, description, entry_data):
506
506
  """Initialize the sensor."""
507
- super().__init__(coordinator)
507
+ super().__init__(sensor_coordinator)
508
508
  self.entity_description = description
509
509
  self.api_key = entry_data["api_key"]
510
510
  self._town_name = entry_data["town_name"]
@@ -782,16 +782,29 @@ class MeteocatHourlyForecastStatusSensor(CoordinatorEntity[MeteocatEntityCoordin
782
782
  # Assign entity_category if defined in the description
783
783
  self._attr_entity_category = getattr(description, "entity_category", None)
784
784
 
785
- @property
786
- def native_value(self):
785
+ def _get_first_date(self):
787
786
  hourly_data = self.coordinator.data.get("hourly")
788
787
  if hourly_data and "dies" in hourly_data:
789
- first_date = datetime.fromisoformat(hourly_data["dies"][0]["data"].rstrip("Z")).date()
788
+ return datetime.fromisoformat(hourly_data["dies"][0]["data"].rstrip("Z")).date()
789
+ return None
790
+
791
+ @property
792
+ def native_value(self):
793
+ first_date = self._get_first_date()
794
+ if first_date:
790
795
  today = datetime.now(timezone.utc).date()
791
796
  days_difference = (today - first_date).days
792
797
  _LOGGER.debug(f"Diferencia de días para predicciones horarias: {days_difference}")
793
798
  return "updated" if days_difference <= 1 else "obsolete"
794
799
  return "unknown"
800
+
801
+ @property
802
+ def extra_state_attributes(self):
803
+ attributes = super().extra_state_attributes or {}
804
+ first_date = self._get_first_date()
805
+ if first_date:
806
+ attributes["update_date"] = first_date.isoformat()
807
+ return attributes
795
808
 
796
809
  @property
797
810
  def device_info(self) -> DeviceInfo:
@@ -820,16 +833,29 @@ class MeteocatDailyForecastStatusSensor(CoordinatorEntity[MeteocatEntityCoordina
820
833
  # Assign entity_category if defined in the description
821
834
  self._attr_entity_category = getattr(description, "entity_category", None)
822
835
 
823
- @property
824
- def native_value(self):
836
+ def _get_first_date(self):
825
837
  daily_data = self.coordinator.data.get("daily")
826
838
  if daily_data and "dies" in daily_data:
827
- first_date = datetime.fromisoformat(daily_data["dies"][0]["data"].rstrip("Z")).date()
839
+ return datetime.fromisoformat(daily_data["dies"][0]["data"].rstrip("Z")).date()
840
+ return None
841
+
842
+ @property
843
+ def native_value(self):
844
+ first_date = self._get_first_date()
845
+ if first_date:
828
846
  today = datetime.now(timezone.utc).date()
829
847
  days_difference = (today - first_date).days
830
848
  _LOGGER.debug(f"Diferencia de días para predicciones diarias: {days_difference}")
831
849
  return "updated" if days_difference <= 1 else "obsolete"
832
850
  return "unknown"
851
+
852
+ @property
853
+ def extra_state_attributes(self):
854
+ attributes = super().extra_state_attributes or {}
855
+ first_date = self._get_first_date()
856
+ if first_date:
857
+ attributes["update_date"] = first_date.isoformat()
858
+ return attributes
833
859
 
834
860
  @property
835
861
  def device_info(self) -> DeviceInfo:
@@ -858,15 +884,28 @@ class MeteocatUviStatusSensor(CoordinatorEntity[MeteocatUviCoordinator], SensorE
858
884
  # Assign entity_category if defined in the description
859
885
  self._attr_entity_category = getattr(description, "entity_category", None)
860
886
 
887
+ def _get_first_date(self):
888
+ if self.coordinator.data:
889
+ return datetime.strptime(self.coordinator.data[0].get("date"), "%Y-%m-%d").date()
890
+ return None
891
+
861
892
  @property
862
893
  def native_value(self):
863
- if self.coordinator.data:
864
- first_date = datetime.strptime(self.coordinator.data[0].get("date"), "%Y-%m-%d").date()
894
+ first_date = self._get_first_date()
895
+ if first_date:
865
896
  today = datetime.now(timezone.utc).date()
866
897
  days_difference = (today - first_date).days
867
898
  _LOGGER.debug(f"Diferencia de días para UVI: {days_difference}")
868
899
  return "updated" if days_difference <= 1 else "obsolete"
869
900
  return "unknown"
901
+
902
+ @property
903
+ def extra_state_attributes(self):
904
+ attributes = super().extra_state_attributes or {}
905
+ first_date = self._get_first_date()
906
+ if first_date:
907
+ attributes["update_date"] = first_date.isoformat()
908
+ return attributes
870
909
 
871
910
  @property
872
911
  def device_info(self) -> DeviceInfo:
@@ -135,13 +135,40 @@
135
135
  "name": "Min Temperature Today"
136
136
  },
137
137
  "hourly_forecast_file_status": {
138
- "name": "Hourly File"
138
+ "name": "Hourly File",
139
+ "state": {
140
+ "updated": "Updated",
141
+ "obsolete": "Obsolete"
142
+ },
143
+ "state_attributes": {
144
+ "update_date": {
145
+ "name": "Date"
146
+ }
147
+ }
139
148
  },
140
149
  "daily_forecast_file_status": {
141
- "name": "Daily File"
150
+ "name": "Daily File",
151
+ "state": {
152
+ "updated": "Updated",
153
+ "obsolete": "Obsolete"
154
+ },
155
+ "state_attributes": {
156
+ "update_date": {
157
+ "name": "Date"
158
+ }
159
+ }
142
160
  },
143
161
  "uvi_file_status": {
144
- "name": "Uvi File"
162
+ "name": "Uvi File",
163
+ "state": {
164
+ "updated": "Updated",
165
+ "obsolete": "Obsolete"
166
+ },
167
+ "state_attributes": {
168
+ "update_date": {
169
+ "name": "Date"
170
+ }
171
+ }
145
172
  }
146
173
  }
147
174
  }
@@ -135,13 +135,40 @@
135
135
  "name": "Temperatura Min Avui"
136
136
  },
137
137
  "hourly_forecast_file_status": {
138
- "name": "Arxiu Horari"
138
+ "name": "Arxiu Horari",
139
+ "state": {
140
+ "updated": "Actualitzat",
141
+ "obsolete": "Obsolet"
142
+ },
143
+ "state_attributes": {
144
+ "update_date": {
145
+ "name": "Data"
146
+ }
147
+ }
139
148
  },
140
149
  "daily_forecast_file_status": {
141
- "name": "Arxiu Diari"
150
+ "name": "Arxiu Diari",
151
+ "state": {
152
+ "updated": "Actualitzat",
153
+ "obsolete": "Obsolet"
154
+ },
155
+ "state_attributes": {
156
+ "update_date": {
157
+ "name": "Data"
158
+ }
159
+ }
142
160
  },
143
161
  "uvi_file_status": {
144
- "name": "Arxiu UVI"
162
+ "name": "Arxiu UVI",
163
+ "state": {
164
+ "updated": "Actualitzat",
165
+ "obsolete": "Obsolet"
166
+ },
167
+ "state_attributes": {
168
+ "update_date": {
169
+ "name": "Data"
170
+ }
171
+ }
145
172
  }
146
173
  }
147
174
  }
@@ -135,13 +135,40 @@
135
135
  "name": "Min Temperature Today"
136
136
  },
137
137
  "hourly_forecast_file_status": {
138
- "name": "Hourly File"
138
+ "name": "Hourly File",
139
+ "state": {
140
+ "updated": "Updated",
141
+ "obsolete": "Obsolete"
142
+ },
143
+ "state_attributes": {
144
+ "update_date": {
145
+ "name": "Date"
146
+ }
147
+ }
139
148
  },
140
149
  "daily_forecast_file_status": {
141
- "name": "Daily File"
150
+ "name": "Daily File",
151
+ "state": {
152
+ "updated": "Updated",
153
+ "obsolete": "Obsolete"
154
+ },
155
+ "state_attributes": {
156
+ "update_date": {
157
+ "name": "Date"
158
+ }
159
+ }
142
160
  },
143
161
  "uvi_file_status": {
144
- "name": "Uvi File"
162
+ "name": "Uvi File",
163
+ "state": {
164
+ "updated": "Updated",
165
+ "obsolete": "Obsolete"
166
+ },
167
+ "state_attributes": {
168
+ "update_date": {
169
+ "name": "Date"
170
+ }
171
+ }
145
172
  }
146
173
  }
147
174
  }
@@ -135,15 +135,41 @@
135
135
  "name": "Temperatura Min Hoy"
136
136
  },
137
137
  "hourly_forecast_file_status": {
138
- "name": "Archivo Horario"
138
+ "name": "Archivo Horario",
139
+ "state": {
140
+ "updated": "Actualizado",
141
+ "obsolete": "Obsoleto"
142
+ },
143
+ "state_attributes": {
144
+ "update_date": {
145
+ "name": "Fecha"
146
+ }
147
+ }
139
148
  },
140
149
  "daily_forecast_file_status": {
141
- "name": "Archivo Diario"
150
+ "name": "Archivo Diario",
151
+ "state": {
152
+ "updated": "Actualizado",
153
+ "obsolete": "Obsoleto"
154
+ },
155
+ "state_attributes": {
156
+ "update_date": {
157
+ "name": "Fecha"
158
+ }
159
+ }
142
160
  },
143
161
  "uvi_file_status": {
144
- "name": "Archivo UVI"
162
+ "name": "Archivo UVI",
163
+ "state": {
164
+ "updated": "Actualizado",
165
+ "obsolete": "Obsoleto"
166
+ },
167
+ "state_attributes": {
168
+ "update_date": {
169
+ "name": "Fecha"
170
+ }
171
+ }
145
172
  }
146
173
  }
147
174
  }
148
175
  }
149
-
@@ -1,2 +1,2 @@
1
1
  # version.py
2
- __version__ = "0.1.43"
2
+ __version__ = "0.1.45"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "meteocat",
3
- "version": "0.1.43",
3
+ "version": "0.1.45",
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 = "0.1.43"
3
+ version = "0.1.45"
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"