Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
d464da9
fix: authenticate via Cognito GetUser instead of userInfo
tarrinho Sep 27, 2026
c6ed3b0
chore: bump version to 0.1.1
tarrinho Sep 27, 2026
f74f8ed
chore: point project metadata at this fork
tarrinho Sep 27, 2026
1fe980c
fix: stop polling the absent recharge-session endpoint every 30s
tarrinho Sep 27, 2026
eee8610
chore: bump version to 0.1.2
tarrinho Sep 27, 2026
470e930
fix: read the fields the API actually returns
tarrinho Sep 27, 2026
6e288e7
docs: show the current version at the top of the README
tarrinho Sep 27, 2026
88efcb7
fix: send the serial and session ID with charge commands
tarrinho Sep 27, 2026
5206351
fix: explain why the charger refused a command
tarrinho Sep 27, 2026
8ce7737
fix: retry charge commands through the flaky Daze RPC link
tarrinho Sep 27, 2026
e5a5b45
feat: report waiting-for-EV and follow state transitions
tarrinho Sep 27, 2026
6bf7b53
docs: credit the original author
tarrinho Sep 27, 2026
3cafbba
fix: stop logging retried command failures as warnings
tarrinho Sep 27, 2026
522dd92
fix: space out command retries instead of hammering the link
tarrinho Sep 27, 2026
f35c38f
feat: let the command finder run without prompts
tarrinho Sep 27, 2026
1513ab2
fix: read the session ID at command time, not from the cache
tarrinho Sep 27, 2026
fb1cf56
test: fix two fixtures broken by the fresh session lookup
tarrinho Sep 27, 2026
8550dcd
docs: name the fork's author and list what changed
tarrinho Sep 27, 2026
9735e8b
feat: optimistic switch state and a configurable poll interval
tarrinho Sep 27, 2026
03cef35
fix: bound the charging current by what the charger accepts
tarrinho Sep 27, 2026
3277377
fix: do not cap the current slider at sccLimit
tarrinho Sep 27, 2026
d278e3b
fix: make the current-range probe survive a network stall
tarrinho Sep 27, 2026
eab8efe
style: collapse a nested conditional in the range probe
tarrinho Sep 27, 2026
bde6200
fix: derive the current floor from the charger's power minimum
tarrinho Sep 27, 2026
6d51f06
test: add QA checks for the charging current bounds
tarrinho Sep 27, 2026
e995bc3
fix: retry unreachable commands in the background
tarrinho Sep 28, 2026
acb4e5a
fix: show a changed current or mode straight away
tarrinho Sep 28, 2026
7ac8b75
test: run the real entities against a stubbed Home Assistant
tarrinho Sep 28, 2026
e28bd27
fix: never offer a range that excludes the charger's own setting
tarrinho Sep 28, 2026
eb4295a
feat: add a tool that sets the charging limit and keeps it
tarrinho Sep 28, 2026
340357d
feat: set the charging limit in watts as well as milliamps
tarrinho Sep 28, 2026
e6fd2dc
feat: reject out-of-range currents before sending them
tarrinho Sep 28, 2026
8efdad0
fix: act on the code review's behavioural findings
tarrinho Sep 28, 2026
9d3b2fd
fix: cancel scheduled work on unload, and unify the optimistic state
tarrinho Sep 28, 2026
4b6916d
docs: name the charging limit controls Power and Current
tarrinho Sep 28, 2026
dea2808
fix: do not append a vendor suffix to the device name
tarrinho Sep 28, 2026
fd0a242
fix: keep the power and current views in step
tarrinho Sep 28, 2026
4e38888
feat: do not send commands to a charger that is not reporting
tarrinho Sep 28, 2026
eee0b96
fix: act on the second review
tarrinho Sep 29, 2026
1378866
docs: add a worked solar surplus charging setup
tarrinho Sep 29, 2026
e685a51
docs: design for solar surplus control inside the integration
tarrinho Sep 29, 2026
e29a2f7
docs: implementation plan for solar surplus control
tarrinho Sep 29, 2026
5b0bdae
feat: add the solar surplus decision function
tarrinho Sep 29, 2026
1865373
fix: make test_target_is_clamped_to_the_floor exercise the clamp
tarrinho Sep 29, 2026
fc30cf6
feat: compute and smooth solar surplus
tarrinho Sep 29, 2026
ea5972e
fix: narrow backward-clock handling in SurplusSmoother
tarrinho Sep 29, 2026
ba07cde
feat: let the user pick grid import and export sensors
tarrinho Sep 29, 2026
dd021cf
docs: correct three defects in the solar control plan
tarrinho Sep 29, 2026
30e2383
docs: attribution follows the authoring model, not a fixed name
tarrinho Sep 29, 2026
547874c
docs: describe the grid sensors in the options step docstring
tarrinho Sep 29, 2026
ac37732
feat: add the solar controller
tarrinho Sep 29, 2026
8f51de8
fix: ship solar control off by default
tarrinho Sep 29, 2026
64c8ab3
fix: harden the solar controller against 11 review findings
tarrinho Sep 29, 2026
b4b7089
docs: strengthen two assertions that could not fail in the plan
tarrinho Sep 29, 2026
4b82fd4
docs: express downstream test expectations as deltas, not totals
tarrinho Sep 29, 2026
1ccb145
fix: address five follow-on findings from the I1 error handling
tarrinho Sep 29, 2026
a5c9170
feat: back off when a started car does not draw, cancel retries on su…
tarrinho Sep 29, 2026
19db54f
docs: keep Task 9's seeding off the draw-grace clock
tarrinho Sep 29, 2026
eca7e60
fix: split the draw-grace clock from the minimum-run clock
tarrinho Sep 29, 2026
47d6dc4
docs: place Task 9's seeding outside the ACTIVE gate
tarrinho Sep 29, 2026
83e9463
fix: guard the draw-grace mark against disconnect, stale carry, and r…
tarrinho Sep 29, 2026
96b32e5
docs: rewrite Tasks 6-10 and the spec against the pre-flight audit
tarrinho Sep 29, 2026
39052a0
docs: split Task 9 into the refusals and the restart
tarrinho Sep 29, 2026
5240635
feat: wire solar control into the entry and disarm on override
tarrinho Sep 29, 2026
87920b3
test: cover the entry lifecycle and the remaining disarm call sites
tarrinho Sep 29, 2026
e7af169
fix: tolerate a missing DOMAIN key when unloading a failed setup
tarrinho Sep 29, 2026
7f6575a
feat: add solar control, reserve and surplus entities
tarrinho Sep 29, 2026
7b7c30e
test: cover the reserve's read path and the select's simulate refusal
tarrinho Sep 29, 2026
d8c1dcf
feat: start the stop clock when surplus actually collapses
tarrinho Sep 29, 2026
0ec27dd
test: force the collapse-anchor and fast-path-latch tests to discrimi…
tarrinho Sep 29, 2026
2b89645
fix: close the sensor-event race and cover the anchor's unguarded clears
tarrinho Sep 29, 2026
43d08e2
feat: refuse setups solar control cannot follow
tarrinho Sep 29, 2026
1ae7d6b
fix: read the schedule field that actually survives the merge, and th…
tarrinho Sep 29, 2026
5163723
fix: stop the options merge from making cleared sensors unclearable, …
tarrinho Sep 29, 2026
8207370
feat: survive a Home Assistant restart
tarrinho Sep 29, 2026
ab943c2
docs: say what a fresh install actually shows
tarrinho Sep 29, 2026
d86b73e
test: cover the seeding flag's release and two unguarded restore paths
tarrinho Sep 29, 2026
cac0bec
docs: document solar control
tarrinho Sep 29, 2026
70f6111
chore: keep the working rules file out of the repository
tarrinho Sep 29, 2026
4dc4f82
fix: close five cross-task defects found in the final branch review
tarrinho Sep 29, 2026
ccd8c53
chore: ignore stray copies of the WebConsole runbook
tarrinho Sep 29, 2026
7bc5ece
fix: an unreported charging limit is not a limit of zero
tarrinho Sep 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,17 @@ credentials.*
*.key
*.cert
*.p12
*.pfx
*.pfx
# Probe and diagnostic output (may contain device identifiers)
/log
*.out
probe-*.txt

# Subagent-driven development scratch
/.superpowers/

# Working rules, kept local by operator decision 2026-09-29
/rules.md
# Stray copies of another project's runbook have landed here at least once.
# Ignore the dotted form too rather than relying on nobody running `git add -A`.
/.rules.md
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2025 andrea
Copyright (c) 2025 Andrea Restello

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
33 changes: 33 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
Daze Wallbox Integration for Home Assistant
===========================================

Original author
---------------

Created by Andrea Restello (@arest).
Upstream project: https://github.com/arest/daze-addon

The integration architecture, config flow, entity model, sensor catalog
and API client are his work, including the reverse engineering of the
Daze web API, which the vendor does not publish.

This repository
---------------

A fork maintained by Pedro Tarrinho (@tarrinho) at
https://github.com/tarrinho/daze-addon

The changes in this fork are the work of Pedro Tarrinho. They are bug
fixes found by running the integration against a DT01 charger and
measuring the API's actual responses: authentication, payload parsing,
charge command shape and retry behaviour, state reporting, and
diagnostics.

It is not a redesign, and it carries no claim over the original work.
See the "Changes in this fork" section of README.md for the detail.

Licence
-------

MIT, Copyright (c) 2025 Andrea Restello. See LICENSE, which is carried
over from the upstream project unchanged.
181 changes: 174 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
# Daze Wallbox

[![Version](https://img.shields.io/github/v/tag/tarrinho/daze-addon?label=version&sort=semver&color=blue)](https://github.com/tarrinho/daze-addon/releases)
[![HA Community](https://img.shields.io/badge/Home%20Assistant-2025.x-41BDF5?logo=homeassistant)](https://www.home-assistant.io/)
[![HACS Validation](https://github.com/arest/daze-addon/actions/workflows/validate.yaml/badge.svg)](https://github.com/arest/daze-addon/actions/workflows/validate.yaml)
[![GitHub](https://img.shields.io/github/license/arest/daze-addon)](LICENSE)
[![HACS Validation](https://github.com/tarrinho/daze-addon/actions/workflows/validate.yaml/badge.svg)](https://github.com/tarrinho/daze-addon/actions/workflows/validate.yaml)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we not change this ?

[![GitHub](https://img.shields.io/github/license/tarrinho/daze-addon)](LICENSE)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we not change this ?


Home Assistant integration for **Daze WallBox EV chargers**. Monitor charging metrics in real time and control your wallbox directly from your HA dashboard — no separate app required.

Daze wallboxes are managed through the [Daze web portal](https://webportal.dazeservice.com). This integration bridges the gap, bringing your wallbox into Home Assistant alongside all your other smart home devices.

> **This is a fork.** The original integration was created by **Andrea Restello** ([@arest](https://github.com/arest)) at [arest/daze-addon](https://github.com/arest/daze-addon), and all of the original design and implementation is his work. This fork, maintained by **Pedro Tarrinho** ([@tarrinho](https://github.com/tarrinho)), adds fixes found while running it against a DT01 charger — see [Changes in this fork](#changes-in-this-fork).

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we not change this ?


---

## Features

- **Real-time monitoring** — Power (W), delivered energy (Wh), charging current per phase (mA), AC voltage per phase (V), board and case temperatures (°C)
- **EVSE status** — See whether the wallbox is charging, idle, paused, or in error
- **Charge control** — Start and stop charging from HA switches, automations, or dashboards
- **Current limit** — Set the maximum charging current as a number entity (6–32 A, 0.1 A steps)
- **Charging limit** — Set it in amps or in watts. Both bounds come from the charger: its power floor at the measured voltage, and the installation rating
- **Operation mode** — Switch between eco, fast, scheduled, and other modes
- **Session history** — Track energy, duration, and cost per recharge session
- **Lifetime totals** — Total energy delivered and session count
Expand All @@ -33,7 +36,7 @@ Daze wallboxes are managed through the [Daze web portal](https://webportal.dazes
3. Click the three dots in the top-right corner and select **Custom repositories**
4. Add this repository URL:
```
https://github.com/arest/daze-addon
https://github.com/tarrinho/daze-addon

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we not change this ?

```
5. Select **Integration** as the category and click **Add**
6. Close the dialog — the Daze Wallbox integration should now appear in HACS
Expand Down Expand Up @@ -84,14 +87,15 @@ If your tokens expire, the integration will automatically prompt you to re-enter
| `sensor.daze_ac_voltage_l3` | AC Voltage L3 | `voltage` | `measurement` | V |
| `sensor.daze_board_temperature` | Board Temperature | `temperature` | `measurement` | °C |
| `sensor.daze_case_temperature` | Case Temperature | `temperature` | `measurement` | °C |
| `sensor.daze_evse_status` | EVSE Status | `enum` | — | idle / charging / paused / error |
| `sensor.daze_evse_status` | EVSE Status | `enum` | — | idle / waiting_for_ev / charging / paused / error / offline |
| `sensor.daze_last_session_energy` | Last Session Energy | `energy` | `total_increasing` | Wh |
| `sensor.daze_last_session_duration` | Last Session Duration | — | — | min |
| `sensor.daze_last_session_cost` | Last Session Cost | `monetary` | — | EUR |
| `sensor.daze_last_session_start` | Last Session Start | `timestamp` | — | |
| `sensor.daze_last_session_end` | Last Session End | `timestamp` | — | |
| `sensor.daze_lifetime_energy` | Lifetime Energy | `energy` | `total_increasing` | Wh |
| `sensor.daze_total_sessions` | Total Sessions | — | `total_increasing` | sessions |
| `sensor.daze_solar_surplus` | Solar surplus | `power` | `measurement` | W |

#### Diagnostic sensors

Expand All @@ -107,8 +111,17 @@ If your tokens expire, the integration will automatically prompt you to re-enter
| Platform | Entity ID | Name | Purpose |
|----------|-----------|------|---------|
| Switch | `switch.daze_charge_control` | Charge Control | Start / stop charging |
| Number | `number.daze_max_charging_current` | Max Charging Current | Set charging current limit (6–32 A) |
| Number | `number.daze_max_charging_current` | Current | Charging current limit, bounded by the charger's own floor and the installation rating |
| Number | `number.daze_max_charging_power` | Power | The same limit in watts, bounded by the charger's 1.5 kW floor |
| Select | `select.daze_operation_mode` | Operation Mode | Switch between eco, fast, scheduled |
| Select | `select.daze_solar_control` | Solar control | `off` / `simulate` / `active` |
| Number | `number.daze_solar_reserve` | Solar reserve | Watts to leave for the house before the car gets any |

No entity in this integration sets an explicit name or translation
key, so none of the IDs above are guaranteed — they follow the device
name, and a renamed device changes the prefix. Confirm the real object
IDs for your own install under **Settings → Devices & services →
[your device] → entities** before using them in an automation.

---

Expand Down Expand Up @@ -148,8 +161,92 @@ data:

---

## Solar control

Charges the car from what the house would otherwise export, adjusting
the limit as production and load change, and stopping when there is not
enough surplus to charge at all.

The controller itself defaults to **off**, so nothing runs before the
entities exist. But the **Solar control** select lands on `simulate`
the first time it is added — a fresh install never actually shows
`off`. In `simulate` it decides and logs but sends nothing to the
charger; nothing reaches hardware until you pick `active` yourself.

1. In the integration's options, pick your **grid import** and **grid
export** power sensors, and answer **grid supply**: single-phase or
three-phase. This is a declaration, not something the integration
can detect — the Daze API does not report how many phases feed the
house — and solar control refuses to arm until it is answered. If
you are upgrading from an earlier version, this is the field that
will make solar control refuse to arm until you go and set it.
2. Leave **Solar control** on `simulate`. The select's attributes show
the surplus it sees and what it would have done.
3. Leave it for a day, then work through the validation checklist
below before switching to `active`.
4. If the decisions look right, set it to `active`.

It never imports to charge: the charger cannot run below 1500 W, so
when surplus falls below that it stops rather than topping up from the
grid.

Changing the charging limit yourself — from the dashboard, or from your
own automation — turns solar control off. Starting or stopping the
charge by hand does the same. It does not fight you.

### When the control is unavailable

Solar control refuses to arm rather than guess, and says why in the
log (`Solar control cannot run: …`). It is unavailable when:

- **Both grid sensors are not set.** It has nothing to measure.
- **The grid supply has not been declared.** The charger cannot tell
the integration how many phases feed the house, so you have to say
so yourself, and there is no default. A three-phase meter reports
surplus added up across all three phases; a single-phase charger can
only use one of them, so following that figure would load one phase
with all three phases' surplus. For the same reason, a **three-phase
supply with a single-phase charger is refused outright** — see the
YAML guide below if that is your setup.
- **The charger's own eco mode is on, or it has a schedule set.**
Something else is already deciding when the car charges, and two
controllers fighting over one charger is worse than either alone.

### The reserve

**Solar reserve** is watts to leave for the house before the car gets
any: set it to 500 and the car is only offered surplus above 500 W. It
is saved with the integration's settings and survives a restart.

### Before you trust it

A day in `simulate` is only useful if you actually check it against
what happened. Before switching to `active`:

- **Does the surplus figure go to zero at night?** If it does not, a
sensor's sign convention is inverted.
- **Does it rise when the car stops charging?** It should not — that
means the car's own draw is being double-counted.
- **Set a schedule on the charger and confirm solar control refuses to
arm, then clear it and confirm it arms again.** This is the one guard
whose positive direction has never been confirmed on real hardware:
it reads the charger's `nextScheduleInfo` field, and all that has
actually been observed is that the field is null when no schedule is
set.
- **Confirm a smart-tariff pause does not populate `nextScheduleInfo`**
and so does not falsely refuse to arm.
- **Check the logged decisions against what actually happened** before
switching to `active`.

For a version you build and tune yourself, see
[docs/solar-surplus-charging.md](docs/solar-surplus-charging.md).

---

## Automation Examples

For charging from solar surplus, see [docs/solar-surplus-charging.md](docs/solar-surplus-charging.md) — a worked setup that follows your export, respects the charger's 1.5 kW floor, and reads its bounds from the entity rather than hardcoding them.

### Stop charging when energy price is high

```yaml
Expand Down Expand Up @@ -231,6 +328,76 @@ The integration is validated with:
- `hassfest` for Home Assistant integration validation
- HACS validation

---

## Credits

This integration was created by **Andrea Restello** ([@arest](https://github.com/arest)).
The upstream project is [arest/daze-addon](https://github.com/arest/daze-addon).

Everything this fork does rests on his work: the integration architecture, the
config flow, the entity model, the sensor catalog and the API client were all
written upstream. He also reverse-engineered the Daze web API, which is not
publicly documented — that is the hard part, and none of what follows would
exist without it.

### Changes in this fork

Maintained by **Pedro Tarrinho** ([@tarrinho](https://github.com/tarrinho)).

Every change below was found by running the integration against a real DT01
wallbox and measuring the API's actual responses, rather than by reading the
code alone.

**Setup**

- Authenticate through the Cognito `GetUser` operation instead of
`/oauth2/userInfo`. The Daze portal issues access tokens scoped
`aws.cognito.signin.user.admin` without `openid`, which `userInfo` rejects,
so setup previously failed for every user with `invalid_token`.

**Reading data**

- Read the live metrics from where the API actually returns them. Power,
energy, currents and voltages arrive nested under `chargeSession`, not at the
top level, so every sensor read `Unknown` with no error logged.
- Fetch the EVSE record as well as the socket state. Temperatures, the grid
limit, eco mode and the configured current appear only there.
- Derive the charger status from the integer `evseState` plus the pause and
error flags. The API never returns the status string the code expected.
- Report `waiting_for_ev`, the state the charger passes through after a start
before the car begins drawing, and hold the charge switch on through it so it
does not appear to snap back.

**Charge control**

- Send the serial number and the session ID with `playcharge` and `stopcharge`.
An empty body is rejected with `ErrorWrongSessionID`, and the session ID alone
is accepted but does nothing.
- Read the session ID from the charger at command time. It changes whenever a
session ends, so a cached copy can name one that has already closed.
- Retry commands through the Daze RPC link, which fails intermittently with
HTTP 500 code 101. Delays grow from 1.5s to 6s across eight attempts, roughly
33 seconds in total, because a tight burst of retries does not outlast the
outage.
- Re-read the charger at 3, 8, 15 and 30 seconds after a command, so a start or
pause shows up promptly instead of waiting for the next poll.

**Robustness and diagnostics**

- Treat HTTP 404 from the recharge-session endpoint as a durable condition.
It was retried every 30 seconds and logged a warning each time.
- Throttle the session history fetch to once every five minutes instead of
requesting up to 1000 records twice a minute.
- Log retried failures at debug and report a single warning only when a command
genuinely gives up, instead of one warning per attempt.
- Add diagnostic tools under `tools/` for reproducing each API call outside
Home Assistant, and tests that use captured API responses as fixtures.

These are bug fixes to someone else's design, not a redesign. If the upstream
project adopts them, this fork becomes unnecessary.

### License

This project is licensed under the [MIT License](LICENSE).
This project is licensed under the [MIT License](LICENSE), Copyright (c) 2025
Andrea Restello, carried over unchanged from the upstream project.
Loading