Language: English · 中文
A vendor-agnostic Home Assistant integration for EV chargers. One HA integration, a pluggable Provider SPI, support for many brands. Currently bundled: Geely Galaxy / Direct Wallbox (吉利银河 / 浩瀚能源).
- ⚡ Start / stop charging remotely (switch, Siri-controllable via HomeKit)
- 📊 Live status: idle / charging / plugged / online / offline / fault
- 🔋 Live telemetry during charge: current, voltage, power, kWh, elapsed time
- 🩺 Health checks: voltage / grounding / network / faults
- 🔧 Diagnostics: firmware version, OTA availability, active charging user
- 🔑 Token lifecycle monitoring: access / refresh token remaining time + state-change events (thresholds tunable via UI)
- 🍎 HomeKit / Siri / Mijia / XiaoAi bridge-friendly via HA's built-in HomeKit Bridge
| Provider key | Brand / hardware | Login methods | Status |
|---|---|---|---|
geely |
Geely Galaxy / 浩瀚能源 (DIRECT_WDZ, etc.) | SMS / Token file / paste JWT | ✅ Author-tested |
| PRs welcome | TELD / Star Charge / YKC / Zhida / NIO / XPeng / … | — | 🤝 Recruiting |
See
docs/PROVIDER-GUIDE.mdfor how to add a new vendor.
Using custom repositories:
- HACS → three-dot menu → Custom repositories
- Repository:
https://github.com/jiusanzhou/evse-hub-ha - Type:
Integration - Save, then search for EVSE Hub in HACS and install
- Restart Home Assistant
cd /path/to/evse-hub-ha
./install-ha.sh
# Remote HAOS:
HA_SSH=ha HA_PATH=/mnt/data/supervisor/homeassistant ./install-ha.sh
ssh ha "docker exec hassio_cli ha core restart"When adding the integration you pick a provider first, then follow that provider's login flow.
No prerequisite setup — the integration ships with the current Geely Galaxy app client parameters baked in, so you can install and log in right away.
Overriding the built-in AppSecrets
The GEELY_RECHARGE_SECRET / GEELY_GALAXY_SECRET values that sign
gateway requests are client-fixed parameters — the same for every
Geely Galaxy app install, not per-user credentials. They're comparable
to the client_id / base_url that many other HA integrations hard-code.
If the vendor ever rotates them, override with either:
# Option 1: environment variables (highest priority)
export GEELY_RECHARGE_SECRET=<new value>
export GEELY_GALAXY_SECRET=<new value>
# Option 2: /config/.evse_hub_secrets.json
{
"geely_recharge_secret": "<new value>",
"geely_galaxy_secret": "<new value>"
}Extract fresh values from the app following
docs/capture-guide.md.
| Method | One-time cost | Ongoing maintenance | Status |
|---|---|---|---|
| A. SMS login ⭐ | Phone number + slider + one SMS | Auto-refresh every 7 days; re-login after 30 days | ✅ Recommended |
| B. Token file | Android emulator + capture login once | Daemon auto-refreshes | ✅ |
| C. Paste JWT manually | Capture / obtain token once | Re-paste every 7 days | ✅ Emergency |
New users should just use A — no extra tooling required.
Method A: SMS login (recommended, zero setup)
- HA → Settings → Devices & services → Add integration → search EVSE Hub
- Pick provider Geely Galaxy / 浩瀚能源
- Pick auth method "SMS login (recommended, one-click)"
- HA gives you a URL (
/api/evse_hub/auth?session=...) — open it in a phone browser on the same network - On the page: enter phone number → complete slider CAPTCHA → enter 6-digit SMS code → submit
- Page shows "🎉 login successful", then submit the HA form → integration persists the token
Technical note: SMS login is a 6-step chain (galaxy security config →
geeTestV4/validate → sendSms → mobileCodeLogin → oauth2/code → api-recharge
getTokenByCode). All signing (including Alibaba API Gateway's alphabetical
query-arg rules) is implemented in provider/geely/sms_auth.py.
Method B: Android emulator + token daemon (unattended, long-term)
- Set up an Android emulator (Google APIs image, needs root), install the Geely Galaxy app, log in
- Capture the login response with mitmproxy — or after rooting, read
/data/data/com.geelygalaxy.customer/files/mmkv/directly
Write the token to ~/.geely_jwt.json:
{
"accessToken": "eyJ...",
"refreshToken": "eyJ...",
"sub": "your userId",
"expiresAt": 1234567890,
"refreshExpiresAt": 1234567890
}python3 tools/geely_jwt_daemon.py &Every 30 minutes the daemon:
- pulls the latest JWT from the emulator's MMKV storage
- checks expiry and auto-refreshes when close
- optionally syncs to HA over SSH (
HA_TOKEN_DEST)
When adding the integration, pick "Token file" and enter the token path
(default /config/geely_jwt.json).
Method C: Paste JWT manually (emergency, 5-minute setup)
- Use mitmproxy / Charles on your phone to capture the login response from
api.geely.com - Pull out
accessToken,refreshToken,sub(your userId) - In the HA add-integration flow, pick "Paste JWT manually (emergency)" and paste the three values
- The integration writes
/config/geely_jwt.jsonand runs in Token-file mode - After 7 days, if the daemon isn't running, you'll need to re-paste
After install, Settings → Integrations → EVSE Hub → CONFIGURE:
| Field | Unit | Default | Meaning |
|---|---|---|---|
| Poll interval | seconds | 30 | Coordinator poll frequency |
| Access-token warning threshold | hours | 24 | Fire warning event below this |
| Access-token critical threshold | hours | 2 | Fire critical event below this |
| Refresh-token warning threshold | days | 3 | Fire needs_relogin event below this |
Event name: evse_hub_token_state.
- HomeKit / Siri: see
docs/homekit-setup.md - Xiaomi / Mijia / XiaoAi: see
docs/homekit-mijia.md
| Entity | Kind | Description |
|---|---|---|
switch.charger_charging |
switch | Start / stop charging |
sensor.charger_status |
sensor | idle / charging / fault / offline |
sensor.charger_power |
sensor (kW) | Live power |
sensor.charger_current / _voltage |
sensor (A/V) | Live current / voltage |
sensor.charger_session_energy |
sensor (kWh) | Energy delivered this session |
sensor.charger_duration |
sensor (min) | Duration of this session |
sensor.charger_firmware / _active_user |
sensor | Diagnostics |
binary_sensor.charger_plugged / _charging / _online |
binary | State |
binary_sensor.charger_health / _fault / _update_available |
problem/update | Diagnostics |
sensor.access_token_remaining / refresh_token_remaining / token_status |
sensor/enum | Token lifecycle |
(Actual entity names follow the charger's Chinese display name in Geely's app; you can rename them in HA.)
Token about to expire → Telegram notification:
automation:
- alias: "Charger token needs relogin"
trigger:
- platform: event
event_type: evse_hub_token_state
condition:
- condition: template
value_template: >
{{ trigger.event.data.new_state in ['warning','critical','needs_relogin','expired'] }}
action:
- service: notify.telegram
data:
message: >
🔌 Charger token state: {{ trigger.event.data.new_state }}
Access left: {{ trigger.event.data.access_remaining_hours }} h;
Refresh left: {{ trigger.event.data.refresh_remaining_days }} d.More examples (off-peak auto-charge, session-end notifications, fault alerts,
Lovelace cards) in examples/.
┌────────────────────────────────────────────┐
│ Home Assistant │
│ │
│ ┌── coordinator (30s poll) ──┐ │
│ │ ↓ │ │
│ │ Equipment / ChargeStatus │ ← unified │
│ │ ↑ │ models │
│ │ Provider SPI │ │
│ │ ↑ │ │
│ │ ┌─────┴──────┐ │ │
│ │ │ │ │ │
│ ▼ ▼ ▼ │ │
│ geely starcharge (future) … │ │
│ │ │ │ │
└──┼────────┼───────────────────┘
│ │
▼ ▼
api-recharge.geely.com …vendor cloud
Design pillars:
- Provider SPI: vendor adapters implement the
ProviderABC (list_equipments,get_status,start_charge,stop_charge, …) - Unified data model:
Equipment,ChargeStatus,TokenBundle,Health,Versions— entity layer never sees vendor-specific fields - Pluggable: adding a vendor = writing one
provider/<key>/package and@register_provider. Seedocs/PROVIDER-GUIDE.md
# custom_components/evse_hub/provider/starcharge/__init__.py
from ...models import Equipment, ChargeStatus, TokenBundle
from .. import Provider, register_provider
@register_provider
class StarChargeProvider(Provider):
key = "starcharge"
display_name = "Star Charge"
supports_sms_login = True
async def load_token(self, token_path): ...
async def list_equipments(self, bundle): ...
async def get_status(self, bundle, eq): ...
async def start_charge(self, bundle, eq): ...
async def stop_charge(self, bundle, eq, order_id=None): ...Full guide: docs/PROVIDER-GUIDE.md
Requesting a new provider? Use the 📦 New Provider Request issue template.
- Auth lifetime varies by provider. Geely refresh tokens last 30 days; the
evse_hub_token_stateevent warns you in time. - SMS slider SDK needs public network. GeeTest v4 (
captcha4.geely.com) must be reachable — pure-offline setups can't SMS-login. - Field names may differ across chargers. The Geely provider is currently only verified on Galaxy E5 +
DIRECT_WDZ. Please open issues with captures for other models. - Signing is vendor-private. Support comes from interoperability research; if the vendor changes its algorithm, this integration may break temporarily.
- HomeKit Bridge is capped at 150 accessories. If your household has lots of Mijia devices, run a dedicated bridge for the charger to avoid the cap.
- 🐛 Issues — bugs, model coverage, feature requests
- 🔧 PRs welcome, especially:
- New provider adapters (TELD / Star Charge / YKC / NIO / XPeng / …)
- Field-adapter tweaks for additional charger models
- Getting the integration into the HACS default store
- MQTT Discovery variant
docs/PROVIDER-GUIDE.md— how to write a providerdocs/capture-guide.md— how to capture tokens from a vendor appdocs/api-reference.md— known API endpoint referencedocs/deployment.md— full deployment walk-throughdocs/troubleshooting.md— common problemsdocs/research/— interoperability research methodology
- This project is a personal interoperability research effort, intended for learning and to let users connect their own chargers to their own smart home.
- It does not provide any capability to bypass paywalls, defraud billing, perform mass access, or operate on other people's accounts. Users must own or have permission to control the charger they connect.
- The compatibility layer uses publicly reachable HTTPS endpoints with the user's own credentials; it does not redistribute proprietary software or circumvent commercial licensing.
- Official APIs may change without notice; the author makes no availability guarantee.
- Any loss (vehicle, appliance, account ban, …) resulting from use of this project is the user's responsibility.
- If a vendor takes issue with this project's positioning, please open an issue — the author will cooperate on adjustments.
MIT
