From cf08a7dfa23f30e29541744f7612cd38cd271101 Mon Sep 17 00:00:00 2001 From: Ashish D'Souza Date: Wed, 14 May 2025 21:15:45 -0500 Subject: [PATCH] Setup repeat camera down notifications #24 --- uptime-go/uptime/config/config.go | 10 ++++---- uptime-go/uptime/config/config.yaml | 3 +-- uptime-go/uptime/monitor.go | 40 +++++++++++++---------------- uptime-go/uptime/notify/notifier.go | 3 +-- uptime-go/uptime/notify/ntfy.go | 25 +++++++++--------- uptime-go/uptime/ping/ip_ping.go | 1 - uptime-go/uptime/ping/video_ping.go | 1 - 7 files changed, 37 insertions(+), 46 deletions(-) diff --git a/uptime-go/uptime/config/config.go b/uptime-go/uptime/config/config.go index d4168af..db98eaf 100644 --- a/uptime-go/uptime/config/config.go +++ b/uptime-go/uptime/config/config.go @@ -4,12 +4,12 @@ import "os" import "gopkg.in/yaml.v3" - type Config struct { - Cameras map[string]string `yaml:"cameras"` - PingIntervalSeconds int64 `yaml:"ping_interval_s"` - PingTimeoutSeconds int64 `yaml:"ping_timeout_s"` - ConsecutiveDownThreshold int `yaml:"consecutive_down_threshold"` + Cameras map[string]string `yaml:"cameras"` + PingIntervalSeconds int64 `yaml:"ping_interval_s"` + PingTimeoutSeconds int64 `yaml:"ping_timeout_s"` + ConsecutiveDownThreshold int `yaml:"consecutive_down_threshold"` + NotificationRepeatThreshold int `yaml:"notification_repeat_threshold"` } func ReadConfig(configFilename string) Config { diff --git a/uptime-go/uptime/config/config.yaml b/uptime-go/uptime/config/config.yaml index e748bba..375999e 100644 --- a/uptime-go/uptime/config/config.yaml +++ b/uptime-go/uptime/config/config.yaml @@ -1,9 +1,8 @@ cameras: back_door: 'rtsp://frigate:8554/back_door' doorbell: 'rtsp://frigate:8554/doorbell' - front_door: 'rtsp://frigate:8554/front_door' garage: 'rtsp://frigate:8554/garage' ping_interval_s: 60 ping_timeout_s: 30 consecutive_down_threshold: 3 - +notification_repeat_threshold: 30 diff --git a/uptime-go/uptime/monitor.go b/uptime-go/uptime/monitor.go index 5098e27..04772da 100644 --- a/uptime-go/uptime/monitor.go +++ b/uptime-go/uptime/monitor.go @@ -13,44 +13,40 @@ import ( ) type CameraMonitor struct { - pingInterval time.Duration - pingTimeout time.Duration - consecutiveDownThreshold int - downtime map[string]int + pingInterval time.Duration + pingTimeout time.Duration + consecutiveDownThreshold int + notificationRepeatThreshold int + downtime map[string]int notify.Notifier } -func NewCameraMonitor(pingInterval time.Duration, pingTimeout time.Duration, consecutiveDownThreshold int, notifier notify.Notifier) CameraMonitor { +func NewCameraMonitor(pingInterval time.Duration, pingTimeout time.Duration, consecutiveDownThreshold int, notificationRepeatThreshold int, notifier notify.Notifier) CameraMonitor { return CameraMonitor{ - pingInterval: pingInterval, - pingTimeout: pingTimeout, - consecutiveDownThreshold: consecutiveDownThreshold, - downtime: make(map[string]int), - Notifier: notifier, + pingInterval: pingInterval, + pingTimeout: pingTimeout, + consecutiveDownThreshold: consecutiveDownThreshold, + notificationRepeatThreshold: notificationRepeatThreshold, + downtime: make(map[string]int), + Notifier: notifier, } } -func (c CameraMonitor) onCameraUp(camera string) { - c.SendNotification(camera, true) - slog.Info(fmt.Sprintf("%s camera is back online!", camera)) -} - -func (c CameraMonitor) onCameraDown(camera string) { - c.SendNotification(camera, false) - slog.Info(fmt.Sprintf("%s camera is offline!", camera)) -} - func (c CameraMonitor) onCameraPingResult(camera string, online bool) { if online { if c.downtime[camera] >= c.consecutiveDownThreshold { - c.onCameraUp(camera) + c.SendNotification(camera, true) + slog.Info(fmt.Sprintf("%s camera is back online!", camera)) } c.downtime[camera] = 0 } else { c.downtime[camera] += 1 if c.downtime[camera] == c.consecutiveDownThreshold { - c.onCameraDown(camera) + c.SendNotification(camera, false) + slog.Info(fmt.Sprintf("%s camera is offline!", camera)) + } else if c.notificationRepeatThreshold >= c.consecutiveDownThreshold && c.downtime[camera]%c.notificationRepeatThreshold == c.consecutiveDownThreshold { + c.SendNotification(camera, false) } } } diff --git a/uptime-go/uptime/notify/notifier.go b/uptime-go/uptime/notify/notifier.go index 6096205..86fc3b6 100644 --- a/uptime-go/uptime/notify/notifier.go +++ b/uptime-go/uptime/notify/notifier.go @@ -5,14 +5,13 @@ import ( "strings" ) - type Notifier interface { SendNotification(camera string, online bool) } func createMessage(camera string, online bool) string { var msgTemplates = map[bool]string{ - true: "%s camera is back online!", + true: "%s camera is back online!", false: "%s camera is offline!", } diff --git a/uptime-go/uptime/notify/ntfy.go b/uptime-go/uptime/notify/ntfy.go index 65929cb..b1e25c0 100644 --- a/uptime-go/uptime/notify/ntfy.go +++ b/uptime-go/uptime/notify/ntfy.go @@ -1,15 +1,14 @@ package notify import ( - "crypto/tls" "bytes" + "crypto/tls" "encoding/json" "fmt" "log/slog" "net/http" ) - type NtfyNotifier struct { client *http.Client } @@ -26,21 +25,21 @@ func NewNtfyNotifier() NtfyNotifier { func (n NtfyNotifier) SendNotification(camera string, online bool) { type ntfyJson struct { - Topic string `json:"topic"` - Title string `json:"title"` - Message string `json:"message"` - Priority int `json:"priority"` - Click string `json:"click"` - Icon string `json:"icon"` + Topic string `json:"topic"` + Title string `json:"title"` + Message string `json:"message"` + Priority int `json:"priority"` + Click string `json:"click"` + Icon string `json:"icon"` } var reqJson, jsonErr = json.Marshal(ntfyJson{ - Topic: "frigate_camera_uptime", - Title: "Frigate", - Message: createMessage(camera, online), + Topic: "frigate_camera_uptime", + Title: "Frigate", + Message: createMessage(camera, online), Priority: 3, - Click: fmt.Sprintf("https://frigate.homelab.net/cameras/%s", camera), - Icon: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/frigate.png", + Click: fmt.Sprintf("https://frigate.homelab.net/cameras/%s", camera), + Icon: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/frigate.png", }) if jsonErr != nil { slog.Error("Failed to construct JSON request body", "error", jsonErr) diff --git a/uptime-go/uptime/ping/ip_ping.go b/uptime-go/uptime/ping/ip_ping.go index 23695c0..f8e4c1d 100644 --- a/uptime-go/uptime/ping/ip_ping.go +++ b/uptime-go/uptime/ping/ip_ping.go @@ -2,7 +2,6 @@ package ping import "os/exec" - func IPPing(host string) bool { var cmd = exec.Command("ping", "-w", "3", "-c", "1", host) var err = cmd.Run() diff --git a/uptime-go/uptime/ping/video_ping.go b/uptime-go/uptime/ping/video_ping.go index 92ce6a3..d739642 100644 --- a/uptime-go/uptime/ping/video_ping.go +++ b/uptime-go/uptime/ping/video_ping.go @@ -2,7 +2,6 @@ package ping import "os/exec" - func VideoPing(url string) bool { var cmd = exec.Command("ffprobe", "-rtsp_transport", "tcp", "-i", url, "-timeout", "10000000") var err = cmd.Run()