Skip to content

energyConsumptionCurve: curve key format differs by stat_type (year: month-of-year vs week/month: full date), and a tz-aware datetime silently returns no data #88

Description

@bob15982

Context
I'm building a one-time historical backfill of get_energy_consumption_curve() data into Home Assistant's recorder long-term statistics (for a washing machine + dryer, via connectlife-ha, connectlife==0.9.1). While reverse-engineering the response shape to iterate day-by-day, I ran into two things that cost a fair amount of debugging and might be worth documenting / hardening.

  1. electric_curve/water_curve key format is not just "per-day vs per-month" — it also changes shape
    The EnergyResult docstring says:

Bucket granularity depends on the endpoint and stat_type: air_duct_energy's day curve is per-hour (keys "0".."23"), while week/month curves are per-day and year is per-month.

That's true for granularity, but the actual key format also changes in a way that's easy to miss:

stat_type="week" / "month": keys are full ISO date strings, e.g. "2026-07-01", "2026-07-02", ... (confirmed against both the real gateway and test_server.py's energy_consumption_curve, which builds keys with day.isoformat()).
stat_type="year": keys are not dates at all — they're zero-padded month-of-year strings "01".."12" (plus an "all" total key), e.g. {"01": "24.54", ..., "09": "0.00", "all": "201.87"}. This is real gateway behavior; test_server.py currently leaves the year curve empty, so there's no test coverage pinning this down.

Because week/month use real dates and year uses bare numbers, a caller who writes one generic "parse this key as a date, fall back to int" is bound to mis-parse one of the two — I did, initially assuming year's "01" meant day-of-month 1 rather than month 1. A short callout in the docstring (e.g. "year buckets are month-of-year 01-12, not dates") would have saved a debugging session.
2. Passing a tz-aware datetime as date= silently returns no data
get_energy_consumption_curve(..., date=...) is typed as date: dt.date | None. Since datetime.datetime is a subclass of datetime.date, it's easy to accidentally pass a tz-aware datetime (e.g. Home Assistant's dt_util.now(), or just datetime.now(tz)). date.isoformat() is used verbatim for the datePeriodEnd request parameter — for a datetime this produces a full timestamp ("2026-07-01T00:00:00+02:00") instead of a plain date. The gateway appears to silently reject/ignore this: get_energy_consumption_curve returns None, no exception — indistinguishable from "no data for this appliance/period".

This is a real footgun since nothing errors, it just looks like the appliance has no history. A defensive date = date.date() if isinstance(date, dt.datetime) else date at the top of get_energy_consumption_curve (and get_air_duct_energy) would remove the whole class of bug; at minimum a docstring note would help.
Why I hit this
I wrote a small one-off Home Assistant component that walks month-by-month back through get_energy_consumption_curve(stat_type="month", ...) to backfill about 1.5 years of real cloud history into HA's recorder (the local recorder only had about a week of data since installing connectlife-ha). Happy to share the (very hacky, HA-specific) script if useful, but mainly wanted to report the two gotchas above since they'd trip up anyone doing multi-period aggregation against this endpoint.

Versions: connectlife==0.9.1 (via connectlife-ha); confirmed the same behavior reading main at time of writing (relevant parts of EnergyResult/_energy_date_range unchanged as of pyproject.toml version 0.10.0).

Thanks for the library — happy to open a small PR for the docstring clarification / date-coercion fix if that's welcome instead of just an issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions