All notable changes to this project will be documented in this file.
ChargePower/HousePower(andFVPower,BatteryPower,GridPower) showedWwhile the value was actuallykWin cloud-only (4G) mode (#42). The cloud→LAN synthesis scaled these power fields by 1000 only when avoltage/voltageinstallationfield happened to be present in the payload and below 10 — an unrelated heuristic that silently skipped the conversion on accounts where that field was absent or out of range. The cloud always reports power measurements in kW, so the kW→W conversion is now applied unconditionally, the same wayContractedPoweralready is.
- SBOM assets (SPDX-JSON / CycloneDX-JSON) no longer attached to releases. Since they were introduced in
1.3.0, every release shipped 3 assets instead of 1 (v2c_cloud.zipplus the two SBOM files). HACS' download counter readsdownload_countfrom the release's asset list and is known to pick the wrong entry when more than one asset is present (see hacs/integration#4438), which tracked with the integration's HACS download count going blank. Releases now publish onlyv2c_cloud.zip.
Maintenance release. No functional change to the integration — runtime code,
entities and the config-entry schema are identical to 1.3.1. Dependency,
test-tooling and CI-action updates only. Full suite (474 tests), the ruff
lint + format gates and the pip-audit dependency audit re-verified green
against every bumped pin.
Supersedes the unreleased
1.3.2commit: its release pipeline failed on thesecuritygate (a fresh batch of aiohttp test-only advisories landed) before any tag or artifact was published. This release folds in that audit fix.
ruff0.15.16 → 0.15.17 (requirements.txt, Dependabot #30) — lint + format gates re-verified clean.pip>=26.1.1 → >=26.1.2 (requirements.txt, Dependabot #35).pytest>=9.0.3 → >=9.1.0 (requirements_test.txt, Dependabot #33, upper bound<10retained).pytest-asyncio>=1.3.0 → >=1.4.0 (requirements_test.txt, Dependabot #32, upper bound<2retained).codecov/codecov-actionv6.0.1 → v7.0.0 (Dependabot #37) — removes an internal license-compliance workflow; no input/output changes for callers.gitleaks/gitleaks-actionv2 → v3.0.0 (Dependabot #34) — runtime Node 20 → Node 24, no input/output/behaviour changes; clears the Node 20 deprecation ahead of GitHub's 2026-09-16 runner removal.home-assistant/actions/hassfestpinned SHA refreshed to upstreammaster(Dependabot #36).
- 11 aiohttp advisories now affect the pinned test dependency
aiohttp<3.14(requirements_test.txt): the original CVE-2026-34993 / CVE-2026-47265 plus a fresh batch (CVE-2026-50269 and CVE-2026-54273…54280), every one fixed only in aiohttp 3.14.0/3.14.1. The upgrade to aiohttp 3.14 (Dependabot #31) was verified to break the entire test suite —aioresponses0.7.8 (its latest release) does not pass thestream_writerkwarg that aiohttp 3.14 made mandatory. End users are unaffected: the integration ships"requirements": []; the patched aiohttp is provided by Home Assistant core at runtime. The advisories are scoped to the test harness — thesecurity.yamltest-deps audit now ignores all 11 (runtime audit stays--strictwith zero ignores), and the matching Dependabot alerts are dismissed astolerable_risk— untilaioresponsesships a 3.14-compatible release. The durable fix (migrating offaioresponses) is tracked in the backlog.
Maintenance release. No functional change to the integration — runtime code,
entities and the config-entry schema are identical to 1.3.0. Dependency and
CI-tooling updates only.
ruff0.15.13 → 0.15.16 (requirements.txt, Dependabot #26) — lint + format gates re-verified clean against the bumped pin.softprops/action-gh-releasev2.5.0 → v3.0.0 intag-and-release.yaml(Dependabot #29). v3.0.0 moves the action runtime from Node 20 to Node 24 (no input/API changes); this clears the Node 20 deprecation ahead of the 2026-06-16 GitHub Actions enforcement, matching theactions/stalev10 bump shipped in1.3.0.
Stable release. Promotes the 1.3.0 line to general availability after the
public beta window (beta.1 2026-05-19 → beta.3 2026-06-01) closed with no
regressions reported. No code changes relative to 1.3.0-beta.3.
This is the cumulative 1.2.x → 1.3.0 change set, developed and validated
across the three pre-releases listed below. The integration gains full V2C
Cloud endpoint coverage, automatic multi-charger discovery, a LAN-vs-cloud
control router, and substantially better cloud-only (4G) behaviour.
Breaking (auto-migrated): the config entry schema is upgraded from v1 to v2 on first load — no user action required. Rolling back to
1.2.xis not supported; see Upgrade / downgrade notes below.
- Full V2C Cloud endpoint coverage – 10 new client methods cover every previously missing public endpoint:
start_charge,pause_charge,intensity,locked,dynamic,chargefvmode,max_car_int,min_car_int,denka/max_power, andGET /device/connected. Each is exercised by dedicated tests intests/test_cloud_endpoints_1_3.py. - 10 new Home Assistant services:
start_charge,pause_charge,set_charge_intensity,set_locked,set_dynamic,set_fv_mode,set_max_car_intensity,set_min_car_intensity,set_denka_max_power,get_connected_status. The first five use the LAN-vs-cloud router; the photovoltaic and Denka calls are cloud-only. - Automatic multi-charger discovery – an account with N chargers is fully supported. Every charger's LAN IP is sourced from the cloud
/pairings/meresponse at runtime and a normalised snapshot is persisted on every successful refresh (entry.data["cached_pairings"]). During a cloud outage every previously-seen charger stays addressable via its last-known IP; when the cloud returns, the cache is reconciled (added devices appear, removed devices disappear). Replaces the single user-typed fallback IP. - Smart LAN-vs-cloud router (
local_api.async_route_local_or_cloud) – control commands shared between LAN (/write/) and cloud (/device/*) prefer the LAN path and transparently fall back to the cloud endpoint when LAN is unreachable or the device is cloud-only. Covers start/pause charge, intensity, locked, dynamic. Controls with no cloud endpoint (LightLED,ContractedPower,Timer,PauseDynamic,ChargeMode,DynamicPowerMode) raise a clear, user-facingHomeAssistantErrorin cloud-only mode instead of silently dropping the write. - Editable connection type – an options-flow
Local (Wi-Fi)/Cloud only (4G)toggle switches modes post-setup and triggers an automatic integration reload. ChargeModeselect (monophasic / threephasic / mixed) andLightLEDnumber (0-100 %) entities.- User-configurable local refresh interval (5-300 s, default 30 s) via the Reconfigure dialog (
CONF_LOCAL_UPDATE_INTERVAL). Cloud-only (4G) devices keep their fixed cadence and ignore the option. Applied live via an entry update listener — no reload required. - Expanded cloud-only entity coverage –
_build_realtime_from_reportedsynthesises a LAN-shaped payload from the cloud/reporteddocument, including seven additional numeric keys plus device metadata (ID, firmware, MAC, SSID, IP via thewifi_infoblob). The set of entities showing real data in cloud-only mode grows from ~12 to ~20+. Structurally LAN-only entities (ReadyState,SignalStatus,Timer,ChargeMode,DynamicPowerMode,PauseDynamic) now correctly advertise as Unavailable in cloud-only mode instead of the misleading "Unknown". - Discovered
/device/logo_ledcloud endpoint (undocumented, live on firmware 2.4.6) – the LogoLED switch is now controllable from cloud-only mode viaasync_cloud_set_logo_led. - Spanish UI translation – the previously incomplete Spanish support is now a full
translations/es.json(235 keys), at parity withen.jsonandit.json. - Live smoke-test script (
scripts/live_smoke_test.py) – exercises every read endpoint and issues safe no-op writes against a real Trydan plus the V2C Cloud, then verifies snapshot/restore. Requires the explicit--confirm-restoreflag and is never run in CI. - CI / supply-chain hardening – Python 3.12/3.13/3.14 matrix, ruff lint + format gates, Codecov coverage reporting (
.coveragerc),concurrency:blocks on every workflow, pip caching,.github/dependabot.yml(weekly grouped Actions + pip updates), SBOM (SPDX-JSON + CycloneDX-JSON viaanchore/sbom-action) attached to every release, and a reusablesecurity.yaml(workflow_call) so the release pipeline gates on the exact same SAST / dependency-audit / secret-scan jobs as PRs.
- Config entry schema v1 → v2 (auto-migrated).
async_migrate_entryis version-aware via a_MIGRATIONSregistry;SCHEMA_VERSION = 2inconst.pyis the single source of truth for bothconfig_flow.VERSIONand the migration target. Legacy entries are translated: the cloud-only sentinel (fallback_ip == ""/"0.0.0.0") becomescloud_only: True; a non-emptyfallback_ippaired withfallback_device_idbecomes a one-recordcached_pairings; aninitial_pairingssnapshot wins over the single-device pair. Legacy keys are dropped fromentry.data. - Cloud-only mode is encoded as
entry.data["cloud_only"]: boolinstead of the empty-stringfallback_ipsentinel. The first-setup fallback-IP step is gone — initial setup now requires the cloud to be reachable to capture the pairings list, consistent with the integration's name and removing a single point of failure. - SSRF guard deduplicated into
custom_components/v2c_cloud/_net.py::validate_private_ip(private + not loopback + not link-local + not unspecified), replacing four scattered copies with a single tested helper. async_write_keywordvalidates the keyword against a documentedWRITEABLE_KEYWORDSwhitelist to reduce the LAN write/SSRF surface and prevent accidental misuse from automations.- Local API constants consolidated in
const.py:LOCAL_HTTP_TIMEOUT,LOCAL_MAX_RETRIES,LOCAL_RETRY_BACKOFF,LOCAL_WRITE_RETRY_DELAY,CLOUD_ONLY_UPDATE_INTERVAL, and the newDEFAULT/MIN/MAX_LOCAL_INTERVALbounds. - HA minimum version stays in
hacs.json("homeassistant": "2025.4.0") — hassfest rejectsmin_ha_versioninmanifest.jsonas an unknown field.
ChargeModeSelect showed "Unknown" in LAN mode – it is write-enabled but absent from/RealTimeData; the integration's read-only-keyword augmentation coveredLogoLED+LightLEDbut missedChargeMode. The local coordinator now also fetches/read/ChargeModein parallel and the Select displays the live value.Local refresh intervaloption was not persisted – the options flow returnedasync_create_entry(title="", data={}), and HA uses thatdataargument to overwriteentry.options, so the field always snapped back to 30 s. Fix: pass the populated options dict toasync_create_entry(data=new_options).- Connection-type radio labels were not translated – the schema used a hard-coded
vol.In({label: ...})dict. Migrated toSelectSelector(translation_key="connection_type")with a top-levelselectorblock instrings.jsonand all translation files. Italian "Intensità Light LED" renamed to "Intensità LED". - Cloud-only data accuracy (validated end-to-end against a live firmware-2.4.6
/device/reported+/device/currentstatechargecapture):VoltageInstallationreported a spurious ~77 V – the cloudvoltagefield is a small internal signal; the real mains/installation voltage is carried bycp_level(e.g.248on a 230 V EU install). Remappedcp_level → VoltageInstallationand dropped the misleadingvoltagemapping.ContractedPowerwas off by 100× – the cloud encodescontract_poweras W/100 ("7"= 700 W = 0.7 kW), but the Number entity divides by 1000 to render kW. Added a_CLOUD_TO_LAN_MULTIPLIERStable that multipliesContractedPowerby 100 during synthesis.LightLEDshowed1for a LED set to 100 % – the cloud serialiseslight_ledas a 0.0-1.0 fraction; the LAN keyword and entity use 0-100 % integers. Added a × 100 multiplier.- Number / Switch / Select writes were silently dropped in cloud-only (4G) – every setter called
async_write_keyworddirectly, so the LAN write raisedV2CLocalApiErrorand no cloud fallback fired. Every setter now routes throughasync_route_local_or_cloud. device_identifier/firmware_version/wifi_ssid/wifi_ipsensors were "Unknown" – the synthesis loop coerced every value viafloat(str(raw))and silently dropped non-numeric ones. Added a string-passthrough path plus inline parsing of the cloud'swifi_infoJSON blob.
- UI strings referencing the removed
fallback_ipstep / field were cleaned up acrossstrings.jsonand the en/it/es translations; theconnection_typeandinitdescriptions now mention auto-discovered per-device IPs and automatic LAN→cloud routing. requirements.txt:pyyamlis now version-pinned (>=6.0,<7).requirements_test.txt: all packages have upper bounds for reproducible CI builds..ruff.toml:target-versionaligned with CI (py312); test/script directories get a targetedper-file-ignoresso the strictselect = ALLrule set no longer drowns the lint output. The whole tree isruff format-clean and bothruff checkandruff format --checkgate every PR and release.- CI hardening:
persist-credentials: falseon every read-only checkout;pip-audit --strict; bandit artifact retention pinned to 30 days;hacs.yaml+hassfest.yamlpush triggers scoped tobranches: [main](daily cron retained).
_normalise_pairingsdeduplicated into a single_pairings.pymodule imported by bothconfig_flow.pyand__init__.py, eliminating drift between the two persistence paths. Persisted lists are capped at 64 records during normalisation, andasync_setup_entrynow passes the raw entry data through_normalise_pairingsso a malformed snapshot ([{}],[{"deviceId": None}], a non-list value) no longer prevents the integration from loading.- LAN-vs-cloud router takes a
cloud_callfactory (Callable[[], Awaitable]) instead of a pre-constructed coroutine. On the LAN-success happy path the cloud awaitable is no longer created, eliminating theRuntimeWarning: coroutine was never awaitedpollution. - Parallel local-coordinator first-refresh in the
sensorplatform – setup time on multi-charger accounts is bounded by the slowest device's LAN response rather than the sum of all devices'. config_flow.pyno longer surfaces exception args in the unknown-error branch (_LOGGER.exception(...)→_LOGGER.error("…: %s", type(err).__name__)) so a future exception-class change cannot leak the API key into a traceback.- Legacy
fallback_ipwithout afallback_device_idis logged during migration so a dropped IP that could not be turned into a(deviceId, ip)record is diagnosable.
- Tighter local-write surface – writes are rejected unless the keyword is in the documented Trydan write-list and the resolved IP parses cleanly and satisfies the private / non-loopback / non-link-local / non-unspecified policy.
- Audit of credential masking, SSRF guards and
eval/exec/pickle/yaml.unsafe_loaduse confirmed clean — no new findings.
- Rolling back from
1.3.xto1.2.xvia HACS is not supported. The v2 schema dropsfallback_device_id/initial_pairingsand persists multi-device IPs only incached_pairings(a key1.2.xdoes not understand). v2 entries leave a vestigialfallback_ip: ""sentinel so the older code path loads instead of crashing onKeyError, but a rollback degrades a multi-device account to cloud-only mode and silently loses LAN data. Re-setup the integration after a downgrade.
Pre-release on the HACS beta channel. Post-beta.2 hardening pass from a full security + performance + architecture review — schema-migration safety, pairings-persistence robustness, internal API shape, and log hygiene — with no user-observable behaviour change in the happy path. Folded into [1.3.0].
Pre-release on the HACS beta channel. Added the breaking multi-device auto-discovery schema (config entry v1 → v2), the editable connection-type toggle, the expanded cloud-only entity coverage, and the cloud-only data-accuracy fixes (VoltageInstallation / ContractedPower / LightLED / routed writes). Folded into [1.3.0].
First pre-release of the 1.3.0 line on the HACS beta channel — full V2C Cloud endpoint coverage, the LAN-vs-cloud router, and the CI / supply-chain hardening. Published with prerelease: true so HACS only proposed it to users who opted into "Show beta versions". Folded into [1.3.0].
- Reauth completion shows wrong message – the reauth config flow called
async_update_reload_and_abortwithout an explicitreason=argument, which defaults to"reconfigure_successful". As a result, after a successful re-authentication the UI displayed "Reconfiguration was successful" instead of "Re-authentication was successful". Thereason="reauth_successful"argument is now passed explicitly. - Raw
reconfigure_successfulkey shown in UI – theconfig.abort.reconfigure_successfulkey was missing fromstrings.jsonand both translation files (en.json,it.json). Home Assistant rendered the raw key string instead of the localised message after a successful reconfigure flow. The key has been added to all three files. - Gitleaks CI false positive on test fixture – the placeholder API key
test-api-key-abc123used intests/conftest.pytriggered thegeneric-api-keyGitleaks rule on the full git history scan, causing the security CI job to fail. Added.gitleaks.tomlwith astopwordsentry fortest-api-keyand a path allowlist for thetests/directory; the fixture is intentionally non-functional and has never been a real credential.
- Removed unused
cannot_connecterror key – theconfig.error.cannot_connectkey was declared instrings.jsonand both translation files but was never emitted byconfig_flow.py. When the V2C Cloud is unreachable during initial setup the flow redirects to thefallback_ipstep rather than showing a connection error. The dead key has been removed from all three files.
- Self-reinforcing rate-limit loop eliminated – when the V2C Cloud API returned HTTP 429, the integration retried the same request up to three times before raising the error. Each retry consumed an additional call from an already-exhausted daily quota (1 000 calls/day), causing the budget to be burned at up to 3× the normal rate. Once the limit was hit, the quota was spent in its entirety on retries alone, making recovery impossible until the next daily reset. HTTP 429 responses are now raised immediately without any retry; the coordinator's exponential back-off (see below) handles pacing instead.
- Coordinator keeps hammering the API when rate-limited – after a 429, the cloud polling interval was not adjusted, so the integration kept attempting requests every 120 s regardless of how many times it had been rejected. The poll interval now doubles on each rate-limit cycle (
120 s → 240 s → 480 s → 600 s), capped at 10 minutes. The interval automatically resets to the normal cadence on the first successful response, so no manual intervention is required once the daily quota window resets.
- Proactive pacing via
RateLimit-Remainingheader – successful responses from the V2C Cloud include aRateLimit-Remainingheader indicating how many calls are left in the current daily window. When this value drops below 150, the integration stretches the polling interval proportionally (reserving 50 calls for user-initiated commands), so the remaining budget lasts a full 24 hours in the worst case. This prevents the quota from being exhausted mid-day on days with heavy polling or frequent HA restarts.
- Clear-text logging of sensitive data eliminated – three CodeQL alerts (
py/clear-text-logging-sensitive-data) resolved:headersandbodyremoved from the HTTP debug log in_request(theapikeyheader was already masked but the dict comprehension still constituted a taint path);paramsmasking made case-insensitive;fallback_device_id(derived fromentry.data, which contains the API key) removed from startup warning messages in__init__.py; exception objects replaced withtype(err).__name__to prevent accidental credential leakage via exception messages.
- SSRF guard now blocks link-local addresses – on Python 3.11+ link-local IPs (
169.254.x.x) haveis_private=True, so the previous guard (is_private AND NOT is_loopback) incorrectly allowed them through. All three guard sites (config_flow._probe_local_api,local_api.async_write_keyword,local_api._async_fetch_local_data) now also rejectis_link_localaddresses. - API key / authorization headers masked in debug logs – the
apikeyandauthorizationheaders are now logged as***in all request debug output, preventing credential leakage in log files.
- Startup failure when cloud is rate-limited in Cloud+LAN mode – if the V2C Cloud returned HTTP 429 during initial coordinator startup, the integration raised
ConfigEntryNotReadyand retried indefinitely at a very short interval. It now treats the rate-limit error as a transient failure and backs off to the normal poll cadence (#6). - OCPP server URL, date fields and RFID tag data tightened – malformed values are now rejected early with clear validation errors before reaching the API.
_normalize_boolsynced withcoerce_bool– the API client's bool parser now recognises"enabled"/"disabled"tokens, matching the entity-layer helper and preventing silent mismatches on firmware variants that report boolean fields as strings.
- Parallel cloud fetch per device –
_fetch_single_device_statenow fires thereported,rfidandversionAPI calls concurrently viaasyncio.gatherinstead of sequentially, reducing per-device cloud poll latency by up to 2 × on fast connections. - Rate-limit retry jitter – backoff after a
429response now includes a small random component to avoid simultaneous retries across multiple devices. - Type annotations cleaned up – entity modules use
V2CClientinstead ofAnyfor the client parameter;device_infonow declares aDeviceInforeturn type;DataUpdateCoordinatorimports follow theTYPE_CHECKING-only pattern where the type is annotation-only.
- Test suite expanded to 350 tests – ten new test modules cover all entity types (binary sensor, sensor, switch, number, select, button), config flow SSRF guard, local API and device-state gathering. The full suite runs without a live Home Assistant instance or charger.
actions/checkoutupgraded to v6 – bumped from v2 (inhacs.yaml,hassfest.yaml) and v4 (intests.yaml,security.yaml,codeql.yaml,tag-and-release.yaml) to v6, resolving the Node.js 20 deprecation warning ahead of the June 2026 enforcement deadline.hacs/actionpinned to v22.5.0 – replaced the mutable@mainfloating tag with a commit-pinned reference (d556e736...) for supply-chain security.
- Re-auth / Reconfigure no longer blocked when cloud is unavailable – if
/pairings/mereturns 403 or the V2C Cloud is unreachable during the reauth or reconfigure flow, the new API key is now accepted and saved immediately. The coordinator will validate connectivity on the next refresh cycle. Only a definitive HTTP 401 (invalid credentials) still blocks the flow. - Slave device select shows "MQTT" for type 11 – devices configured with MQTT-based energy monitoring (
slave_type = 11) were previously stuck in unknown state because the value was missing from the options map.
- Timer switch – new local switch entity that enables or disables the charger's built-in timer directly via the local HTTP API (
/write/Timer), with instant state feedback from RealTimeData polling. - Fallback local IP during setup – if the V2C Cloud API is unreachable when adding the integration, the config flow now offers a second step where you can enter the charger's local IP address. The integration operates entirely over the local LAN until the cloud comes back; once it does, the real cloud device list is used automatically without any manual intervention.
- Local fallback IP option – the fallback IP can also be set or updated at any time via the integration options panel (Settings → Devices & Services → V2C Cloud → Configure).
- API key reconfiguration – a new "Reconfigure" button is available in the integration panel (Settings → Devices & Services → V2C Cloud → Reconfigure). It lets you update the API key at any time without removing and re-adding the integration. The new key is validated before saving, and the integration reloads automatically on success.
- Logo LED switch is now fully local: state is polled via
GET /read/LogoLED(sinceLogoLEDis absent from/RealTimeData) and writes use/write/LogoLED=1(on) or/write/LogoLED=0(off). The cloud/device/logo_ledendpoint is no longer called, removing one daily API call and making the toggle work when the cloud is offline. - Cloud-offline resilience – local entities (switches, numbers,
DynamicPowerModeselect) now derive theiravailablestate from the local coordinator instead of the cloud coordinator. When the cloud is unreachable, locally-controlled entities stay available and controllable as long as the charger is reachable on the LAN. - 403 on
/pairings/meno longer blocks the coordinator – tokens that have permission for/device/reportedbut not/pairings/meno longer cause an endless startup failure. When/pairings/mereturns an error, the coordinator builds a synthetic pairing from the configuredfallback_device_idand proceeds to fetch device state normally. - Case-insensitive local key lookup – all local entities now use a
get_local_valuehelper that tries an exact match first and falls back to a case-insensitive scan, preventing entities from appearing unavailable if firmware reports keys in unexpected casing. - The reauthentication flow now uses
_get_reauth_entry()andasync_update_reload_and_abort(), matching the modernized pattern used by the reconfigure flow.
- LogoLED switch state now reflects changes made from the V2C app without waiting for a manual refresh.
- LogoLED write value corrected: the device only accepts
1/0, not100/0as older documentation implied. - Removed unreachable
else: breakdead-code branch in the local RealTimeData retry loop. - Removed unused
DeviceMetadatadataclass and five unused constants (DEFAULT_BASE_URL,RATE_LIMIT_DAILY,ATTR_KW,ATTR_VALUE,ATTR_PROFILE_MODE).
- LightLED support – experimental switch and all related API calls removed; the feature was not functional on production firmware.
V2CClient.async_set_logo_led()– cloud Logo LED method removed; Logo LED is now fully managed via the local write API.
- Moved the V2C Cloud portal URL in the config flow copy into translation placeholders to comply with hassfest validation.
- Added a link to the main projects site in both README files.
- Trap
ConfigEntryNotReadyerrors raised during the local RealTimeData coordinator bootstrap so forwarded platforms no longer log setup failures when a charger IP is temporarily unavailable; entities now stay loaded while the LAN poller retries in the background.
- Highlighted the companion Octopus Energy Italy integration so users can pair Intelligent Octopus with V2C for smart-charging workflows.
- Minor follow-up to the setup instructions to match the English wording now used by the V2C Cloud portal (menu and button labels).
- Locked the integration to the official V2C Cloud endpoint: the config flow, re-auth flow and stored entries no longer accept a custom base URL, so the onboarding form now only asks for the API key.
- Updated translations/strings to remove the unused Base URL field across the UI.
- Clarified the configuration instructions in both READMEs with step-by-step guidance (English UI labels included) on how to obtain the API token from the V2C Cloud portal.
v2c_cloud.set_installation_voltageservice that writes to the local/write/VoltageInstallationendpoint so automations can adjust the parameter explicitly, now validated between 100 V and 450 V.
- The "Installation voltage" number entity; use the new service action instead, consistent with other write-only operations such as RFID management.
- Restore the cloud polling interval to the default cadence whenever authentication or network failures occur so entities resume refreshing quickly after long outages without needing a manual reload.
- Harden the LAN realtime telemetry by retrying
/RealTimeDataup to three times with progressive backoff before giving up, logging recoveries once the wallbox comes back online. - Schedule an automatic LAN refresh a few seconds after write timeouts/HTTP errors so commands eventually reconcile with the UI as soon as Wi-Fi connectivity is restored.
- Sync the OCPP, logo LED and RFID reader toggles immediately after commands by caching the new value, skipping the instant refresh and scheduling a delayed poll so the UI no longer flips back while the cloud API propagates the change.
- Dropped the per-entity extra state attributes to reduce clutter now that diagnostics can rely on logs and events.
- Constrained the “Contracted power” number entity to 1–22 kW with 0.5 kW increments for a more realistic slider range.
- Dropped the redundant “Contracted power” sensor; continue to use the corresponding number entity which already exposes the same data with write support.
- Dedicated Material Design icons for all config numbers, select entities and the V2C Cloud connection sensor to improve clarity in the Home Assistant UI.
First public release of the V2C Cloud integration for Home Assistant.
- Config flow with API-key validation – authenticates against
/pairings/me, caches the initial pairings and stores a deterministic unique ID for future re-auth flows. - Hybrid cloud/LAN architecture – asynchronous client for every documented V2C Cloud endpoint plus LAN helpers for
/RealTimeDataand/write/<Keyword>=<Value>, including retry/backoff and rate-limit handling. - Adaptive polling – cloud coordinator that automatically scales to the number of chargers with a minimum interval of 90 s, caching pairings for 60 minutes, refreshing RFID cards every 6 h and firmware versions every 12 h.
- Realtime local telemetry – per-device coordinators that poll
/RealTimeDataevery 30 s and expose sensors for identifier, firmware version, charge status, timer state, power/energy metrics, grid voltage, Wi-Fi diagnostics and device error codes (with localized labels). - Home Assistant entities – connection binary sensor, local-first switches (Dynamic, PauseDynamic, Locked, Pause charge, Logo LED, RFID reader, OCPP), selects (installation type, slave type, language, dynamic power mode), numbers (intensity, min/max intensity, contracted power, installation voltage) and buttons (reboot, trigger update) with optimistic UI smoothing.
- Service surface – Wi-Fi credentials, timer programming, RFID lifecycle (register, add, update, delete), scheduled charging helpers (stop/start via kWh or minutes), OCPP and inverter configuration, firmware update trigger, photovoltaic power profile management (create, update, get, list, delete) and statistics retrieval for devices and the global account.
- Automation events – data retrieval services fire
v2c_cloud_wifi_scan,v2c_cloud_device_statistics,v2c_cloud_global_statisticsandv2c_cloud_power_profilesevents containing the raw payload to power custom automations. - Diagnostics & tooling – rate-limit headers stored in coordinator data, comprehensive documentation (README, release notes, technical notes) and translation files for UI strings.