Skip to content
ย 
ย 

Latest commit

ย 

History

57 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Eero-AdGuard-Sync

Sync Eero DHCP client list to AdGuard Home

Release PyPI Code style

eero-adguard-sync

Table of Contents

๐Ÿ‘ถ Dependencies

๐Ÿ› ๏ธ Installation

From PyPI

pip install eero-adguard-sync

From source (local development)

Clone the repo and install in editable mode so your changes are reflected immediately:

git clone https://github.com/amickael/eero-adguard-sync.git
cd eero-adguard-sync
pip install -e .

This installs all dependencies from requirements.txt and registers the eag-sync command on your PATH. Any edits you make to the source files take effect without reinstalling.

๐Ÿš€ Usage

eag-sync is a command-line program to sync your Eero DHCP client list to AdGuard Home. It is a one-way sync from Eero to AdGuard and requires Python 3.10+.

Run a sync:

eag-sync sync

You will be prompted for your Eero email and an SMS/email verification code on first run. Your credentials are cached locally โ€” they never leave your computer.

To clear all locally cached credentials:

eag-sync clear

Duplicate and rotating MAC handling

When a device (e.g. an iPhone with Private Wi-Fi Address) rotates its MAC address, it retains its name in Eero. The sync detects this and updates the existing AdGuard client with the new MAC rather than deleting and recreating it, preserving any per-client rules you have configured.

If two Eero devices share the same name (e.g. two devices both called "Living Room"), the conflicting name is automatically stripped from both clients' AdGuard identifiers so neither causes a rejection.

โš™๏ธ Options

eag-sync

Usage: eag-sync [OPTIONS] COMMAND [ARGS]...

Options:
  --version  Show the version and exit.
  --help     Show this message and exit.

Commands:
  sync
  clear

eag-sync sync

Usage: eag-sync sync [OPTIONS]

Options:
  --adguard-host TEXT     AdGuard Home host IP address  [env: EAG_ADGUARD_HOST]
  --adguard-user TEXT     AdGuard Home username  [env: EAG_ADGUARD_USER]
  --adguard-password TEXT AdGuard Home password  [env: EAG_ADGUARD_PASS]
  --eero-user TEXT        Eero email address or phone number  [env: EAG_EERO_USER]
  --eero-cookie TEXT      Eero session cookie  [env: EAG_EERO_COOKIE]
  -d, --delete            Delete AdGuard clients not found in Eero DHCP list
                          [env: EAG_DELETE]
  -y, --confirm           Skip interactive confirmation  [env: EAG_CONFIRM]
  -o, --overwrite         Delete all AdGuard clients before sync
                          [env: EAG_OVERWRITE]
  -x, --exclude-range TEXT
                          CIDR range(s) protected from deletion when --delete
                          is active (e.g. 192.168.1.0/24). Repeatable.
                          Env var: comma-separated string.  [env: EAG_EXCLUDE_RANGE]
  -e, --exclude-id TEXT   Client identifier(s) protected from deletion when
                          --delete is active. Accepts MAC address, client name,
                          or hostname. Supports wildcards and regex (re: prefix).
                          Repeatable. Env var: comma-separated string.  [env: EAG_EXCLUDE_ID]
  --debug                 Display debug information
  --no-global-id TEXT     Client identifier(s) always registered in AdGuard with
                          'Use global settings' disabled. Accepts MAC address,
                          client name, or hostname. Supports wildcards and regex
                          (re: prefix). Repeatable.
                          Env var: comma-separated string.  [env: EAG_NO_GLOBAL_ID]
  --no-global-rewrites    Keep DNS rewrites active for --no-global-id clients
                          while bypassing all other filter rules.
                          [env: EAG_NO_GLOBAL_REWRITES]
  --help                  Show this message and exit.

Per-client AdGuard settings

--no-global-id registers specific devices in AdGuard with "Use global settings" turned off, letting you configure per-client DNS rules, blocked services, or upstream resolvers for those devices without affecting the rest of the network. Unlike --exclude-id, the device is still fully synced (name, IPs, tags) โ€” only use_global_settings is pinned to false.

Patterns are matched against the client's nickname only. Plain patterns use shell-style wildcards (*, ?). Prefix a pattern with re: to use a Python regex instead.

# Pin by device name
eag-sync sync --no-global-id "Alice's iPad"

# Pin by MAC address
eag-sync sync --no-global-id "aa-bb-cc-dd-ee-ff"

# Pin multiple devices
eag-sync sync --no-global-id "Alice's iPad" --no-global-id "Alice's iPhone"

# Wildcard โ€” all devices whose name starts with a prefix
eag-sync sync --no-global-id "Alice*"

# Regex โ€” all devices starting with "Alice" except "Alice's HomePod"
eag-sync sync --no-global-id "re:^Alice(?!.*HomePod)"

# Or via env var (comma-separated)
# EAG_NO_GLOBAL_ID="Alice's iPad,Alice's iPhone"
# EAG_NO_GLOBAL_ID="re:^Alice(?!.*HomePod)"

Rewrite-only clients

AdGuard Home only applies DNS rewrites when a client's filtering is enabled. Set --no-global-rewrites together with --no-global-id to keep rewrites active for the matched clients while allowing all other DNS requests.

The sync maintains one marked custom rule in AdGuard Home, scoped to the matching client names. DNS rewrites take precedence over that allow rule, so only the rewrites continue to apply. The list is regenerated on each sync and does not affect unrelated custom rules.

eag-sync sync \
  --no-global-id "re:^Alice(?!.*HomePod)" \
  --no-global-rewrites
EAG_NO_GLOBAL_ID='re:^Alice(?!.*HomePod)'
EAG_NO_GLOBAL_REWRITES=true

Protecting clients from deletion

When running with --delete, you can protect specific clients from being removed. Both plain wildcards (*, ?) and re: prefixed Python regex are supported.

# Protect an entire subnet
eag-sync sync --delete --exclude-range 192.168.1.0/24

# Protect a specific device by MAC address
eag-sync sync --delete --exclude-id "11:22:33:44:55:66"

# Protect a device by its AdGuard client name
eag-sync sync --delete --exclude-id "My Device"

# Protect all devices whose name starts with a prefix (wildcard)
eag-sync sync --delete --exclude-id "my-prefix*"

# Regex โ€” protect all devices starting with "Alice" except "Alice's HomePod"
eag-sync sync --delete --exclude-id "re:^Alice(?!.*HomePod)"

# Combine multiple protections
eag-sync sync --delete \
  --exclude-range 192.168.2.0/24 \
  --exclude-id "11:22:33:44:55:66" \
  --exclude-id "my-server"

This is useful for:

  • Devices with custom AdGuard rules (blocked services, custom upstreams) that you don't want reset
  • Devices that are temporarily offline at sync time
  • Static IP devices outside the Eero DHCP range

eag-sync clear

Usage: eag-sync clear [OPTIONS]

Options:
  -y, --confirm  Skip interactive confirmation
  --help         Show this message and exit.

๐Ÿ”ฎ Autocompletion

bash

Add to ~/.bashrc:

eval "$(_EAG_SYNC_COMPLETE=bash_source eag-sync)"

zsh

Add to ~/.zshrc:

eval "$(_EAG_SYNC_COMPLETE=zsh_source eag-sync)"

๐Ÿ‹ Docker

A Docker image that executes eag-sync sync on a cron schedule is available on Docker Hub: amickael/eero-adguard-sync.

All configuration is passed via environment variables. Every CLI option has a corresponding env var โ€” see the table below.

Variable Description Required Default
EAG_EERO_COOKIE Eero session cookie (from eag-sync sync --debug) Yes
EAG_ADGUARD_HOST AdGuard Home host IP address Yes
EAG_ADGUARD_USER AdGuard admin username Yes
EAG_ADGUARD_PASS AdGuard admin password Yes
EAG_DELETE Enable deletion of AdGuard clients not in Eero (true/1) No
EAG_OVERWRITE Wipe all AdGuard clients before sync (true/1) No
EAG_CONFIRM Skip interactive confirmation (true/1) No
EAG_EXCLUDE_RANGE Comma-separated CIDR ranges protected from deletion No
EAG_EXCLUDE_ID Comma-separated client identifiers (MAC, name, hostname) protected from deletion No
EAG_NO_GLOBAL_ID Comma-separated client identifiers always given per-client AdGuard settings (MAC, name, or hostname, wildcards ok) No
EAG_NO_GLOBAL_REWRITES Keep DNS rewrites active for matching EAG_NO_GLOBAL_ID clients while allowing all other DNS requests No
EAG_CRON_SCHEDULE Sync schedule in cron syntax No 0 0 * * *

Example docker run

docker run -d \
  -e EAG_EERO_COOKIE="your-cookie" \
  -e EAG_ADGUARD_HOST="192.168.1.1" \
  -e EAG_ADGUARD_USER="admin" \
  -e EAG_ADGUARD_PASS="password" \
  -e EAG_DELETE="true" \
  -e EAG_CONFIRM="true" \
  -e EAG_EXCLUDE_RANGE="192.168.1.0/24" \
  -e EAG_EXCLUDE_ID="11:22:33:44:55:66,my-server" \
  -e EAG_CRON_SCHEDULE="0 * * * *" \
  amickael/eero-adguard-sync

Example docker-compose.yml

services:
  eero-adguard-sync:
    image: amickael/eero-adguard-sync
    environment:
      EAG_EERO_COOKIE: "your-cookie"
      EAG_ADGUARD_HOST: "192.168.1.1"
      EAG_ADGUARD_USER: "admin"
      EAG_ADGUARD_PASS: "password"
      EAG_DELETE: "true"
      EAG_CONFIRM: "true"
      EAG_EXCLUDE_RANGE: "192.168.1.0/24"
      EAG_EXCLUDE_ID: "11:22:33:44:55:66,my-server"
      EAG_NO_GLOBAL_ID: "Alice's iPad,Alice's iPhone"
      EAG_NO_GLOBAL_REWRITES: "true"
      EAG_CRON_SCHEDULE: "0 * * * *"
    restart: unless-stopped

๐Ÿ”„ Migration

EAG_SYNC_FLAGS (deprecated)

Older deployments used EAG_SYNC_FLAGS to pass raw CLI flags to the sync script (e.g. EAG_SYNC_FLAGS="-y -d"). This is still supported for backwards compatibility, but is superseded by the individual env vars.

Old New
EAG_SYNC_FLAGS="-y" EAG_CONFIRM=true
EAG_SYNC_FLAGS="-d" EAG_DELETE=true
EAG_SYNC_FLAGS="-y -d" EAG_CONFIRM=true + EAG_DELETE=true

โš–๏ธ License

MIT ยฉ 2022 Andrew Mickael

About

Sync Eero DHCP clients to AdGuard Home

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages