Conversation
kingwap99
force-pushed
the
feature/macwatch
branch
from
September 21, 2026 02:20
49f7fd1 to
9504801
Compare
Cameras get their IP address from a DHCP server, so the address can change after a router reboot. All links to the camera in the config file are pinned to the old address and stop working. The new macwatch module remembers the MAC address of every camera, finds its actual IP address in the ARP table and rewrites the config file when the address has changed. The running stream will be reconnected to the new address without a go2rtc restart. ARP table is read from /proc/net/arp (Linux), route socket (macOS, BSD) or the arp tool (Windows). Also added API endpoint and a "Rescan IP" button on the config web page.
kingwap99
force-pushed
the
feature/macwatch
branch
from
September 22, 2026 20:03
9504801 to
b112048
Compare
kingwap99
marked this pull request as ready for review
September 22, 2026 20:07
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Cameras get their IP address from a DHCP server, so it can change after a router
reboot, a long power outage or a hardware swap. Stream links in the config are
pinned to that address:
When the camera moves to another address the link stops working and go2rtc
cannot recover, because it only knows the IP address and has no idea which
physical device that address belongs to.
Solution
A new
macwatchmodule. It is opt-in and does nothing unless it is configured.It remembers the MAC address of every camera, resolves the actual IP address
from the ARP table and rewrites the config file when the address has changed:
What happens on every check:
and read the table again.
stream URL answers there.
are kept) and update the in-memory stream URL, so the running connection
reconnects to the new address without a restart.
MAC addresses do not have to be collected by hand:
returns a ready to use config section for every stream that has an IP address
in the source URL.
GET /api/macwatchreports the state of every camera andPOST /api/macwatchforces a rescan. There is also a "Rescan IP" button on the config web page: it reports thecameras that were changed and lists everything that needs attention, including
dry_run mode with the address it would use.
ARP table
/proc/net/arpgolang.org/x/net/route)arp -aThe macOS/BSD path uses a route socket instead of the
arptool, because thetool needs SystemConfiguration and returns empty output in restricted
environments (services with a minimal environment, sandboxes). No new
dependency:
golang.org/x/netis already required.Implementation
internal/macwatch- the new module (ARP lookup, scheduling, config rewrite, API)internal/streams-Stream.ReplaceSourceandProducer.ReplaceURLto swapthe source URL and let the existing reconnect loop pick it up
main.go- module registration (can be disabled withapp.modules)www/config.html- the Rescan IP buttonwebsite/api/openapi.yaml- API descriptioninternal/macwatch/README.md- documentation (picked up by the website build)The config rewrite uses the existing
app.PatchConfig/pkg/yaml.Patch, sothe file is edited in place: comments, indentation and every other key are
preserved. If a stream name is not found in the config file (a second config
file, streams added dynamically by the Home Assistant integration), the module
never touches it and reports an error for that camera instead.
Testing
go test ./internal/macwatch/...- 12 tests: MAC normalization (macOS singledigit octets, Windows dashes, Cisco dots, plain hex), ARP output parsing for
macOS/Linux/Windows, host replacement in URLs (including
@insidecredentials, with ports, queries and fragments), in-place rewrite of all three
config forms (string, list,
{url: ...}), the resolve flow and subnetexpansion
linux 386/amd64/arm/arm64/mipsle, windows 386/amd64/arm64
go vetandgofmtcleanok;after deleting the ARP entries of 5 cameras a forced check resolved all of
them again in about 2 seconds; a stream with a deliberately wrong IP was
rewritten to the correct address in the config file and in memory, and the
diff against the previous config contained nothing but the new section
DHCP lease moved was reported with the exact target address while the module was in
dry_runmode (192.168.31.111->192.168.31.223), and the confignow points at the address where the camera actually answers (ONVIF port open, frames
served - 2528x2528 JPEG, HTTP 200). A camera that dropped off the network was
reported as
not_foundand picked up again on its own when it came back,without touching the config file in the meantime.
One finding worth sharing: sending all 254 UDP probes of a /24 at once does not
fill the ARP table reliably - the kernel has a limit on unresolved neighbours
and drops the queued packets, which left 5 cameras at
(incomplete). Pacingthe sweep (4 hosts, then a 20 ms pause) resolved every device on that network.
Notes
router is not visible in the local ARP table, so Docker users need
network_mode: host.-c go2rtc.yaml). A config passed as a commandline string cannot be rewritten.
homekit) orwithout a TCP port at all (
xiaomi).a camera connected over both Wi-Fi bands) is supported: the module keeps the
address that is already in the config while it is still in the ARP table.
sweep_interval(5 minutes by default).