Skip to content

Add HomeWizard P1 usermod: live grid power visualization ("Grid Flow" effect)#5719

Open
stephancar wants to merge 13 commits into
wled:mainfrom
stephancar:usermod/homewizard-p1
Open

Add HomeWizard P1 usermod: live grid power visualization ("Grid Flow" effect)#5719
stephancar wants to merge 13 commits into
wled:mainfrom
stephancar:usermod/homewizard-p1

Conversation

@stephancar

@stephancar stephancar commented Jul 5, 2026

Copy link
Copy Markdown

What it does

New usermod homewizard_p1 (ESP32 only) that polls a HomeWizard P1 meter (a popular WiFi P1 dongle for European smart meters) on the local network and visualizes the home's live grid power through a new "Grid Flow" effect:

  • Import/offtake (consuming from grid): purple pulses flowing toward the segment start, speed and brightness scale with wattage
  • Export/injection (e.g. solar): green pulses flowing toward the segment end
  • Near zero: calm white breathing (configurable deadband)

The meter is discovered automatically via mDNS (_hwenergy._tcp), or a fixed host can be configured. Deadband, full-scale wattage, and poll interval are configurable in Usermod Settings; the effect has Speed / Pulses / Trail / Blur sliders.

How it works

  • All networking (mDNS discovery + HTTP polling of the local API v1 /api/v1/data) runs on a dedicated low-priority FreeRTOS task pinned to core 0 (same pattern as the audioreactive usermod's processing task), so blocking calls can never stall the LED pipeline. The task publishes 32-bit values (atomic on ESP32); host strings are exchanged under a mutex.
  • The effect renders from a low-pass filtered power value (~1.2 s time constant), and the pulse position is integrated over time, so poll steps, deadband crossings and import/export flips all animate smoothly with no jumps.
  • Data-loss handling: the effect falls back to a clearly visible dim breathing; the last discovered meter IP is never discarded (background re-discovery only replaces it on success), so the usermod self-heals after WiFi/mDNS hiccups or meter IP changes.

Testing

  • Tested on real hardware: ESP32 (esp32dev) + WS2812B (120 LEDs) + HomeWizard HWE-P1 (local API v1).
  • Long-run stability: 12 minutes of continuous injection/neutral/offtake state cycling with stable heap and no resets; separate stress tests for data-loss recovery (meter unreachable → dim breathing → automatic recovery) and mDNS rediscovery.
  • The folder includes p1_simulator.py, a small fake local-API server that cycles injection/neutral/offtake every 10 s, so the usermod can be developed and tested without a real meter. Rendered output was verified against it via /json/live.
  • Compiles clean for esp32dev; library.json restricts the usermod to espressif32 (it needs a FreeRTOS task).

Notes

  • No changes outside usermods/homewizard_p1/; no platformio.ini changes.
  • Larger AI-generated sections are marked with // AI: comments per AGENTS.md; the code was written with AI assistance, reviewed and hardware-tested by the contributor.
  • Happy to receive maintainer guidance on anything (naming, effect metadata, etc.).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added an ESP32-only “HomeWizard P1” WLED usermod that fetches meter power via the local API, using mDNS auto-discovery or a manual host:port override.
    • Added a “Grid Flow” visualization that smoothly responds to active_power_w, including import/export direction, neutral deadband breathing, and a graceful neutral “no data” state when updates stop.
    • Added visual tuning (Speed, Pulses, Trail, Blur) and behavior controls (update interval, deadband, full-scale).
  • Documentation

    • Added full README setup instructions, configuration details, effect guidance, troubleshooting, and a P1 simulator for testing.

stephancar and others added 8 commits July 4, 2026 22:06
Polls a HomeWizard P1 meter (local API v1) and visualizes live grid
power as a custom effect: purple pulses for offtake, green for
injection, white breathing when neutral. The meter is discovered
automatically via mDNS (_hwenergy._tcp) or set manually.

HTTP polling is fully asynchronous (AsyncClient); TCP callbacks only
buffer data and parsing happens on the main loop task, avoiding the
blocking-request watchdog resets of the previous attempt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Deleting the client inside onTimeout runs the destructor, whose close
fires onDisconnect, which deleted the client a second time. Only flag
the failure in onTimeout; the rx timeout closes the connection and
onDisconnect performs the single delete.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Render from a low-pass filtered power value (~1.2 s time constant) so
3 s poll steps ramp instead of jump. Fade the color white -> purple/
green proportionally with power (no hard cut at the deadband edge),
let pulses gradually emerge from the neutral breathing, and cross-fade
the waiting/active brightness via a smoothed presence factor.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…r ramp

Testing revealed stuttering pulses, no visible green during injection,
and a lockup after about a minute of running.

- Move all networking (mDNS discovery + HTTP polling) to a dedicated
  low-priority task pinned to core 0, replacing the AsyncClient state
  machine. This removes the client deletion races that most plausibly
  caused the lockup, and discovery no longer pauses the LEDs.
- Integrate the pulse position over time instead of deriving it from
  time * speed; speed changes no longer rescale the phase and teleport
  the pulses (the stutter).
- Saturate the identity color (purple/green) at ~25% of the power range
  with an ease-out curve so a few hundred watts is clearly colored;
  magnitude keeps scaling flow speed and brightness to full scale.
- Add a Blur slider and a quadratic comet-style trail falloff.
- Add p1_simulator.py, a fake local API v1 that cycles injection/
  neutral/offtake every 10 s for testing without a real meter; verified
  rendered colors against it via /json/live.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Investigation of a reported 'LEDs off until power cycle' incident ruled
out brownout (full-white stress test), meter rate limiting (90 fresh
connections in 3 min, zero failures) and crashes under state changes
(12 min of simulated injection/neutral/offtake cycling, stable heap).
The remaining explanation: fetch failures put the effect into its
no-data state, which was so dim it read as 'off', and discovery could
fail to recover because the last known meter address was discarded.

- Never forget the discovered meter IP; background re-discovery only
  replaces it on success, so a broken mDNS state no longer strands the
  usermod and polling resumes as soon as the meter answers.
- Raise the no-data breathing level so a data outage is visibly
  'breathing dimly' instead of looking switched off.
- Report seconds since the last successful fetch on the info page.
- Guard the smoothing filters against NaN poisoning.
- Halve the flow speed range (2-30 px/s): ambient, not alarming.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
State the ESP32 requirement explicitly, document the Blur slider, and
add a power-supply note (white is the maximum-current state; configure
ABL with headroom for the ESP32).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The networking runs on a FreeRTOS task, so the usermod is ESP32-only;
declaring the platform lets ESP8266 CI builds skip it cleanly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Root cause of the recurring switch-off-at-white incidents, captured
live with the firmware healthy and rendering: master power was toggled
off (and the segment color randomized to green) with no HTTP or UDP
trace - phantom presses of the default GPIO0 button from electrical
noise during the white-transition current step. Self-latching because
an off strip draws no current, so no phantom press turns it back on.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • ✅ Review completed - (🔄 Check again to review again)

Walkthrough

Adds an ESP32-only HomeWizard P1 usermod that discovers or uses a configured host, polls the local API on a dedicated task, smooths power readings, and renders a “Grid Flow” effect. It also adds build metadata, a simulator, and user-facing documentation.

Changes

HomeWizard P1 Usermod

Layer / File(s) Summary
Shared state and effect definitions
usermods/homewizard_p1/homewizard_p1.cpp
Defines shared state and constants, and the Grid Flow rendering mode that maps smoothed power to directional pulses with trail, blur, and presence-based breathing.
Discovery and fetch task implementation
usermods/homewizard_p1/homewizard_p1.cpp
Adds HomeWizardP1Usermod task state, mutex-protected host handling, mDNS discovery, HTTP fetch and streamed JSON parsing of active_power_w, and the background polling loop with retry and rediscovery behavior.
Loop smoothing and status reporting
usermods/homewizard_p1/homewizard_p1.cpp
loop() filters power and presence over time, and addToJsonInfo() reports live readings or task-derived status/error strings.
Configuration and registration
usermods/homewizard_p1/homewizard_p1.cpp, usermods/homewizard_p1/library.json
addToConfig/readFromConfig serialize and clamp settings, update task-visible host state, define the module build metadata, and register the usermod instance.
Simulator and documentation
usermods/homewizard_p1/p1_simulator.py, usermods/homewizard_p1/readme.md
Adds the Python HomeWizard API simulator and README coverage for setup, configuration, troubleshooting, simulator usage, and technical notes.

Estimated code review effort: 4 (Complex) | ~60 minutes

Suggested reviewers: blazoncek

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the new HomeWizard P1 usermod and its live Grid Flow visualization feature.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@usermods/homewizard_p1/homewizard_p1.cpp`:
- Line 322: The early return in the HomeWizard usermod update flow leaves the
Grid Flow effect state active when the usermod is disabled. Update the logic
around the enabled check in homewizard_p1.cpp (the update/smoothing path in the
HomeWizard usermod class) so disabling the usermod also clears or resets the
registered Grid Flow state before returning, preventing stale import/export
visuals from persisting.
- Line 224: The host/port parsing in homewizard_p1.cpp currently uses atoi() and
assigns directly to a uint16_t, which lets malformed, negative, or oversized
ports wrap to unintended values. Update the host:port parsing logic around the
colon handling to validate the port string explicitly in the same parsing flow,
reject non-numeric or out-of-range values, and only accept ports within the
valid 1–65535 range before storing them in port. Use the existing parsing block
near the colon check to enforce this validation and fail the config instead of
silently normalizing bad input.
- Around line 176-188: The mutex/task creation paths in homewizard_p1 need
failure handling: `ensureMutex()` currently assumes `xSemaphoreCreateMutex()`
succeeds, and `setup()` appears to ignore a failed `xTaskCreatePinnedToCore()`
result. Update `ensureMutex()` and `getEffectiveHost()` so they detect a null
`p1Mutex` and skip any `xSemaphoreTake()`/`xSemaphoreGive()` usage when creation
fails, and add a check around the `xTaskCreatePinnedToCore()` call in `setup()`
to surface the error instead of leaving the usermod idle. Use the existing
`ensureMutex`, `getEffectiveHost`, and `setup` symbols to locate the affected
code.
- Around line 29-30: The shared P1 scalar fields are crossing the
fetch-task/main-thread boundary without a real synchronization mechanism, so
protect `p1PowerW`, `p1LastGoodMs`, `taskStatus`, `taskHttpCode`,
`updateIntervalMs`, `autoDiscover`, and `cfgEnabled` using the existing
`p1Mutex` or convert them to `std::atomic` and read/write them consistently.
Update the relevant access points in the HomeWizard P1 task and its readers so
these values are accessed under the same synchronization scheme as the host
strings, rather than relying on `volatile`.
- Around line 242-255: Parse the HomeWizard response as a stream in the logic
around http.getString(), deserializeJson, and p1PowerW so the filter works
without buffering the whole body, and replace the containsKey check with a
numeric type check on active_power_w. Update the flow in the same block to
deserialize directly from http.getStream() and only assign p1PowerW when
doc["active_power_w"].is<float>() is true; otherwise set ST_JSON_ERR and return.
- Around line 419-420: The wattage normalization in the configuration path can
overflow when `p1DeadbandW` is at `INT_MAX`, so update the logic around
`p1DeadbandW` and `p1FullScaleW` to avoid evaluating `p1DeadbandW + 1` in the
same integer type. Use a wider intermediate or clamp the upper bound first, then
enforce that `p1FullScaleW` remains strictly greater than `p1DeadbandW` inside
the `homewizard_p1` normalization code.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7f1ca196-802d-4942-a4d2-62dfaae98475

📥 Commits

Reviewing files that changed from the base of the PR and between 8a67495 and 0d6a248.

📒 Files selected for processing (4)
  • usermods/homewizard_p1/homewizard_p1.cpp
  • usermods/homewizard_p1/library.json
  • usermods/homewizard_p1/p1_simulator.py
  • usermods/homewizard_p1/readme.md

Comment thread usermods/homewizard_p1/homewizard_p1.cpp
Comment thread usermods/homewizard_p1/homewizard_p1.cpp Outdated
Comment thread usermods/homewizard_p1/homewizard_p1.cpp Outdated
Comment thread usermods/homewizard_p1/homewizard_p1.cpp Outdated
Comment thread usermods/homewizard_p1/homewizard_p1.cpp Outdated
Comment thread usermods/homewizard_p1/homewizard_p1.cpp Outdated
stephancar and others added 2 commits July 5, 2026 15:42
Second failure mode captured live: hard chip freeze (serial silent, no
panic) exactly as a ~5 kW load switched off, i.e. a mains transient.
Distinct from the phantom-button mode and inherent to the use case,
since a grid-power light lives near big switching loads. Document the
hardware mitigations and the WLED_WATCHDOG_TIMEOUT build flag.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The switch-off-at-transition incidents were caused by a leftover Home
Assistant automation reacting to the same P1 meter, not by GPIO0 noise:
the signature (on=false, brightness and color set) recurred with the
button removed, and the HA WLED integration polling was visible in the
debug serial all along as Not-Found /presets.json calls. Replace the
phantom-button advice with guidance on identifying external
controllers, which is the far more likely cause for this usermod
audience.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@softhack007 softhack007 added the AI Partly generated by an AI. Make sure that the contributor fully understands the code! label Jul 5, 2026
- Use std::atomic for all scalars crossing the fetch-task boundary
  instead of volatile.
- Handle mutex and task creation failures: ensureMutex() reports
  failure, all xSemaphoreTake() paths are guarded against a null
  mutex, and a failed xTaskCreatePinnedToCore() is surfaced on the
  info page instead of leaving the usermod silently idle.
- Validate host:port with strtol and reject malformed or out-of-range
  ports instead of wrapping them.
- Parse the HTTP response from the stream (no full-body buffering)
  and require active_power_w to be numeric, rejecting null.
- Reset the smoothed visuals when the usermod is disabled so the
  still-registered effect does not show stale import/export state.
- Clamp deadbandW before deriving the full-scale floor to avoid
  signed overflow at extreme config values.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@stephancar

Copy link
Copy Markdown
Author

All coderabbit findings addressed in 2c6efd0:

  • Cross-task scalars: switched from volatile to std::atomic for everything crossing the fetch-task boundary (p1PowerW, p1LastGoodMs, taskStatus, taskHttpCode, updateIntervalMs, autoDiscover, cfgEnabled).
  • Mutex/task creation failures: ensureMutex() now reports failure, every xSemaphoreTake() path is guarded against a null mutex, and a failed xTaskCreatePinnedToCore() is surfaced on the info page (ST_TASK_FAIL) instead of leaving the usermod silently idle.
  • host:port validation: strtol with full range/format checking; malformed or out-of-range ports are rejected (connection-error status) instead of wrapping.
  • Stream parsing + numeric check: response is parsed via http.getStream() (no full-body buffering) and the assignment is gated on doc["active_power_w"].is<float>(), which also rejects a present-but-null field.
  • Disabled-state reset: disabling the usermod clears the smoothed power/presence state so the still-registered effect falls back to its idle rendering instead of showing stale import/export visuals.
  • Overflow guard: deadbandW is clamped before deriving the full-scale floor, so deadbandW + 1 can no longer overflow at extreme config values.

Compiled for esp32dev and re-tested on the real hardware setup (ESP32 + WS2812B + HWE-P1): meter auto-discovery, polling, and the Grid Flow effect all verified working on the updated build.

🤖 Generated with Claude Code

// Returns false when no host is known yet.
bool getEffectiveHost(char *buf, size_t len) {
bool have = false;
if (xSemaphoreTake(p1Mutex, portMAX_DELAY) == pdTRUE) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

portMAX_DELAY can hang forever. Better to use a realistic shorter dalay, and some code to handle mutex aquisition failure.

Comment thread usermods/homewizard_p1/homewizard_p1.cpp Outdated
strip.addEffect(255, &mode_grid_flow, _data_FX_MODE_GRID_FLOW);
#ifdef ARDUINO_ARCH_ESP32
ensureMutex();
if (xSemaphoreTake(p1Mutex, portMAX_DELAY) == pdTRUE) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

portMAX_DELAY => see my previous comments

}
cfgEnabled = enabled;
// Low priority, pinned to core 0 (WLED's LED loop runs on core 1)
xTaskCreatePinnedToCore(fetchTask, "P1Fetch", 10240, this, 1, &fetchTaskHandle, 0);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

if this is not timing-critical (=needs to respond to an event within 1-2milliseconds), you can better use xTaskCreate (without pin to core).

Also check if 10240 words of stack are really needed, it seems excessive.

Comment thread usermods/homewizard_p1/homewizard_p1.cpp Outdated
Comment thread usermods/homewizard_p1/homewizard_p1.cpp Outdated
@softhack007

softhack007 commented Jul 5, 2026

Copy link
Copy Markdown
Member

Compiled for esp32dev and re-tested on the real hardware setup (ESP32 + WS2812B + HWE-P1): meter auto-discovery, polling, and the Grid Flow effect all verified working on the updated build.

🤖 Generated with Claude Code

@stephancar I would prefer if you take the time to respond in person, instead of letting your AI talk for you.
After all, I'm also taking the time to review your work in person.

}
cfgEnabled = enabled;
// Low priority, pinned to core 0 (WLED's LED loop runs on core 1)
if (xTaskCreatePinnedToCore(fetchTask, "P1Fetch", 10240, this, 1, &fetchTaskHandle, 0) != pdPASS) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

No need to pin this task to core #0. Simply use xTaskCreate() instead.

if (found < 0 && n > 0) found = 0; // no explicit P1: fall back to the first device
if (found >= 0) {
String ip = MDNS.IP(found).toString();
if (p1Mutex != nullptr && xSemaphoreTake(p1Mutex, portMAX_DELAY) == pdTRUE) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Don't use portMAX_DELAY. Better to find a reasonable max delay, and handle mutex acquisition failure gracefully.

if (um->taskStatus != ST_OK && um->autoDiscover &&
millis() - p1LastGoodMs > 20000 && millis() - lastDiscoveryMs > 30000) {
bool manual = false;
if (um->p1Mutex != nullptr && xSemaphoreTake(um->p1Mutex, portMAX_DELAY) == pdTRUE) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

portMAX_DELAY is dangerous - see my previous comment.


#ifdef ARDUINO_ARCH_ESP32
ensureMutex();
if (xSemaphoreTake(p1Mutex, portMAX_DELAY) == pdTRUE) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same.

- **Blur**: softens the pulses for a smoother look.

## Troubleshooting

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@stephancar why did you add this to the readme?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I've lost days to problems that turned out to be other things (a leftover home assistant automation that controlled the wled controller as well as an undersized power supply)

Comment thread usermods/homewizard_p1/readme.md Outdated
strip turns white:

- **Device browns out / reboots at the white transition**: set a realistic
PSU limit in Config → LED Preferences (ABL), leaving ~250 mA headroom for

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@stephancar is brownout directly caused by your usermod?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

no this turned out to be the undersized PSU and/or the home assistant automation that I forgot about (it turned wled on or of based on whether I had injection or not)

char manualHost[64] = ""; // copy of 'host' for the task
char discoveredHost[48] = ""; // written by the task after mDNS discovery

#ifdef ARDUINO_ARCH_ESP32

@softhack007 softhack007 Jul 5, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This ifdef can be omitted - the complete usermod will not compile on 8266 any way.

// Returns false when no host is known yet.
bool getEffectiveHost(char *buf, size_t len) {
bool have = false;
if (p1Mutex != nullptr && xSemaphoreTake(p1Mutex, portMAX_DELAY) == pdTRUE) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

same

@softhack007 softhack007 added the usermod usermod related label Jul 5, 2026
@@ -0,0 +1,473 @@
#include "wled.h"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggestion: add a compile-time blocker for 8266 here. Then you can remove all remaining #ifdef ARDUINO_ARCH_ESP32 checks.

#ifndef ARDUINO_ARCH_ESP32
  #error "this usermod only supports esp32 boards"
#endif

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

None of them should be necessary at all. The supported platform list is already set in library.json.

@softhack007

Copy link
Copy Markdown
Member

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@usermods/homewizard_p1/homewizard_p1.cpp`:
- Around line 456-457: Guard the mutex acquisition in readFromConfig() because
ensureMutex() may fail and leave p1Mutex null before xSemaphoreTake() is called.
Update the readFromConfig() path to check the result of ensureMutex() (or
combine it with the mutex take like the other call sites) and return early if
the mutex could not be created, so xSemaphoreTake(p1Mutex, ...) is never reached
with a null handle.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ab7709e6-53af-4439-bf3b-2dae27abb9d9

📥 Commits

Reviewing files that changed from the base of the PR and between bc2c80d and 0f9ec56.

📒 Files selected for processing (4)
  • usermods/homewizard_p1/homewizard_p1.cpp
  • usermods/homewizard_p1/library.json
  • usermods/homewizard_p1/p1_simulator.py
  • usermods/homewizard_p1/readme.md

Comment thread usermods/homewizard_p1/homewizard_p1.cpp Outdated
- Handle init failures once in setup(): if mutex or task creation
  fails the usermod disables itself (reason shown on the info page)
  and the effect falls back to the segment color; this removes the
  scattered null-handle checks (softhack007's suggestion).
- Replace all portMAX_DELAY mutex waits with a 50 ms bounded wait;
  on timeout the caller skips the cycle and retries on the next one.
- Use xTaskCreate instead of xTaskCreatePinnedToCore (no need to pin).
- Right-size the task stack: measured high-water mark on real hardware
  is ~2.3 KB used (mDNS + HTTP + JSON), so 10240 -> 4096, leaving
  ~1.8 KB margin (verified on-device: 1852 B headroom). Debug builds
  report the headroom on the info page.
- Remove all ARDUINO_ARCH_ESP32 guards: library.json already restricts
  the usermod to espressif32 (willmmiles).
- Trim the readme troubleshooting to the usermod-specific pitfall
  (external meter-triggered automations); drop the generic PSU and
  EMI hardware advice (softhack007's readme questions).
- Guard the config-save host sync against the pre-setup case where the
  mutex does not exist yet (coderabbit).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@stephancar

Copy link
Copy Markdown
Author

Compiled for esp32dev and re-tested on the real hardware setup (ESP32 + WS2812B + HWE-P1): meter auto-discovery, polling, and the Grid Flow effect all verified working on the updated build.
🤖 Generated with Claude Code

@stephancar I would prefer if you take the time to respond in person, instead of letting your AI talk for you. After all, I'm also taking the time to review your work in person.

Fair point, sorry! This is my first PR and Im learning about AI tooling for the code (as marked in the sources). From here on the replies are my own. Thanks for taking the time to review my code, the suggestions are very helpfull!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI Partly generated by an AI. Make sure that the contributor fully understands the code! usermod usermod related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants