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. This integration bridges the gap, bringing your wallbox into Home Assistant alongside all your other smart home devices.
This integration was created and is maintained by Andrea Restello (@arest). Thanks to Pedro Tarrinho (@tarrinho) for major bug-fix contributions originally developed against a DT01 charger — see Contribution highlights.
- 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
- 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
- Diagnostics — Grid max power, photovoltaic presence, three-phase supply info
- Fully UI-driven — Set up entirely through the Home Assistant UI, no YAML editing required
- Make sure HACS is installed in your Home Assistant instance
- Go to HACS → Integrations
- Click the three dots in the top-right corner and select Custom repositories
- Add this repository URL:
https://github.com/arest/daze-addon - Select Integration as the category and click Add
- Close the dialog — the Daze Wallbox integration should now appear in HACS
- Click Install on the Daze Wallbox card
- Restart Home Assistant
- Copy the
custom_components/daze/directory from this repository into your Home Assistantcustom_components/directory - Restart Home Assistant
The Daze web portal does not show tokens anywhere in its UI, and there is no separate Daze developer console to sign in to. Signing in creates the tokens, and the portal keeps them in your browser's local storage. You read them from your own browser:
- Sign in at webportal.dazeservice.com.
- Open your browser's developer tools:
- Chrome / Edge:
F12, orCtrl+Shift+I(Cmd+Option+Ion macOS) - Firefox:
Ctrl+Shift+I(Cmd+Option+Ion macOS) - Safari: first enable Develop → Show Web Inspector in Settings
- Chrome / Edge:
- Open local storage:
- Chrome / Edge: Application → Storage → Local Storage →
https://webportal.dazeservice.com - Firefox: Storage → Local Storage →
https://webportal.dazeservice.com - Safari: Storage → Local Storage →
https://webportal.dazeservice.com
- Chrome / Edge: Application → Storage → Local Storage →
- Find the key ending in
.LastAuthUser. Its value is your portal username. The full key looks like this:CognitoIdentityServiceProvider.4m0rp7oqarbrc3hn67ivvonba8.LastAuthUser - Copy the values of the two keys that start with the same prefix and
end in
.<username>.accessTokenand.<username>.refreshToken. For the usernameyou@example.com, they look like this:CognitoIdentityServiceProvider.4m0rp7oqarbrc3hn67ivvonba8.you@example.com.accessToken CognitoIdentityServiceProvider.4m0rp7oqarbrc3hn67ivvonba8.you@example.com.refreshToken - Paste each value into the matching field in Home Assistant. Copy the whole value, without the quotes a developer tools view may add.
If you prefer not to hunt through the storage table, run this in the browser console while the signed-in portal tab is open. It prints both tokens:
(() => {
const prefix = "CognitoIdentityServiceProvider.4m0rp7oqarbrc3hn67ivvonba8.";
const username = localStorage.getItem(prefix + "LastAuthUser");
const accessToken = localStorage.getItem(`${prefix}${username}.accessToken`);
const refreshToken = localStorage.getItem(`${prefix}${username}.refreshToken`);
if (!username || !accessToken || !refreshToken) {
throw new Error("Sign in at webportal.dazeservice.com in this tab first.");
}
console.log("accessToken:", accessToken);
console.log("refreshToken:", refreshToken);
})();The access token is short-lived — about an hour — so copy it immediately before starting setup. The refresh token lasts much longer; it is what keeps the integration running without asking you to sign in again.
Treat both tokens as passwords. Anyone holding the refresh token can reach your wallbox. Do not paste them into GitHub issues, chats, or screenshots. If a token has been exposed, sign out of the portal to end that session, then copy a fresh pair.
- Go to Settings → Devices & services
- Click Add integration and search for Daze Wallbox
- Enter your Daze Access Token and Refresh Token (see Getting your tokens above)
- Click Submit — the integration validates your tokens
- Select your network (installation location) from the list
- Review the confirmation screen with your wallbox details
- Click Submit to complete setup
The wallbox should now appear as a single device with all sensors and controls grouped under it.
If your tokens expire, the integration will automatically prompt you to re-enter them through the HA UI. You'll see a notification and a re-authentication flow.
| Entity ID | Name | Device Class | State Class | Unit |
|---|---|---|---|---|
sensor.daze_instant_power |
Instant Power | power |
measurement |
W |
sensor.daze_delivered_energy |
Delivered Energy | energy |
total_increasing |
Wh |
sensor.daze_charging_current_l1 |
Charging Current L1 | current |
measurement |
mA |
sensor.daze_charging_current_l2 |
Charging Current L2 | current |
measurement |
mA |
sensor.daze_charging_current_l3 |
Charging Current L3 | current |
measurement |
mA |
sensor.daze_ac_voltage_l1 |
AC Voltage L1 | voltage |
measurement |
V |
sensor.daze_ac_voltage_l2 |
AC Voltage L2 | voltage |
measurement |
V |
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 / waiting_for_ev / charging / paused / error / offline |
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 |
| Entity ID | Name | Device Class | Category |
|---|---|---|---|
sensor.daze_grid_max_power |
Grid Max Power | power |
diagnostic |
sensor.daze_is_photovoltaic |
Photovoltaic Present | enum |
diagnostic |
sensor.daze_is_three_phase |
Three-Phase Supply | enum |
diagnostic |
| Platform | Entity ID | Name | Purpose |
|---|---|---|---|
| Switch | switch.daze_charge_control |
Charge Control | Start / stop charging |
| 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.
These services are available for automations and scripts:
Start charging on a Daze wallbox.
service: daze.start_chargeStop charging on a Daze wallbox.
service: daze.stop_chargeSet the maximum charging current.
| Field | Required | Description |
|---|---|---|
current |
Yes | Maximum charging current in milliamps (mA). Range: 6000–32000, step 100. |
service: daze.set_charging_current
data:
current: 16000Charges 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.
- In the integration's options, pick one signed grid power sensor and
answer grid supply: single-phase or three-phase. Positive grid power
means import; negative grid power means export. If your meter exposes
separate positive import and export sensors, create a signed helper first
as shown in
docs/solar-surplus-charging.md. Grid supply 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, select the new signed sensor here before arming solar control. - Leave Solar control on
simulate. The select's attributes show the surplus it sees and what it would have done. - Leave it for a day, then work through the validation checklist
below before switching to
active. - If the decisions look right, set it to
active.
Pick an instantaneous net-grid power sensor in watts (W). Positive = importing (drawing from grid). Negative = exporting (feeding back to grid). The integration will not accept energy totals (kWh) or sensors in any unit other than W.
Correct choices:
- Your home grid meter / utility meter sensor.
- If your charger exposes net-grid power as an instantaneous reading in W, that works too.
Do not use:
- PV / solar production alone. PV output is never negative — it cannot represent export. Grid export happens only when PV exceeds total house draw.
- House load alone. House load is a positive consumption figure; it never goes negative to represent export.
- Charger power. That is the car's draw, not the grid exchange.
- kWh totals. The controller needs instantaneous W to compute surplus per tick.
Adding charger draw back into the signal: solar control computes
surplus as car_draw - grid_power, so when the car is charging the
charger's own draw gets subtracted from the grid power reading.
During a healthy solar charge the grid meter naturally settles near
zero W — that is expected.
Battery homes — virtual signed-grid template:
A worked example of this, measured on a running installation with the arithmetic checked against real readings, is in docs/solar-control-in-practice.md. It also covers how to confirm your house-load figure includes the charger, which decides whether this template is correct or a feedback loop.
If your house has a battery, the physical grid meter may sit at or near zero even when solar surplus exists, because the battery absorbs it. Use a template that subtracts PV from house load so solar control sees what would have hit the grid:
value_template: >
{% set pv = states('sensor.<pv_power>') | default(0) %}
{% set house = states('sensor.<house_load_power>') | default(0) %}
{{ (house | float) - (pv | float) }}Replace <pv_power> and <house_load_power> with your actual
sensor IDs. House load must include the charger if you want the
template to reflect reality while the car is charging. Add an
availability guard so a dropped sensor does not silently appear as
full PV surplus:
value_template: >
{% set pv = states('sensor.<pv_power>') %}
{% set house = states('sensor.<house_load_power>') %}
{% if pv in ['unknown','unavailable'] or house in ['unknown','unavailable'] %}
unavailable
{% else %}
{{ (house | float) - (pv | float) }}
{% endif %}Verification before you trust it:
- Does the value go to zero at night when the car is idle? If it does not, the sign convention is inverted.
- Does it rise (become more positive) when the car stops charging? Without the template above, the grid meter may stay flat because the battery is absorbing the change.
- At midday, with PV running and the car idle, does the value turn negative (export)? If it stays positive, the template is inverted or the PV sensor is reading energy rather than power.
Optional smoothing: a Statistics sensor with a 3–5 minute
state_round window averages out short spikes and can make the
surplus calculation more stable. Not required — pick one or the
other.
Battery SoC floor: a battery's minimum state-of-charge (SoC) limit is a separate automation in Home Assistant. Solar control does not know about SoC floors and should not be relied on to protect them.
The 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.
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.
Solar control refuses to arm rather than guess, and says why in the
log (Solar control cannot run: …). It is unavailable when:
- The signed grid power sensor is 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.
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.
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
nextScheduleInfofield, 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
nextScheduleInfoand 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.
For charging from solar surplus, see 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.
If you run automations alongside solar control — a cheap-rate window, a house-battery floor — read docs/automations-with-solar-control.md first. Any automation that commands the charger turns solar control off, nothing re-arms it, and the examples there include the re-arm that closes the gap.
automation:
- alias: "Stop Daze charging during peak hours"
trigger:
- platform: time
at: "17:00:00"
condition:
- condition: state
entity_id: switch.daze_charge_control
state: "on"
action:
- service: daze.stop_chargeautomation:
- alias: "Adjust Daze charging to solar surplus"
trigger:
- platform: numeric_state
entity_id: sensor.solar_production
above: 3000
action:
- service: daze.set_charging_current
data:
current: 16000Make sure you copied the full values of the accessToken and
refreshToken entries, not the idToken and not the .LastAuthUser
value. Tokens must be active (not expired), so copy a fresh pair from the
portal just before setup — see Getting your tokens.
If it still fails, python3 tools/check_daze_tokens.py reports which
token was rejected without printing either one.
- Check your internet connection — the Daze API is cloud-based
- Verify your wallbox is online (check the Daze mobile app)
- The integration automatically retries; entities become available again once the API responds
If your refresh token has expired, the integration will trigger a re-authentication flow. Follow the prompts in Settings → Devices & services to enter new tokens.
- The integration polls every 30 seconds by default
- If the Daze API returns errors, the coordinator retries automatically
- Check the Home Assistant logs for Daze-related error messages
The integration automatically refreshes data after sending a start/stop/current command. If values don't update, wait for the next scheduled poll cycle.
Not every charger populates every field the Daze API defines. On a Dazebox C (device profile DB07), a user reported that voltage, the two temperatures, lifetime energy and total sessions are never reported — and the Daze web portal shows the same gaps, so the readings are genuinely absent rather than lost on the way through.
Those entities stay unavailable rather than reading zero. That is deliberate: a missing measurement is not a measurement of zero, and publishing it as 0 V or 0 kWh would put a false value into your history and, for the energy totals, record it as a meter reset.
To check whether a reading is missing at the source, open the same charger in the Daze web portal. If the portal shows nothing or zero there too, the charger is not reporting it and there is nothing the integration can recover.
- Daze WallBox EV chargers accessible via the Daze REST API
- Tested against the DT01 device profile, and reported working on a Dazebox C (device profile DB07, firmware 14.0.0) by a user
Which readings you get depends on the charger. See the troubleshooting note below on readings the API does not report.
- All data flows through the Daze cloud API — no local/offline control
- The integration stores only your access token and refresh token, in the Home Assistant config entry. As with every integration, that means plain text in
.storage/core.config_entries— Home Assistant does not encrypt config entry storage. Treat your configuration directory and your backups as holding live credentials. - The stored tokens are the ones you entered at setup, or at your last re-authentication. Refreshing an access token updates it in memory only and never writes it back, so what is on disk does not rotate on its own. Two things follow: an old backup can still hold a usable refresh token, and every restart begins again from the tokens stored at setup — which is why an integration that has been running for weeks can still ask you to re-authenticate after a restart.
- No data is sent to third parties beyond the Daze API
The integration is validated with:
- ruff for linting
- pyright for type checking
hassfestfor Home Assistant integration validation- HACS validation
This integration was created by Andrea Restello (@arest). The upstream project is arest/daze-addon.
Everything this project does rests on his work: the integration architecture, config flow, entity model, sensor catalog and 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.
The following fixes were contributed by Pedro Tarrinho (@tarrinho) and merged here.
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
GetUseroperation instead of/oauth2/userInfo. The Daze portal issues access tokens scopedaws.cognito.signin.user.adminwithoutopenid, whichuserInforejects, so setup previously failed for every user withinvalid_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 readUnknownwith 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
evseStateplus 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
playchargeandstopcharge. An empty body is rejected withErrorWrongSessionID, 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 the existing design, not a redesign.
This project is licensed under the MIT License, Copyright (c) 2025 Andrea Restello, carried over unchanged from the upstream project.