feat: Add Deye EV Charger (SUN-EVSE22K01-EU) support#1073
Conversation
|
Hey @DJm00n , nice work. Energy: 0x0022 and 0x0023 look like total kWh and today’s charge (today is ×0.1). I matched them to the app counters. You don’t have those as sensors yet. Protection on 0x003B — bit0 leakage(Leakage Current Detection in the app), bit1 grounding(Grounding Detection in the app). Tracks the app toggles and you can write them with FC16. Didn’t see that in the yaml. On reg18 — it’s not just a limit slider. Anything above 0 still clamps to ~6A minimum. Zero is a real hard stop and often throws reg57 into that 641 fault-ish state. with Tesla i sometimes got the red port. Also when you flip WiFi/LoRa on reg21, firmware rewrites reg18 on its own (LoRa tends to slam it to 0, back to WiFi it jumps to 22000), so worth re-setting the limit after a mode change. I also watch reg36 next to reg57 — rough pattern 9 while charging, 4 idle, 0 on EVSE stop. reg44 goes to zero when it’s really stopped. And reg69–72 mirror the schedule times in reg25–28, same numbers. The 76/77/78 block — i log them but honestly still guessing. 77 often goes 1 on EVSE-side stop or in LoRa-y states, usually 0 when charging on WiFi. Tried writing 77 and 78 — ACK but read-back stays 0, so probably status not control. 76 mostly sits at 1, not much movement. Wouldn’t wire them as switches yet, more like extra context when you’re debugging reg57. Raw reg57 fingerprints i kept for diffs: 416 charging, 392 done/idle, 385 unplugged, 641 EVSE 0W stop, 897 saw once on LoRa flip. Your byte split on 57 is probably the right way to show it — i just kept the raw numbers. One naming trap: your Program 1 time on 0x0019 matches what i have (that’s decimal reg 25, time code hour*12 + min/5). Your off-grid switch is on 0x0025 though — that’s reg 37, not 25. Easy to read "25" in the hex and think it’s the first schedule slot. I haven’t confirmed off-grid on my side yet (reg37 was usually 0), but if you’ve seen that bit follow the inverter UI it’s probably right — just worth calling out so nobody mixes the two addresses. Happy to sync or dump snapshot refs if any of it helps. I did a lot of snapshots of all the regs 0-79 while changing the car/evse/charger port states. The most awful part is the lack of "clean" stop/suspend of the charging. Ive sent a feedback to their support and waiting for solution. |
|
Hey @Stormhand, thanks a lot, your findings were really valuable. We've incorporated all of them into the PR. On the 0x0081 transition - yes, I've seen the same thing. When the EVSE drops into that state mid-session (due to low PV in Solar-only mode for example), my e-Tron actually tries to close its charge port flap, which means the car sees it as a completed session. Looks like a state machine bug on the EVSE side rather than anything we can work around in the profile. Interestingly, Deye support reached out a couple of days ago and offered a firmware update - I agreed, but it hasn't been pushed to my unit yet. Fingers crossed they've already fixed this in the new build; will report back once it lands. Right now I have: |
|
My EVSE firmware version is the same. |
|
@DJm00n i found that the times are not displayed properly because of the strange deye format for the minutes(*5) so if i have start time 10:30 its gonna be displayed as 10:06. |
|
@Stormhand should work in latest revision. Added code-fix for this case. |
|
Do I need to wait for a new solarman version? |
|
@Stormhand yes. Or maybe you can sync to the latest testing and replace corresponding files on your home assistant instance with files from this PR. |
a1f2a8e to
05aacb8
Compare
|
Hola. Soy un poco nuevo en esto de las integraciones. Me podéis ayudar? He creado el archivo deye.evse.yaml y he pegado el código. Pero ahora no se como tengo que agregar el dispositivo. Tengo el cargador conectado por LORA al inversor. Que ip tengo que poner? La del cargador o la del inversor? El inversor lo tengo bien agregado. Y que mas datos tengo que poner para agregar el cargador? Muchas gracias de antemano. |
|
@Jairo2106 you have to put ip address of evse that is connected to your wifi. also, dont forget to set "modbus slave id" 3 under additional options: |
|
Si pongo la ip del EV no carga, me da error. Será porque lo tengo con protocolo LORA ??? |
|
@Jairo2106 No, the EV charger can operate simultaneously via both LoRa and Wi-Fi. If “Working mode 2 - LoRa” is selected, the Wi-Fi connection will be used for monitoring, and LoRa will be used for control from the inverter. Please refer to the manual. |
Adds support for the Deye AC EV Charger (SUN-EVSE11K01-EU/SUN-EVSE22K01-EU) with full profile, autodetection, and automatic slave ID discovery. All register interpretations and state machine values are based on direct firmware reverse-engineering (MCU9_EV_C020_EU_3_26.bin). Profile (deye_evse.yaml): - Info: device type (0x0904), serial, firmware/protocol version, model class (22 kW / 11 kW EV Charger from register 0x0013 hi-byte) - Configuration: inverter LoRa link status, date/time, charging start mode, communication mode, LoRa channel, grid voltage protection thresholds, off-grid charge inhibit - Time Of Charge: 4 scheduled charge time points with enable switches - Control: charging power limit setpoint (0–22000 W, IEC 61851 clamping noted) - State: Charging Control State and Charging Operational State (register 0x0039), split by high/low byte, state machine values from firmware handlers, update_interval: 2 to capture short-lived transitions - Grid: Grid Capacity (0x0038, dynamic firmware-computed power cap), Grid Voltage L1–L3 - Fault: Charger Fault binary_sensor (0x0036), 11-bit bitmask with confirmed bit assignments; Stuck Relay (bit 6) is a current-based relay detector, Overtemperature (bit 7, ≥110°C), Undertemperature (bit 8, <−40°C) - Charging: per-phase and total power, charging voltage L1–L3, charging current L1–L3, Relay Temperature 1/2 (0x001D, two NTC sensors packed in one register, −50°C offset) - Energy: total and daily EV charge counters Autodetection (const.py): - Register value 0x0904 mapped to deye_evse.yaml via AUTODETECTION_DEYE_EVSE Slave ID discovery (device.py): - setup() retries slave IDs 1→2→3 if ProfileProvider.init() fails, so the EVSE (which uses slave 3) is found automatically without user configuration Parser/time fixes: - parser.py, time.py: support `mul` parameter for time entity encoding, required by EVSE Time Of Charge registers (5-minute slots, dec: 12, mul: 5) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>





Adds support for the Deye AC EV Charger (SUN-EVSE11K01-EU/SUN-EVSE22K01-EU) with full profile, autodetection, and automatic slave ID discovery.
This PR extends the EVSE support that was partially introduced in PR #1065 (inverter-based control via the LoRa communication channel).
NOTE: Deye has not published an official Modbus specification for the EV Charger. All register mappings in this profile are based on reverse engineering. Special thanks to @Stormhand for his reverse engineering work that made this possible and @ZajoCZ for MCU9_EV_C020_EU_3_26.bin firmware file.
Profile (deye_evse.yaml):
Autodetection (const.py):
Slave ID discovery (device.py):
EVSE (which uses slave 3) is found automatically without user configuration
Parser/time fixes:
mulparameter for time entity encoding,required by EVSE Time Of Charge registers (5-minute slots, dec: 12, mul: 5)
EVSE State Diagram:
stateDiagram-v2 direction TB [*] --> Available : system init Available : Available · 0x01, CP = +12V DC (IEC A) Finishing : Finishing · 0x02, CP = +12V DC Preparing : Preparing · 0x04, CP = +12V DC (IEC B, EVSE not ready) SuspendedEV : Suspended EV · 0x08, CP = PWM (IEC B, EVSE ready) SuspendedEVSE : Suspended EVSE · 0x10, CP = +12V DC (IEC B, EVSE withdrawn) Charging : Charging · 0x20, CP = PWM · relay ON (IEC C) Faulted : Faulted · 0x40, relay OPEN Available --> Preparing : EV plugs in, [FUN_0000b44c] Available --> SuspendedEVSE : auth received before EV, [FUN_0000b484] Available --> Faulted : relay fault, [FUN_0000ba24] Finishing --> SuspendedEV : EV plugs in (immediate PWM), [FUN_0000b44c] Finishing --> Charging : auth active + current ≥ 6A, [FUN_0000b484] Finishing --> Faulted : relay fault Preparing --> Available : EV unplugs, [FUN_0000b50c] Preparing --> SuspendedEV : auth OK (2s timer), [FUN_0000b5c8] Preparing --> Faulted : relay fault SuspendedEV --> Charging : EV closes S2 (2s timer · auth · current ≥ 6A), [FUN_0000b698] SuspendedEV --> Finishing : EV unplugs, [FUN_0000b50c] SuspendedEV --> Preparing : auth revoked / current < 6A, [FUN_0000b8cc] SuspendedEV --> Faulted : relay fault SuspendedEVSE --> Available : EV unplugs, [FUN_0000b55c] SuspendedEVSE --> Available : auth revoked (no EV), [FUN_0000b968] SuspendedEVSE --> Charging : EV closes S2 (unconditional · no auth check), [FUN_0000b74c] Charging --> Finishing : normal stop (EV unplugs), [FUN_0000b55c] Charging --> SuspendedEVSE : auth revoked (relay open · 3s PWM timer set), [FUN_0000b7c0→b880] Charging --> SuspendedEV : EV opens S2 (CP B · relay open), [FUN_0000b84c] Charging --> Faulted : relay fault, [FUN_0000ba24] Faulted --> Available : relay opens (auto-recovery), [+0x66=1]