SMART energy module stubs get_daily_stats/get_monthly_stats even when the firmware supports get_energy_data
Summary
The SMART energy module unconditionally raises KasaException("Device does not support periodic statistics") for both get_daily_stats and get_monthly_stats, for every SMART/KLAP device — regardless of whether the device firmware actually supports historical energy queries.
Many SMART metering devices (e.g. KP125M, P110/P115, etc.) implement a get_energy_data method that returns per-day and per-month history. Because the module stubs the interface methods out, none of that history is reachable through python-kasa, even though the equivalent IOT module (kasa/iot/modules/emeter.py) does implement get_daily_stats/get_monthly_stats. The result is that the library can only report current month/day totals (get_energy_usage) for SMART meters, while the Kasa mobile app shows the full history from the same device.
Where
|
async def get_daily_stats( |
|
self, *, year: int | None = None, month: int | None = None, kwh: bool = True |
|
) -> dict: |
|
"""Return daily stats for the given year & month. |
|
|
|
The return value is a dictionary of {day: energy, ...}. |
|
""" |
|
raise KasaException("Device does not support periodic statistics") |
|
|
|
async def get_monthly_stats( |
|
self, *, year: int | None = None, kwh: bool = True |
|
) -> dict: |
|
"""Return monthly stats for the given year.""" |
|
raise KasaException("Device does not support periodic statistics") |
async def get_daily_stats(self, *, year=None, month=None, kwh=True) -> dict:
"""Return daily stats for the given year & month."""
raise KasaException("Device does not support periodic statistics")
async def get_monthly_stats(self, *, year=None, kwh=True) -> dict:
"""Return monthly stats for the given year."""
raise KasaException("Device does not support periodic statistics")
Affected / tested device
- Model: KP125M(US)
- Type: SMART.KASAPLUG, encryption KLAP, login v2
- Energy component: {'id': 'energy_monitoring', 'ver_code': 2}
- python-kasa: 0.10.2 (stub also present on master @ a29d061)
Reproduction
energy = dev.modules[Module.Energy]
await energy.get_monthly_stats(year=2026)
# kasa.exceptions.KasaException: Device does not support periodic statistics
…yet the firmware answers get_energy_data directly. A raw query returns real history:
resp = await dev.protocol.query({
"get_energy_data": {
"start_timestamp": <local Jan 1 00:00 of the year>,
"end_timestamp": <local Jan 1 00:00 of the next year>,
"interval": 43200, # minutes; 43200 = monthly, 1440 = daily, 60 = hourly
}
})
# -> {"get_energy_data": {
# "start_timestamp": ..., "end_timestamp": ..., "interval": 43200, "local_time": ...,
# "data": [<Wh for Jan>, <Wh for Feb>, ... 12 buckets ...]
# }}
Behaviour notes discovered while testing (relevant to any implementation)
These are firmware constraints on get_energy_data, not python-kasa bugs, but an implementation has to respect them:
- The request must be period-aligned, and the interval selects the bucket size:
- interval=43200 (monthly): start_timestamp = local Jan 1 of a year → returns that year's 12 monthly buckets.
- interval=1440 (daily): start_timestamp = first day of a quarter → returns that quarter's daily buckets.
- interval=60 (hourly): start_timestamp = midnight of a day → returns 24 hourly buckets.
A too-large / misaligned window returns PARAMS_ERROR(-1008).
- Responses can paginate — response.end_timestamp may be earlier than the requested end_timestamp; the app re-issues the request with that value as the new start_timestamp and concatenates the data arrays.
- Retention differs by resolution: monthly totals are kept for the whole year, but daily granularity only covers a rolling recent window (~3 months on the tested device). Older daily buckets return 0, while the monthly total for that same month is still populated. An implementation should not treat trailing/older zeros as "no data".
- Values are in Wh (consistent with get_energy_usage.month_energy).
Proposed approach
- Implement get_daily_stats/get_monthly_stats in kasa/smart/modules/energy.py on top of get_energy_data, mapping the returned data arrays into the interface's {day: energy} / {month: energy} dict contract and honouring the kwh flag.
- Gate on capability (component ver_code, and/or a graceful PARAMS_ERROR/unknown-method fallback) so devices that genuinely lack get_energy_data keep raising the existing exception.
- Encode the alignment + pagination rules above.
Contribution
Happy to open a PR. I have a working KP125M against real hardware and can supply a fixture with representative get_energy_data responses (monthly + daily) plus component_nego / get_energy_usage. Guidance welcome on how you'd prefer to fixture a parameterized call like get_energy_data in the current SMART test framework, since the existing fixtures capture static responses.
SMART energy module stubs get_daily_stats/get_monthly_stats even when the firmware supports get_energy_data
Summary
The SMART energy module unconditionally raises KasaException("Device does not support periodic statistics") for both get_daily_stats and get_monthly_stats, for every SMART/KLAP device — regardless of whether the device firmware actually supports historical energy queries.
Many SMART metering devices (e.g. KP125M, P110/P115, etc.) implement a get_energy_data method that returns per-day and per-month history. Because the module stubs the interface methods out, none of that history is reachable through python-kasa, even though the equivalent IOT module (kasa/iot/modules/emeter.py) does implement get_daily_stats/get_monthly_stats. The result is that the library can only report current month/day totals (get_energy_usage) for SMART meters, while the Kasa mobile app shows the full history from the same device.
Where
python-kasa/kasa/smart/modules/energy.py
Lines 202 to 215 in a29d061
Affected / tested device
Reproduction
…yet the firmware answers get_energy_data directly. A raw query returns real history:
Behaviour notes discovered while testing (relevant to any implementation)
These are firmware constraints on get_energy_data, not python-kasa bugs, but an implementation has to respect them:
A too-large / misaligned window returns PARAMS_ERROR(-1008).
Proposed approach
Contribution
Happy to open a PR. I have a working KP125M against real hardware and can supply a fixture with representative get_energy_data responses (monthly + daily) plus component_nego / get_energy_usage. Guidance welcome on how you'd prefer to fixture a parameterized call like get_energy_data in the current SMART test framework, since the existing fixtures capture static responses.