Skip to content

Inovelli VZM32-SN: add mmWave area commands and reports#4944

Open
tmmueller wants to merge 2 commits intozigpy:devfrom
tmmueller:inovelli-vzm32-area-commands
Open

Inovelli VZM32-SN: add mmWave area commands and reports#4944
tmmueller wants to merge 2 commits intozigpy:devfrom
tmmueller:inovelli-vzm32-area-commands

Conversation

@tmmueller
Copy link
Copy Markdown

Summary

The VZM32-SN mmWave cluster (0xFC32) exposes three area-definition commands
(interference, detection, stay) and five device-to-coordinator reports that
are currently only defined in zigbee-herdsman-converters' inovelli.ts.
This PR brings them to zha-device-handlers so ZHA users can configure and
read back mmWave zones natively.

What's added

zhaquirks/inovelli/types.py — two structs:

  • MMWaveArea — x/y/z min/max bounds in mm
  • MMWaveTarget — x, y, z, doppler, id for live target reports

zhaquirks/inovelli/__init__.py, in InovelliVZM32SNMMWaveCluster:

  • MMWaveControlId enum: add Reset_detection_area = 0x04 and
    Clear_stay_areas = 0x05.
  • ServerCommandDefs: add set_interference_area (0x01),
    set_detection_area (0x02), set_stay_area (0x03).
  • ClientCommandDefs (new): anyone_in_reporting_area (0x00),
    report_target_info (0x01, variable-length t.List[MMWaveTarget]),
    report_interference_area (0x02), report_detection_area (0x03),
    report_stay_area (0x04).

Command names are snake_case per the project's convention; payload layouts
match inovelli.ts.

A note on set_stay_area on v1.00

The docstring records a community-reported bug
on main MCU firmware v1.00 where set_stay_area's x_min/x_max are
swapped and sign-inverted on write. Pre-compensation (send -b, -a to land
on (a, b)) is documented as a workaround; symmetric ranges [-n, +n] are
self-correcting. Status on v1.01/v1.02 betas is not publicly documented.
This is a device-firmware issue, not something this quirk can fix — the
note is there so callers know why asymmetric x-axis stay zones may need
pre-compensation.

Test plan

  • python -m pytest tests/test_inovelli_blue.py -v passes (1 existing + 4 new tests)
  • python -m ruff check zhaquirks/inovelli/ tests/test_inovelli_blue.py — clean
  • python -m ruff format --check zhaquirks/inovelli/ tests/test_inovelli_blue.py — clean
  • Full suite python -m pytest tests/ — 4746 pass on this branch (3 pre-existing Tuya/time_machine failures on Python 3.14, unrelated)
  • Round-trip verified against real VZM32-SN devices on firmware v1.00 (set_stay_area writes succeed; no regression in existing mmWave attribute reads)

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 23, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.09%. Comparing base (69bdc15) to head (20aaa66).

Additional details and impacted files
@@            Coverage Diff             @@
##              dev    #4944      +/-   ##
==========================================
+ Coverage   93.07%   93.09%   +0.01%     
==========================================
  Files         401      401              
  Lines       13306    13331      +25     
==========================================
+ Hits        12385    12410      +25     
  Misses        921      921              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds ZHA-side definitions for the Inovelli VZM32-SN mmWave (0xFC32) area configuration commands and device reports so ZHA can configure/read mmWave zones and parse live target/area reporting payloads.

Changes:

  • Introduces MMWaveArea and MMWaveTarget Zigpy Structs to model area bounds and live target reports.
  • Extends InovelliVZM32SNMMWaveCluster with new server commands for setting interference/detection/stay areas and new client (device→coordinator) report commands.
  • Adds unit tests validating round-trip serialize/deserialize of the new command payload schemas, including variable-length target reporting.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
zhaquirks/inovelli/types.py Adds new Zigpy Struct types used by mmWave command/report schemas.
zhaquirks/inovelli/__init__.py Extends the VZM32-SN mmWave cluster with new control IDs and command/report definitions.
tests/test_inovelli_blue.py Adds coverage for serialization/deserialization of the new mmWave commands/reports.

Comment thread zhaquirks/inovelli/__init__.py Outdated
Comment thread tests/test_inovelli_blue.py Outdated
tmmueller added 2 commits May 9, 2026 08:21
The VZM32-SN mmWave cluster (0xFC32) exposes three area-definition
commands (interference, detection, stay) and five device-to-coordinator
reports that were previously only defined in zigbee-herdsman-converters'
inovelli.ts. This commit brings them to zha-device-handlers:

zhaquirks/inovelli/types.py
  - MMWaveArea struct: x/y/z min/max bounds in mm
  - MMWaveTarget struct: x, y, z, doppler, id for live target reports

zhaquirks/inovelli/__init__.py
  - MMWaveControlId: add Reset_detection_area (0x04) and
    Clear_stay_areas (0x05) to match the full device command set
  - InovelliVZM32SNMMWaveCluster.ServerCommandDefs: add set_interference_area
    (0x01), set_detection_area (0x02), set_stay_area (0x03). Docstring notes
    the community-reported v1.00 set_stay_area xMin/xMax swap+negate bug
    and the pre-compensation workaround.
  - InovelliVZM32SNMMWaveCluster.ClientCommandDefs: new class with the five
    device-originated reports. anyone_in_reporting_area (0x00) for per-area
    occupancy, report_target_info (0x01) for live position streams using
    t.List[MMWaveTarget], and report_interference_area / report_detection_area
    / report_stay_area (0x02-0x04) as readback responses to
    mmwave_control_command(Obtain_areas).

Command names are snake_case per zha-device-handlers convention; payload
layouts match zigbee-herdsman-converters.

tests/test_inovelli_blue.py
  - Round-trip tests for set_stay_area, report_stay_area, report_target_info
    (variable-length), and anyone_in_reporting_area.
- ServerCommandDefs docstring: clarify the area_id indexing convention
  rather than treating it as inconsistent. Wire-level area_id is
  0-indexed (0..3) per inovelli.ts, while report payloads use
  area_1..area_4 field names to match Inovelli's user-facing 1-indexed
  labeling. Document the mapping explicitly so callers don't read it
  as an off-by-one bug.
- test_vzm32_mmwave_report_target_info_variable_length: drop the
  schema-introspection trick that grabbed the compiled list type from
  report_target.fields. zigpy's Struct coerces a plain Python list
  into the t.List[MMWaveTarget] field, so the test no longer reaches
  into zigpy internals.
@tmmueller tmmueller force-pushed the inovelli-vzm32-area-commands branch from 9c854e4 to 20aaa66 Compare May 9, 2026 13: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.

2 participants