Skip to content

Upgrade ZMK to v0.4 / Zephyr 4.1 #2

@rdlu

Description

@rdlu

Warning

AI-generated research — verify before acting.
This issue was initially researched with Claude Sonnet 4.6 and then reviewed with Claude Opus 4.6 (Anthropic) in April 2026 as a planning aid. The author has no prior ZMK experience (familiar with Arduino/nice!nano hardware, but not the ZMK/Zephyr build system). The migration steps have not been tested — they were derived by inspecting the adv360pro board on ZMK main and the ZMK blog. Do not apply them blindly — cross-check against the official ZMK migration docs and real examples before touching your board definition or firmware config. Incorrect changes could result in firmware that fails to build or boots into a broken state.

Background

ZMK announced Zephyr 4.1 support in a December 2025 blog post. This is a significant upgrade from the current v0.3.0 (Zephyr 3.5.0+zmk-fixes). As of April 2026, no new tagged release exists — HWMv2 changes are only on ZMK main. This issue tracks the migration work needed once a stable release is tagged.

Current state

Item Current
ZMK revision v0.3.0
Zephyr (via ZMK fork) v3.5.0+zmk-fixes
Zephyr SDK 0.17.0
GitHub Actions workflow zmkfirmware/zmk/.github/workflows/build-user-config.yml@v0.3.0

What's changing with Zephyr 4.1 / HWMv2

The Zephyr 4.1 upgrade introduces Hardware Model v2 (HWMv2), which changes how boards and shields are identified. Key changes:

  • Board identifiers now use a // variant separator (e.g. eyelash_sofle_lefteyelash_sofle_left//zmk)
  • boards/arm/<board>/ directory structure → boards/<vendor>/<board>/
  • New board.yml replaces <board>.yaml
  • Kconfig changes: depends on SOC_*select SOC_*, one file per board variant, plus additional select/imply lines
  • CONFIG_NFCT_PINS_AS_GPIOS=y removed from .conf (moved to DTS by ZMK core)

Board migration plan

This repo (rdlu/zmk-sofle) is already a fork of a741725193/zmk-sofle, so the board HWMv2 migration can be done directly here — no separate fork needed.

File operations in eyelash_sofle/boards/

MOVE   boards/arm/eyelash_sofle/  →  boards/<vendor>/eyelash_sofle/

DELETE eyelash_sofle.yaml
ADD    board.yml  (new format, declares vendor + socs + zmk variant)

RENAME Kconfig.board
    → Kconfig.eyelash_sofle_left
    → Kconfig.eyelash_sofle_right

RENAME eyelash_sofle_left.dts              → eyelash_sofle_left_nrf52840_zmk.dts
RENAME eyelash_sofle_right.dts             → eyelash_sofle_right_nrf52840_zmk.dts
RENAME eyelash_sofle_left_defconfig        → eyelash_sofle_left_nrf52840_zmk_defconfig
RENAME eyelash_sofle_right_defconfig       → eyelash_sofle_right_nrf52840_zmk_defconfig

KEEP   eyelash_sofle.dtsi
KEEP   eyelash_sofle-layouts.dtsi
KEEP   board.cmake
KEEP   Kconfig.defconfig

Content changes

New board.yml (replaces eyelash_sofle.yaml):

boards:
  - name: eyelash_sofle_left
    vendor: <vendor-slug>
    socs:
      - name: nrf52840
        variants:
          - name: zmk
  - name: eyelash_sofle_right
    vendor: <vendor-slug>
    socs:
      - name: nrf52840
        variants:
          - name: zmk

Kconfig.eyelash_sofle_left (and equivalent for _right):

config BOARD_EYELASH_SOFLE_LEFT
    select SOC_NRF52840_QIAA
    select ZMK_BOARD_COMPAT
    imply RETAINED_MEM
    imply RETENTION
    imply RETENTION_BOOT_MODE

Based on the adv360pro reference. The ZMK_BOARD_COMPAT, RETAINED_MEM, RETENTION, and RETENTION_BOOT_MODE lines may be needed for settings reset and bootloader features.

*_defconfig files — remove 3 lines now handled by Kconfig:

-CONFIG_SOC_SERIES_NRF52X=y
-CONFIG_SOC_NRF52840_QIAA=y
-CONFIG_BOARD_EYELASH_SOFLE_LEFT=y

eyelash_sofle.zmk.yml — update siblings:

-  - eyelash_sofle_left
-  - eyelash_sofle_right
+  - eyelash_sofle_left//zmk
+  - eyelash_sofle_right//zmk

build.yaml changes

# before → after
eyelash_sofle_left   → eyelash_sofle_left//zmk
eyelash_sofle_right  → eyelash_sofle_right//zmk

Note on nice_nano / settings_reset: The nice_nano in ZMK main uses revision overlays (nice_nano_nrf52840_zmk_2_0_0.overlay). The correct board identifier for the v2 hardware may be nice_nano@2.0.0//zmk rather than nice_nano//zmk. Verify against ZMK docs at migration time.

config/west.yml changes

Bump ZMK revision to the next tagged release. For the eyelash_sofle module, the cleanest approach is to make it a local module (removing the remote URL entirely) since this repo IS the fork:

projects:
  - name: eyelash_sofle
    path: eyelash_sofle    # local path, no remote fetch
  - name: zmk
    remote: zmkfirmware
    revision: <next-tagged-release>
    import: app/west.yml

The previous suggestion to point the URL at rdlu/zmk-sofle with a branch revision would work but creates a circular reference (the repo pulling itself as a west module). A local module path is simpler.

Other files

  • .github/workflows/build.yml: update workflow ref to @<next-tagged-release>
  • eyelash_sofle.conf: check for CONFIG_NFCT_PINS_AS_GPIOS=y and remove if present
  • mise.toml build tasks: update -b board name flags

Reference implementation

Follow app/boards/kinesis/adv360pro/ in ZMK main — it is a two-half nRF52840 split board with the same HWMv2 structure needed here. Verified April 2026.

Checklist

  • Wait for a tagged ZMK release with HWMv2 support (as of April 2026, only on main)
  • Perform the board HWMv2 migration in this repo (file renames + content changes above)
  • Convert eyelash_sofle to a local west module (or update URL to point at this fork)
  • Update config/west.yml ZMK revision to the new tag
  • Update build.yaml board identifiers (including verifying nice_nano naming)
  • Update .github/workflows/build.yml workflow ref
  • Check eyelash_sofle.conf for CONFIG_NFCT_PINS_AS_GPIOS=y
  • Confirm Zephyr SDK 0.17.0 is still compatible (or upgrade)
  • Test a full build for both halves + settings_reset

References

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requesthelp wantedExtra attention is needed

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions