From 87b8bb94bdddff4fee37cf3dda1f2c6ce9c1daa0 Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Sun, 8 Nov 2026 14:30:33 +0100 Subject: [PATCH] fix(easee_cloud): declare the coarse session counter (1.4.1) Easee moves session energy in steps of about 1 kWh. FTW's energy record judged each step against the time since the last reading, and rejected those that landed moments later. On one home box it kept 10 of 24.3 kWh. The driver now says so with session_wh_coarse. Measured power came within 0.1 % of Easee's own total on three charges. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Fredrik Ahlgren --- CHANGELOG.md | 9 ++++++++ SUPPORT_STATUS.md | 4 ++-- devices.yaml | 2 +- drivers/lua/easee_cloud.lua | 6 ++++- .../test_easee_cloud_session_counter.lua | 23 +++++++++++++++++++ .../tests/test_easee_cloud_session_counter.py | 12 ++++++++++ index.yaml | 6 ++--- manifests/easee_cloud.yaml | 6 ++--- support-status.json | 2 +- 9 files changed, 59 insertions(+), 11 deletions(-) create mode 100644 drivers/tests/lua_harness/test_easee_cloud_session_counter.lua create mode 100644 drivers/tests/test_easee_cloud_session_counter.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 352b581..aaf58aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ ## [Unreleased] +### easee_cloud 1.4.1 + +The driver says its session energy is coarse, with `session_wh_coarse`. Easee +moves that figure in steps of about 1 kWh, and FTW's energy record rejected +steps that landed moments after the last reading. On one home box that kept +10 of 24.3 kWh. FTW now uses measured power for this charger's energy, which +came within 0.1 % of Easee's own session total on three charges (6.6, 24.3 and +31.7 kWh). + ### saj-emanager 0.1.2 The NovaCore device-support registry accepts this driver. diff --git a/SUPPORT_STATUS.md b/SUPPORT_STATUS.md index f602598..1574553 100644 --- a/SUPPORT_STATUS.md +++ b/SUPPORT_STATUS.md @@ -46,8 +46,8 @@ Catalog source is not proof that a target can install or run a driver. | deye | 2.1.1 | blixt-l1 | not_assessed | — | not_recorded | not_assessed | | easee | 1.0.4 | ftw-core | not_assessed | — | not_recorded | not_assessed | | easee | 1.0.4 | blixt-l1 | not_assessed | — | not_recorded | not_assessed | -| easee_cloud | 1.4.0 | ftw-core | not_assessed | — | not_recorded | not_assessed | -| easee_cloud | 1.4.0 | blixt-l1 | not_assessed | — | not_recorded | not_assessed | +| easee_cloud | 1.4.1 | ftw-core | not_assessed | — | not_recorded | not_assessed | +| easee_cloud | 1.4.1 | blixt-l1 | not_assessed | — | not_recorded | not_assessed | | esphome_dsmr | 1.0.7 | ftw-core | not_assessed | — | not_recorded | not_assessed | | esphome_dsmr | 1.0.7 | blixt-l1 | not_assessed | — | not_recorded | not_assessed | | etrel | 1.0.3 | ftw-core | not_assessed | — | not_recorded | not_assessed | diff --git a/devices.yaml b/devices.yaml index 7dfd711..317220b 100644 --- a/devices.yaml +++ b/devices.yaml @@ -338,7 +338,7 @@ manufacturers: protocols: - protocol: http driver: "easee_cloud" - version: "1.4.0" + version: "1.4.1" ders: [ev] control: true firmware_versions: "" diff --git a/drivers/lua/easee_cloud.lua b/drivers/lua/easee_cloud.lua index 8ff13ef..fd123f9 100644 --- a/drivers/lua/easee_cloud.lua +++ b/drivers/lua/easee_cloud.lua @@ -29,7 +29,7 @@ DRIVER = { id = "easee_cloud", name = "Easee Cloud", manufacturer = "Easee", - version = "1.4.0", + version = "1.4.1", protocols = { "http" }, capabilities = { "ev" }, description = "Easee Home/Charge via Cloud REST API. No local protocol needed.", @@ -1100,6 +1100,10 @@ function driver_poll() charging = charging, request_active = request_active, session_wh = session_wh, + -- Easee moves session energy in steps of about 1 kWh, in its own + -- time. It is right for what a session delivered, and too coarse to + -- say when the energy flowed, so Core's energy record uses power. + session_wh_coarse = true, power_observed_at = power_observed_at, -- Control verification needs distinct source samples. A fresh cloud -- reply alone does not establish a new physical power measurement. diff --git a/drivers/tests/lua_harness/test_easee_cloud_session_counter.lua b/drivers/tests/lua_harness/test_easee_cloud_session_counter.lua new file mode 100644 index 0000000..b86fe22 --- /dev/null +++ b/drivers/tests/lua_harness/test_easee_cloud_session_counter.lua @@ -0,0 +1,23 @@ +dofile("drivers/tests/lua_harness/host_mock.lua") +-- Easee's session energy moves in steps of about 1 kWh, so the driver says +-- so and FTW's energy record uses power. The figure itself stays. +local driver = "drivers/lua/easee_cloud.lua" +host.reset() +host._millis_step = 0 +host._http_responses["/accounts/login"] = '{"accessToken":"test","expiresIn":3600}' +host._http_responses["/config"] = '{"maxChargerCurrent":16}' +host._http_responses["/sessions/ongoing"] = '{}' +dofile(driver) +driver_init({email="test@example.invalid",password="test",serial="TEST123"}) +host._http_responses["/observations?ids="] = host.json_encode({ + {id=109,value=3,timestamp="2026-11-08T02:00:00Z"}, + {id=120,value=9.6,timestamp="2026-11-08T02:00:00Z"}, + {id=121,value=12.0,timestamp="2026-11-08T02:00:00Z"}, +}) +driver_poll() +local rows = host._emitted.ev +assert(rows and #rows > 0, "no EV sample") +local sample = rows[#rows] +assert(sample.session_wh_coarse == true, "the coarse session counter was not declared") +assert(sample.session_wh == 12000, "session energy lost: " .. tostring(sample.session_wh)) +print("Easee session counter: passed") diff --git a/drivers/tests/test_easee_cloud_session_counter.py b/drivers/tests/test_easee_cloud_session_counter.py new file mode 100644 index 0000000..23a330e --- /dev/null +++ b/drivers/tests/test_easee_cloud_session_counter.py @@ -0,0 +1,12 @@ +"""Easee's coarse session counter must be declared, and stay reported.""" +from pathlib import Path +import subprocess + + +def test_easee_cloud_declares_its_coarse_session_counter(): + root = Path(__file__).resolve().parents[2] + result = subprocess.run( + [str(root / "lua55"), "drivers/tests/lua_harness/test_easee_cloud_session_counter.lua"], + cwd=root, text=True, capture_output=True, check=False, + ) + assert result.returncode == 0, result.stdout + result.stderr diff --git a/index.yaml b/index.yaml index 1a99d9a..0f09d7f 100644 --- a/index.yaml +++ b/index.yaml @@ -193,15 +193,15 @@ drivers: size_bytes: 4054 sha256: "4a2cd1efb4a5583468ce897ebd88a000e348917295c40210e86ecf834c0ba543" - name: "easee_cloud" - version: "1.4.0" + version: "1.4.1" tier: core protocol: http connectivity: cloud setup: [vendor_portal] ders: [ev] control: true - size_bytes: 64126 - sha256: "94653989702cb805c56db296be0651886b4b685a0d407bd69089450b86571abe" + size_bytes: 64392 + sha256: "de954b416dcab6d9d7af06075056dce30a1e9d8dbba80223d78a1cdb806101cd" - name: "esphome_dsmr" version: "1.0.7" tier: core diff --git a/manifests/easee_cloud.yaml b/manifests/easee_cloud.yaml index 3b55ee8..8ab261a 100644 --- a/manifests/easee_cloud.yaml +++ b/manifests/easee_cloud.yaml @@ -1,5 +1,5 @@ name: "easee_cloud" -version: "1.4.0" +version: "1.4.1" tier: core author: "Sourceful Labs AB" protocol: http @@ -16,9 +16,9 @@ tested_devices: notes: "Easee Home/Charge via Cloud REST API. No local protocol needed." min_driver_version: "1.0.1" min_host_version: "2.0.0" -size_bytes: 64126 +size_bytes: 64392 dkb_id: "easee_cloud" -sha256: "94653989702cb805c56db296be0651886b4b685a0d407bd69089450b86571abe" +sha256: "de954b416dcab6d9d7af06075056dce30a1e9d8dbba80223d78a1cdb806101cd" signature: "" bytecode_sha256: "" diff --git a/support-status.json b/support-status.json index 309845d..65543b7 100644 --- a/support-status.json +++ b/support-status.json @@ -443,7 +443,7 @@ }, { "catalog_source": true, - "catalog_version": "1.4.0", + "catalog_version": "1.4.1", "driver_id": "easee_cloud", "targets": { "blixt-l1": {