Skip to content

Zigbee2MQTT: add WOOX R7051 smart siren#2477

Open
William-De71 wants to merge 4 commits intoGladysAssistant:masterfrom
William-De71:features/woox-siren
Open

Zigbee2MQTT: add WOOX R7051 smart siren#2477
William-De71 wants to merge 4 commits intoGladysAssistant:masterfrom
William-De71:features/woox-siren

Conversation

@William-De71
Copy link
Copy Markdown
Contributor

@William-De71 William-De71 commented Mar 2, 2026

Pull Request check-list

To ensure your Pull Request can be accepted as fast as possible, make sure to review and check all of these items:

  • If your changes affect the code, did you write the tests?
  • Are tests passing? (npm test on both front/server)
  • Is the linter passing? (npm run eslint on both front/server)
  • x ] Did you run prettier? (npm run prettier on both front/server)
  • If you are adding a new feature/service, did you run the integration comparator? (npm run compare-translations on front)
  • Did you test this pull request in real life? With real devices? If this development is a big feature or a new service, we recommend that you provide a Docker image to the community (forum) for testing before merging.
  • If your changes modify the API (REST or Node.js), did you modify the API documentation? (Documentation is based on comments in code)
  • If you are adding a new features/services which needs explanation, did you modify the user documentation? See the GitHub repo and the website.
  • Did you add fake requests data for the demo mode (front/src/config/demo.js) so that the demo website is working without a backend? (if needed) See https://demo.gladysassistant.com.

NOTE: these things are not required to open a PR and can be done afterwards / while the PR is open.

Description of change

Add support of WOOX R7051 Smart siren
image

Summary by CodeRabbit

Release Notes

  • New Features
    • Added siren mode control with options for stop, burglar, fire, emergency, and various panic modes
    • Added siren volume level adjustment (low, medium, high, very high)
    • Added strobe and strobe level support for siren devices
    • Added AC connected device category
    • Extended device support with improved multi-language configurations

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 2, 2026

📝 Walkthrough

Walkthrough

This PR adds comprehensive support for siren device features with configurable modes, volume levels, and strobe settings. It introduces new React components for mode/level selection, backend mappings for zigbee2mqtt siren exposures, composite feature handling with parent-child relationships, and internationalized UI text across German, English, and French languages, alongside extensive test coverage.

Changes

Cohort / File(s) Summary
Frontend Siren Components
front/src/components/boxs/device-in-room/DeviceRow.jsx, front/src/components/boxs/device-in-room/device-features/SirenModeDeviceFeature.jsx, front/src/components/boxs/device-in-room/device-features/SirenLevelDeviceFeature.jsx
New siren feature components with mode (stop, burglar, fire, emergency, panic variants) and level (low, medium, high, very_high) select inputs bound to debounced value updates; DeviceRow extended to route new SIREN feature types to corresponding components.
Frontend Internationalization
front/src/config/i18n/de.json, front/src/config/i18n/en.json, front/src/config/i18n/fr.json
Added translations for siren modes, levels, strobe controls, and new ac-connected category across German, English, and French language files.
Frontend Icon Mappings
front/src/utils/consts.js
Extended DeviceFeatureCategoriesIcon with new SIREN sub-types (MODE, LEVEL, STROBE, STROBE_LEVEL, STROBE_DUTY_CYCLE) and new AC_CONNECTED category mapping.
Zigbee2MQTT Expose Mappings
server/services/zigbee2mqtt/exposes/binaryType.js, server/services/zigbee2mqtt/exposes/enumType.js, server/services/zigbee2mqtt/exposes/numericType.js, server/services/zigbee2mqtt/exposes/compositeType.js
Added new binary (ac_connected, strobe), enum (mode, level, strobe_level), and numeric (strobe_duty_cycle) feature mappings with read/write value conversions; compositeType now conditionally handles color_xy vs. other composite types.
Core MQTT Value Handling
server/services/zigbee2mqtt/lib/handleMqttMessage.js, server/services/zigbee2mqtt/lib/readValue.js, server/services/zigbee2mqtt/lib/setValue.js, server/services/zigbee2mqtt/lib/findMatchingExpose.js
New composite object value handling in MQTT ingestion; findMatchingExpose now returns {expose, parent} structure; readValue and setValue adapted to destructure and handle parent context for composite sub-features with nested payload construction.
Backend Constants
server/utils/constants.js
Added SIREN_MODE constants (stop, burglar, fire, emergency, police_panic, fire_panic, emergency_panic), VERY_HIGH to SIREN_LMH_VOLUME, AC_CONNECTED category, and expanded SIREN feature types (MODE, LEVEL, STROBE, STROBE_LEVEL, STROBE_DUTY_CYCLE).
Test Files - Expose Mappings
server/test/services/zigbee2mqtt/exposes/warningModeEnumType.test.js, server/test/services/zigbee2mqtt/exposes/warningLevelEnumType.test.js, server/test/services/zigbee2mqtt/exposes/compositeType.test.js
New test files validating enum writeValue/readValue conversions for siren mode and level; compositeType tests updated with colorExpose fixture and new pass-through tests for non-color composites.
Test Files - MQTT Logic
server/test/services/zigbee2mqtt/lib/findMatchingExpose.test.js, server/test/services/zigbee2mqtt/lib/handleMqttMessage.test.js, server/test/services/zigbee2mqtt/lib/readValue.test.js, server/test/services/zigbee2mqtt/lib/setValue.test.js, server/test/services/zigbee2mqtt/lib/getDiscoveredDevices.test.js
New assertions for {expose, parent} structure in findMatchingExpose; composite object value handling in MQTT ingestion; readValue and setValue sub-feature tests with nested payload verification; extended mock chains to support additional state lookups.
Test Fixtures
server/test/services/zigbee2mqtt/lib/payloads/mqtt_devices_get.json, server/test/services/zigbee2mqtt/lib/payloads/event_device_result.json
New TS0216 siren device entry with composite warning feature (mode, level, strobe, strobe_level, strobe_duty_cycle, duration) and corresponding event result fixture.

Sequence Diagram

sequenceDiagram
    participant Device as Siren Device
    participant MQTT as MQTT Broker
    participant Handler as handleMqttMessage
    participant FindExpose as findMatchingExpose
    participant ReadValue as readValue
    participant StateManager as State Manager
    participant UI as Frontend UI

    Device->>MQTT: Publish siren state (warning: {mode, level, strobe})
    MQTT->>Handler: MQTT message received
    Handler->>Handler: Detect composite object value
    Handler->>FindExpose: Find expose for 'warning'
    FindExpose-->>Handler: {expose: warning, parent: undefined}
    Handler->>Handler: Iterate subFields (mode, level, strobe)
    
    loop For each sub-field
        Handler->>FindExpose: Find expose for sub-field
        FindExpose-->>Handler: {expose: subExpose, parent: warning}
        Handler->>ReadValue: readValue(subExpose, subValue)
        ReadValue-->>Handler: Converted value
        Handler->>StateManager: Emit NEW_STATE with subFeature
    end
    
    StateManager->>UI: Update siren components
    UI->>UI: Render mode, level, strobe selections
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • Pierre-Gilles

Poem

🐰 Hoppy siren sounds now ring,
Modes and levels we can sing,
Burglar, fire, sirens blare,
Composite features everywhere!
Safety features, bright and clear—
What a thrilling rabbit cheer! 🚨✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title mentions adding support for WOOX R7051 smart siren, which aligns with the PR objectives and the majority of changes across multiple files introducing siren-related features, UI components, and translations.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
server/test/services/zigbee2mqtt/lib/findMatchingExpose.test.js (1)

51-56: Rename this test for accuracy.

The title says “with parent” but the assertions validate parent is undefined. Please rename to avoid ambiguity.

✏️ Suggested rename
-  it('expose discovered with parent on cover position', () => {
+  it('expose discovered without parent on cover position', () => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/test/services/zigbee2mqtt/lib/findMatchingExpose.test.js` around lines
51 - 56, The test title is misleading: the it() string "expose discovered with
parent on cover position" claims a parent but assertions check parent is
undefined; update the test description to reflect that no parent is present
(e.g., "expose discovered without parent on cover position" or "expose
discovered with no parent on cover position") in the test that calls
zigbee2MqttService.device.findMatchingExpose('0x00158d00045b2740', 'position')
so the name matches the assertions checking result.parent === undefined.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@server/test/services/zigbee2mqtt/lib/findMatchingExpose.test.js`:
- Around line 59-61: The test currently dereferences sirenDevice and its
friendly_name without asserting the fixture exists; add an explicit assertion
that the fixture was found (e.g., assert(sirenDevice) or
expect(sirenDevice).toBeDefined()) before assigning to
zigbee2MqttService.device.discoveredDevices and before calling
zigbee2MqttService.device.findMatchingExpose('0x00158d00045b2741','mode');
repeat the same explicit existence check for the other fixture use around the
block referenced at lines 70-72 so failures report a clear missing-fixture error
rather than a TypeError; use the sirenDevice variable and the
zigbee2MqttService.device.discoveredDevices lookup to locate where to add the
assertion.

---

Nitpick comments:
In `@server/test/services/zigbee2mqtt/lib/findMatchingExpose.test.js`:
- Around line 51-56: The test title is misleading: the it() string "expose
discovered with parent on cover position" claims a parent but assertions check
parent is undefined; update the test description to reflect that no parent is
present (e.g., "expose discovered without parent on cover position" or "expose
discovered with no parent on cover position") in the test that calls
zigbee2MqttService.device.findMatchingExpose('0x00158d00045b2740', 'position')
so the name matches the assertions checking result.parent === undefined.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8db6b0d and 4919757.

📒 Files selected for processing (26)
  • front/src/components/boxs/device-in-room/DeviceRow.jsx
  • front/src/components/boxs/device-in-room/device-features/SirenLevelDeviceFeature.jsx
  • front/src/components/boxs/device-in-room/device-features/SirenModeDeviceFeature.jsx
  • front/src/config/i18n/de.json
  • front/src/config/i18n/en.json
  • front/src/config/i18n/fr.json
  • front/src/utils/consts.js
  • server/services/zigbee2mqtt/exposes/binaryType.js
  • server/services/zigbee2mqtt/exposes/compositeType.js
  • server/services/zigbee2mqtt/exposes/enumType.js
  • server/services/zigbee2mqtt/exposes/numericType.js
  • server/services/zigbee2mqtt/lib/findMatchingExpose.js
  • server/services/zigbee2mqtt/lib/handleMqttMessage.js
  • server/services/zigbee2mqtt/lib/readValue.js
  • server/services/zigbee2mqtt/lib/setValue.js
  • server/test/services/zigbee2mqtt/exposes/compositeType.test.js
  • server/test/services/zigbee2mqtt/exposes/warningLevelEnumType.test.js
  • server/test/services/zigbee2mqtt/exposes/warningModeEnumType.test.js
  • server/test/services/zigbee2mqtt/lib/findMatchingExpose.test.js
  • server/test/services/zigbee2mqtt/lib/getDiscoveredDevices.test.js
  • server/test/services/zigbee2mqtt/lib/handleMqttMessage.test.js
  • server/test/services/zigbee2mqtt/lib/payloads/event_device_result.json
  • server/test/services/zigbee2mqtt/lib/payloads/mqtt_devices_get.json
  • server/test/services/zigbee2mqtt/lib/readValue.test.js
  • server/test/services/zigbee2mqtt/lib/setValue.test.js
  • server/utils/constants.js

Comment on lines +59 to +61
const sirenDevice = discoveredDevices.find((d) => d.friendly_name === '0x00158d00045b2741');
zigbee2MqttService.device.discoveredDevices[sirenDevice.friendly_name] = sirenDevice;
const result = zigbee2MqttService.device.findMatchingExpose('0x00158d00045b2741', 'mode');
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add an explicit fixture existence assertion before dereferencing.

If the fixture entry is missing/renamed, this will fail with a generic TypeError instead of a clear test failure.

✅ Suggested hardening
   const sirenDevice = discoveredDevices.find((d) => d.friendly_name === '0x00158d00045b2741');
+  assert.isDefined(sirenDevice, 'Expected siren fixture 0x00158d00045b2741 to exist in mqtt_devices_get.json');
   zigbee2MqttService.device.discoveredDevices[sirenDevice.friendly_name] = sirenDevice;

Also applies to: 70-72

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/test/services/zigbee2mqtt/lib/findMatchingExpose.test.js` around lines
59 - 61, The test currently dereferences sirenDevice and its friendly_name
without asserting the fixture exists; add an explicit assertion that the fixture
was found (e.g., assert(sirenDevice) or expect(sirenDevice).toBeDefined())
before assigning to zigbee2MqttService.device.discoveredDevices and before
calling
zigbee2MqttService.device.findMatchingExpose('0x00158d00045b2741','mode');
repeat the same explicit existence check for the other fixture use around the
block referenced at lines 70-72 so failures report a clear missing-fixture error
rather than a TypeError; use the sirenDevice variable and the
zigbee2MqttService.device.discoveredDevices lookup to locate where to add the
assertion.

@relativeci
Copy link
Copy Markdown

relativeci bot commented Mar 2, 2026

#3964 Bundle Size — 11.4MiB (+0.1%).

4919757(current) vs 8db6b0d master#3902(baseline)

Warning

Bundle contains 2 duplicate packages – View duplicate packages

Bundle metrics  Change 3 changes Regression 1 regression
                 Current
#3964
     Baseline
#3902
Regression  Initial JS 6.39MiB(+0.07%) 6.38MiB
No change  Initial CSS 310.18KiB 310.18KiB
Change  Cache Invalidation 64.81% 0%
No change  Chunks 51 51
No change  Assets 179 179
Change  Modules 1645(+0.12%) 1643
No change  Duplicate Modules 21 21
No change  Duplicate Code 0.94% 0.94%
No change  Packages 136 136
No change  Duplicate Packages 2 2
Bundle size by type  Change 1 change Regression 1 regression
                 Current
#3964
     Baseline
#3902
Regression  JS 8.29MiB (+0.13%) 8.28MiB
No change  IMG 2.66MiB 2.66MiB
No change  CSS 328.03KiB 328.03KiB
No change  Fonts 93.55KiB 93.55KiB
No change  Other 18.82KiB 18.82KiB
No change  HTML 13.58KiB 13.58KiB

Bundle analysis reportBranch William-De71:features/woox-sirenProject dashboard


Generated by RelativeCIDocumentationReport issue

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 3, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.79%. Comparing base (55c4cfc) to head (4919757).
⚠️ Report is 24 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2477      +/-   ##
==========================================
+ Coverage   98.74%   98.79%   +0.04%     
==========================================
  Files         990     1006      +16     
  Lines       17114    17514     +400     
==========================================
+ Hits        16900    17303     +403     
+ Misses        214      211       -3     

☔ 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.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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