diff --git a/app/api/devices.go b/app/api/devices.go index a7655c9..644d0a5 100644 --- a/app/api/devices.go +++ b/app/api/devices.go @@ -30,6 +30,57 @@ func Devices(r gin.IRoutes) { return fetchDevices(ctxOf(c), c.Param("fetch")) })) + r.PUT("/batch", handler(func(c *gin.Context) (interface{}, error) { + var body []struct { + Fetch string `json:"fetch"` + SetState models.NewDeviceState `json:"setState"` + } + err := parseBody(c, &body) + if err != nil { + return nil, err + } + + set := make(map[int]bool) + changed := make([]models.Device, 0, 64) + for _, job := range body { + devices, err := fetchDevices(ctxOf(c), job.Fetch) + if err != nil { + return nil, err + } + if len(devices) == 0 { + return []models.Device{}, nil + } + + for i := range devices { + if set[devices[i].ID] { + continue + } + + err := devices[i].SetState(job.SetState) + if err != nil { + return nil, err + } + + set[devices[i].ID] = true + changed = append(changed, devices[i]) + } + } + + config.PublishChannel <- changed + + go func() { + for _, device := range changed { + err := config.DeviceRepository().Save(context.Background(), &device) + if err != nil { + log.Println("Failed to save device for state:", err) + continue + } + } + }() + + return changed, nil + })) + r.PUT("/:fetch/state", handler(func(c *gin.Context) (interface{}, error) { state := models.NewDeviceState{} err := parseBody(c, &state) diff --git a/internal/mysql/devicerepo.go b/internal/mysql/devicerepo.go index 1854b64..4ff1ba7 100644 --- a/internal/mysql/devicerepo.go +++ b/internal/mysql/devicerepo.go @@ -259,6 +259,10 @@ func (r *DeviceRepo) populate(ctx context.Context, records []deviceRecord) ([]mo Tags: make([]string, 0, 8), } + if device.ButtonNames[0] == "" { + device.ButtonNames = device.ButtonNames[:0] + } + caps := make([]models.DeviceCapability, 0, 16) for _, capStr := range strings.Split(record.Capabilities, ",") { caps = append(caps, models.DeviceCapability(capStr))