|
@ -6,8 +6,8 @@ import ( |
|
|
"encoding/json" |
|
|
"encoding/json" |
|
|
"fmt" |
|
|
"fmt" |
|
|
"git.aiterp.net/lucifer/new-server/models" |
|
|
"git.aiterp.net/lucifer/new-server/models" |
|
|
|
|
|
"golang.org/x/sync/errgroup" |
|
|
"io" |
|
|
"io" |
|
|
"log" |
|
|
|
|
|
"net" |
|
|
"net" |
|
|
"net/http" |
|
|
"net/http" |
|
|
"strconv" |
|
|
"strconv" |
|
@ -98,17 +98,17 @@ func (b *Bridge) Refresh(ctx context.Context) error { |
|
|
|
|
|
|
|
|
func (b *Bridge) SyncStale(ctx context.Context) error { |
|
|
func (b *Bridge) SyncStale(ctx context.Context) error { |
|
|
indices := make([]int, 0, 4) |
|
|
indices := make([]int, 0, 4) |
|
|
arrayIndices := make([]int, 0, 4) |
|
|
|
|
|
inputs := make([]LightStateInput, 0, 4) |
|
|
inputs := make([]LightStateInput, 0, 4) |
|
|
|
|
|
|
|
|
|
|
|
eg, ctx := errgroup.WithContext(ctx) |
|
|
|
|
|
|
|
|
b.mu.Lock() |
|
|
b.mu.Lock() |
|
|
for i, state := range b.lightStates { |
|
|
|
|
|
|
|
|
for _, state := range b.lightStates { |
|
|
if !state.stale { |
|
|
if !state.stale { |
|
|
continue |
|
|
continue |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
indices = append(indices, state.index) |
|
|
indices = append(indices, state.index) |
|
|
arrayIndices = append(arrayIndices, i) |
|
|
|
|
|
inputs = append(inputs, state.input) |
|
|
inputs = append(inputs, state.input) |
|
|
} |
|
|
} |
|
|
b.mu.Unlock() |
|
|
b.mu.Unlock() |
|
@ -117,85 +117,24 @@ func (b *Bridge) SyncStale(ctx context.Context) error { |
|
|
return nil |
|
|
return nil |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
groups := make([]*syncGroup, 0, 4) |
|
|
|
|
|
for i := range inputs { |
|
|
|
|
|
input := inputs[i] |
|
|
|
|
|
|
|
|
|
|
|
found := false |
|
|
|
|
|
for _, group := range groups { |
|
|
|
|
|
if group.State.Equal(input) { |
|
|
|
|
|
group.Indexes = append(group.Indexes, indices[i]) |
|
|
|
|
|
group.ArrayIndexes = append(group.ArrayIndexes, arrayIndices[i]) |
|
|
|
|
|
found = true |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
if !found { |
|
|
|
|
|
groups = append(groups, &syncGroup{ |
|
|
|
|
|
GroupIndex: -1, |
|
|
|
|
|
State: input, |
|
|
|
|
|
Indexes: []int{indices[i]}, |
|
|
|
|
|
ArrayIndexes: []int{arrayIndices[i]}, |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
groupMap, err := b.getGroups(ctx) |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
return err |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for id, data := range groupMap { |
|
|
|
|
|
for _, group := range groups { |
|
|
|
|
|
if group.Matches(&data) { |
|
|
|
|
|
group.GroupIndex = id |
|
|
|
|
|
break |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for _, group := range groups { |
|
|
|
|
|
if group.GroupIndex == -1 { |
|
|
|
|
|
data := GroupData{ |
|
|
|
|
|
Name: "lucifer_auto_group", |
|
|
|
|
|
Lights: []string{}, |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
for i, input := range inputs { |
|
|
|
|
|
iCopy := i |
|
|
|
|
|
index := indices[i] |
|
|
|
|
|
inputCopy := input |
|
|
|
|
|
|
|
|
for _, idx := range group.Indexes { |
|
|
|
|
|
data.Lights = append(data.Lights, strconv.Itoa(idx)) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
id, err := b.postGroup(ctx, data) |
|
|
|
|
|
|
|
|
eg.Go(func() error { |
|
|
|
|
|
err := b.putLightState(ctx, index, inputCopy) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
return err |
|
|
return err |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
group.GroupIndex = id |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
log.Println("Updating", len(inputs), "lights on Hue bridge", b.externalID, "in", len(groups), "groups") |
|
|
|
|
|
|
|
|
|
|
|
for _, group := range groups { |
|
|
|
|
|
err := b.putGroupLightState(ctx, group.GroupIndex, group.State) |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
return err |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
b.mu.Lock() |
|
|
|
|
|
for _, arrayIndex := range group.ArrayIndexes { |
|
|
|
|
|
b.lightStates[arrayIndex].stale = false |
|
|
|
|
|
} |
|
|
|
|
|
b.mu.Unlock() |
|
|
|
|
|
|
|
|
b.lightStates[iCopy].stale = false |
|
|
|
|
|
|
|
|
if groupMap[group.GroupIndex].Name == "lucifer_auto_group" { |
|
|
|
|
|
err := b.deleteGroup(ctx, group.GroupIndex) |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
log.Println("Could not delete temporary group", err) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
return nil |
|
|
|
|
|
}) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return nil |
|
|
|
|
|
|
|
|
return eg.Wait() |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (b *Bridge) SyncSensors(ctx context.Context) ([]models.Event, error) { |
|
|
func (b *Bridge) SyncSensors(ctx context.Context) ([]models.Event, error) { |
|
@ -296,7 +235,6 @@ func (b *Bridge) postGroup(ctx context.Context, input GroupData) (int, error) { |
|
|
return id, err |
|
|
return id, err |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (b *Bridge) deleteGroup(ctx context.Context, index int) error { |
|
|
func (b *Bridge) deleteGroup(ctx context.Context, index int) error { |
|
|
return b.delete(ctx, "groups/"+strconv.Itoa(index), nil) |
|
|
return b.delete(ctx, "groups/"+strconv.Itoa(index), nil) |
|
|
} |
|
|
} |
|
@ -343,7 +281,6 @@ func (b *Bridge) delete(ctx context.Context, resource string, target interface{} |
|
|
return json.NewDecoder(res.Body).Decode(target) |
|
|
return json.NewDecoder(res.Body).Decode(target) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (b *Bridge) post(ctx context.Context, resource string, body interface{}, target interface{}) error { |
|
|
func (b *Bridge) post(ctx context.Context, resource string, body interface{}, target interface{}) error { |
|
|
rb, err := reqBody(body) |
|
|
rb, err := reqBody(body) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|