Skip to content

Sync beta to main: WizMote remote control + IR receiver removal#39

Open
bharvey88 wants to merge 26 commits into
mainfrom
beta
Open

Sync beta to main: WizMote remote control + IR receiver removal#39
bharvey88 wants to merge 26 commits into
mainfrom
beta

Conversation

@bharvey88

@bharvey88 bharvey88 commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Version: 26.6.22.1

What does this implement/fix?

Sync beta into main for release. Includes:

  • WizMote (ESP-NOW) remote control, with buttons remappable from Home Assistant
  • Home Assistant blueprint for WizMote buttons (moved to the Blueprints repo)
  • Removed unused IR remote_receiver (IR removed from the PCB)
  • README: documents WizMote HA control + blueprint

Types of changes

  • Bugfix (fixed change that fixes an issue)
  • New feature (thanks!)
  • Breaking change (repair/feature that breaks existing functionality)
  • Dependency Update - Does not publish
  • Other - Does not publish
  • Website of github readme file update - Does not publish
  • Github workflows - Does not publish

Checklist / Checklijst:

  • The code change has been tested and works locally
  • The code change has not yet been tested

If user-visible functionality or configuration variables are added/modified:

  • Added/updated documentation for the web page

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added WizMote remote control support with customizable button mapping for media playback, light control, and Home Assistant events
    • Implemented auto-discovery mode for remote pairing
    • Added manual MAC address configuration for saved remotes
  • Documentation

    • Updated README with WizMote integration guide and Home Assistant blueprint import instructions

bharvey88 and others added 26 commits June 18, 2026 20:14
Pair a WizMote and control playback over ESP-NOW. Button mapping:
ON play / OFF pause; Scene 1/2 previous/next track; Scene 3/4 fire HA
events (cast1_wizmote_scene_3 / _4) for playlists/favorites; Bright +/-
volume up/down; Night toggles the RGB light.

Pairing via the WizMote MAC text entity, an Auto-Discovery switch, a
status sensor, and a Clear Pairing button; the peer is restored on boot.

ESP-NOW carries no channel in Core.yaml so it follows WiFi on CAST-1_W.
CAST-1_ETH (no WiFi) adds a starting channel plus a scan interval that
hops channels until the WizMote is heard, then holds. Bump version.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
The on_broadcast handler logged the raw button number, but nothing
showed what the dispatch actually did with it, so a press that lands
on volume or an HA event looked like nothing happened. Log the mapped
action in each branch (volume logs the resulting level), and warn on
any unmapped button.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Pull the WizMote pieces (espnow, pairing entities, button dispatch,
globals, substitutions, boot restore) out of Core.yaml into their own
wizmote.yaml, included via packages. Pure reorg: the fully-resolved
config is byte-for-byte the same set of entities on both variants.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Add a select per WizMote button (On, Off, Night, Brightness Up/Down,
Button 1-4) so the action is chosen in HA, no YAML editing. Options:
Nothing / Play / Pause / Play-Pause / Next / Previous / Volume Up/Down /
Toggle Light / Send HA Event. Defaults match the previous fixed mapping.

process_wizmote_button now looks up the pressed button's select and runs
a shared run_wizmote_action sub-script. "Send HA Event" fires
esphome.cast1_wizmote_event with the button label in the payload, so any
button can be wired to a playlist/scene/etc. in a HA automation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Lets users wire any "Send HA Event" button to an HA action (playlist,
scene, script) without editing automations by hand. One action selector
per button; triggers on esphome.cast1_wizmote_event.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
YAML parsed the bare On/Off input names as booleans, so HA rejected the
import. Quote all names. Also relocate the blueprint to a top-level
Blueprints/ directory and point source_url at the new path.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
So testers can confirm they flashed this build.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
The event delivers the button as a number, so the string comparisons in
the choose never matched and no action ran. Cast it with | string.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
HA's template engine coerces the numeric button "3" to the int 3 when it
stores the pressed variable, so a variable-level | string is undone and
3 == '3' stayed false. Move | string into each comparison where the cast
survives, so the numeric buttons match.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Replace the template choose with one event trigger per button (event_data
filter + trigger id) and condition: trigger. HA matches the raw event
value instead of a Jinja-coerced variable, so the numeric buttons can't
break, it validates at load instead of failing silently, and quoting the
button values avoids the on/off YAML-boolean trap.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Each button now has its own Action dropdown (same 10 options as the
device) plus a custom action, grouped in collapsible sections. On HA
start and on save, the blueprint pushes each pick down to the matching
WizMote select on the CAST-1 via select.select_option, so the device
page no longer needs touching - the blueprint is the source of truth.
Local media actions still run on-device; "Send HA Event" runs the
button's custom action. Needs a CAST-1 device picker; no firmware change.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Match the BTN-1 blueprint pattern: filter by manufacturer ApolloAutomation
and the CAST-1-W / CAST-1-ETH models so the picker only lists CAST-1s
instead of every ESPHome device.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Adds a "Default: <action>" hint to every button so the shipped behavior
is visible even after someone changes the dropdown.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Rename the file (source_url updated to match) and replace the description
blob with scannable emoji-labeled lines.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Lead line, a Features list, and a plain-language explainer of "Send HA
Event" with examples (Music Assistant playlist, toggle a room's lights,
run a scene). Emojis only on the bullets, not the section headers.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Clearer phrasing: defaults you can override to suit your needs, override
from the dropdown, and "Send HA Event" to set up a custom action.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Merge the "ships with a default" and "override from the dropdown" bullets
into one, since they said the same thing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Lives in ApolloAutomation/Blueprints (CAST-1/CAST-1-WizMote.yaml, PR #16);
this PR is now firmware-only.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
README: document WizMote Home Assistant control + blueprint
Configure the WizMote from Home Assistant (per-button selects + blueprint)
Trevor removed the IR hardware from the CAST-1 PCB; the remote_receiver on
GPIO07 was unused (nothing consumed it) and left dump: all on. Removes it and
bumps version to 26.6.22.1.

Closes #16

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Remove unused IR remote_receiver (IR removed from PCB)
@github-actions github-actions Bot added the new-feature New feature or request label Jun 23, 2026
@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Adds WizMote ESP-NOW remote control support to the Apollo CAST-1. A new wizmote.yaml package implements pairing state globals, Home Assistant configuration entities (per-button selects, MAC input, discovery switch), action/routing scripts, and ESP-NOW receive handlers. CAST-1_ETH.yaml gains periodic channel scanning, Core.yaml includes the package and removes remote_receiver, and the README documents the feature.

Changes

WizMote ESP-NOW Integration

Layer / File(s) Summary
WizMote globals, HA entities, and pairing UI
Integrations/ESPHome/wizmote.yaml
Defines substitutions for button codes and blank MAC, runtime globals (last sequence, paired MAC, last-packet timestamp, scan channel), a "Clear WizMote Pairing" button, an "Auto-Discovery" switch, per-button select entities mapping each physical button to configurable actions, a diagnostic status text sensor, and a validated MAC text entity that adds/removes ESP-NOW peers on change.
Action scripts and ESP-NOW receive/boot handlers
Integrations/ESPHome/wizmote.yaml
Defines run_wizmote_action (maps select string to media play/pause/toggle/next/prev, volume up/down, RGB light toggle, or esphome.cast1_wizmote_event) and process_wizmote_button (routes button code to select value). Configures espnow with on_unknown_peer pairing (when discovery mode is on) and on_broadcast filtering/dispatch, plus on_boot peer restoration.
ETH variant ESP-NOW channel scan
Integrations/ESPHome/CAST-1_ETH.yaml
Adds espnow: channel: 1 and a 2-second interval that increments/wraps wizmote_scan_channel (1–13) and calls espnow.set_channel when discovery mode is active or when a valid MAC is paired but no packet received in the last 30 seconds.
Core.yaml wiring and README
Integrations/ESPHome/Core.yaml, README.md
Bumps substitutions.version to 26.6.22.1, adds packages include for wizmote.yaml, removes the remote_receiver GPIO07 block, adjusts testScript, and adds a "WizMote" README subsection with blueprint import badge.

Sequence Diagram(s)

sequenceDiagram
  participant WizMote as WizMote Remote
  participant ESPNOW as espnow (CAST-1)
  participant Scripts as process_wizmote_button / run_wizmote_action
  participant HA as Home Assistant

  rect rgba(100, 149, 237, 0.5)
    Note over WizMote,HA: Pairing Flow
    WizMote->>ESPNOW: broadcast (unknown peer)
    ESPNOW->>ESPNOW: discovery mode ON → capture sender MAC
    ESPNOW->>ESPNOW: disable discovery mode, store paired MAC
  end

  rect rgba(144, 238, 144, 0.5)
    Note over WizMote,HA: Button Press Flow
    WizMote->>ESPNOW: broadcast packet (paired MAC)
    ESPNOW->>ESPNOW: validate size, deduplicate sequence, update last_packet_ms
    ESPNOW->>Scripts: process_wizmote_button(button_code)
    Scripts->>Scripts: map code → select entity value
    Scripts->>Scripts: run_wizmote_action(action string)
    Scripts->>HA: media control call / light.toggle / esphome.cast1_wizmote_event
  end

  rect rgba(255, 165, 0, 0.5)
    Note over ESPNOW,HA: Channel Scan (ETH, no recent packet)
    ESPNOW->>ESPNOW: every 2 s: increment wizmote_scan_channel (1–13)
    ESPNOW->>ESPNOW: espnow.set_channel(wizmote_scan_channel)
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • ApolloAutomation/CAST-1#1: Established the Core.yaml and CAST-1_ETH.yaml baseline that this PR directly builds on with the wizmote.yaml package include and ETH-variant ESP-NOW additions.
  • ApolloAutomation/CAST-1#32: Implements the same espnow: block and periodic wizmote_scan_channel increment/espnow.set_channel pattern in CAST-1_ETH.yaml.
  • ApolloAutomation/CAST-1#35: Overlaps on the same wizmote.yaml per-button select mapping structure, process_wizmote_button/run_wizmote_action scripts, and esphome.cast1_wizmote_event emission.

Suggested labels

new-feature

🐇 Hop hop, a WizMote appears,
Nine buttons mapped through ESP-NOW gears,
Discovery mode finds the remote with glee,
Each channel scanned so packets run free,
Now CAST-1 and WizMote dance in harmony! 🎵

🚥 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 accurately captures the two main changes: introducing WizMote remote control functionality and removing the IR receiver, directly reflecting the core modifications in the changeset.
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.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch beta

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.

@bharvey88 bharvey88 requested a review from TrevorSchirmer June 23, 2026 15:57

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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 `@Integrations/ESPHome/wizmote.yaml`:
- Around line 463-482: The on_boot block restores the saved WizMote peer by
adding it via espnow.peer.add but fails to record this restored MAC address in
the wizmote_previous_mac variable. Since wizmote_previous_mac has restore_value
set to no, it remains empty after boot, causing the on_value delete branch to
skip removing the old peer if the MAC is later changed, leaving a stale peer.
After the espnow.peer.add action completes in the on_boot block, add an action
to set wizmote_previous_mac to the value of wizmote_mac_address so that future
MAC changes can properly delete the boot-restored peer.
- Around line 204-240: The return statement in the initial MAC validation lambda
only exits that lambda without preventing the subsequent espnow.peer.delete and
espnow.peer.add actions from executing. A malformed MAC value will bypass the
validation guard and still be processed by sscanf and stored. Fix this by
creating a global boolean variable wizmote_mac_valid initialized to false, then
set it to true only after successful MAC validation in the first lambda, and
update the conditions for both the espnow.peer.delete if block and the
espnow.peer.add if block to check this flag alongside their existing conditions
to ensure peer operations only execute when the MAC is valid.

In `@README.md`:
- Around line 8-17: The blueprint import link in the WizMote section contains a
broken URL that returns HTTP 404. Locate the correct URL path for the
CAST-1-WizMote.yaml file in the ApolloAutomation/Blueprints repository and
update the blueprint_url parameter in the redirect link to point to the correct
location. If the blueprint file is no longer available or has been moved, either
remove the entire blueprint import badge and link section, or replace it with
the correct working URL.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 877e8fde-7d2b-4c76-97a5-e5b99c392dda

📥 Commits

Reviewing files that changed from the base of the PR and between 3eee497 and c53a2d2.

📒 Files selected for processing (4)
  • Integrations/ESPHome/CAST-1_ETH.yaml
  • Integrations/ESPHome/Core.yaml
  • Integrations/ESPHome/wizmote.yaml
  • README.md

Comment on lines +204 to +240
- lambda: |-
std::string mac = x;
bool valid = true;
for (int i = 0; i < 17; i++) {
if (i % 3 == 2) { if (mac[i] != ':') { valid = false; break; } }
else { if (!std::isxdigit(mac[i])) { valid = false; break; } }
}
if (!valid) {
ESP_LOGW("wizmote", "Invalid MAC: %s", mac.c_str());
return;
}
- if:
condition:
lambda: 'return (id(wizmote_previous_mac) != "" && id(wizmote_previous_mac) != "00:00:00:00:00:00");'
then:
- espnow.peer.delete:
address: !lambda |-
std::string mac = id(wizmote_previous_mac);
std::array<uint8_t, 6> mac_bytes;
sscanf(mac.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
&mac_bytes[0], &mac_bytes[1], &mac_bytes[2],
&mac_bytes[3], &mac_bytes[4], &mac_bytes[5]);
return mac_bytes;
- if:
condition:
lambda: 'return (x != "00:00:00:00:00:00" && x != "");'
then:
- espnow.peer.add:
address: !lambda |-
std::string mac = x;
std::array<uint8_t, 6> mac_bytes;
sscanf(mac.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
&mac_bytes[0], &mac_bytes[1], &mac_bytes[2],
&mac_bytes[3], &mac_bytes[4], &mac_bytes[5]);
return mac_bytes;
- lambda: 'id(wizmote_previous_mac) = x;'
- lambda: 'id(wizmote_status).update();'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In ESPHome, does a return; statement inside a lambda action stop the remaining actions in the same automation action list, or only that lambda?

💡 Result:

In ESPHome, a return; statement inside a lambda action only exits the lambda function itself [1][2][3]. It does not stop, cancel, or otherwise influence the remaining actions in the automation's action list [3]. Because the lambda is executed as a single action within the automation's sequence, the control flow of the automation will proceed to the next action in the list immediately after the lambda finishes executing, regardless of whether you used a return; statement inside the lambda [3]. If you need to stop the execution of an entire automation sequence from within a lambda, you cannot do so simply by returning [3]. Instead, you should consider alternatives such as: 1. Using conditional logic (if/else) within your YAML configuration to decide whether subsequent actions should run [1][4]. 2. If the automation is inside a script, you can use the script.stop action [5][6]. 3. Designing your logic such that subsequent actions are wrapped in a conditional action that checks a state variable you might update in your lambda [1][7].

Citations:


Invalid-MAC guard does not stop peer operations.

A return; statement inside the validation lambda (lines 204–214) only exits that lambda—it does not stop the remaining actions in the sequence. The subsequent if blocks for espnow.peer.delete and espnow.peer.add (lines 219, 231) will still execute, even when MAC validation fails. A malformed value (e.g., zz:zz:zz:zz:zz:zz) bypasses the guard and reaches sscanf with invalid bytes, and is stored as the previous MAC.

Gate the peer operations on validity by using a global flag:

🐛 Proposed fix

Add a global:

globals:
  - id: wizmote_mac_valid
    type: bool
    restore_value: no
    initial_value: 'false'

Then set and check it:

       - lambda: |-
           std::string mac = x;
           bool valid = true;
           for (int i = 0; i < 17; i++) {
             if (i % 3 == 2) { if (mac[i] != ':') { valid = false; break; } }
             else { if (!std::isxdigit(mac[i])) { valid = false; break; } }
           }
+          id(wizmote_mac_valid) = valid;
           if (!valid) {
             ESP_LOGW("wizmote", "Invalid MAC: %s", mac.c_str());
             return;
           }
       - if:
           condition:
-            lambda: 'return (id(wizmote_previous_mac) != "" && id(wizmote_previous_mac) != "00:00:00:00:00:00");'
+            lambda: 'return id(wizmote_mac_valid) && id(wizmote_previous_mac) != "" && id(wizmote_previous_mac) != "00:00:00:00:00:00";'
           then:
             - espnow.peer.delete:
@@
       - if:
           condition:
-            lambda: 'return (x != "00:00:00:00:00:00" && x != "");'
+            lambda: 'return id(wizmote_mac_valid) && x != "00:00:00:00:00:00" && x != "";'
           then:
             - espnow.peer.add:
🤖 Prompt for 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.

In `@Integrations/ESPHome/wizmote.yaml` around lines 204 - 240, The return
statement in the initial MAC validation lambda only exits that lambda without
preventing the subsequent espnow.peer.delete and espnow.peer.add actions from
executing. A malformed MAC value will bypass the validation guard and still be
processed by sscanf and stored. Fix this by creating a global boolean variable
wizmote_mac_valid initialized to false, then set it to true only after
successful MAC validation in the first lambda, and update the conditions for
both the espnow.peer.delete if block and the espnow.peer.add if block to check
this flag alongside their existing conditions to ensure peer operations only
execute when the MAC is valid.

Comment on lines +463 to +482
on_boot:
# Re-add the saved WizMote peer after ESP-NOW is up.
- priority: -100
then:
- delay: 2s
- if:
condition:
lambda: |-
std::string mac = id(wizmote_mac_address).state;
return (mac != "00:00:00:00:00:00" && mac != "");
then:
- logger.log: "Restoring WizMote pairing on boot..."
- espnow.peer.add:
address: !lambda |-
std::string mac = id(wizmote_mac_address).state;
std::array<uint8_t, 6> mac_bytes;
sscanf(mac.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
&mac_bytes[0], &mac_bytes[1], &mac_bytes[2],
&mac_bytes[3], &mac_bytes[4], &mac_bytes[5]);
return mac_bytes;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Boot peer restore leaves wizmote_previous_mac unset, leaking the old peer on reconfigure.

wizmote_previous_mac has restore_value: no, so it is "" after boot. The on_boot block adds the saved peer (Line 475) but never records it in wizmote_previous_mac. When the user later changes the MAC, the on_value delete branch (Line 217) sees an empty previous_mac, skips deletion, and the boot-added peer is never removed — a stale ESP-NOW peer accumulates.

🛠️ Record the restored MAC
               - espnow.peer.add:
                   address: !lambda |-
                     std::string mac = id(wizmote_mac_address).state;
                     std::array<uint8_t, 6> mac_bytes;
                     sscanf(mac.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
                            &mac_bytes[0], &mac_bytes[1], &mac_bytes[2],
                            &mac_bytes[3], &mac_bytes[4], &mac_bytes[5]);
                     return mac_bytes;
+              - lambda: 'id(wizmote_previous_mac) = id(wizmote_mac_address).state;'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
on_boot:
# Re-add the saved WizMote peer after ESP-NOW is up.
- priority: -100
then:
- delay: 2s
- if:
condition:
lambda: |-
std::string mac = id(wizmote_mac_address).state;
return (mac != "00:00:00:00:00:00" && mac != "");
then:
- logger.log: "Restoring WizMote pairing on boot..."
- espnow.peer.add:
address: !lambda |-
std::string mac = id(wizmote_mac_address).state;
std::array<uint8_t, 6> mac_bytes;
sscanf(mac.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
&mac_bytes[0], &mac_bytes[1], &mac_bytes[2],
&mac_bytes[3], &mac_bytes[4], &mac_bytes[5]);
return mac_bytes;
on_boot:
# Re-add the saved WizMote peer after ESP-NOW is up.
- priority: -100
then:
- delay: 2s
- if:
condition:
lambda: |-
std::string mac = id(wizmote_mac_address).state;
return (mac != "00:00:00:00:00:00" && mac != "");
then:
- logger.log: "Restoring WizMote pairing on boot..."
- espnow.peer.add:
address: !lambda |-
std::string mac = id(wizmote_mac_address).state;
std::array<uint8_t, 6> mac_bytes;
sscanf(mac.c_str(), "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
&mac_bytes[0], &mac_bytes[1], &mac_bytes[2],
&mac_bytes[3], &mac_bytes[4], &mac_bytes[5]);
return mac_bytes;
- lambda: 'id(wizmote_previous_mac) = id(wizmote_mac_address).state;'
🤖 Prompt for 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.

In `@Integrations/ESPHome/wizmote.yaml` around lines 463 - 482, The on_boot block
restores the saved WizMote peer by adding it via espnow.peer.add but fails to
record this restored MAC address in the wizmote_previous_mac variable. Since
wizmote_previous_mac has restore_value set to no, it remains empty after boot,
causing the on_value delete branch to skip removing the old peer if the MAC is
later changed, leaving a stale peer. After the espnow.peer.add action completes
in the on_boot block, add an action to set wizmote_previous_mac to the value of
wizmote_mac_address so that future MAC changes can properly delete the
boot-restored peer.

Comment thread README.md
Comment on lines +8 to +17
## WizMote

The CAST-1 gives you full Home Assistant control over a paired Wiz WizMote. Each of the nine buttons (On, Off, Night, Brightness Up/Down, and 1–4) is a configurable select on the device — assign it Play, Pause, Play / Pause, Next/Previous Track, Volume Up/Down, Toggle Light, or Send HA Event. The defaults give you media controls out of the box.

Set any button to **Send HA Event** to trigger a custom Home Assistant action — play a Music Assistant playlist, toggle a room's lights, run a scene or script.

Configure every button without leaving Home Assistant using the [CAST-1 WizMote blueprint](https://github.com/ApolloAutomation/Blueprints/tree/main/CAST-1):

[![Import Blueprint](https://my.home-assistant.io/badges/blueprint_import.svg)](https://my.home-assistant.io/redirect/blueprint_import/?blueprint_url=https%3A%2F%2Fgithub.com%2FApolloAutomation%2FBlueprints%2Fblob%2Fmain%2FCAST-1%2FCAST-1-WizMote.yaml)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Verify the WizMote blueprint file exists and is accessible

BLUEPRINT_URL="https://raw.githubusercontent.com/ApolloAutomation/Blueprints/main/CAST-1/CAST-1-WizMote.yaml"

echo "Checking blueprint accessibility..."
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$BLUEPRINT_URL")

if [[ "$HTTP_CODE" == "200" ]]; then
  echo "✓ Blueprint is accessible (HTTP $HTTP_CODE)"
  # Verify it's valid YAML
  curl -s "$BLUEPRINT_URL" | python -c "import yaml, sys; yaml.safe_load(sys.stdin)" && echo "✓ Valid YAML syntax" || echo "✗ Invalid YAML syntax"
else
  echo "✗ Blueprint not accessible (HTTP $HTTP_CODE)"
  echo "  URL: $BLUEPRINT_URL"
  exit 1
fi

Repository: ApolloAutomation/CAST-1

Length of output: 336


Update or remove the broken blueprint import link.

The blueprint URL at https://raw.githubusercontent.com/ApolloAutomation/Blueprints/main/CAST-1/CAST-1-WizMote.yaml returns HTTP 404 and is not accessible. Verify the correct location of the CAST-1-WizMote.yaml file in the ApolloAutomation/Blueprints repository and update the link, or remove the import badge if the blueprint is no longer available.

🤖 Prompt for 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.

In `@README.md` around lines 8 - 17, The blueprint import link in the WizMote
section contains a broken URL that returns HTTP 404. Locate the correct URL path
for the CAST-1-WizMote.yaml file in the ApolloAutomation/Blueprints repository
and update the blueprint_url parameter in the redirect link to point to the
correct location. If the blueprint file is no longer available or has been
moved, either remove the entire blueprint import badge and link section, or
replace it with the correct working URL.

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

Labels

new-feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants