Added more filters for zones, cameras, and objects.
This commit is contained in:
committed by
GitHub
parent
41719c4557
commit
68749e219b
88
main.py
88
main.py
@ -10,14 +10,12 @@ import time
|
||||
import threading
|
||||
import logging
|
||||
|
||||
# Logging setup
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s [%(levelname)s] %(message)s'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Load config
|
||||
with open('config.json', 'r') as f:
|
||||
config = json.load(f)
|
||||
|
||||
@ -28,18 +26,64 @@ SMTP_PASSWORD = config["smtp"]["password"]
|
||||
EMAIL_FROM = config["smtp"]["from"]
|
||||
EMAIL_TO = config["smtp"]["to"]
|
||||
HOMEASSISTANT_URL = config["homeassistant_url"]
|
||||
HOMEASSISTANT_IP = config["homeassistant_ip"]
|
||||
HOMEASSISTANT_IP = config.get("homeassistant_ip", HOMEASSISTANT_URL)
|
||||
|
||||
MQTT_BROKER_IP = config["mqtt"]["broker_ip"]
|
||||
MQTT_PORT = config["mqtt"]["port"]
|
||||
MQTT_USERNAME = config["mqtt"]["username"]
|
||||
MQTT_PASSWORD = config["mqtt"]["password"]
|
||||
|
||||
FILTERED_CAMERAS = config.get("allowed_cameras", [])
|
||||
IGNORED_LABELS = config.get("ignored_labels", [])
|
||||
try:
|
||||
with open("alert_rules.json", "r") as f:
|
||||
alert_rules_raw = json.load(f)
|
||||
logger.info(f"Loaded alert_rules.json: {alert_rules_raw}")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to load alert_rules.json, no events will be processed: {e}")
|
||||
alert_rules_raw = {}
|
||||
|
||||
alert_rules = {}
|
||||
for cam, rules in alert_rules_raw.items():
|
||||
alert_rules[cam.lower()] = {
|
||||
"labels": [lbl.lower() for lbl in rules.get("labels", [])],
|
||||
"ignore": [lbl.lower() for lbl in rules.get("ignore", [])],
|
||||
"zones": [zone.lower() for zone in rules.get("zones", [])]
|
||||
}
|
||||
|
||||
event_cache = {}
|
||||
|
||||
def rule_allows_event(camera, label, zones):
|
||||
cam_key = camera.lower()
|
||||
lbl = label.lower()
|
||||
zones_check = [z.lower() for z in zones] if zones else []
|
||||
|
||||
if cam_key not in alert_rules:
|
||||
logger.debug(f"Camera '{camera}' not in alert_rules.json — event blocked")
|
||||
return False
|
||||
|
||||
rule = alert_rules[cam_key]
|
||||
|
||||
if rule["labels"]:
|
||||
if lbl not in rule["labels"]:
|
||||
logger.debug(f"Label '{label}' not allowed for camera '{camera}' — event blocked")
|
||||
return False
|
||||
|
||||
if rule["ignore"]:
|
||||
if lbl in rule["ignore"]:
|
||||
logger.debug(f"Label '{label}' is ignored for camera '{camera}' — event blocked")
|
||||
return False
|
||||
|
||||
if rule["zones"]:
|
||||
if not zones_check:
|
||||
logger.debug(f"No zone info in event but zones filter present — event blocked")
|
||||
return False
|
||||
allowed_zones = [z.lower() for z in rule["zones"]]
|
||||
if not any(zone in allowed_zones for zone in zones_check):
|
||||
logger.debug(f"Zones {zones} not allowed for camera '{camera}' — event blocked")
|
||||
return False
|
||||
|
||||
logger.debug(f"Event allowed for camera '{camera}', label '{label}', zones '{zones}'")
|
||||
return True
|
||||
|
||||
def send_email(message, snapshot_urls, event_label, clip_url):
|
||||
subject = f"{event_label} detected!"
|
||||
msg = MIMEMultipart()
|
||||
@ -58,7 +102,7 @@ def send_email(message, snapshot_urls, event_label, clip_url):
|
||||
image_data = BytesIO(response.content)
|
||||
msg.attach(MIMEImage(image_data.read(), name="snapshot.jpg"))
|
||||
except Exception:
|
||||
pass # silent fail for snapshot issues
|
||||
pass # silently fail snapshot issues
|
||||
|
||||
try:
|
||||
with smtplib.SMTP(SMTP_SERVER, SMTP_PORT, timeout=10) as server:
|
||||
@ -70,7 +114,7 @@ def send_email(message, snapshot_urls, event_label, clip_url):
|
||||
logger.error(f"Failed to send email: {e}")
|
||||
|
||||
def handle_event(event_id):
|
||||
time.sleep(10) # Delay to collect full snapshots
|
||||
time.sleep(10) # Delay to collect snapshots
|
||||
|
||||
if event_id not in event_cache:
|
||||
return
|
||||
@ -93,17 +137,16 @@ def on_message(client, userdata, message):
|
||||
if not after:
|
||||
return
|
||||
|
||||
event_id = after.get("id")
|
||||
event_label = after.get("label")
|
||||
event_id = after.get("id")
|
||||
camera = after.get("camera")
|
||||
zones = after.get("current_zones") or after.get("entered_zones") or []
|
||||
|
||||
if not event_id or not event_label or not camera:
|
||||
if not event_label or not event_id or not camera:
|
||||
return
|
||||
|
||||
if FILTERED_CAMERAS and camera.lower() not in [c.lower() for c in FILTERED_CAMERAS]:
|
||||
return
|
||||
|
||||
if event_label in IGNORED_LABELS:
|
||||
if not rule_allows_event(camera, event_label, zones):
|
||||
logger.info(f"Event from camera '{camera}' with label '{event_label}' and zones '{zones}' blocked by alert rules.")
|
||||
return
|
||||
|
||||
snapshot_url = f"{HOMEASSISTANT_IP}/api/frigate/notifications/{event_id}/snapshot.jpg"
|
||||
@ -118,20 +161,29 @@ def on_message(client, userdata, message):
|
||||
}
|
||||
threading.Thread(target=handle_event, args=(event_id,), daemon=True).start()
|
||||
|
||||
logger.info(f"Received event: {event_label} from {camera} (Event ID: {event_id})")
|
||||
logger.info(f"Received event: {event_label} from {camera} (Event ID: {event_id}, Zones: {zones})")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error processing MQTT message: {e}")
|
||||
|
||||
def on_connect(client, userdata, flags, rc):
|
||||
if rc == 0:
|
||||
def on_connect(client, userdata, flags, rc, properties=None):
|
||||
if rc != 0:
|
||||
logger.error(f"MQTT connection failed with code {rc}")
|
||||
return
|
||||
|
||||
if userdata.get("first_connect", True):
|
||||
client.subscribe("frigate/events")
|
||||
logger.info("Connected to MQTT broker and subscribed to frigate/events")
|
||||
userdata["first_connect"] = False
|
||||
else:
|
||||
logger.error(f"MQTT connection failed with code {rc}")
|
||||
logger.debug("Reconnected to MQTT broker")
|
||||
|
||||
def connect_mqtt():
|
||||
client = mqtt.Client(client_id="frigate_smtp", protocol=mqtt.MQTTv311)
|
||||
client = mqtt.Client(
|
||||
client_id="frigate_smtp",
|
||||
protocol=mqtt.MQTTv5,
|
||||
userdata={"first_connect": True}
|
||||
)
|
||||
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)
|
||||
client.on_connect = on_connect
|
||||
client.on_message = on_message
|
||||
|
||||
Reference in New Issue
Block a user