Skip to content

vNext: migrate a 4.x setup without user action - #519

Merged
RobHofmann merged 2 commits into
5.0-devfrom
feat/migrate-from-4x
Sep 23, 2026
Merged

RobHofmann merged 2 commits into
5.0-devfrom
feat/migrate-from-4x

Conversation

@RobHofmann

@RobHofmann RobHofmann commented Sep 23, 2026 •

Copy link
Copy Markdown
Owner

Summary

Users of 4.x (domain gree) now move to this version without doing anything. Their config entries, their gree: YAML block, and their device and entity registry rows come over. Entity IDs, areas, device names and history stay, so automations, scripts and dashboards keep working.

  • A 4.x UI entry becomes a device in the local-only entry.
  • A 4.x gree: block stays YAML: it is converted at every start and goes through the normal YAML import. A repair issue shows the gree_custom: block to paste, and says that the legacy import will be removed in a later version.
  • A second repair issue asks the user to delete custom_components/gree, which HACS leaves behind.

The design is in docs/config-entry.md, section "Migration from 4.x".

How it works

migration.py works in two phases.

Phase 1, in async_setup. It reads the 4.x entries and the gree: block and converts every device. The mapping table is in the docs. Two points matter:

  • The swing modes are matched on the value sent to the unit, not on the name. For example, 4.x swing_downmost and 5.0 swing_upper both send 7, so a migrated unit moves its louvers the same way as before.
  • The 4.x temperature step number and the external sensor selects become options.

When a YAML block manages the local devices, the devices are merged into the YAML import. Otherwise a new migrate flow step adds them to the local-only entry. That step only adds devices.

Phase 2, in async_setup_entry, before the platforms.

  1. Unload the 4.x entry.
  2. Move its entity rows with async_update_entity_platform.
  3. Move the device row. It has to go after the entities, because Home Assistant removes the old entry's entities when their device moves.
  4. Disable the 4.x entry while its folder exists, or remove it once the folder is gone.

After the platforms are set up, moved rows without an entity are removed. 4.x created every switch, also for features the unit lacks.

What starts it

Home Assistant only sets up an integration that has a config entry or a YAML key. A 4.x user has neither for gree_custom, so the migration code would never run by itself. Two ways cover this:

  • A small hook in the last 4.x release starts gree_custom when it is installed. This is the path without user action. It is a separate PR on master: Start the 5.0 integration when it is installed next to 4.x #520.
  • Without that release, opening Add Integration > Gree A/C starts the migration and stops the flow with a short message. The DHCP discovery flow does the same.

Testing

On the dev instance against the real unit (192.168.252.99, firmware V3.75), with a UI entry that had an area, a user name and a stored temperature step of 0.5:

Scenario Result
4.x UI entry, 4.x folder present, hook installed 15 entities moved with their IDs, device kept its area and name, step 0.5 became an option, 4.x entry disabled, 3 unsupported entities removed, only legacy_folder raised
Same, second start nothing moves again, no reload
4.x folder deleted 4.x entry removed, no repair issues left, entities unchanged
4.x gree: block, folder present YAML-managed local entry, legacy_yaml issue with a block that parses and validates
Generated block pasted in place of gree: entry unchanged, no reload, legacy_yaml gone
gree: block, folder deleted 4.x entry removed
Original 4.0.6 code, no hook gree_custom does not start. Opening the setup flow starts the migration with the same result.
Stored 4.x state dropped between starts step 0.5 kept, entry unchanged

A conversion harness with 30 checks covers the field mapping, the swing value mapping, VRF keys, the unique ID mapping, and the round trip of the generated YAML through ITEM_SCHEMA. pytest passes: 227 tests.

Ruff check and format pass. Mypy finds nothing new in the changed files. Pylint could not run with the Home Assistant plugin outside the devcontainer.

Notes

  • I could not see the repair issue in the UI, because that needs a login. The description puts the placeholder in a fenced yaml block, the same way core MQTT and Lovelace do.
  • VRF: only the climate entity moves. 4.x used the controller MAC in the unique IDs of all other entities. Not tested, no VRF unit.
  • Home Assistant writes the registries during startup with a delay of 180 seconds. If it is killed before that, the next start moves the rows again. I saw this once in testing, and the result was the same.
  • The repair issue can hold a user-set encryption_key, the same value that is already in their configuration.yaml.
  • nl.json has the new strings. The other languages fall back to English.
  • No version bump.

Releases 4.x used the domain gree. This moves a 4.x setup to gree_custom
at start, in two phases (migration.py):

- In async_setup: read the 4.x config entries and the gree: YAML block,
  convert every device (swing modes are matched on the value sent to the
  unit), and bring the devices in. When a YAML block manages the local
  devices they are merged into the YAML import, otherwise the new
  "migrate" flow step adds them to the local-only entry.
- In async_setup_entry, before the platforms: unload the 4.x entry, move
  its entity rows (entity IDs, history and automations stay), then its
  device row (area and user name stay), then disable the 4.x entry while
  the 4.x folder exists, or remove it once the folder is gone. Moved rows
  that get no entity for a bound device are removed.

Two repair issues guide the user: legacy_yaml shows the gree_custom:
block to paste in place of gree:, and says the legacy import will be
removed later; legacy_folder asks to delete custom_components/gree,
which HACS leaves behind. Both are checked at every start.

Home Assistant only sets up an integration with a config entry or a YAML
key, so a 4.x user never starts gree_custom by itself. A small hook in
the last 4.x release starts it (separate PR on master). Without it,
opening the setup flow starts the migration and stops the flow.

Tested on the dev instance against the real unit: UI entry, YAML block,
both with the 4.x folder present and after it is deleted, the paste of
the generated block, the flow fallback, and repeated starts.
A 4.x number or select that never had a value is stored as "unknown".
The migration logged that as a value that is not valid, once per source
of the device. Such states now count as no value and are skipped.
@RobHofmann
RobHofmann merged commit 2745f8b into 5.0-dev Sep 23, 2026
4 checks passed
@RobHofmann
RobHofmann deleted the feat/migrate-from-4x branch September 23, 2026 19:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant