meteocat 2.2.2 → 2.2.3

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.
@@ -39,6 +39,8 @@ from .const import (
39
39
  TOWN_ID,
40
40
  STATION_NAME,
41
41
  STATION_ID,
42
+ REGION_NAME,
43
+ REGION_ID,
42
44
  WIND_SPEED,
43
45
  WIND_DIRECTION,
44
46
  WIND_DIRECTION_CARDINAL,
@@ -76,6 +78,9 @@ from .const import (
76
78
  ALERT_WARM,
77
79
  ALERT_WARM_NIGHT,
78
80
  ALERT_SNOW,
81
+ LIGHTNING_FILE_STATUS,
82
+ LIGHTNING_REGION,
83
+ LIGHTNING_TOWN,
79
84
  WIND_SPEED_CODE,
80
85
  WIND_DIRECTION_CODE,
81
86
  TEMPERATURE_CODE,
@@ -97,6 +102,7 @@ from .const import (
97
102
  ALERT_VALIDITY_MULTIPLIER_200,
98
103
  ALERT_VALIDITY_MULTIPLIER_500,
99
104
  ALERT_VALIDITY_MULTIPLIER_DEFAULT,
105
+ DEFAULT_LIGHTNING_VALIDITY_TIME,
100
106
  )
101
107
 
102
108
  from .coordinator import (
@@ -112,6 +118,8 @@ from .coordinator import (
112
118
  MeteocatAlertsRegionCoordinator,
113
119
  MeteocatQuotesCoordinator,
114
120
  MeteocatQuotesFileCoordinator,
121
+ MeteocatLightningCoordinator,
122
+ MeteocatLightningFileCoordinator,
115
123
  )
116
124
 
117
125
  # Definir la zona horaria local
@@ -237,6 +245,16 @@ SENSOR_TYPES: tuple[MeteocatSensorEntityDescription, ...] = (
237
245
  state_class=SensorStateClass.MEASUREMENT,
238
246
  native_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
239
247
  ),
248
+ MeteocatSensorEntityDescription(
249
+ key=LIGHTNING_REGION,
250
+ translation_key="lightning_region",
251
+ icon="mdi:weather-lightning",
252
+ ),
253
+ MeteocatSensorEntityDescription(
254
+ key=LIGHTNING_TOWN,
255
+ translation_key="lightning_town",
256
+ icon="mdi:weather-lightning",
257
+ ),
240
258
  # Sensores estáticos
241
259
  MeteocatSensorEntityDescription(
242
260
  key=TOWN_NAME,
@@ -262,6 +280,18 @@ SENSOR_TYPES: tuple[MeteocatSensorEntityDescription, ...] = (
262
280
  icon="mdi:identifier",
263
281
  entity_category=EntityCategory.DIAGNOSTIC,
264
282
  ),
283
+ MeteocatSensorEntityDescription(
284
+ key=REGION_NAME,
285
+ translation_key="region_name",
286
+ icon="mdi:broadcast",
287
+ entity_category=EntityCategory.DIAGNOSTIC,
288
+ ),
289
+ MeteocatSensorEntityDescription(
290
+ key=REGION_ID,
291
+ translation_key="region_id",
292
+ icon="mdi:identifier",
293
+ entity_category=EntityCategory.DIAGNOSTIC,
294
+ ),
265
295
  MeteocatSensorEntityDescription(
266
296
  key=STATION_TIMESTAMP,
267
297
  translation_key="station_timestamp",
@@ -313,6 +343,12 @@ SENSOR_TYPES: tuple[MeteocatSensorEntityDescription, ...] = (
313
343
  icon="mdi:update",
314
344
  entity_category=EntityCategory.DIAGNOSTIC,
315
345
  ),
346
+ MeteocatSensorEntityDescription(
347
+ key=LIGHTNING_FILE_STATUS,
348
+ translation_key="lightning_file_status",
349
+ icon="mdi:update",
350
+ entity_category=EntityCategory.DIAGNOSTIC,
351
+ ),
316
352
  MeteocatSensorEntityDescription(
317
353
  key=ALERTS,
318
354
  translation_key="alerts",
@@ -414,6 +450,8 @@ async def async_setup_entry(hass, entry, async_add_entities: AddEntitiesCallback
414
450
  alerts_region_coordinator = entry_data.get("alerts_region_coordinator")
415
451
  quotes_coordinator = entry_data.get("quotes_coordinator")
416
452
  quotes_file_coordinator = entry_data.get("quotes_file_coordinator")
453
+ lightning_coordinator = entry_data.get("lightning_coordinator")
454
+ lightning_file_coordinator = entry_data.get("lightning_file_coordinator")
417
455
 
418
456
  # Sensores generales
419
457
  async_add_entities(
@@ -426,7 +464,7 @@ async def async_setup_entry(hass, entry, async_add_entities: AddEntitiesCallback
426
464
  async_add_entities(
427
465
  MeteocatStaticSensor(static_sensor_coordinator, description, entry_data)
428
466
  for description in SENSOR_TYPES
429
- if description.key in {TOWN_NAME, TOWN_ID, STATION_NAME, STATION_ID}
467
+ if description.key in {TOWN_NAME, TOWN_ID, STATION_NAME, STATION_ID, REGION_NAME, REGION_ID}
430
468
  )
431
469
 
432
470
  # Sensor UVI
@@ -513,6 +551,20 @@ async def async_setup_entry(hass, entry, async_add_entities: AddEntitiesCallback
513
551
  if description.key in {QUOTA_XDDE, QUOTA_PREDICCIO, QUOTA_BASIC, QUOTA_XEMA, QUOTA_QUERIES}
514
552
  )
515
553
 
554
+ # Sensores de estado de rayos
555
+ async_add_entities(
556
+ MeteocatLightningStatusSensor(lightning_coordinator, description, entry_data)
557
+ for description in SENSOR_TYPES
558
+ if description.key == LIGHTNING_FILE_STATUS
559
+ )
560
+
561
+ # Sensores de rayos en comarca y municipio
562
+ async_add_entities(
563
+ MeteocatLightningSensor(lightning_file_coordinator, description, entry_data)
564
+ for description in SENSOR_TYPES
565
+ if description.key in {LIGHTNING_REGION, LIGHTNING_TOWN}
566
+ )
567
+
516
568
  # Cambiar UTC a la zona horaria local
517
569
  def convert_to_local_time(utc_time: str, local_tz: str = "Europe/Madrid") -> datetime | None:
518
570
  """
@@ -538,7 +590,7 @@ def convert_to_local_time(utc_time: str, local_tz: str = "Europe/Madrid") -> dat
538
590
 
539
591
  class MeteocatStaticSensor(CoordinatorEntity[MeteocatStaticSensorCoordinator], SensorEntity):
540
592
  """Representation of a static Meteocat sensor."""
541
- STATIC_KEYS = {TOWN_NAME, TOWN_ID, STATION_NAME, STATION_ID}
593
+ STATIC_KEYS = {TOWN_NAME, TOWN_ID, STATION_NAME, STATION_ID, REGION_NAME, REGION_ID}
542
594
 
543
595
  _attr_has_entity_name = True # Activa el uso de nombres basados en el dispositivo
544
596
 
@@ -550,6 +602,8 @@ class MeteocatStaticSensor(CoordinatorEntity[MeteocatStaticSensorCoordinator], S
550
602
  self._town_id = entry_data["town_id"]
551
603
  self._station_name = entry_data["station_name"]
552
604
  self._station_id = entry_data["station_id"]
605
+ self._region_name = entry_data["region_name"]
606
+ self._region_id = entry_data["region_id"]
553
607
 
554
608
  # Unique ID for the entity
555
609
  self._attr_unique_id = f"sensor.{DOMAIN}_{self._station_id}_{self.entity_description.key}"
@@ -578,6 +632,10 @@ class MeteocatStaticSensor(CoordinatorEntity[MeteocatStaticSensorCoordinator], S
578
632
  return self._station_name
579
633
  if self.entity_description.key == STATION_ID:
580
634
  return self._station_id
635
+ if self.entity_description.key == REGION_NAME:
636
+ return self._region_name
637
+ if self.entity_description.key == REGION_ID:
638
+ return self._region_id
581
639
 
582
640
  @property
583
641
  def device_info(self) -> DeviceInfo:
@@ -1611,3 +1669,120 @@ class MeteocatQuotaSensor(CoordinatorEntity[MeteocatQuotesFileCoordinator], Sens
1611
1669
  manufacturer="Meteocat",
1612
1670
  model="Meteocat API",
1613
1671
  )
1672
+
1673
+ class MeteocatLightningStatusSensor(CoordinatorEntity[MeteocatLightningCoordinator], SensorEntity):
1674
+ _attr_has_entity_name = True # Activa el uso de nombres basados en el dispositivo
1675
+
1676
+ def __init__(self, lightning_coordinator, description, entry_data):
1677
+ super().__init__(lightning_coordinator)
1678
+ self.entity_description = description
1679
+ self._town_name = entry_data["town_name"]
1680
+ self._town_id = entry_data["town_id"]
1681
+ self._station_id = entry_data["station_id"]
1682
+
1683
+ # Unique ID for the entity
1684
+ self._attr_unique_id = f"sensor.{DOMAIN}_{self._town_id}_lightning_status"
1685
+
1686
+ # Assign entity_category if defined in the description
1687
+ self._attr_entity_category = getattr(description, "entity_category", None)
1688
+
1689
+ def _get_data_update(self):
1690
+ """Obtiene la fecha de actualización directamente desde el coordinador."""
1691
+ data_update = self.coordinator.data.get("actualizado")
1692
+ if data_update:
1693
+ try:
1694
+ return datetime.fromisoformat(data_update.rstrip("Z"))
1695
+ except ValueError:
1696
+ _LOGGER.error("Formato de fecha de actualización inválido: %s", data_update)
1697
+ return None
1698
+
1699
+ @property
1700
+ def native_value(self):
1701
+ """Devuelve el estado actual de las alertas basado en la fecha de actualización."""
1702
+ data_update = self._get_data_update()
1703
+ if not data_update:
1704
+ return "unknown"
1705
+
1706
+ current_time = datetime.now(ZoneInfo("UTC"))
1707
+
1708
+ # Comprobar si el archivo de alertas está obsoleto
1709
+ if current_time - data_update >= timedelta(minutes=DEFAULT_LIGHTNING_VALIDITY_TIME):
1710
+ return "obsolete"
1711
+
1712
+ return "updated"
1713
+
1714
+ @property
1715
+ def extra_state_attributes(self):
1716
+ """Devuelve los atributos adicionales del estado."""
1717
+ attributes = super().extra_state_attributes or {}
1718
+ data_update = self._get_data_update()
1719
+ if data_update:
1720
+ attributes["update_date"] = data_update.isoformat()
1721
+ return attributes
1722
+
1723
+ @property
1724
+ def device_info(self) -> DeviceInfo:
1725
+ """Devuelve la información del dispositivo."""
1726
+ return DeviceInfo(
1727
+ identifiers={(DOMAIN, self._town_id)},
1728
+ name=f"Meteocat {self._station_id} {self._town_name}",
1729
+ manufacturer="Meteocat",
1730
+ model="Meteocat API",
1731
+ )
1732
+
1733
+ class MeteocatLightningSensor(CoordinatorEntity[MeteocatLightningFileCoordinator], SensorEntity):
1734
+ """Representation of Meteocat Lightning sensors."""
1735
+
1736
+ _attr_has_entity_name = True # Activa el uso de nombres basados en el dispositivo
1737
+
1738
+ def __init__(self, lightning_file_coordinator, description, entry_data):
1739
+ super().__init__(lightning_file_coordinator)
1740
+ self.entity_description = description
1741
+ self._town_name = entry_data["town_name"]
1742
+ self._town_id = entry_data["town_id"]
1743
+ self._station_id = entry_data["station_id"]
1744
+ self._region_id = entry_data["region_id"]
1745
+
1746
+ # Unique ID for the entity
1747
+ self._attr_unique_id = f"sensor.{DOMAIN}_{self._town_id}_{self.entity_description.key}"
1748
+
1749
+ # Assign entity_category if defined in the description
1750
+ self._attr_entity_category = getattr(description, "entity_category", None)
1751
+
1752
+ @property
1753
+ def native_value(self):
1754
+ """Return the total number of lightning strikes."""
1755
+ if self.entity_description.key == LIGHTNING_REGION:
1756
+ return self.coordinator.data.get("region", {}).get("total", 0)
1757
+ elif self.entity_description.key == LIGHTNING_TOWN:
1758
+ return self.coordinator.data.get("town", {}).get("total", 0)
1759
+ return None
1760
+
1761
+ @property
1762
+ def extra_state_attributes(self):
1763
+ """Return additional attributes for the sensor."""
1764
+ attributes = super().extra_state_attributes or {}
1765
+ if self.entity_description.key == LIGHTNING_REGION:
1766
+ data = self.coordinator.data.get("region", {})
1767
+ elif self.entity_description.key == LIGHTNING_TOWN:
1768
+ data = self.coordinator.data.get("town", {})
1769
+ else:
1770
+ return attributes
1771
+
1772
+ # Agregar atributos específicos
1773
+ attributes.update({
1774
+ "cloud_cloud": data.get("cc", 0),
1775
+ "cloud_ground_neg": data.get("cg-", 0),
1776
+ "cloud_ground_pos": data.get("cg+", 0),
1777
+ })
1778
+ return attributes
1779
+
1780
+ @property
1781
+ def device_info(self) -> DeviceInfo:
1782
+ """Return the device info."""
1783
+ return DeviceInfo(
1784
+ identifiers={(DOMAIN, self._town_id)},
1785
+ name=f"Meteocat {self._station_id} {self._town_name}",
1786
+ manufacturer="Meteocat",
1787
+ model="Meteocat API",
1788
+ )
@@ -151,6 +151,12 @@
151
151
  "station_timestamp": {
152
152
  "name": "Station Timestamp"
153
153
  },
154
+ "region_name": {
155
+ "name": "Region Name"
156
+ },
157
+ "region_id": {
158
+ "name": "Region ID"
159
+ },
154
160
  "condition": {
155
161
  "name": "Condition",
156
162
  "state": {
@@ -237,6 +243,46 @@
237
243
  }
238
244
  }
239
245
  },
246
+ "lightning_file_status": {
247
+ "name": "Lightning File",
248
+ "state": {
249
+ "updated": "Updated",
250
+ "obsolete": "Obsolete"
251
+ },
252
+ "state_attributes": {
253
+ "update_date": {
254
+ "name": "Date"
255
+ }
256
+ }
257
+ },
258
+ "lightning_region": {
259
+ "name": "Lightning Region",
260
+ "state_attributes": {
261
+ "cloud_cloud": {
262
+ "name": "Cloud-Cloud"
263
+ },
264
+ "cloud_ground_neg":{
265
+ "name": "Cloud-Ground Negative"
266
+ },
267
+ "cloud_ground_pos": {
268
+ "name": "Cloud-Ground Positive"
269
+ }
270
+ }
271
+ },
272
+ "lightning_town": {
273
+ "name": "Lightning Town",
274
+ "state_attributes": {
275
+ "cloud_cloud": {
276
+ "name": "Cloud-Cloud"
277
+ },
278
+ "cloud_ground_neg":{
279
+ "name": "Cloud-Ground Negative"
280
+ },
281
+ "cloud_ground_pos": {
282
+ "name": "Cloud-Ground Positive"
283
+ }
284
+ }
285
+ },
240
286
  "quota_xdde": {
241
287
  "name": "Quota XDDE",
242
288
  "state": {
@@ -151,6 +151,12 @@
151
151
  "station_timestamp": {
152
152
  "name": "Estació Timestamp"
153
153
  },
154
+ "region_name": {
155
+ "name": "Comarca Nom"
156
+ },
157
+ "region_id": {
158
+ "name": "Comarca ID"
159
+ },
154
160
  "condition": {
155
161
  "name": "Estat del Cel",
156
162
  "state": {
@@ -237,6 +243,46 @@
237
243
  }
238
244
  }
239
245
  },
246
+ "lightning_file_status": {
247
+ "name": "Arxiu Llamps",
248
+ "state": {
249
+ "updated": "Actualitzat",
250
+ "obsolete": "Obsolet"
251
+ },
252
+ "state_attributes": {
253
+ "update_date": {
254
+ "name": "Data"
255
+ }
256
+ }
257
+ },
258
+ "lightning_region": {
259
+ "name": "Llamps Comarca",
260
+ "state_attributes": {
261
+ "cloud_cloud": {
262
+ "name": "Núvol-Núvol"
263
+ },
264
+ "cloud_ground_neg":{
265
+ "name": "Núvol-Terra Negatiu"
266
+ },
267
+ "cloud_ground_pos": {
268
+ "name": "Núvol-Terra Positiu"
269
+ }
270
+ }
271
+ },
272
+ "lightning_town": {
273
+ "name": "Llamps Municipi",
274
+ "state_attributes": {
275
+ "cloud_cloud": {
276
+ "name": "Núvol-Núvol"
277
+ },
278
+ "cloud_ground_neg":{
279
+ "name": "Núvol-Terra Negatiu"
280
+ },
281
+ "cloud_ground_pos": {
282
+ "name": "Núvol-Terra Positiu"
283
+ }
284
+ }
285
+ },
240
286
  "quota_xdde": {
241
287
  "name": "Quota XDDE",
242
288
  "state": {
@@ -151,6 +151,12 @@
151
151
  "station_timestamp": {
152
152
  "name": "Station Timestamp"
153
153
  },
154
+ "region_name": {
155
+ "name": "Region Name"
156
+ },
157
+ "region_id": {
158
+ "name": "Region ID"
159
+ },
154
160
  "condition": {
155
161
  "name": "Condition",
156
162
  "state": {
@@ -237,6 +243,46 @@
237
243
  }
238
244
  }
239
245
  },
246
+ "lightning_file_status": {
247
+ "name": "Lightning File",
248
+ "state": {
249
+ "updated": "Updated",
250
+ "obsolete": "Obsolete"
251
+ },
252
+ "state_attributes": {
253
+ "update_date": {
254
+ "name": "Date"
255
+ }
256
+ }
257
+ },
258
+ "lightning_region": {
259
+ "name": "Lightning Region",
260
+ "state_attributes": {
261
+ "cloud_cloud": {
262
+ "name": "Cloud-Cloud"
263
+ },
264
+ "cloud_ground_neg":{
265
+ "name": "Cloud-Ground Negative"
266
+ },
267
+ "cloud_ground_pos": {
268
+ "name": "Cloud-Ground Positive"
269
+ }
270
+ }
271
+ },
272
+ "lightning_town": {
273
+ "name": "Lightning Town",
274
+ "state_attributes": {
275
+ "cloud_cloud": {
276
+ "name": "Cloud-Cloud"
277
+ },
278
+ "cloud_ground_neg":{
279
+ "name": "Cloud-Ground Negative"
280
+ },
281
+ "cloud_ground_pos": {
282
+ "name": "Cloud-Ground Positive"
283
+ }
284
+ }
285
+ },
240
286
  "quota_xdde": {
241
287
  "name": "Quota XDDE",
242
288
  "state": {
@@ -151,6 +151,12 @@
151
151
  "station_timestamp": {
152
152
  "name": "Estación Timestamp"
153
153
  },
154
+ "region_name": {
155
+ "name": "Comarca Nombre"
156
+ },
157
+ "region_id": {
158
+ "name": "Comarca ID"
159
+ },
154
160
  "condition": {
155
161
  "name": "Estado del cielo",
156
162
  "state": {
@@ -237,6 +243,46 @@
237
243
  }
238
244
  }
239
245
  },
246
+ "lightning_file_status": {
247
+ "name": "Archivo Rayos",
248
+ "state": {
249
+ "updated": "Actualizado",
250
+ "obsolete": "Obsoleto"
251
+ },
252
+ "state_attributes": {
253
+ "update_date": {
254
+ "name": "Fecha"
255
+ }
256
+ }
257
+ },
258
+ "lightning_region": {
259
+ "name": "Rayos Comarca",
260
+ "state_attributes": {
261
+ "cloud_cloud": {
262
+ "name": "Nube-Nube"
263
+ },
264
+ "cloud_ground_neg":{
265
+ "name": "Nube-Tierra Negativo"
266
+ },
267
+ "cloud_ground_pos": {
268
+ "name": "Nube-Tierra Positivo"
269
+ }
270
+ }
271
+ },
272
+ "lightning_town": {
273
+ "name": "Rayos Municipio",
274
+ "state_attributes": {
275
+ "cloud_cloud": {
276
+ "name": "Nube-Nube"
277
+ },
278
+ "cloud_ground_neg":{
279
+ "name": "Nube-Tierra Negativo"
280
+ },
281
+ "cloud_ground_pos": {
282
+ "name": "Nube-Tierra Positivo"
283
+ }
284
+ }
285
+ },
240
286
  "quota_xdde": {
241
287
  "name": "Cuota XDDE",
242
288
  "state": {
@@ -1,2 +1,2 @@
1
1
  # version.py
2
- __version__ = "2.2.2"
2
+ __version__ = "2.2.3"
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "meteocat",
3
- "version": "2.2.2",
3
+ "version": "2.2.3",
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": {