2021-11-07 01:41:12 +00:00
|
|
|
"""Implementation of the usage interface."""
|
2024-04-16 18:21:20 +00:00
|
|
|
|
2024-04-17 13:39:24 +00:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2021-11-07 01:41:12 +00:00
|
|
|
from datetime import datetime
|
|
|
|
|
2024-02-19 17:01:31 +00:00
|
|
|
from ..iotmodule import IotModule, merge
|
2021-11-07 01:41:12 +00:00
|
|
|
|
|
|
|
|
2024-02-04 15:20:08 +00:00
|
|
|
class Usage(IotModule):
|
2021-11-07 01:41:12 +00:00
|
|
|
"""Baseclass for emeter/usage interfaces."""
|
|
|
|
|
2024-11-10 18:55:13 +00:00
|
|
|
def query(self) -> dict:
|
2021-11-07 01:41:12 +00:00
|
|
|
"""Return the base query."""
|
2024-01-05 01:01:00 +00:00
|
|
|
now = datetime.now()
|
|
|
|
year = now.year
|
|
|
|
month = now.month
|
2021-11-07 01:41:12 +00:00
|
|
|
|
|
|
|
req = self.query_for_command("get_realtime")
|
|
|
|
req = merge(
|
|
|
|
req, self.query_for_command("get_daystat", {"year": year, "month": month})
|
|
|
|
)
|
|
|
|
req = merge(req, self.query_for_command("get_monthstat", {"year": year}))
|
|
|
|
|
|
|
|
return req
|
|
|
|
|
2023-09-14 18:51:40 +00:00
|
|
|
@property
|
2024-11-10 18:55:13 +00:00
|
|
|
def estimated_query_response_size(self) -> int:
|
2023-09-14 18:51:40 +00:00
|
|
|
"""Estimated maximum query response size."""
|
|
|
|
return 2048
|
|
|
|
|
2021-11-19 15:41:49 +00:00
|
|
|
@property
|
2024-11-10 18:55:13 +00:00
|
|
|
def daily_data(self) -> list[dict]:
|
2021-11-19 15:41:49 +00:00
|
|
|
"""Return statistics on daily basis."""
|
|
|
|
return self.data["get_daystat"]["day_list"]
|
|
|
|
|
|
|
|
@property
|
2024-11-10 18:55:13 +00:00
|
|
|
def monthly_data(self) -> list[dict]:
|
2021-11-19 15:41:49 +00:00
|
|
|
"""Return statistics on monthly basis."""
|
|
|
|
return self.data["get_monthstat"]["month_list"]
|
|
|
|
|
|
|
|
@property
|
2024-11-10 18:55:13 +00:00
|
|
|
def usage_today(self) -> int | None:
|
2021-11-19 15:41:49 +00:00
|
|
|
"""Return today's usage in minutes."""
|
|
|
|
today = datetime.now().day
|
2024-01-05 01:01:00 +00:00
|
|
|
# Traverse the list in reverse order to find the latest entry.
|
|
|
|
for entry in reversed(self.daily_data):
|
|
|
|
if entry["day"] == today:
|
|
|
|
return entry["time"]
|
|
|
|
return None
|
2021-11-19 15:41:49 +00:00
|
|
|
|
|
|
|
@property
|
2024-11-10 18:55:13 +00:00
|
|
|
def usage_this_month(self) -> int | None:
|
2021-11-19 15:41:49 +00:00
|
|
|
"""Return usage in this month in minutes."""
|
|
|
|
this_month = datetime.now().month
|
2024-01-05 01:01:00 +00:00
|
|
|
# Traverse the list in reverse order to find the latest entry.
|
|
|
|
for entry in reversed(self.monthly_data):
|
|
|
|
if entry["month"] == this_month:
|
|
|
|
return entry["time"]
|
|
|
|
return None
|
2021-11-19 15:41:49 +00:00
|
|
|
|
2024-11-10 18:55:13 +00:00
|
|
|
async def get_raw_daystat(
|
|
|
|
self, *, year: int | None = None, month: int | None = None
|
|
|
|
) -> dict:
|
2023-02-18 19:53:02 +00:00
|
|
|
"""Return raw daily stats for the given year & month."""
|
2021-11-07 01:41:12 +00:00
|
|
|
if year is None:
|
|
|
|
year = datetime.now().year
|
|
|
|
if month is None:
|
|
|
|
month = datetime.now().month
|
2021-11-19 15:41:49 +00:00
|
|
|
|
2021-11-07 01:41:12 +00:00
|
|
|
return await self.call("get_daystat", {"year": year, "month": month})
|
|
|
|
|
2024-11-10 18:55:13 +00:00
|
|
|
async def get_raw_monthstat(self, *, year: int | None = None) -> dict:
|
2023-02-18 19:53:02 +00:00
|
|
|
"""Return raw monthly stats for the given year."""
|
2021-11-07 01:41:12 +00:00
|
|
|
if year is None:
|
|
|
|
year = datetime.now().year
|
2021-11-19 15:41:49 +00:00
|
|
|
|
2021-11-07 01:41:12 +00:00
|
|
|
return await self.call("get_monthstat", {"year": year})
|
|
|
|
|
2024-11-10 18:55:13 +00:00
|
|
|
async def get_daystat(
|
|
|
|
self, *, year: int | None = None, month: int | None = None
|
|
|
|
) -> dict:
|
2023-10-29 22:15:42 +00:00
|
|
|
"""Return daily stats for the given year & month.
|
|
|
|
|
|
|
|
The return value is a dictionary of {day: time, ...}.
|
|
|
|
"""
|
2023-02-18 19:53:02 +00:00
|
|
|
data = await self.get_raw_daystat(year=year, month=month)
|
|
|
|
data = self._convert_stat_data(data["day_list"], entry_key="day")
|
|
|
|
return data
|
|
|
|
|
2024-11-10 18:55:13 +00:00
|
|
|
async def get_monthstat(self, *, year: int | None = None) -> dict:
|
2023-10-29 22:15:42 +00:00
|
|
|
"""Return monthly stats for the given year.
|
|
|
|
|
|
|
|
The return value is a dictionary of {month: time, ...}.
|
|
|
|
"""
|
2023-02-18 19:53:02 +00:00
|
|
|
data = await self.get_raw_monthstat(year=year)
|
|
|
|
data = self._convert_stat_data(data["month_list"], entry_key="month")
|
|
|
|
return data
|
|
|
|
|
2024-11-10 18:55:13 +00:00
|
|
|
async def erase_stats(self) -> dict:
|
2021-11-07 01:41:12 +00:00
|
|
|
"""Erase all stats."""
|
|
|
|
return await self.call("erase_runtime_stat")
|
2023-02-18 19:53:02 +00:00
|
|
|
|
2024-11-10 18:55:13 +00:00
|
|
|
def _convert_stat_data(self, data: list[dict], entry_key: str) -> dict:
|
2023-02-18 19:53:02 +00:00
|
|
|
"""Return usage information keyed with the day/month.
|
|
|
|
|
|
|
|
The incoming data is a list of dictionaries::
|
|
|
|
|
|
|
|
[{'year': int,
|
|
|
|
'month': int,
|
|
|
|
'day': int, <-- for get_daystat not get_monthstat
|
|
|
|
'time': int, <-- for usage (mins)
|
|
|
|
}, ...]
|
|
|
|
|
|
|
|
:return: return a dictionary keyed by day or month with time as the value.
|
|
|
|
"""
|
|
|
|
if not data:
|
|
|
|
return {}
|
|
|
|
|
2024-11-10 18:55:13 +00:00
|
|
|
res = {entry[entry_key]: entry["time"] for entry in data}
|
2023-02-18 19:53:02 +00:00
|
|
|
|
2024-11-10 18:55:13 +00:00
|
|
|
return res
|