sensor.py 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. """Sensor platform for knmi."""
  2. from collections.abc import Callable
  3. from dataclasses import dataclass
  4. from datetime import datetime
  5. from typing import Any
  6. from homeassistant.components.sensor import (
  7. SensorDeviceClass,
  8. SensorEntity,
  9. SensorEntityDescription,
  10. SensorStateClass,
  11. )
  12. from homeassistant.config_entries import ConfigEntry
  13. from homeassistant.const import (
  14. CONF_NAME,
  15. PERCENTAGE,
  16. UnitOfSoundPressure,
  17. UnitOfDataRate
  18. )
  19. from homeassistant.core import HomeAssistant
  20. from homeassistant.helpers.entity import EntityCategory
  21. from homeassistant.helpers.entity_platform import AddEntitiesCallback
  22. from homeassistant.helpers.typing import StateType
  23. from homeassistant.helpers.update_coordinator import CoordinatorEntity
  24. from .const import (DOMAIN,
  25. EP_CELLINFO,
  26. EP_DEVICESTATUS,
  27. EP_LANINFO,
  28. EP_TRAFFIC,
  29. EP_COMMON)
  30. from .coordinator import RouterCoordinator
  31. @dataclass(kw_only=True, frozen=True)
  32. class RouterSensorDescription(SensorEntityDescription):
  33. """Class describing Router sensor entities."""
  34. value_fn: Callable[[dict[str, Any]], StateType | datetime | None]
  35. attr_fn: Callable[[dict[str, Any]], dict[str, Any]] = lambda _: {}
  36. DESCRIPTIONS: list[RouterSensorDescription] = [
  37. RouterSensorDescription(
  38. key='rssi',
  39. icon='mdi:wifi-check',
  40. value_fn=lambda coordinator: coordinator.get_value(EP_CELLINFO, ["CellIntfInfo", "RSSI"]),
  41. native_unit_of_measurement=UnitOfSoundPressure.WEIGHTED_DECIBEL_A,
  42. device_class=SensorDeviceClass.SOUND_PRESSURE,
  43. state_class=SensorStateClass.MEASUREMENT,
  44. translation_key='rssi',
  45. entity_registry_enabled_default=True,
  46. ),
  47. RouterSensorDescription(
  48. key='rsrq',
  49. icon='mdi:wifi-arrow-up-down',
  50. value_fn=lambda coordinator: coordinator.get_value(EP_CELLINFO, ["CellIntfInfo", "X_ZYXEL_RSRQ"]),
  51. native_unit_of_measurement=UnitOfSoundPressure.DECIBEL,
  52. device_class=SensorDeviceClass.SOUND_PRESSURE,
  53. state_class=SensorStateClass.MEASUREMENT,
  54. translation_key='rsrq',
  55. entity_registry_enabled_default=False
  56. ),
  57. RouterSensorDescription(
  58. key='rsrp',
  59. icon='mdi:wifi-arrow-down',
  60. value_fn=lambda coordinator: coordinator.get_value(EP_CELLINFO, ["CellIntfInfo", "X_ZYXEL_RSRP"]),
  61. native_unit_of_measurement=UnitOfSoundPressure.WEIGHTED_DECIBEL_A,
  62. device_class=SensorDeviceClass.SOUND_PRESSURE,
  63. state_class=SensorStateClass.MEASUREMENT,
  64. translation_key='rsrp',
  65. entity_registry_enabled_default=False
  66. ),
  67. RouterSensorDescription(
  68. key='sinr',
  69. icon='mdi:wifi-alert',
  70. value_fn=lambda coordinator: coordinator.get_value(EP_CELLINFO, ["CellIntfInfo", "X_ZYXEL_SINR"]),
  71. state_class=SensorStateClass.MEASUREMENT,
  72. translation_key='sinr',
  73. entity_registry_enabled_default=False
  74. ),
  75. RouterSensorDescription(
  76. key='network_technology',
  77. icon='mdi:radio-tower',
  78. value_fn=lambda coordinator: coordinator.get_value(EP_CELLINFO, ["CellIntfInfo", "CurrentAccessTechnology"]),
  79. translation_key='network_technology',
  80. entity_registry_enabled_default=True
  81. ),
  82. RouterSensorDescription(
  83. key='network_band',
  84. icon='mdi:signal-5g',
  85. value_fn=lambda coordinator: coordinator.get_value(EP_CELLINFO, ["CellIntfInfo", "X_ZYXEL_CurrentBand"]),
  86. translation_key='network_band',
  87. entity_registry_enabled_default=False,
  88. ),
  89. RouterSensorDescription(
  90. key='wan_downloaded',
  91. icon='mdi:cloud-download',
  92. value_fn=lambda coordinator: coordinator.get_value(EP_TRAFFIC, ['ipIfaceSt', 1, 'BytesReceived']) \
  93. + coordinator.get_value(EP_TRAFFIC, ['ipIfaceSt', 2, 'BytesReceived']),
  94. native_unit_of_measurement='B',
  95. suggested_unit_of_measurement='GB',
  96. device_class=SensorDeviceClass.DATA_SIZE,
  97. state_class=SensorStateClass.TOTAL,
  98. translation_key='wan_downloaded',
  99. entity_registry_enabled_default=False
  100. ),
  101. RouterSensorDescription(
  102. key='wan_uploaded',
  103. icon='mdi:cloud-upload',
  104. value_fn=lambda coordinator: coordinator.get_value(EP_TRAFFIC, ['ipIfaceSt', 1, 'BytesSent']) \
  105. + coordinator.get_value(EP_TRAFFIC, ['ipIfaceSt', 2, 'BytesSent']),
  106. native_unit_of_measurement='B',
  107. suggested_unit_of_measurement='GB',
  108. device_class=SensorDeviceClass.DATA_SIZE,
  109. state_class=SensorStateClass.TOTAL,
  110. translation_key='wan_uploaded',
  111. entity_registry_enabled_default=False,
  112. ),
  113. RouterSensorDescription(
  114. key='lan1_downloaded',
  115. icon='mdi:download-network',
  116. # Reverse sent because the is what the router is sending to the port
  117. # thus what the port is downloading
  118. value_fn=lambda coordinator: coordinator.get_value(EP_TRAFFIC, ['ethIfaceSt', 0, 'BytesSent']),
  119. native_unit_of_measurement='B',
  120. suggested_unit_of_measurement='GB',
  121. device_class=SensorDeviceClass.DATA_SIZE,
  122. state_class=SensorStateClass.TOTAL,
  123. translation_key='lan1_downloaded',
  124. entity_registry_enabled_default=False
  125. ),
  126. RouterSensorDescription(
  127. key='lan1_uploaded',
  128. icon='mdi:upload-network',
  129. # Reverse receive because the is what the router is receiving to the port
  130. # thus what the port is uploading
  131. value_fn=lambda coordinator: coordinator.get_value(EP_TRAFFIC, ['ethIfaceSt', 0, 'BytesReceived']),
  132. native_unit_of_measurement='B',
  133. suggested_unit_of_measurement='GB',
  134. device_class=SensorDeviceClass.DATA_SIZE,
  135. state_class=SensorStateClass.TOTAL,
  136. translation_key='lan1_uploaded',
  137. entity_registry_enabled_default=False,
  138. ),
  139. RouterSensorDescription(
  140. key='lan2_downloaded',
  141. icon='mdi:download-network',
  142. # Reverse sent because the is what the router is sending to the port
  143. # thus what the port is downloading
  144. value_fn=lambda coordinator: coordinator.get_value(EP_TRAFFIC, ['ethIfaceSt', 1, 'BytesSent']),
  145. native_unit_of_measurement='B',
  146. suggested_unit_of_measurement='GB',
  147. device_class=SensorDeviceClass.DATA_SIZE,
  148. state_class=SensorStateClass.TOTAL,
  149. translation_key='lan2_downloaded',
  150. entity_registry_enabled_default=False
  151. ),
  152. RouterSensorDescription(
  153. key='lan2_uploaded',
  154. icon='mdi:upload-network',
  155. # Reverse receive because the is what the router is receiving to the port
  156. # thus what the port is uploading
  157. value_fn=lambda coordinator: coordinator.get_value(EP_TRAFFIC, ['ethIfaceSt', 1, 'BytesReceived']),
  158. native_unit_of_measurement='B',
  159. suggested_unit_of_measurement='GB',
  160. device_class=SensorDeviceClass.DATA_SIZE,
  161. state_class=SensorStateClass.TOTAL,
  162. translation_key='lan2_uploaded',
  163. entity_registry_enabled_default=False,
  164. ),
  165. RouterSensorDescription(
  166. key='wan_ip_address',
  167. icon='mdi:ip-network',
  168. value_fn=lambda coordinator: coordinator.get_value(EP_COMMON, ['WanLanInfo', 1, 'IPv4Address', 0, 'IPAddress']),
  169. translation_key='wan_ip_address',
  170. entity_registry_enabled_default=False
  171. ),
  172. # RouterSensorDescription(
  173. # key='network_devices',
  174. # state_class=SensorStateClass.MEASUREMENT,
  175. # translation_key='network_devices',
  176. # entity_registry_enabled_default=True
  177. # )
  178. ]
  179. async def async_setup_entry(
  180. hass: HomeAssistant,
  181. entry: ConfigEntry,
  182. async_add_entities: AddEntitiesCallback,
  183. ) -> None:
  184. """Set up Router sensors based on a config entry."""
  185. conf_name = entry.data.get(CONF_NAME)
  186. coordinator = entry.runtime_data.coordinator
  187. #coordinator = hass.data[DOMAIN][entry.entry_id]
  188. entities: list[RouterSensor] = []
  189. # Add all sensors described above.
  190. for description in DESCRIPTIONS:
  191. entities.append(
  192. RouterSensor(
  193. conf_name=conf_name,
  194. coordinator=coordinator,
  195. description=description,
  196. )
  197. )
  198. async_add_entities(entities)
  199. class RouterSensor(CoordinatorEntity[RouterCoordinator], SensorEntity):
  200. """Defines a Router sensor."""
  201. _attr_has_entity_name = True
  202. entity_description: RouterSensorDescription
  203. def __init__(
  204. self,
  205. conf_name: str,
  206. coordinator: RouterCoordinator,
  207. description: SensorEntityDescription,
  208. ) -> None:
  209. """Initialize Router sensor."""
  210. super().__init__(coordinator=coordinator)
  211. #self._attr_attribution = self.coordinator.get_value(["api", 0, "bron"])
  212. self._attr_device_info = coordinator.device_info
  213. self._attr_unique_id = f"{conf_name}_{description.key}".lower()
  214. self.entity_description = description
  215. @property
  216. def native_value(self) -> StateType:
  217. """Return the state."""
  218. return self.entity_description.value_fn(self.coordinator)
  219. @property
  220. def extra_state_attributes(self) -> dict[str, Any]:
  221. """Return the state attributes."""
  222. return self.entity_description.attr_fn(self.coordinator)