First data
This commit is contained in:
commit
f5a209bb4a
13 changed files with 811 additions and 0 deletions
87
.github/copilot-instructions.md
vendored
Normal file
87
.github/copilot-instructions.md
vendored
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
# Home Assistant MCP Instructions
|
||||||
|
|
||||||
|
## OPNsense MCP Availability
|
||||||
|
|
||||||
|
This workspace also provides an OPNsense MCP server for network management and diagnostics.
|
||||||
|
|
||||||
|
- Preferred access path: HTTP MCP endpoint at `http://localhost:8811/mcp`
|
||||||
|
- Backed by the Docker service under `mcp/opnsense`
|
||||||
|
- Intended use: read-only diagnostics, firewall inspection, NAT inspection, routing analysis, ARP inspection, HAProxy inspection, and other OPNsense network-management tasks
|
||||||
|
|
||||||
|
When a user asks for OPNsense firewall, routing, NAT, VLAN, ARP, HAProxy, DNS blocklist, backup, or general network-diagnostics work in this workspace, prefer the available `mcp_opnsense_*` tools before falling back to manual shell commands.
|
||||||
|
|
||||||
|
Prefer read-only OPNsense operations first unless the user explicitly asks for a change.
|
||||||
|
|
||||||
|
This workspace manages two separate Home Assistant instances through MCP servers:
|
||||||
|
|
||||||
|
- `home`: use tools with the `mcp_hass-home_*` prefix.
|
||||||
|
- `casa`: use tools with the `mcp_hass-casa_*` prefix.
|
||||||
|
|
||||||
|
## Mandatory Instance Selection Rule
|
||||||
|
|
||||||
|
If a Home Assistant request does not explicitly say `home` or `casa`, do not assume.
|
||||||
|
|
||||||
|
You must ask which instance to use with the `vscode_askQuestions` tool before taking action.
|
||||||
|
|
||||||
|
Use a short forced-choice question such as:
|
||||||
|
|
||||||
|
- Header: `Home Assistant instance`
|
||||||
|
- Question: `Which Home Assistant instance should I use for this request?`
|
||||||
|
- Options: `home`, `casa`
|
||||||
|
- `allowFreeformInput: false`
|
||||||
|
|
||||||
|
This rule applies to all Home Assistant tasks, including diagnostics, state queries, automations, helpers, dashboards, scripts, devices, entities, areas, add-ons, and service calls.
|
||||||
|
|
||||||
|
## How To Distinguish The Instances
|
||||||
|
|
||||||
|
Primary distinction:
|
||||||
|
|
||||||
|
- `home` always maps to `mcp_hass-home_*` tools.
|
||||||
|
- `casa` always maps to `mcp_hass-casa_*` tools.
|
||||||
|
|
||||||
|
Operational fingerprints from diagnostics:
|
||||||
|
|
||||||
|
- `home`
|
||||||
|
- MCP prefix: `mcp_hass-home_*`
|
||||||
|
- Home Assistant location name: `Casa 24`
|
||||||
|
- Base URL: `https://home.maddo.science`
|
||||||
|
- Installation type: `Home Assistant Container`
|
||||||
|
- Host architecture: `amd64`
|
||||||
|
- Approximate size seen in diagnostics: 1391 entities, 17 areas
|
||||||
|
|
||||||
|
- `casa`
|
||||||
|
- MCP prefix: `mcp_hass-casa_*`
|
||||||
|
- Home Assistant location name: `Home`
|
||||||
|
- Base URL seen from HA: `http://supervisor/core`
|
||||||
|
- Host IP from health data: `192.168.100.69`
|
||||||
|
- Installation type: `Home Assistant OS`
|
||||||
|
- Host architecture: `aarch64` on `rpi5-64`
|
||||||
|
- Approximate size seen in diagnostics: 1414 entities, 11 areas
|
||||||
|
|
||||||
|
Do not infer the target instance from entity names, room names, or natural language alone. Only use the instance the user explicitly names, or the instance selected through `vscode_askQuestions`.
|
||||||
|
|
||||||
|
## Diagnostic Baseline
|
||||||
|
|
||||||
|
The following read-only checks were run successfully against both instances:
|
||||||
|
|
||||||
|
- `ha_check_config()`: valid on both `home` and `casa`
|
||||||
|
- `ha_get_overview(detail_level="minimal")`: successful on both
|
||||||
|
- `ha_get_system_health()`: successful on both
|
||||||
|
|
||||||
|
## Local MQTT Diagnostics File
|
||||||
|
|
||||||
|
For broker-level MQTT investigations in this workspace, first check for a local untracked file at `.local/mqtt-home.env`.
|
||||||
|
|
||||||
|
- This file is intended to stay out of git and may be missing on a fresh clone or a new PC.
|
||||||
|
- If the file is missing, incomplete, or clearly stale for the requested task, prompt the user to update it before attempting deeper MQTT diagnostics.
|
||||||
|
- Treat the file as local machine state, not repository configuration.
|
||||||
|
|
||||||
|
## Usage Examples
|
||||||
|
|
||||||
|
- If the user says `turn on the kitchen light`, ask which instance.
|
||||||
|
- If the user says `check automations on casa`, use `mcp_hass-casa_*` tools directly.
|
||||||
|
- If the user says `what is the state of the alarm in home`, use `mcp_hass-home_*` tools directly.
|
||||||
|
|
||||||
|
## Safety Rule
|
||||||
|
|
||||||
|
Before any write action on Home Assistant, confirm you are operating on the intended instance. If the request is ambiguous, stop and ask.
|
||||||
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
.local/
|
||||||
301
docs/shelly-dhcp-investigation.md
Normal file
301
docs/shelly-dhcp-investigation.md
Normal file
|
|
@ -0,0 +1,301 @@
|
||||||
|
# Shelly DHCP Investigation
|
||||||
|
|
||||||
|
Date: 2026-04-17
|
||||||
|
|
||||||
|
Update: the Kea reservation workaround was applied during this pass.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This document investigates why `Shelly-Server` is live at `192.168.100.127` even though OPNsense at `192.168.100.254` has a reservation for the device at `192.168.100.75` and is expected to be the only authoritative DHCP server on the LAN.
|
||||||
|
|
||||||
|
No destructive changes were made during this pass. All checks were read-only diagnostics.
|
||||||
|
|
||||||
|
## Executive Summary
|
||||||
|
|
||||||
|
The strongest current evidence does not point to a confirmed rogue DHCP server.
|
||||||
|
|
||||||
|
It also does not support the idea that OPNsense is holding an old reservation for a replaced Shelly unit.
|
||||||
|
|
||||||
|
The stronger explanation is:
|
||||||
|
|
||||||
|
1. `Shelly-Server` is configured for DHCP, not a static IP.
|
||||||
|
2. The device is live and reports itself as `192.168.100.127`.
|
||||||
|
3. The firewall still has a static reservation for the device's factory MAC `34:94:54:73:E2:28` at `192.168.100.75`.
|
||||||
|
4. On the LAN, `192.168.100.127` resolves to a different MAC, `02:0F:B5:73:E2:28`, not the Shelly factory MAC.
|
||||||
|
5. That observed MAC is locally administered and preserves only the last three bytes of the Shelly MAC.
|
||||||
|
|
||||||
|
This strongly suggests an intermediate bridge/router/AP behavior that rewrites the client MAC on the wire. If that is true, OPNsense may still be the DHCP server, but the reservation on `34:94:54:73:E2:28` will never match because the DHCP server sees `02:0F:B5:73:E2:28` instead.
|
||||||
|
|
||||||
|
If you had replaced the Shelly and forgotten to update the reservation, the reservation MAC and the live device's own reported MAC would differ. In this case they match, so the reservation appears tied to the correct physical Shelly, just not to the effective MAC seen on the LAN.
|
||||||
|
|
||||||
|
## Confirmed Facts
|
||||||
|
|
||||||
|
### 1. OPNsense LAN identity
|
||||||
|
|
||||||
|
- LAN interface IP in OPNsense config: `192.168.100.254/24`
|
||||||
|
- The local Windows host on the same subnet has:
|
||||||
|
- IPv4 address `192.168.100.134`
|
||||||
|
- default gateway `192.168.100.254`
|
||||||
|
- DHCP server `192.168.100.254`
|
||||||
|
- DNS server `192.168.100.254`
|
||||||
|
|
||||||
|
This confirms that normal clients on the LAN are getting DHCP from the firewall.
|
||||||
|
|
||||||
|
### 2. Shelly device runtime state
|
||||||
|
|
||||||
|
Direct HTTP inspection of the live device at `http://192.168.100.127/` returned:
|
||||||
|
|
||||||
|
- device name `Shelly-Server`
|
||||||
|
- device type `SHEM` / Shelly EM
|
||||||
|
- factory MAC `34945473E228`
|
||||||
|
- Wi-Fi SSID `Shellynet`
|
||||||
|
- IP `192.168.100.127`
|
||||||
|
- Wi-Fi mode `ipv4_method: dhcp`
|
||||||
|
- MQTT connected `true`
|
||||||
|
|
||||||
|
This rules out a device-side static IP configuration.
|
||||||
|
|
||||||
|
### 3. OPNsense reservation and DNS state
|
||||||
|
|
||||||
|
OPNsense config contains a reservation for:
|
||||||
|
|
||||||
|
- IP `192.168.100.75`
|
||||||
|
- MAC `34:94:54:73:e2:28`
|
||||||
|
- hostname `Shelly-Server`
|
||||||
|
|
||||||
|
The live Shelly web API reports the same factory MAC, `34:94:54:73:E2:28`.
|
||||||
|
|
||||||
|
That means the reservation is mapped to the correct Shelly hardware identity.
|
||||||
|
|
||||||
|
Firewall DNS answers currently conflict:
|
||||||
|
|
||||||
|
- `Shelly-Server.maddo.science -> 192.168.100.75`
|
||||||
|
- `shellyem-34945473E228.maddo.science -> 192.168.100.127`
|
||||||
|
- reverse lookup of `192.168.100.127` returns `shellyem-34945473E228.maddo.science`
|
||||||
|
|
||||||
|
That means the firewall has both:
|
||||||
|
|
||||||
|
- a static name tied to the reserved IP
|
||||||
|
- a learned live record tied to the current IP
|
||||||
|
|
||||||
|
### 4. Local ARP evidence
|
||||||
|
|
||||||
|
Known Shelly devices on the same subnet resolve normally to their vendor MACs:
|
||||||
|
|
||||||
|
- `192.168.100.62 -> 24-4C-AB-41-87-35`
|
||||||
|
- `192.168.100.76 -> 24-4C-AB-41-6D-0C`
|
||||||
|
- `192.168.100.96 -> 34-94-54-78-06-1B`
|
||||||
|
|
||||||
|
But the live `Shelly-Server` IP resolves as:
|
||||||
|
|
||||||
|
- `192.168.100.127 -> 02-0F-B5-73-E2-28`
|
||||||
|
|
||||||
|
The first octet `02` marks this as a locally administered MAC, not the Shelly factory OUI. The last three bytes `73-E2-28` match the device suffix.
|
||||||
|
|
||||||
|
That is the key anomaly in this investigation.
|
||||||
|
|
||||||
|
## Interpretation
|
||||||
|
|
||||||
|
The observed facts fit this model best:
|
||||||
|
|
||||||
|
1. `Shelly-Server` is connected through something on `Shellynet` that rewrites or virtualizes the client MAC on the LAN side.
|
||||||
|
2. OPNsense may still be handing out the lease, but it is likely handing it to `02:0F:B5:73:E2:28`, not to `34:94:54:73:E2:28`.
|
||||||
|
3. Because the reservation is keyed to the factory MAC, the reservation at `192.168.100.75` is bypassed.
|
||||||
|
4. The device then receives a dynamic address inside the general pool, which explains `192.168.100.127`.
|
||||||
|
|
||||||
|
So the most likely correction is not "replace the old reservation MAC with the new device MAC." The factory MAC already matches. The only MAC mismatch is between the factory MAC and the translated on-wire MAC observed for the live IP.
|
||||||
|
|
||||||
|
This explanation is more consistent with the evidence than a rogue DHCP server because:
|
||||||
|
|
||||||
|
- the local host is using `192.168.100.254` as DHCP correctly
|
||||||
|
- the firewall DNS has a live learned name for `192.168.100.127`
|
||||||
|
- the on-wire MAC for `192.168.100.127` does not match the reservation MAC
|
||||||
|
|
||||||
|
## Alternative Explanation
|
||||||
|
|
||||||
|
A second DHCP server is still possible, but current evidence is weaker for that theory.
|
||||||
|
|
||||||
|
For a rogue DHCP explanation to fit all observations, one of these would also need to be true:
|
||||||
|
|
||||||
|
- the firewall is somehow learning dynamic DNS records for a lease it did not issue
|
||||||
|
- or the second DHCP domain is bridged into the LAN in a way that still produces the rewritten local MAC pattern
|
||||||
|
|
||||||
|
That is possible, but it is not the simplest explanation from the data collected so far.
|
||||||
|
|
||||||
|
## Likely Root Causes
|
||||||
|
|
||||||
|
### 1. Wireless bridge or router mode on the `Shellynet` path
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
- Wi-Fi extender in router mode
|
||||||
|
- client bridge with MAC NAT
|
||||||
|
- WISP mode
|
||||||
|
- AP/client isolation feature that synthesizes per-client LAN MACs
|
||||||
|
- travel router or embedded bridge in front of the Shelly
|
||||||
|
|
||||||
|
### 2. Reservation keyed to the wrong effective MAC
|
||||||
|
|
||||||
|
If the DHCP server sees `02:0F:B5:73:E2:28` on the wire, a reservation for `34:94:54:73:E2:28` will never apply.
|
||||||
|
|
||||||
|
### 3. Stale naming and reservation state on the firewall
|
||||||
|
|
||||||
|
The static host entry for `Shelly-Server.maddo.science` still points to `.75`, while the firewall also knows a live dynamic name at `.127`. That split-brain state makes troubleshooting harder even if DHCP itself is still on the firewall.
|
||||||
|
|
||||||
|
## What I Could Not Prove In This Pass
|
||||||
|
|
||||||
|
- I did not directly read the active DHCP lease database from OPNsense because the available SSH wrapper restricted several generic shell commands.
|
||||||
|
- I did not capture a DHCP exchange packet trace from the firewall.
|
||||||
|
- I did not inspect the AP/controller behind `Shellynet` because that system is not exposed through the current toolset.
|
||||||
|
|
||||||
|
So the exact point where the MAC changes is still unverified.
|
||||||
|
|
||||||
|
## Recommended Next Checks
|
||||||
|
|
||||||
|
### Highest value checks
|
||||||
|
|
||||||
|
1. Inspect the device or controller that provides `Shellynet`.
|
||||||
|
- Determine whether it is a pure bridge, router, repeater, WISP client, or extender.
|
||||||
|
- Look for features such as MAC NAT, proxy ARP, client isolation, wireless bridge translation, or MAC cloning.
|
||||||
|
|
||||||
|
2. Check the live DHCP lease table on OPNsense for `192.168.100.127`.
|
||||||
|
- Confirm which MAC the firewall associates with that lease.
|
||||||
|
- Check whether the hostname is `shellyem-34945473E228`.
|
||||||
|
|
||||||
|
3. Run a packet capture during a DHCP renew from the Shelly.
|
||||||
|
- Capture on the LAN side of the firewall for UDP `67/68`.
|
||||||
|
- Confirm whether the DHCP client identifier or source MAC is `34:94:54:73:E2:28` or `02:0F:B5:73:E2:28`.
|
||||||
|
|
||||||
|
### Good follow-up checks
|
||||||
|
|
||||||
|
4. Search the AP client list for both MACs:
|
||||||
|
- `34:94:54:73:E2:28`
|
||||||
|
- `02:0F:B5:73:E2:28`
|
||||||
|
|
||||||
|
5. Check whether any other Shelly devices on `Shellynet` show the same MAC translation pattern.
|
||||||
|
|
||||||
|
6. Verify whether `Shellynet` is bridged directly onto `192.168.100.0/24` or routed/NATed by an intermediate device.
|
||||||
|
|
||||||
|
## Proposed Fixes
|
||||||
|
|
||||||
|
## Plain-English Explanation
|
||||||
|
|
||||||
|
The simplest reading of the evidence is this:
|
||||||
|
|
||||||
|
- the Shelly itself is fine
|
||||||
|
- OPNsense is probably still the DHCP server
|
||||||
|
- the `Shellynet` extender is likely changing how the Shelly appears on the network
|
||||||
|
- because of that, OPNsense does not match the Shelly to its reservation at `192.168.100.75`
|
||||||
|
- the Shelly then gets a normal dynamic IP instead, currently `192.168.100.127`
|
||||||
|
|
||||||
|
So the real problem is probably not the Shelly and not Home Assistant.
|
||||||
|
|
||||||
|
The likely problem is the Wi-Fi extender path.
|
||||||
|
|
||||||
|
## Recommended Solution
|
||||||
|
|
||||||
|
The best solution is to stop using the extender path for this Shelly if possible.
|
||||||
|
|
||||||
|
Preferred order:
|
||||||
|
|
||||||
|
1. Move `Shelly-Server` onto a normal Wi-Fi network that is bridged directly to the main LAN.
|
||||||
|
2. If that is not possible, reconfigure the extender so it behaves as a simple bridge or access point and does not rewrite client identity.
|
||||||
|
3. Only if neither is possible, use a DHCP reservation for the effective MAC currently seen on the LAN as a workaround.
|
||||||
|
|
||||||
|
## Best Fix
|
||||||
|
|
||||||
|
Move the Shelly off `Shellynet` and onto a normal SSID served directly by the main Wi-Fi infrastructure.
|
||||||
|
|
||||||
|
Why this is the best fix:
|
||||||
|
|
||||||
|
- it should let OPNsense see the Shelly's real MAC again
|
||||||
|
- it should make the existing reservation at `192.168.100.75` work normally
|
||||||
|
- it removes the weird translation behavior from the network path
|
||||||
|
- it is simpler and more robust than working around the extender behavior
|
||||||
|
|
||||||
|
After moving the Shelly to a normal SSID:
|
||||||
|
|
||||||
|
1. reboot the Shelly or renew its network connection
|
||||||
|
2. verify that it takes `192.168.100.75`
|
||||||
|
3. verify that `Shelly-Server.maddo.science` resolves correctly
|
||||||
|
4. verify that Home Assistant still sees live MQTT updates
|
||||||
|
|
||||||
|
## Good Workaround
|
||||||
|
|
||||||
|
If the extender must stay in place, use the MAC that the LAN is actually seeing for the live IP.
|
||||||
|
|
||||||
|
Current observed effective MAC:
|
||||||
|
|
||||||
|
- `02:0F:B5:73:E2:28`
|
||||||
|
|
||||||
|
That workaround would mean:
|
||||||
|
|
||||||
|
1. update the OPNsense reservation to use `02:0F:B5:73:E2:28` instead of `34:94:54:73:E2:28`
|
||||||
|
2. keep the reserved IP as `192.168.100.75`
|
||||||
|
3. reconnect or reboot the Shelly
|
||||||
|
4. verify whether it then gets `192.168.100.75`
|
||||||
|
|
||||||
|
Current state after applying the workaround:
|
||||||
|
|
||||||
|
- reservation IP: `192.168.100.75`
|
||||||
|
- reserved effective MAC: `02:0F:B5:73:E2:28`
|
||||||
|
- hostname: `Shelly-Server`
|
||||||
|
- Kea description: `Shelly-Server via Shellynet extender workaround; physical MAC 34:94:54:73:e2:28`
|
||||||
|
- firewall config backup created before change: `/conf/config.xml.pre-shellynet-workaround-20260417`
|
||||||
|
|
||||||
|
This workaround may succeed, but it has a risk:
|
||||||
|
|
||||||
|
- if the extender changes that translated MAC later, the reservation will break again
|
||||||
|
|
||||||
|
## What I Recommend You Actually Do
|
||||||
|
|
||||||
|
If you want the most reliable outcome with the least long-term confusion:
|
||||||
|
|
||||||
|
1. first try to get `Shelly-Server` off `Shellynet`
|
||||||
|
2. if that is not realistic, reserve `192.168.100.75` for `02:0F:B5:73:E2:28` as a workaround
|
||||||
|
3. once it works, keep both MACs documented:
|
||||||
|
- physical Shelly MAC: `34:94:54:73:E2:28`
|
||||||
|
- effective LAN-side MAC through extender: `02:0F:B5:73:E2:28`
|
||||||
|
|
||||||
|
## What Not To Do
|
||||||
|
|
||||||
|
- do not assume the reservation is stale because of a replaced Shelly; the current Shelly reports the same physical MAC stored in OPNsense
|
||||||
|
- do not delete historical information about the physical MAC; it is still the real hardware identity of the device
|
||||||
|
- do not assume Home Assistant is the problem; it is working correctly because MQTT is working
|
||||||
|
|
||||||
|
### Preferred fix
|
||||||
|
|
||||||
|
Remove the MAC-rewriting hop from the Shelly path.
|
||||||
|
|
||||||
|
That means:
|
||||||
|
|
||||||
|
- put the Shelly on a normal bridged SSID
|
||||||
|
- or reconfigure the `Shellynet` infrastructure so the original client MAC reaches the firewall unchanged
|
||||||
|
|
||||||
|
If the original MAC reaches OPNsense, the existing reservation at `192.168.100.75` should be able to work as intended.
|
||||||
|
|
||||||
|
### Acceptable workaround
|
||||||
|
|
||||||
|
If the `Shellynet` path must stay as-is, create the reservation for the effective on-wire MAC actually seen by DHCP, after confirming it is stable.
|
||||||
|
|
||||||
|
Based on current evidence, that candidate MAC is:
|
||||||
|
|
||||||
|
- `02:0F:B5:73:E2:28`
|
||||||
|
|
||||||
|
This is only a workaround. If that translated MAC is generated dynamically by the bridge and can change, it is not a robust long-term fix.
|
||||||
|
|
||||||
|
It should not be documented as an "old Shelly MAC." It is better treated as an observed effective LAN-side MAC associated with the current path to `Shelly-Server`.
|
||||||
|
|
||||||
|
### Cleanup after the root issue is fixed
|
||||||
|
|
||||||
|
1. Align firewall DNS so there is only one canonical name/IP for this device.
|
||||||
|
2. Remove or update stale static entries that still point `Shelly-Server` at `.75` if the intended address changes.
|
||||||
|
3. Re-test Home Assistant entity availability and direct web access after the network path is corrected.
|
||||||
|
|
||||||
|
## Working Conclusion
|
||||||
|
|
||||||
|
The current evidence supports this working conclusion:
|
||||||
|
|
||||||
|
OPNsense at `192.168.100.254` is still likely the real DHCP authority, but `Shelly-Server` is probably not presenting its factory MAC to that DHCP server. Instead, something on the `Shellynet` path appears to be rewriting the MAC to `02:0F:B5:73:E2:28`, causing the firewall to hand out a dynamic lease at `192.168.100.127` and bypass the reservation for `192.168.100.75`.
|
||||||
|
|
||||||
|
That makes this look less like a rogue DHCP server problem and more like a MAC translation or bridging mode problem that breaks DHCP reservations.
|
||||||
195
docs/shelly-network-inventory.md
Normal file
195
docs/shelly-network-inventory.md
Normal file
|
|
@ -0,0 +1,195 @@
|
||||||
|
# Shelly Network Inventory and Home Assistant Correlation
|
||||||
|
|
||||||
|
Date: 2026-04-17
|
||||||
|
|
||||||
|
This document combines:
|
||||||
|
|
||||||
|
- OPNsense ARP visibility on `192.168.100.0/24` (`vtnet0`)
|
||||||
|
- Home Assistant `home` entity search results
|
||||||
|
- Direct HTTP probing of responsive devices
|
||||||
|
|
||||||
|
The main goal is to make Shelly troubleshooting easier by keeping the likely device-to-entity mapping in one place.
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
- OPNsense live ARP alone did not expose Shelly hostnames reliably, but `config.xml` did expose static host reservations and DNS-style host entries for several Shelly devices.
|
||||||
|
- Home Assistant `home` contains multiple Shelly devices with clear naming and entity groupings.
|
||||||
|
- Three devices were positively confirmed over HTTP:
|
||||||
|
- `192.168.100.62` is a Shelly EM named `MaddoProd`.
|
||||||
|
- `192.168.100.76` is a Shelly EM named `Shelly-Pompa`.
|
||||||
|
- `192.168.100.96` is a Shelly EM named `shelly-pannello-ovest`.
|
||||||
|
- `Shelly-Server` is now traced in OPNsense config as a static reservation and host entry:
|
||||||
|
- hostname `Shelly-Server`
|
||||||
|
- reserved IP `192.168.100.75`
|
||||||
|
- Kea workaround reservation MAC `02:0F:B5:73:E2:28`
|
||||||
|
- physical Shelly MAC `34:94:54:73:E2:28`
|
||||||
|
- live MQTT and HTTP diagnostics show the device is actually online at `192.168.100.127`
|
||||||
|
- the live Shelly web API reports the same factory MAC `34:94:54:73:E2:28`, so this does not look like an outdated reservation from a replaced unit
|
||||||
|
- local ARP for the live IP resolves to translated on-wire MAC `02:0F:B5:73:E2:28`
|
||||||
|
- the Kea workaround reservation was updated to the translated MAC so the device should become trackable once it renews DHCP
|
||||||
|
- One additional OPNsense ARP entry has a Shelly-looking OUI but did not behave like a Shelly web UI during probing:
|
||||||
|
- `192.168.100.114` / `34:94:54:34:1e:fc`
|
||||||
|
- Several remaining Home devices still rely on inferred MACs from entity IDs because they were not visible as live hosts during this pass.
|
||||||
|
- I was not able to complete the `casa` MCP correlation in this pass, so the `Casa IDs` column is left as `unverified`.
|
||||||
|
|
||||||
|
## Inventory
|
||||||
|
|
||||||
|
| Likely device | Model / type | Home IDs | Casa IDs | OPNsense IP | MAC | Network / Wi-Fi | Confidence | Notes |
|
||||||
|
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
||||||
|
| Shelly Pompa | Shelly EM (`SHEM`) | `switch.shelly_pompa_relay_0`, `sensor.shelly_pompa_power_0`, `sensor.shelly_pompa_power_1`, `update.shelly_pompa_firmware` | unverified | `192.168.100.76` | `24:4C:AB:41:6D:0C` | `vtnet0`, SSID `Salnove`, RSSI `-77` | confirmed | Confirmed by OPNsense host reservation, live HTTP UI, `/shelly`, `/status`, and `/settings`. Device name `Shelly-Pompa`. MQTT connected. Channel names: `Pompa`, `Sottosuolo`. |
|
||||||
|
| Shelly Server | Shelly EM / Shelly-family power meter | `switch.shelly_server_relay_0`, `sensor.shelly_server_power_0`, `sensor.shelly_server_power_1`, `update.shelly_server_firmware` | unverified | live `192.168.100.127`; reserved `192.168.100.75` | physical `34:94:54:73:E2:28`; effective LAN MAC `02:0F:B5:73:E2:28` | live on `Shellynet`, RSSI `-17` | confirmed | Home history, MQTT discovery, live MQTT telemetry, and direct HTTP all confirm this device is active. Kea reservation was updated to the effective LAN MAC as a workaround so the device should become trackable on `192.168.100.75` after DHCP renewal or reconnect. |
|
||||||
|
| Shelly Galleria | Shelly device, likely 2-channel energy monitor | `switch.shelly_galleria_relay_0`, `sensor.shelly_galleria_power_0`, `sensor.shelly_galleria_power_1`, `update.shelly_galleria_firmware` | unverified | not found | not found | not found | medium | Seen clearly in `home`. Current power sample was about `-3249 W` on ch0 and `3794 W` on ch1. No network match found. |
|
||||||
|
| Shelly 3EM 485519D91C40 | Shelly 3EM | `switch.shelly_3em_485519d91c40_relay_0`, `sensor.shelly_3em_485519d91c40_power_0`, `sensor.shelly_3em_485519d91c40_power_1`, `sensor.shelly_3em_485519d91c40_power_2`, `update.shelly_3em_485519d91c40_firmware` | unverified | not found | inferred `48:55:19:D9:1C:40` | not found | medium | Entity naming strongly suggests MAC suffix `485519D91C40`. Not present in current OPNsense ARP snapshot. Current power sample roughly `-2273 / -2606 / +633 W`. |
|
||||||
|
| Shelly Lorenzo | Shelly EM | `switch.shelly_em_c45bbee1e684_relay_0`, `sensor.shelly_em_c45bbee1e684_power_0`, `sensor.shelly_em_c45bbee1e684_power_1`, `update.shelly_em_c45bbee1e684_firmware` | unverified | not found | inferred `C4:5B:BE:E1:E6:84` | not found | medium | Home naming is clear. Current power sample roughly `-2614 / -2929 W`. Exact MAC not seen in OPNsense ARP. |
|
||||||
|
| Shelly EM 34945478061B | Shelly EM | `switch.shelly_em_34945478061b_relay_0`, `sensor.shelly_em_34945478061b_power_0`, `sensor.shelly_em_34945478061b_power_1`, `update.shelly_em_34945478061b_firmware` | unverified | `192.168.100.96` | `34:94:54:78:06:1B` | `vtnet0`, SSID `Meguka`, RSSI `-76` | confirmed | Confirmed by OPNsense host reservation, live ARP, and HTTP API. Device name is `shelly-pannello-ovest`; OPNsense description is `Shelly-Pannello-Ovest`. Channel 1 label is `pannello-ovest`. |
|
||||||
|
| Shelly EM EC64C9C6893B | Shelly EM | `switch.shelly_em_ec64c9c6893b_relay_0`, `sensor.shelly_em_ec64c9c6893b_power_0`, `sensor.shelly_em_ec64c9c6893b_power_1`, `update.shelly_em_ec64c9c6893b_firmware` | unverified | not found | inferred `EC:64:C9:C6:89:3B` | not found | medium | Device is currently `unavailable` in Home Assistant. Exact inferred MAC not seen in OPNsense ARP. |
|
||||||
|
| MaddoProd | Shelly EM | `switch.maddoprod_relay_0`, `sensor.maddoprod_power_0`, `sensor.maddoprod_power_1`, `update.maddoprod_firmware` | unverified | `192.168.100.62` | `24:4C:AB:41:87:35` | `vtnet0`, SSID `Reisen`, RSSI `-81` | confirmed | Confirmed by OPNsense host reservation, live ARP, and HTTP API. Device name is `MaddoProd`. Current power sample roughly `-7 W / 2899 W`. Secondary configured Wi-Fi SSID is `Top Gun 2 il ritorno`. |
|
||||||
|
| Pannelli AUX | Shelly EM | `switch.pannelli_aux_relay_0`, `sensor.pannelli_aux_power_0`, `sensor.pannelli_aux_power_1`, `update.pannelli_aux_firmware` | unverified | not found | inferred `34:94:54:73:CD:10` | not found | medium | Home naming is clear. Current power sample roughly `364 W / 0 W`. Exact MAC not seen in current ARP. |
|
||||||
|
| Batteria AUX | Shelly EM | `switch.batteria_aux_relay_0`, `sensor.batteria_aux_power_0`, `sensor.batteria_aux_power_1`, `update.batteria_aux_firmware` | unverified | not found | inferred `E8:68:E7:D2:65:F5` | not found | medium | Home naming is clear. Current power sample roughly `219 W / 0 W`. Exact MAC not seen in current ARP. |
|
||||||
|
| Unknown `34:94:54` device | unknown | none matched | unverified | `192.168.100.114` | `34:94:54:34:1E:FC` | `vtnet0` | low | The OUI looks like a possible Shelly-family vendor, but `/`, `/status`, `/shelly`, and `/rpc/...` did not identify it as Shelly. Keep as a candidate only. |
|
||||||
|
|
||||||
|
## Confirmed HTTP details for `192.168.100.76`
|
||||||
|
|
||||||
|
Directly retrieved from the device web API:
|
||||||
|
|
||||||
|
- Name: `Shelly-Pompa`
|
||||||
|
- Type: `SHEM`
|
||||||
|
- Hostname: `shellyem-244CAB416D0C`
|
||||||
|
- MAC: `244CAB416D0C`
|
||||||
|
- IP: `192.168.100.76`
|
||||||
|
- Wi-Fi SSID: `Salnove`
|
||||||
|
- RSSI: `-77`
|
||||||
|
- MQTT: connected
|
||||||
|
- Firmware: `20230913-114150/v1.14.0-gcb84623`
|
||||||
|
- Channel names:
|
||||||
|
- `Pompa`
|
||||||
|
- `Sottosuolo`
|
||||||
|
|
||||||
|
This is a strong match for the Home Assistant `Shelly Pompa` entity group.
|
||||||
|
|
||||||
|
## Confirmed HTTP details for `192.168.100.62`
|
||||||
|
|
||||||
|
Directly retrieved from the device web API:
|
||||||
|
|
||||||
|
- Name: `MaddoProd`
|
||||||
|
- Type: `SHEM`
|
||||||
|
- Hostname: `shellyem-244CAB418735`
|
||||||
|
- MAC: `244CAB418735`
|
||||||
|
- IP: `192.168.100.62`
|
||||||
|
- Wi-Fi SSID: `Reisen`
|
||||||
|
- Secondary Wi-Fi SSID: `Top Gun 2 il ritorno`
|
||||||
|
- RSSI: `-81`
|
||||||
|
- MQTT: connected
|
||||||
|
- Firmware: `20230913-114150/v1.14.0-gcb84623`
|
||||||
|
|
||||||
|
This is a strong match for the Home Assistant `maddoprod` entity group.
|
||||||
|
|
||||||
|
## Confirmed HTTP details for `192.168.100.96`
|
||||||
|
|
||||||
|
Directly retrieved from the device web API:
|
||||||
|
|
||||||
|
- Name: `shelly-pannello-ovest`
|
||||||
|
- Type: `SHEM`
|
||||||
|
- Hostname: `shellyem-34945478061B`
|
||||||
|
- MAC: `34945478061B`
|
||||||
|
- IP: `192.168.100.96`
|
||||||
|
- Wi-Fi SSID: `Meguka`
|
||||||
|
- RSSI: `-76`
|
||||||
|
- MQTT: connected
|
||||||
|
- Firmware: `20230913-114150/v1.14.0-gcb84623`
|
||||||
|
- Channel 1 label: `pannello-ovest`
|
||||||
|
|
||||||
|
This is a strong match for the Home Assistant `shelly_em_34945478061b` entity group and the OPNsense description `Shelly-Pannello-Ovest`.
|
||||||
|
|
||||||
|
## OPNsense reservation details for `Shelly-Server`
|
||||||
|
|
||||||
|
Directly retrieved from OPNsense `config.xml`:
|
||||||
|
|
||||||
|
- Host entry: `Shelly-Server.maddo.science`
|
||||||
|
- Reserved IP: `192.168.100.75`
|
||||||
|
- Current Kea workaround MAC: `02:0F:B5:73:E2:28`
|
||||||
|
- Physical Shelly MAC: `34:94:54:73:E2:28`
|
||||||
|
- Description: `Shelly-Server`
|
||||||
|
|
||||||
|
Live status during this pass:
|
||||||
|
|
||||||
|
- Home Assistant `sensor.shelly_server_power_0` updated every ~30 seconds for the last hour
|
||||||
|
- MQTT discovery identifies this device as `shellyem-34945473E228`
|
||||||
|
- MQTT discovery advertises control URL `http://192.168.100.127/`
|
||||||
|
- direct HTTP to `http://192.168.100.127/` succeeded
|
||||||
|
- live device details from `/settings` and `/status`:
|
||||||
|
- name `Shelly-Server`
|
||||||
|
- SSID `Shellynet`
|
||||||
|
- RSSI `-17`
|
||||||
|
- MQTT connected `true`
|
||||||
|
- channel labels `Server-1`, `Server-2`
|
||||||
|
- firmware `20230913-114150/v1.14.0-gcb84623`
|
||||||
|
- direct MQTT telemetry observed on `shellies/shellyem-34945473E228/emeter/...`
|
||||||
|
- `192.168.100.75` did not answer ping or HTTP during the same pass
|
||||||
|
|
||||||
|
That makes the identity mapping and live status both strong. The real fault is the mismatch between the live IP and the OPNsense reservation.
|
||||||
|
|
||||||
|
It also argues against the reservation MAC simply being stale from an old device replacement, because the live Shelly reports the same factory MAC as the one stored in OPNsense.
|
||||||
|
|
||||||
|
The active Kea workaround now reserves the same IP for the translated LAN-side MAC instead, with description `Shelly-Server via Shellynet extender workaround; physical MAC 34:94:54:73:e2:28`.
|
||||||
|
|
||||||
|
## MQTT findings for `Shelly-Server`
|
||||||
|
|
||||||
|
Broker-level diagnostics against the local `.local/mqtt-home.env` credentials confirmed:
|
||||||
|
|
||||||
|
- MQTT client ID / topic base: `shellyem-34945473E228`
|
||||||
|
- Home Assistant discovery prefix in use: `homeassistant/...`
|
||||||
|
- Shellies topic base in use: `shellies/shellyem-34945473E228/...`
|
||||||
|
- Availability model in discovery:
|
||||||
|
- `~online` topic with `true` / `false`
|
||||||
|
- `~info` JSON field `mqtt.connected`
|
||||||
|
- Live telemetry was observed for:
|
||||||
|
- `shellies/shellyem-34945473E228/emeter/0/power`
|
||||||
|
- `shellies/shellyem-34945473E228/emeter/0/reactive_power`
|
||||||
|
- `shellies/shellyem-34945473E228/emeter/0/pf`
|
||||||
|
- `shellies/shellyem-34945473E228/emeter/0/voltage`
|
||||||
|
- `shellies/shellyem-34945473E228/emeter/0/total`
|
||||||
|
- `shellies/shellyem-34945473E228/emeter/0/total_returned`
|
||||||
|
- `shellies/shellyem-34945473E228/emeter/1/...`
|
||||||
|
|
||||||
|
This proves Home Assistant is receiving live MQTT telemetry, not just stale retained state.
|
||||||
|
|
||||||
|
## Home Assistant groups used for correlation
|
||||||
|
|
||||||
|
Representative entity groups found in `home`:
|
||||||
|
|
||||||
|
- `shelly_pompa`
|
||||||
|
- `shelly_server`
|
||||||
|
- `shelly_galleria`
|
||||||
|
- `shelly_3em_485519d91c40`
|
||||||
|
- `shelly_em_c45bbee1e684`
|
||||||
|
- `shelly_em_34945478061b`
|
||||||
|
- `shelly_em_ec64c9c6893b`
|
||||||
|
- `maddoprod`
|
||||||
|
- `pannelli_aux`
|
||||||
|
- `batteria_aux`
|
||||||
|
|
||||||
|
## OPNsense findings worth keeping in mind
|
||||||
|
|
||||||
|
- Active Shelly-confirmed subnet: `192.168.100.0/24`
|
||||||
|
- Observed interface: `vtnet0`
|
||||||
|
- OPNsense static mappings were more useful than live ARP for `Shelly-Server`.
|
||||||
|
- For `Shelly-Server`, OPNsense reservation data was useful for identity but wrong for the current live IP.
|
||||||
|
- OPNsense ARP snapshot was incomplete relative to Home Assistant inventory.
|
||||||
|
- OPNsense-backed host reservations confirmed:
|
||||||
|
- `192.168.100.62` -> `shelly-maddoProd` / `24:4c:ab:41:87:35`
|
||||||
|
- `192.168.100.75` -> `Shelly-Server` / `34:94:54:73:e2:28`
|
||||||
|
- `192.168.100.76` -> `Shelly-Pompa` / `24:4c:ab:41:6d:0c`
|
||||||
|
- `192.168.100.96` -> `shellyem-34945478061b` / `34:94:54:78:06:1b`
|
||||||
|
- MQTT discovery confirmed that `Shelly-Server` is actually live at `192.168.100.127`.
|
||||||
|
- That usually means one or more of the following:
|
||||||
|
- the device is on a valid live IP that does not match the OPNsense reservation
|
||||||
|
- the reservation is stale, not applied, or not being served by the DHCP source the device is actually using
|
||||||
|
- OPNsense ARP visibility is incomplete because ARP only reflects neighbors the firewall itself has talked to
|
||||||
|
|
||||||
|
## Best next manual checks
|
||||||
|
|
||||||
|
1. Find which DHCP server actually handed out `192.168.100.127` to MAC `34:94:54:73:E2:28`.
|
||||||
|
2. Check the AP or controller for the `Shellynet` client entry for MAC `34:94:54:73:E2:28` and confirm its DHCP source.
|
||||||
|
3. Renew DHCP on the device or reboot it after fixing the intended reservation path, so it either takes `192.168.100.75` or the reservation is updated to `192.168.100.127`.
|
||||||
|
4. Decide whether the intended fix is: make OPNsense own the lease again, or update OPNsense to reflect the real addressing source.
|
||||||
98
docs/shelly-server-power-negative-analysis.md
Normal file
98
docs/shelly-server-power-negative-analysis.md
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
# Analysis: `sensor.shelly_server_power_0` Negative Idle Reading
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
Target instance: `home`
|
||||||
|
|
||||||
|
Investigated entity: `sensor.shelly_server_power_0`
|
||||||
|
|
||||||
|
Question: why the Shelly EM channel reports a negative power value when there is effectively no load, and why that started after previously behaving normally.
|
||||||
|
|
||||||
|
## What I Verified
|
||||||
|
|
||||||
|
The entity is a direct MQTT-backed device sensor, not a template/helper:
|
||||||
|
|
||||||
|
- Entity: `sensor.shelly_server_power_0`
|
||||||
|
- Platform: `mqtt`
|
||||||
|
- Unique ID: `shellyem-34945473e228-emeter-power-0`
|
||||||
|
- Device: `Shelly Server`
|
||||||
|
- Model: `Shelly EM`
|
||||||
|
- Firmware: `20230913-114150/v1.14.0-gcb84623`
|
||||||
|
|
||||||
|
Current live readings observed during the investigation:
|
||||||
|
|
||||||
|
- `sensor.shelly_server_power_0`: about `-12.6 W` to `-13.0 W`
|
||||||
|
- `sensor.shelly_server_power_1`: `0.00 W`
|
||||||
|
- `sensor.shelly_server_total_returned_0`: increasing
|
||||||
|
- `sensor.shelly_server_total_0`: not increasing during the same observation window
|
||||||
|
|
||||||
|
This is the critical point: Home Assistant is not merely displaying a signed power value. The device/integration path is also classifying channel 0 energy as returned/exported energy.
|
||||||
|
|
||||||
|
Observed behavior during sampling:
|
||||||
|
|
||||||
|
- `sensor.shelly_server_power_0` refreshed roughly every 30 seconds and stayed near `-12.8 W`
|
||||||
|
- `sensor.shelly_server_total_returned_0` increased from `55055.2 Wh` to `55055.4 Wh`
|
||||||
|
- `sensor.shelly_server_total_0` remained at `1155447.8 Wh`
|
||||||
|
|
||||||
|
That combination strongly suggests the Shelly path believes current direction on channel 0 is reversed at idle, not that Home Assistant is simply subtracting or transforming something incorrectly.
|
||||||
|
|
||||||
|
## Most Likely Cause
|
||||||
|
|
||||||
|
Highest-confidence explanation: channel 0 on the Shelly EM is seeing reversed current direction or a signed measurement offset large enough that the firmware interprets idle noise as export.
|
||||||
|
|
||||||
|
In practice that usually means one of these:
|
||||||
|
|
||||||
|
1. The CT clamp orientation for channel 0 is reversed relative to the expected power flow direction.
|
||||||
|
2. The monitored conductor arrangement changed months ago, so the clamp is still physically installed but no longer aligned with the original direction/phase assumptions.
|
||||||
|
3. The Shelly EM calibration/zero point drifted enough that a small idle offset now crosses zero on the negative side.
|
||||||
|
4. A Shelly/MQTT discovery behavior change caused Home Assistant to expose the device's signed value and returned-energy counters more faithfully than before.
|
||||||
|
|
||||||
|
Given that `total_returned_0` is actively increasing while idle, the first two causes are more likely than a pure UI regression.
|
||||||
|
|
||||||
|
## Why This Does Not Look Like a Home Assistant Math Bug
|
||||||
|
|
||||||
|
- The entity is not a template sensor.
|
||||||
|
- The entity comes directly from MQTT discovery for the Shelly EM.
|
||||||
|
- Home Assistant exposes both forward and returned energy counters separately.
|
||||||
|
- Channel 1 remains at `0.00 W`, which argues against a system-wide unit/sign issue.
|
||||||
|
- The behavior is internally consistent: negative instantaneous power is paired with growth in `returned_energy` rather than `total`.
|
||||||
|
|
||||||
|
If Home Assistant were incorrectly rendering only the sign, I would expect the energy counters to remain inconsistent or unchanged. They do not.
|
||||||
|
|
||||||
|
## Additional Clues
|
||||||
|
|
||||||
|
- The device registry still lists some Shelly entities that do not currently resolve through the state API. That suggests the MQTT discovery/device registry state is a bit stale, but it does not explain the negative power reading itself.
|
||||||
|
- Several sibling entities on this device have `last_updated` timestamps from April 14 while `power_0` and `total_returned_0` are still changing. That suggests channel 0 export-related data is the only part currently showing active movement.
|
||||||
|
- Firmware is already at the installed/latest version shown by Home Assistant, so there is no obvious pending firmware update to test immediately.
|
||||||
|
|
||||||
|
## What I Could Not Prove From This Session
|
||||||
|
|
||||||
|
I was able to inspect current entity state, registry metadata, device metadata, integration metadata, and system health through MCP.
|
||||||
|
|
||||||
|
I was not able to extract a useful time-series history or relevant HA log lines from the currently exposed MCP tool surface in this session, so I cannot timestamp the exact moment the sign behavior changed. Because of that, I cannot tie the anomaly to a specific restart, firmware flash, MQTT rediscovery event, or wiring intervention from logs alone.
|
||||||
|
|
||||||
|
## Likely Root-Cause Ranking
|
||||||
|
|
||||||
|
1. CT clamp/channel 0 direction is physically reversed relative to expected load direction.
|
||||||
|
2. Wiring or what that clamp encloses changed a few months ago, effectively flipping interpreted flow direction.
|
||||||
|
3. Zero-offset/calibration drift on a very low-load channel is pushing idle around `-13 W`.
|
||||||
|
4. Firmware or MQTT discovery semantics changed and exposed returned energy where earlier handling masked it.
|
||||||
|
5. Home Assistant bug in sign handling.
|
||||||
|
|
||||||
|
Item 5 is the least likely based on the evidence collected.
|
||||||
|
|
||||||
|
## Best Next Checks
|
||||||
|
|
||||||
|
These checks should confirm or eliminate the leading hypotheses quickly:
|
||||||
|
|
||||||
|
1. Physically inspect CT clamp 0 on the Shelly EM and verify the arrow/direction matches intended consumption flow.
|
||||||
|
2. Confirm the clamp is still around the same single conductor it was originally monitoring, and not a different leg/path after electrical changes.
|
||||||
|
3. Temporarily apply a known positive load on the monitored circuit and see whether `sensor.shelly_server_power_0` becomes more negative instead of positive.
|
||||||
|
4. If safe and practical, reverse the CT clamp orientation or use the Shelly's inversion setting if available in the device UI; the reading should flip sign immediately.
|
||||||
|
5. Compare the Shelly web UI/raw topic payload for channel 0 against Home Assistant. If the raw device value is already negative, the issue is upstream of HA.
|
||||||
|
|
||||||
|
## Practical Conclusion
|
||||||
|
|
||||||
|
The anomaly is most likely not caused by Home Assistant itself. The evidence points to the Shelly EM channel 0 measurement path treating idle current as reverse flow, with Home Assistant faithfully exposing that as negative power and increasing returned energy.
|
||||||
|
|
||||||
|
If you want the next step automated, the most useful follow-up would be capturing raw MQTT payloads for this Shelly EM or pulling HA history/logs with a tool that exposes recorder/logbook details more directly.
|
||||||
1
mcp/home-docker/.gitignore
vendored
Normal file
1
mcp/home-docker/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
.env
|
||||||
11
mcp/home-docker/compose.yml
Normal file
11
mcp/home-docker/compose.yml
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
services:
|
||||||
|
ha-mcp:
|
||||||
|
image: ghcr.io/homeassistant-ai/ha-mcp:latest
|
||||||
|
container_name: ha-mcp
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "8086:8086"
|
||||||
|
environment:
|
||||||
|
HOMEASSISTANT_URL: ${HOMEASSISTANT_URL}
|
||||||
|
HOMEASSISTANT_TOKEN: ${HOMEASSISTANT_TOKEN}
|
||||||
|
command: ha-mcp-web
|
||||||
17
mcp/opnsense/.env.example
Normal file
17
mcp/opnsense/.env.example
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Required
|
||||||
|
OPNSENSE_HOST=https://your-opnsense-host:port
|
||||||
|
OPNSENSE_API_KEY=your-api-key
|
||||||
|
OPNSENSE_API_SECRET=your-api-secret
|
||||||
|
OPNSENSE_VERIFY_SSL=false
|
||||||
|
|
||||||
|
# Optional - package version pin used by compose build
|
||||||
|
OPNSENSE_MCP_VERSION=0.8.2
|
||||||
|
SUPERGATEWAY_VERSION=3.4.3
|
||||||
|
MCP_HTTP_PORT=8811
|
||||||
|
|
||||||
|
# Optional - SSH features
|
||||||
|
# OPNSENSE_SSH_HOST=your-opnsense-host
|
||||||
|
# OPNSENSE_SSH_USERNAME=root
|
||||||
|
# OPNSENSE_SSH_PASSWORD=your-password
|
||||||
|
# HOST_SSH_KEY_PATH=C:/Users/your-user/.ssh/id_rsa
|
||||||
|
# OPNSENSE_SSH_KEY_PATH=/run/secrets/opnsense_ssh_key
|
||||||
1
mcp/opnsense/.gitignore
vendored
Normal file
1
mcp/opnsense/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
.env
|
||||||
17
mcp/opnsense/Dockerfile
Normal file
17
mcp/opnsense/Dockerfile
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
ARG OPNSENSE_MCP_VERSION=0.8.2
|
||||||
|
ARG SUPERGATEWAY_VERSION=3.4.3
|
||||||
|
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
|
||||||
|
RUN npm install --global \
|
||||||
|
"opnsense-mcp-server@${OPNSENSE_MCP_VERSION}" \
|
||||||
|
"supergateway@${SUPERGATEWAY_VERSION}"
|
||||||
|
|
||||||
|
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
|
||||||
|
|
||||||
|
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
|
||||||
|
|
||||||
|
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
|
||||||
|
CMD ["supergateway", "--stdio", "opnsense-mcp-server", "--outputTransport", "streamableHttp", "--port", "8000", "--streamableHttpPath", "/mcp", "--healthEndpoint", "/healthz", "--logLevel", "info"]
|
||||||
33
mcp/opnsense/README.md
Normal file
33
mcp/opnsense/README.md
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
# OPNsense MCP Docker Setup
|
||||||
|
|
||||||
|
This folder packages `opnsense-mcp-server` behind an HTTP MCP gateway for local Docker use.
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
- `Dockerfile` installs the published npm package and `supergateway`.
|
||||||
|
- `compose.yml` defines a single long-running `opnsense-mcp` HTTP service.
|
||||||
|
- `.env.example` shows the required and optional environment variables.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
1. Create `.env` from `.env.example`.
|
||||||
|
If you want SSH features with key auth, set `HOST_SSH_KEY_PATH` to a real host path and keep `OPNSENSE_SSH_KEY_PATH=/run/secrets/opnsense_ssh_key`.
|
||||||
|
2. Build and start the service:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f compose.yml up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Connect your MCP client to the Streamable HTTP endpoint:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
http://localhost:8811/mcp
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Check service health if needed:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f compose.yml ps
|
||||||
|
```
|
||||||
|
|
||||||
|
This avoids duplicate one-off containers because the intended workflow uses a single named service with `docker compose up`, not `docker compose run`.
|
||||||
24
mcp/opnsense/compose.yml
Normal file
24
mcp/opnsense/compose.yml
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
services:
|
||||||
|
opnsense-mcp:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
args:
|
||||||
|
OPNSENSE_MCP_VERSION: ${OPNSENSE_MCP_VERSION:-0.8.2}
|
||||||
|
SUPERGATEWAY_VERSION: ${SUPERGATEWAY_VERSION:-3.4.3}
|
||||||
|
container_name: opnsense-mcp
|
||||||
|
restart: unless-stopped
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
ports:
|
||||||
|
- "${MCP_HTTP_PORT:-8811}:8000"
|
||||||
|
volumes:
|
||||||
|
- type: bind
|
||||||
|
source: ${HOST_SSH_KEY_PATH}
|
||||||
|
target: /run/secrets/opnsense_ssh_key
|
||||||
|
read_only: true
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8000/healthz"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
start_period: 15s
|
||||||
25
mcp/opnsense/docker-entrypoint.sh
Normal file
25
mcp/opnsense/docker-entrypoint.sh
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
required_vars="OPNSENSE_HOST OPNSENSE_API_KEY OPNSENSE_API_SECRET"
|
||||||
|
secure_key_path="/tmp/opnsense_ssh_key"
|
||||||
|
|
||||||
|
for name in $required_vars; do
|
||||||
|
eval "value=\${$name:-}"
|
||||||
|
if [ -z "$value" ]; then
|
||||||
|
echo "Missing required environment variable: $name" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "${OPNSENSE_VERIFY_SSL:-}" ]; then
|
||||||
|
export OPNSENSE_VERIFY_SSL=false
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "${OPNSENSE_SSH_KEY_PATH:-}" ] && [ -f "${OPNSENSE_SSH_KEY_PATH}" ]; then
|
||||||
|
cp "${OPNSENSE_SSH_KEY_PATH}" "$secure_key_path"
|
||||||
|
chmod 600 "$secure_key_path"
|
||||||
|
export OPNSENSE_SSH_KEY_PATH="$secure_key_path"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$@"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue