@@ -1,6 +1,8 @@
package main
import (
"encoding/json"
"io"
"io/ioutil"
"os"
"sort"
@@ -19,11 +21,17 @@ type Camera struct {
CameraName string `json:"camera_name"`
ImageDir string `json:"image_dir"`
LastImage string `json:"last_image"`
Status string `json:"status"`
Online bool `json:"online"`
StatusCode string `json:"status_code"`
Timestamp time.Time `json:"timestamp"`
ErrorCount int `json:"error_count"`
}
type Data struct {
Online bool
Timestamp time.Time
}
// Create struct to be used by our custom sort function.
type ByTime []os.FileInfo
@@ -33,30 +41,58 @@ func (f ByTime) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
func (f ByTime ) Less (i , j int ) bool { return f [i ].ModTime ().After (f [j ].ModTime ()) }
var (
mqttBroker = "tcp://HOST:PORT"
image_dirs = []string {"/tmp/hab_camera-1" , "/tmp/hab_camera-2" }
mqttBroker = "tcp://HOSTNAME:8883"
mqttClientId = "Camera-Monitor"
errorThreshold = 2
snapshotCount = 0
)
func copyFile (src , dst string ) (err error ) {
in , err := os .Open (src )
if err != nil {
return
}
defer in .Close ()
out , err := os .Create (dst )
if err != nil {
return
}
defer func () {
cerr := out .Close ()
if err == nil {
err = cerr
}
}()
if _ , err = io .Copy (out , in ); err != nil {
return
}
err = out .Sync ()
return
}
func main () {
cameras := Cameras {
Cameras : []Camera {{"hab_camera-1" , "Exterior (South)" , "/tmp/hab_camera-1" , "" , "offline " , time .Now (), 0 }, {"hab_camera-2" , "Exterior IR (South)" , "/tmp/hab_camera-2" , "" , "offline " , time $
Cameras : []Camera {{"hab_camera-1" , "Exterior (South)" , "/tmp/hab_camera-1" , "" , false , " " , time .Now (), 0 }, {"hab_camera-2" , "Exterior IR (South)" , "/tmp/hab_camera-2" , "" , false , " " , time . Now (), 0 }},
}
opts := MQTT .NewClientOptions ()
opts .AddBroker (mqttBroker )
opts .SetClientID (mqttClientId )
c := MQTT .NewClient (opts )
if token := c .Connect (); token .Wait () && token .Error () != nil {
log .Warn ("Could not connect to: " , mqttBroker )
}
ticker := time.NewTicker (time .Millisecond * 3000 )
go func () {
for timestamp := range ticker .C {
for index , cam := range cameras .Cameras {
for index , cam := range cameras .Cameras {
ticker := time .NewTicker (time .Millisecond * 3000 )
go func (index int , cam Camera ) {
for timestamp := range ticker .C {
files , err := ioutil .ReadDir (cam .ImageDir )
if err != nil {
@@ -69,26 +105,45 @@ func main() {
}
if len (files ) > 0 {
// Check if the last image has been updated.
if cameras .Cameras [index ].LastImage == files [0 ].Name () {
// Allow a threshold for unchanged images due to camera software performance.
if cameras .Cameras [index ].ErrorCount >= errorThreshold {
cameras .Cameras [index ].Status = "offline"
cameras .Cameras [index ].Online = false
cameras .Cameras [index ].StatusCode = "No new image found."
} else {
cameras .Cameras [index ].ErrorCount ++
}
} else {
cameras .Cameras [index ].Status = "online"
cameras .Cameras [index ].Online = true
cameras .Cameras [index ].ErrorCount = 0
cameras .Cameras [index ].StatusCode = ""
if snapshotCount == 0 || snapshotCount > 4 {
cerr := copyFile (cam .ImageDir + "/" + files [0 ].Name (), cam .ImageDir + "/out.jpg" )
if cerr != nil {
log .Warn ("File copy failed" )
log .Warn (cerr )
}
snapshotCount = 0
}
snapshotCount ++
}
cameras .Cameras [index ].LastImage = files [0 ].Name ()
cameras .Cameras [index ].Timestamp = timestamp
}
token := c .Publish ("test/cameras/" + cam .CameraID + "/status" , 0 , false , cameras .Cameras [index ].Status )
// Build message data packet and json.Marshal
var data = & Data {}
data .Timestamp = timestamp
data .Online = cameras .Cameras [index ].Online
messageData , _ := json .Marshal (data )
// Send MQTT message
token := c .Publish ("test/cameras/" + cam .CameraID , 0 , true , messageData )
token .Wait ()
}
}
}()
}
}(index , cam )
}
select {}
}
}