Home Assistant Unofficial Reference 2024.12.1
coordinator.py
Go to the documentation of this file.
1 """Flo device object."""
2 
3 from __future__ import annotations
4 
5 import asyncio
6 from datetime import datetime, timedelta
7 from typing import Any
8 
9 from aioflo.api import API
10 from aioflo.errors import RequestError
11 from orjson import JSONDecodeError
12 
13 from homeassistant.core import HomeAssistant
14 from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
15 import homeassistant.util.dt as dt_util
16 
17 from .const import DOMAIN as FLO_DOMAIN, LOGGER
18 
19 
21  """Flo device object."""
22 
23  _failure_count: int = 0
24 
25  def __init__(
26  self, hass: HomeAssistant, api_client: API, location_id: str, device_id: str
27  ) -> None:
28  """Initialize the device."""
29  self.hasshass: HomeAssistant = hass
30  self.api_client: API = api_client
31  self._flo_location_id: str = location_id
32  self._flo_device_id: str = device_id
33  self._manufacturer: str = "Flo by Moen"
34  self._device_information_device_information: dict[str, Any] = {}
35  self._water_usage_water_usage: dict[str, Any] = {}
36  super().__init__(
37  hass,
38  LOGGER,
39  name=f"{FLO_DOMAIN}-{device_id}",
40  update_interval=timedelta(seconds=60),
41  )
42 
43  async def _async_update_data(self):
44  """Update data via library."""
45  try:
46  async with asyncio.timeout(20):
47  await self.send_presence_pingsend_presence_ping()
48  await self._update_device_update_device()
49  await self._update_consumption_data_update_consumption_data()
50  self._failure_count_failure_count = 0
51  except (RequestError, TimeoutError, JSONDecodeError) as error:
52  self._failure_count_failure_count += 1
53  if self._failure_count_failure_count > 3:
54  raise UpdateFailed(error) from error
55 
56  @property
57  def location_id(self) -> str:
58  """Return Flo location id."""
59  return self._flo_location_id
60 
61  @property
62  def id(self) -> str:
63  """Return Flo device id."""
64  return self._flo_device_id
65 
66  @property
67  def device_name(self) -> str:
68  """Return device name."""
69  return self._device_information_device_information.get(
70  "nickname", f"{self.manufacturer} {self.model}"
71  )
72 
73  @property
74  def manufacturer(self) -> str:
75  """Return manufacturer for device."""
76  return self._manufacturer
77 
78  @property
79  def mac_address(self) -> str:
80  """Return ieee address for device."""
81  return self._device_information_device_information["macAddress"]
82 
83  @property
84  def model(self) -> str:
85  """Return model for device."""
86  return self._device_information_device_information["deviceModel"]
87 
88  @property
89  def rssi(self) -> float:
90  """Return rssi for device."""
91  return self._device_information_device_information["connectivity"]["rssi"]
92 
93  @property
94  def last_heard_from_time(self) -> str:
95  """Return lastHeardFromTime for device."""
96  return self._device_information_device_information["lastHeardFromTime"]
97 
98  @property
99  def device_type(self) -> str:
100  """Return the device type for the device."""
101  return self._device_information_device_information["deviceType"]
102 
103  @property
104  def available(self) -> bool:
105  """Return True if device is available."""
106  return self.last_update_successlast_update_success and self._device_information_device_information["isConnected"]
107 
108  @property
109  def current_system_mode(self) -> str:
110  """Return the current system mode."""
111  return self._device_information_device_information["systemMode"]["lastKnown"]
112 
113  @property
114  def target_system_mode(self) -> str:
115  """Return the target system mode."""
116  return self._device_information_device_information["systemMode"]["target"]
117 
118  @property
119  def current_flow_rate(self) -> float:
120  """Return current flow rate in gpm."""
121  return self._device_information_device_information["telemetry"]["current"]["gpm"]
122 
123  @property
124  def current_psi(self) -> float:
125  """Return the current pressure in psi."""
126  return self._device_information_device_information["telemetry"]["current"]["psi"]
127 
128  @property
129  def temperature(self) -> float:
130  """Return the current temperature in degrees F."""
131  return self._device_information_device_information["telemetry"]["current"]["tempF"]
132 
133  @property
134  def humidity(self) -> float:
135  """Return the current humidity in percent (0-100)."""
136  return self._device_information_device_information["telemetry"]["current"]["humidity"]
137 
138  @property
139  def consumption_today(self) -> float:
140  """Return the current consumption for today in gallons."""
141  return self._water_usage_water_usage["aggregations"]["sumTotalGallonsConsumed"]
142 
143  @property
144  def firmware_version(self) -> str:
145  """Return the firmware version for the device."""
146  return self._device_information_device_information["fwVersion"]
147 
148  @property
149  def serial_number(self) -> str | None:
150  """Return the serial number for the device."""
151  return self._device_information_device_information.get("serialNumber")
152 
153  @property
154  def pending_info_alerts_count(self) -> int:
155  """Return the number of pending info alerts for the device."""
156  return self._device_information_device_information["notifications"]["pending"]["infoCount"]
157 
158  @property
160  """Return the number of pending warning alerts for the device."""
161  return self._device_information_device_information["notifications"]["pending"]["warningCount"]
162 
163  @property
165  """Return the number of pending critical alerts for the device."""
166  return self._device_information_device_information["notifications"]["pending"]["criticalCount"]
167 
168  @property
169  def has_alerts(self) -> bool:
170  """Return True if any alert counts are greater than zero."""
171  return bool(
172  self.pending_info_alerts_countpending_info_alerts_count
173  or self.pending_warning_alerts_countpending_warning_alerts_count
174  or self.pending_warning_alerts_countpending_warning_alerts_count
175  )
176 
177  @property
178  def water_detected(self) -> bool:
179  """Return whether water is detected, for leak detectors."""
180  return self._device_information_device_information["fwProperties"]["telemetry_water"]
181 
182  @property
183  def last_known_valve_state(self) -> str:
184  """Return the last known valve state for the device."""
185  return self._device_information_device_information["valve"]["lastKnown"]
186 
187  @property
188  def target_valve_state(self) -> str:
189  """Return the target valve state for the device."""
190  return self._device_information_device_information["valve"]["target"]
191 
192  @property
193  def battery_level(self) -> float:
194  """Return the battery level for battery-powered device, e.g. leak detectors."""
195  return self._device_information_device_information["battery"]["level"]
196 
197  async def send_presence_ping(self):
198  """Send Flo a presence ping."""
199  await self.api_client.presence.ping()
200 
201  async def async_set_mode_home(self):
202  """Set the Flo location to home mode."""
203  await self.api_client.location.set_mode_home(self._flo_location_id)
204 
205  async def async_set_mode_away(self):
206  """Set the Flo location to away mode."""
207  await self.api_client.location.set_mode_away(self._flo_location_id)
208 
209  async def async_set_mode_sleep(self, sleep_minutes, revert_to_mode):
210  """Set the Flo location to sleep mode."""
211  await self.api_client.location.set_mode_sleep(
212  self._flo_location_id, sleep_minutes, revert_to_mode
213  )
214 
215  async def async_run_health_test(self):
216  """Run a Flo device health test."""
217  await self.api_client.device.run_health_test(self._flo_device_id)
218 
219  async def _update_device(self, *_) -> None:
220  """Update the device information from the API."""
221  self._device_information_device_information = await self.api_client.device.get_info(
222  self._flo_device_id
223  )
224  LOGGER.debug("Flo device data: %s", self._device_information_device_information)
225 
226  async def _update_consumption_data(self, *_) -> None:
227  """Update water consumption data from the API."""
228  today = dt_util.now().date()
229  start_date = datetime(today.year, today.month, today.day, 0, 0)
230  end_date = datetime(today.year, today.month, today.day, 23, 59, 59, 999000)
231  self._water_usage_water_usage = await self.api_client.water.get_consumption_info(
232  self._flo_location_id, start_date, end_date
233  )
234  LOGGER.debug("Updated Flo consumption data: %s", self._water_usage_water_usage)
None __init__(self, HomeAssistant hass, API api_client, str location_id, str device_id)
Definition: coordinator.py:27
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88