From f5e66af3d824e7ea569781ff2e003ae3993b6c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Z=C3=BCrcher?= Date: Tue, 22 Apr 2025 18:01:22 +0200 Subject: [PATCH] add new ip ping for udp device add new function start and stop bus --- cfg/cfg.go | 3 +-- driver/bus.go | 56 +++++++++++++++++++++++++++++++++++++++++- main.go | 4 +++ models/bus.go | 68 +++++++++++++++++++++++++++++++++++++++------------ 4 files changed, 112 insertions(+), 19 deletions(-) diff --git a/cfg/cfg.go b/cfg/cfg.go index 5cac4ee..c551271 100644 --- a/cfg/cfg.go +++ b/cfg/cfg.go @@ -1,7 +1,6 @@ package cfg import ( - "fmt" "os" "path" @@ -51,7 +50,7 @@ func (c *Cfg) SaveCfg(data any) error { func (c *Cfg) LoadCfg(data any) error { p := path.Join(c.Dir, c.Name) + ".cfg" if _, err := os.Stat(p); err != nil { - return fmt.Errorf("no configuration file: '%s' found", p) + return nil } b, err := os.ReadFile(p) diff --git a/driver/bus.go b/driver/bus.go index 4f826cb..b02aa52 100644 --- a/driver/bus.go +++ b/driver/bus.go @@ -42,7 +42,6 @@ func (d *ArtNetDriver) CreateBus(c *gin.Context) { c.JSON(http.StatusBadRequest, gin.H{"error": "bus name missing"}) return } else if addr := net.ParseIP(payload.Ip); addr == nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "wrong ip '" + payload.Ip + "'"}) return } @@ -53,6 +52,7 @@ func (d *ArtNetDriver) CreateBus(c *gin.Context) { } bus := d.NewBus(payload.Name, payload.Ip, payload.GetPort()) + c.JSON(http.StatusOK, gin.H{ "message": fmt.Sprintf("bus '%s' successfully created with ip: %s and on port: %d", bus.Name, bus.Ip, bus.GetPort()), }) @@ -92,3 +92,57 @@ func (d *ArtNetDriver) RemoveBus(c *gin.Context) { }) d.cfgHandler.SaveCfg(*d) } + +func (d *ArtNetDriver) Start(c *gin.Context) { + _, err := auth.GetIDFromAuth(c) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "id: " + err.Error()}) + return + } + + var payload models.Bus + + if err := c.BindJSON(&payload); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "json: " + err.Error()}) + return + } + + if payload.Name == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "bus name missing"}) + return + } + + d.Buses[payload.Name].Start(d.Log) + + c.JSON(http.StatusOK, models.JsonResponse{ + Message: fmt.Sprintf("bus '%s' running", payload.Name), + }) + d.cfgHandler.SaveCfg(*d) +} + +func (d *ArtNetDriver) Stop(c *gin.Context) { + _, err := auth.GetIDFromAuth(c) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "id: " + err.Error()}) + return + } + + var payload models.Bus + + if err := c.BindJSON(&payload); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "json: " + err.Error()}) + return + } + + if payload.Name == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "bus name missing"}) + return + } + + d.Buses[payload.Name].Stop() + + c.JSON(http.StatusOK, models.JsonResponse{ + Message: fmt.Sprintf("bus '%s' stopped", payload.Name), + }) + d.cfgHandler.SaveCfg(*d) +} diff --git a/main.go b/main.go index df3e536..2668782 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ import ( "artNet/driver" "artNet/server" "flag" + "fmt" "os" "github.com/gin-gonic/gin" @@ -41,11 +42,14 @@ func main() { s.Routes.GET("/buses/all", artNetDriver.GetAllBuses) s.Routes.POST("/buses/create", artNetDriver.CreateBus) s.Routes.POST("/buses/remove", artNetDriver.RemoveBus) + s.Routes.POST("/buses/start", artNetDriver.Start) + s.Routes.POST("/buses/stop", artNetDriver.Stop) s.Routes.GET("/", func(c *gin.Context) { c.String(200, "ArtNet Driver WebSocket Server is running!") }) + artNetDriver.Log.Info("main", fmt.Sprintf("listen on %d", *port)) // start http server if err := s.ServeHttp(*port); err != nil { artNetDriver.Log.Error("main", "error http server "+err.Error()) diff --git a/models/bus.go b/models/bus.go index 8e06a7f..3db2ee6 100644 --- a/models/bus.go +++ b/models/bus.go @@ -1,12 +1,13 @@ package models import ( + "context" "fmt" - "log" "net" "time" "github.com/tatsushid/go-fastping" + "github.com/tecamino/tecamino-logger/logging" ) // Art-Net constants @@ -16,10 +17,12 @@ const ( // Art-Net Interface type Bus struct { - Name string `yaml:"name" json:"name"` - Ip string `yaml:"ip" json:"ip"` - Port *int `yaml:"port" json:"port,omitempty"` - Data *DMX `yaml:"-" json:"-"` + Name string `yaml:"name" json:"name"` + Ip string `yaml:"ip" json:"ip"` + Port *int `yaml:"port" json:"port,omitempty"` + Data *DMX `yaml:"-" json:"-"` + Watchdog context.CancelFunc `yaml:"-" json:"-"` + Reachable bool `yaml:"-" json:"-"` } // adds new Art-Net interface to driver port 0 = 6454 (default art-net) @@ -92,8 +95,51 @@ func (b *Bus) Poll(interval time.Duration) error { } } -// start polling dmx data in milliseconds 0 = aprox. 44Hertz +// start bus +func (b *Bus) Start(log *logging.Logger) { + var ctx context.Context + ctx, b.Watchdog = context.WithCancel(context.Background()) + + go func() { + var interval time.Duration = 10 * time.Second + log.Info("bus.Start", fmt.Sprintf("device:%s ip:%s watchdog stopped", b.Name, b.Ip)) + for { + select { + case <-ctx.Done(): + log.Info("bus.Start", fmt.Sprintf("device:%s ip:%s watchdog stopped", b.Name, b.Ip)) + b.Reachable = false + return + default: + b.Reachable = false + if reached, err := isUDPReachable(b.Ip); err != nil { + log.Error("bus.Start", err) + interval = 5 * time.Second + } else if !reached { + log.Error("bus.Start", fmt.Sprintf("device:%s ip:%s not reached", b.Name, b.Ip)) + interval = 5 * time.Second + } else { + b.Reachable = true + log.Info("bus.Start", fmt.Sprintf("device:%s ip:%s watchdog running", b.Name, b.Ip)) + interval = 30 * time.Second + } + time.Sleep(interval) + } + } + }() +} + +// stop bus +func (b *Bus) Stop() { + if b.Watchdog != nil { + b.Watchdog() + } +} + +// send dmx data func (b *Bus) SendData() error { + if !b.Reachable { + return nil + } // Send packet over UDP conn, err := net.DialUDP("udp", nil, &net.UDPAddr{ IP: net.ParseIP(b.Ip), @@ -105,16 +151,6 @@ func (b *Bus) SendData() error { } defer conn.Close() - go func() { - if reached, err := isUDPReachable(b.Ip); err != nil { - log.Println(err) - return - } else if !reached { - log.Println("device not reachable") - return - } - }() - _, err = conn.Write(NewArtNetPackage(b.Data)) return err