From e11ba33cab963115dc2f292366e40afbf73be1c8 Mon Sep 17 00:00:00 2001 From: Gisle Aune Date: Sun, 3 Mar 2019 19:12:41 +0100 Subject: [PATCH] BridgeController: Added DELETE /api/bridge/:bridge_id/light/:light_id --- controllers/bridge-controller.go | 45 ++++++++++++++++++++++++++++++++ light/driver.go | 3 +++ light/hue/driver.go | 22 +++++++++++++++- light/service.go | 29 ++++++++++++++++++++ 4 files changed, 98 insertions(+), 1 deletion(-) diff --git a/controllers/bridge-controller.go b/controllers/bridge-controller.go index c273954..6b37182 100644 --- a/controllers/bridge-controller.go +++ b/controllers/bridge-controller.go @@ -168,6 +168,50 @@ func (c *BridgeController) deleteBridge(w http.ResponseWriter, r *http.Request) respond.Data(w, bridge) } +// deleteBridgeLight (`DELETE /:bridge_id/light/:light_id`): Delete bridge by ID +func (c *BridgeController) deleteBridgeLight(w http.ResponseWriter, r *http.Request) { + idStr := mux.Vars(r)["bridge_id"] + id, err := strconv.ParseInt(idStr, 10, 32) + if err != nil { + respond.Error(w, http.StatusBadRequest, "invalid_id", "The id "+idStr+" is not valid.") + return + } + + lightIDStr := mux.Vars(r)["light_id"] + lightID, err := strconv.ParseInt(lightIDStr, 10, 32) + if err != nil { + respond.Error(w, http.StatusBadRequest, "invalid_id", "The id "+lightIDStr+" is not valid.") + return + } + + bridge, err := c.service.Bridge(r.Context(), int(id)) + if err == sql.ErrNoRows { + respond.Error(w, 404, "bridge_not_found", "The bridge cannot be found.") + return + } else if err != nil { + httperr.Respond(w, err) + return + } + + light, err := c.service.Light(r.Context(), int(lightID)) + if err != nil { + httperr.Respond(w, err) + return + } + if light.BridgeID != bridge.ID { + respond.Error(w, 404, "bridge_not_found", "The bridge cannot be found.") + return + } + + err = c.service.DeleteBridgeLight(r.Context(), bridge, light) + if err != nil { + httperr.Respond(w, err) + return + } + + respond.Data(w, bridge) +} + // Mount mounts the controller func (c *BridgeController) Mount(router *mux.Router, prefix string) { sub := router.PathPrefix(prefix).Subrouter() @@ -179,6 +223,7 @@ func (c *BridgeController) Mount(router *mux.Router, prefix string) { sub.HandleFunc("/{bridge_id}", c.getBridge).Methods("GET") sub.HandleFunc("/{bridge_id}", c.updateBridge).Methods("PUT", "PATCH") sub.HandleFunc("/{bridge_id}", c.deleteBridge).Methods("DELETE") + sub.HandleFunc("/{bridge_id}/light/{light_id}", c.deleteBridgeLight).Methods("DELETE") sub.HandleFunc("/{bridge_id}/discover", c.postBridgeDiscover).Methods("POST") } diff --git a/light/driver.go b/light/driver.go index 698bcba..f5a1d8f 100644 --- a/light/driver.go +++ b/light/driver.go @@ -25,6 +25,9 @@ type Driver interface { // DiscoverLights asks the bridge to start a search for new lights. DiscoverLights(ctx context.Context, bridge models.Bridge) error + // ForgetLight removes the light from the bridge. + ForgetLight(ctx context.Context, bridge models.Bridge, light models.Light) error + // ChangedLights returns a subset of the list describing which lights to update. ChangedLights(ctx context.Context, bridge models.Bridge, lights ...models.Light) ([]models.Light, error) } diff --git a/light/hue/driver.go b/light/hue/driver.go index 47cef7a..422a799 100644 --- a/light/hue/driver.go +++ b/light/hue/driver.go @@ -9,8 +9,8 @@ import ( "sync" "time" + "git.aiterp.net/lucifer/lucifer/internal/httperr" "git.aiterp.net/lucifer/lucifer/internal/huecolor" - "git.aiterp.net/lucifer/lucifer/light" "git.aiterp.net/lucifer/lucifer/models" gohue "github.com/collinux/gohue" @@ -212,6 +212,26 @@ func (d *driver) ChangedLights(ctx context.Context, bridge models.Bridge, lights return subset, nil } +func (d *driver) ForgetLight(ctx context.Context, bridge models.Bridge, light models.Light) error { + hueBridge, err := d.getBridge(bridge) + if err != nil { + return err + } + + hueLights, err := hueBridge.GetAllLights() + if err != nil { + return err + } + + for _, hueLight := range hueLights { + if light.InternalID == hueLight.UniqueID { + return hueLight.Delete() + } + } + + return httperr.NotFound("Light") +} + func (d *driver) calcColor(light models.Light, hueLight gohue.Light) (x, y float64, bri uint8, err error) { r, g, b, err := light.ColorRGBf() if err != nil { diff --git a/light/service.go b/light/service.go index f197ee7..8262ed3 100644 --- a/light/service.go +++ b/light/service.go @@ -84,6 +84,7 @@ func (s *Service) SyncLights(ctx context.Context, bridge models.Bridge) error { log.Println("Adding unknown light", bridgeLight.InternalID) bridgeLight.SetColor("FFFFFF") bridgeLight.Brightness = 254 + bridgeLight.On = true _, err := s.lights.Insert(ctx, bridgeLight) if err != nil { return err @@ -168,6 +169,11 @@ func (s *Service) Bridges(ctx context.Context) ([]models.Bridge, error) { return s.bridges.List(ctx) } +// Light gets all known bridges. +func (s *Service) Light(ctx context.Context, id int) (models.Light, error) { + return s.lights.FindByID(ctx, id) +} + // DeleteBridge deletes the bridge. func (s *Service) DeleteBridge(ctx context.Context, bridge models.Bridge) error { s.mutex.Lock() @@ -193,6 +199,29 @@ func (s *Service) DeleteBridge(ctx context.Context, bridge models.Bridge) error return nil } +// DeleteBridgeLight deletes the light in a bridge. +func (s *Service) DeleteBridgeLight(ctx context.Context, bridge models.Bridge, light models.Light) error { + s.mutex.Lock() + defer s.mutex.Unlock() + + d, ok := drivers[bridge.Driver] + if !ok { + return ErrUnknownDriver + } + + err := d.ForgetLight(ctx, bridge, light) + if err != nil { + return err + } + + err = s.lights.Remove(ctx, light) + if err != nil { + return err + } + + return nil +} + // UpdateBridge updates a bridge. func (s *Service) UpdateBridge(ctx context.Context, bridge models.Bridge) error { s.mutex.Lock()