diff --git a/.env.example b/.env.example index 377949e..c61be2e 100644 --- a/.env.example +++ b/.env.example @@ -7,5 +7,9 @@ ADGUARD_PASSWORD=your-password HASS_URL=https://your-hass-instance.com/api/services/notify/mobile_app_your_phone HASS_TOKEN=your-long-lived-access-token +# (Optional) Notification Templates - Available: {event_type}, {client_name}, {host}, {reason} +# HASS_TITLE_TEMPLATE="{event_type}" +# HASS_MSG_TEMPLATE="{client_name} tried to access \"{host}\"" + # Monitored Clients (JSON Format: {"IP": "Nickname"}) CLIENTS='{"192.168.1.100": "My Laptop", "192.168.1.101": "My Phone"}' diff --git a/README.md b/README.md index fd62e95..aa595f0 100644 --- a/README.md +++ b/README.md @@ -43,4 +43,6 @@ Adguard Monitor is designed for openclaw, which should usually NEVER make a requ - `ADGUARD_USER/PASSWORD`: API credentials. - `CLIENTS`: A JSON-formatted dictionary mapping IPs to display names. - `HASS_URL/TOKEN`: Home Assistant mobile notification endpoint and Long-Lived Access Token. +- `HASS_TITLE_TEMPLATE`: (Optional) Template for notification title. Available: `{event_type}`, `{client_name}`, `{host}`, `{reason}`. Default: `{event_type}`. +- `HASS_MSG_TEMPLATE`: (Optional) Template for notification body. Available: same as title. Default: `{client_name} tried to access "{host}"`. diff --git a/monitor.py b/monitor.py index a786d68..2255a06 100644 --- a/monitor.py +++ b/monitor.py @@ -36,6 +36,10 @@ try: "Authorization": f"Bearer {HASS_TOKEN}", "Content-Type": "application/json", } + + # Optional Notification Overrides + HASS_TITLE_TEMPLATE = os.getenv("HASS_TITLE_TEMPLATE", "{event_type}") + HASS_MSG_TEMPLATE = os.getenv("HASS_MSG_TEMPLATE", "{client_name} tried to access \"{host}\"") # --- Custom Domain List --- CUSTOM_DOMAINS = [] @@ -65,12 +69,19 @@ except (EnvironmentError, json.JSONDecodeError) as e: print(f"Error during startup: {e}") exit(1) -def notify_hass(client_name, host, reason, title="🛡️ Adguard Blocked a Request"): - msg = f"{client_name} tried to access \"{host}\"" +def notify_hass(client_name, host, reason, event_type="🛡️ Adguard Blocked"): + # Format message and title using templates (supporting simple {placeholders}) + try: + msg = HASS_MSG_TEMPLATE.format(client_name=client_name, host=host, reason=reason, event_type=event_type) + title = HASS_TITLE_TEMPLATE.format(client_name=client_name, host=host, reason=reason, event_type=event_type) + except KeyError as e: + logger.error(f"Template error: Missing key {e}. Falling back to defaults.") + msg = f"{client_name} tried to access \"{host}\"" + title = event_type payload = { - "message": msg, "title": title, + "message": msg, "data": { "push": { "sound": "default", @@ -121,6 +132,10 @@ def get_auth_session(): session.auth = HTTPBasicAuth(USERNAME, PASSWORD) return session +def hour_and_minute(): + now = datetime.now() + return now.strftime("%H:%M") + def is_custom_match(host): # Check negative filters first for pattern in NEGATIVE_FILTERS: @@ -175,15 +190,22 @@ def fetch_and_analyze(session, verbose=False): if is_blocked or is_custom: # Check for duplicate notifications within the same "event" # Using host + client_ip as a unique key for the last notification - event_type = "BLOCKED" if is_blocked else "CUSTOM_MATCH" + event_label = "BLOCKED" if is_blocked else "CUSTOM_MATCH" notification_key = f"{client_ip}:{host}:{reason}:{hour_and_minute()}" if stats.last_notified_key == notification_key: continue stats.log_blocked() - title = "🛡️ Adguard Blocked a Request" if is_blocked else "⚠️ Custom Domain Match" - logger.warning(f"{event_type}: {client_name} -> {host} ({reason if is_blocked else 'Manual match'})") - notify_hass(client_name, host, reason if is_blocked else "Custom List", title=title) + default_title = "🛡️ Blocked" if is_blocked else "⚠️ Custom" + logger.warning(f"{event_label}: {client_name} -> {host} ({reason if is_blocked else 'Manual match'})") + + # Pass details for templating + notify_hass( + client_name=client_name, + host=host, + reason=reason if is_blocked else "Custom List", + event_type=default_title + ) stats.last_notified_key = notification_key # Dynamic limit adjustment