Setup repeat camera down notifications #24
This commit is contained in:
parent
7b24dad5b9
commit
e6ccd8f1d7
|
@ -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 {
|
||||
|
|
|
@ -6,4 +6,4 @@ cameras:
|
|||
ping_interval_s: 60
|
||||
ping_timeout_s: 30
|
||||
consecutive_down_threshold: 3
|
||||
|
||||
notification_repeat_threshold: 30
|
||||
|
|
|
@ -12,6 +12,6 @@ func main() {
|
|||
var pingInterval = time.Duration(uptimeConfig.PingIntervalSeconds * int64(time.Second))
|
||||
var pingTimeout = time.Duration(uptimeConfig.PingTimeoutSeconds * int64(time.Second))
|
||||
|
||||
var cameraMonitor CameraMonitor = NewCameraMonitor(pingInterval, pingTimeout, uptimeConfig.ConsecutiveDownThreshold, notify.NewNtfyNotifier())
|
||||
var cameraMonitor CameraMonitor = NewCameraMonitor(pingInterval, pingTimeout, uptimeConfig.ConsecutiveDownThreshold, uptimeConfig.NotificationRepeatThreshold, notify.NewNtfyNotifier())
|
||||
cameraMonitor.Run(uptimeConfig.Cameras)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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!",
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue