refactorings.
This commit is contained in:
@@ -2,7 +2,9 @@ package lucifer3
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServiceKey struct{}
|
type ServiceKey struct{}
|
||||||
@@ -28,6 +30,7 @@ type EventBus struct {
|
|||||||
listeners []*serviceListener
|
listeners []*serviceListener
|
||||||
privilegedList []ActiveService
|
privilegedList []ActiveService
|
||||||
signal chan struct{}
|
signal chan struct{}
|
||||||
|
setStates int32
|
||||||
}
|
}
|
||||||
|
|
||||||
// JoinCallback joins the event bus for a moment.
|
// JoinCallback joins the event bus for a moment.
|
||||||
@@ -62,7 +65,20 @@ func (b *EventBus) JoinPrivileged(service ActiveService) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *EventBus) RunCommand(command Command) {
|
func (b *EventBus) RunCommand(command Command) {
|
||||||
fmt.Println("[COMMAND]", command.CommandDescription())
|
if cd := command.CommandDescription(); !strings.HasPrefix(cd, "SetState") {
|
||||||
|
if setStates := atomic.LoadInt32(&b.setStates); setStates > 0 {
|
||||||
|
fmt.Println("[INFO]", setStates, "SetState commands hidden.")
|
||||||
|
atomic.AddInt32(&b.setStates, -setStates)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("[COMMAND]", cd)
|
||||||
|
} else {
|
||||||
|
if atomic.AddInt32(&b.setStates, 1) >= 1000 {
|
||||||
|
fmt.Println("[INFO] 100 SetState commands hidden.")
|
||||||
|
atomic.AddInt32(&b.setStates, -1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
b.send(serviceMessage{command: command})
|
b.send(serviceMessage{command: command})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+25
-12
@@ -27,24 +27,37 @@ func main() {
|
|||||||
switch event.(type) {
|
switch event.(type) {
|
||||||
case events.DevicesReady:
|
case events.DevicesReady:
|
||||||
bus.RunCommand(commands.AddAlias{Match: "nanoleaf:10.80.1.14:2d0c", Alias: "lucifer:name:Hex 5"})
|
bus.RunCommand(commands.AddAlias{Match: "nanoleaf:10.80.1.14:2d0c", Alias: "lucifer:name:Hex 5"})
|
||||||
bus.RunCommand(commands.AddAlias{Match: "nanoleaf:10.80.1.14:542f", Alias: "lucifer:name:Hex 4"})
|
bus.RunCommand(commands.AddAlias{Match: "nanoleaf:10.80.1.14:542f", Alias: "lucifer:name:Hex 6"})
|
||||||
bus.RunCommand(commands.AddAlias{Match: "nanoleaf:10.80.1.14:e760", Alias: "lucifer:name:Hex 3"})
|
bus.RunCommand(commands.AddAlias{Match: "nanoleaf:10.80.1.14:e760", Alias: "lucifer:name:Hex 7"})
|
||||||
bus.RunCommand(commands.AddAlias{Match: "nanoleaf:10.80.1.14:207a", Alias: "lucifer:name:Hex 2"})
|
bus.RunCommand(commands.AddAlias{Match: "nanoleaf:10.80.1.14:207a", Alias: "lucifer:name:Hex 8"})
|
||||||
bus.RunCommand(commands.AddAlias{Match: "nanoleaf:10.80.1.14:df9a", Alias: "lucifer:name:Hex 1"})
|
bus.RunCommand(commands.AddAlias{Match: "nanoleaf:10.80.1.14:df9a", Alias: "lucifer:name:Hex 9"})
|
||||||
bus.RunCommand(commands.AddAlias{Match: "nanoleaf:10.80.1.14:cdd5", Alias: "lucifer:name:Hex 6"})
|
bus.RunCommand(commands.AddAlias{Match: "nanoleaf:10.80.1.14:cdd5", Alias: "lucifer:name:Hex 4"})
|
||||||
bus.RunCommand(commands.AddAlias{Match: "nanoleaf:10.80.1.14:4597", Alias: "lucifer:name:Hex 7"})
|
bus.RunCommand(commands.AddAlias{Match: "nanoleaf:10.80.1.14:4597", Alias: "lucifer:name:Hex 3"})
|
||||||
bus.RunCommand(commands.AddAlias{Match: "nanoleaf:10.80.1.14:82cb", Alias: "lucifer:name:Hex 8"})
|
bus.RunCommand(commands.AddAlias{Match: "nanoleaf:10.80.1.14:82cb", Alias: "lucifer:name:Hex 2"})
|
||||||
bus.RunCommand(commands.AddAlias{Match: "nanoleaf:10.80.1.14:09fd", Alias: "lucifer:name:Hex 9"})
|
bus.RunCommand(commands.AddAlias{Match: "nanoleaf:10.80.1.14:09fd", Alias: "lucifer:name:Hex 1"})
|
||||||
bus.RunCommand(commands.Assign{
|
bus.RunCommand(commands.Assign{
|
||||||
Match: "nanoleaf:10.80.1.14:*",
|
Match: "nanoleaf:10.80.1.14:*",
|
||||||
Effect: effects.Gradient{
|
Effect: effects.Pattern{
|
||||||
States: []device.State{
|
States: []device.State{
|
||||||
{Power: p(true), Intensity: p(0.3), Color: p(color.MustParse("xy:0.22,0.18"))},
|
{Power: p(true), Intensity: p(0.3), Color: p(color.MustParse("xy:0.22,0.18"))},
|
||||||
|
{Power: p(true), Intensity: p(0.4), Color: p(color.MustParse("xy:0.22,0.18"))},
|
||||||
{Power: p(true), Intensity: p(0.5), Color: p(color.MustParse("xy:0.22,0.18"))},
|
{Power: p(true), Intensity: p(0.5), Color: p(color.MustParse("xy:0.22,0.18"))},
|
||||||
},
|
},
|
||||||
|
AnimationMS: 200,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
bus.RunCommand(commands.AddAlias{Match: "nanoleaf:10.80.1.14:*", Alias: "lucifer:tag:Magic Lamps"})
|
||||||
|
bus.RunCommand(commands.Assign{
|
||||||
|
Match: "lucifer:tag:Magic Lamps",
|
||||||
|
Effect: effects.Gradient{
|
||||||
|
States: []device.State{
|
||||||
|
{Power: p(true), Intensity: p(0.5), Color: p(color.MustParse("xy:0.22,0.18"))},
|
||||||
|
{Power: p(true), Intensity: p(0.8), Color: p(color.MustParse("xy:0.22,0.18"))},
|
||||||
|
},
|
||||||
Interpolate: true,
|
Interpolate: true,
|
||||||
AnimationMS: 1000,
|
AnimationMS: 500,
|
||||||
Reverse: false,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -56,7 +69,7 @@ func main() {
|
|||||||
|
|
||||||
bus.RunCommand(commands.ConnectDevice{
|
bus.RunCommand(commands.ConnectDevice{
|
||||||
ID: "nanoleaf:10.80.1.14",
|
ID: "nanoleaf:10.80.1.14",
|
||||||
APIKey: "",
|
APIKey: "QRj5xcQxAQMQsjK4gvaprdhOwr1sCIcj",
|
||||||
})
|
})
|
||||||
|
|
||||||
time.Sleep(time.Hour)
|
time.Sleep(time.Hour)
|
||||||
|
|||||||
@@ -22,3 +22,9 @@ func (c SetState) Matches(driver string) (sub string, ok bool) {
|
|||||||
func (c SetState) CommandDescription() string {
|
func (c SetState) CommandDescription() string {
|
||||||
return fmt.Sprintf("SetState(%s, %s)", c.ID, c.State)
|
return fmt.Sprintf("SetState(%s, %s)", c.ID, c.State)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SetStateBatch map[string]device.State
|
||||||
|
|
||||||
|
func (c SetStateBatch) CommandDescription() string {
|
||||||
|
return fmt.Sprintf("SetStateBatch(%d devices)", len(c))
|
||||||
|
}
|
||||||
|
|||||||
+2
-2
@@ -47,7 +47,7 @@ func (s State) Interpolate(s2 State, f float64) State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if s.Intensity != nil && s2.Intensity != nil {
|
if s.Intensity != nil && s2.Intensity != nil {
|
||||||
newState.Intensity = gentools.Ptr((*s.Intensity * f) + (*s2.Intensity * (1.0 - f)))
|
newState.Intensity = gentools.Ptr((*s2.Intensity * f) + (*s.Intensity * (1.0 - f)))
|
||||||
} else if s.Intensity != nil {
|
} else if s.Intensity != nil {
|
||||||
newState.Intensity = gentools.ShallowCopy(s.Intensity)
|
newState.Intensity = gentools.ShallowCopy(s.Intensity)
|
||||||
} else if s2.Intensity != nil {
|
} else if s2.Intensity != nil {
|
||||||
@@ -55,7 +55,7 @@ func (s State) Interpolate(s2 State, f float64) State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if s.Temperature != nil && s2.Temperature != nil {
|
if s.Temperature != nil && s2.Temperature != nil {
|
||||||
newState.Temperature = gentools.Ptr((*s.Temperature * f) + (*s2.Temperature * (1.0 - f)))
|
newState.Temperature = gentools.Ptr((*s2.Temperature * f) + (*s.Temperature * (1.0 - f)))
|
||||||
} else if s.Temperature != nil {
|
} else if s.Temperature != nil {
|
||||||
newState.Temperature = gentools.ShallowCopy(s.Temperature)
|
newState.Temperature = gentools.ShallowCopy(s.Temperature)
|
||||||
} else if s2.Temperature != nil {
|
} else if s2.Temperature != nil {
|
||||||
|
|||||||
+4
-29
@@ -3,7 +3,6 @@ package effects
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"git.aiterp.net/lucifer3/server/device"
|
"git.aiterp.net/lucifer3/server/device"
|
||||||
"math"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -14,41 +13,17 @@ type Gradient struct {
|
|||||||
Interpolate bool `json:"interpolate,omitempty"`
|
Interpolate bool `json:"interpolate,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Gradient) State(index, length, round, _ int) device.State {
|
func (e Gradient) State(index, length, round int) device.State {
|
||||||
if len(e.States) == 0 {
|
if len(e.States) == 0 {
|
||||||
return device.State{}
|
return device.State{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if e.Reverse {
|
if e.Reverse {
|
||||||
index = length - (index + 1)
|
round = -round
|
||||||
}
|
}
|
||||||
|
walkedIndex := ((length + index) - round) % length
|
||||||
|
|
||||||
walkedIndex := (index + round) % length
|
return gradientState(e.States, e.Interpolate, walkedIndex, length)
|
||||||
indexFactor := math.Min(float64(walkedIndex)/float64(length-1), 1)
|
|
||||||
stateIncrement := 1.0 / float64(len(e.States)-1)
|
|
||||||
|
|
||||||
for i := range e.States {
|
|
||||||
a := float64(i) * stateIncrement
|
|
||||||
if indexFactor >= a {
|
|
||||||
si := e.States[i]
|
|
||||||
sj := e.States[(i+1)%len(e.States)]
|
|
||||||
f := (indexFactor - a) / stateIncrement
|
|
||||||
|
|
||||||
if f < 0 || f > 1 {
|
|
||||||
panic(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.Interpolate {
|
|
||||||
return si.Interpolate(sj, f)
|
|
||||||
} else if f < 0.5 {
|
|
||||||
return si
|
|
||||||
} else {
|
|
||||||
return sj
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return e.States[len(e.States)-1]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Gradient) Frequency() time.Duration {
|
func (e Gradient) Frequency() time.Duration {
|
||||||
|
|||||||
+2
-2
@@ -15,14 +15,14 @@ type Manual struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e Manual) EffectDescription() string {
|
func (e Manual) EffectDescription() string {
|
||||||
return fmt.Sprintf("Manual%s", e.State(0, 0, 0, 0).String())
|
return fmt.Sprintf("Manual%s", e.State(0, 0, 0).String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Manual) Frequency() time.Duration {
|
func (e Manual) Frequency() time.Duration {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Manual) State(int, int, int, int) device.State {
|
func (e Manual) State(int, int, int) device.State {
|
||||||
return device.State{
|
return device.State{
|
||||||
Power: e.Power,
|
Power: e.Power,
|
||||||
Temperature: e.Temperature,
|
Temperature: e.Temperature,
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ type Pattern struct {
|
|||||||
AnimationMS int64 `json:"animationMs,omitempty"`
|
AnimationMS int64 `json:"animationMs,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Pattern) State(index, _, round, _ int) device.State {
|
func (e Pattern) State(index, _, round int) device.State {
|
||||||
if len(e.States) == 0 {
|
if len(e.States) == 0 {
|
||||||
return device.State{}
|
return device.State{}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-26
@@ -13,36 +13,12 @@ type Random struct {
|
|||||||
AnimationMS int64 `json:"animationMs,omitempty"`
|
AnimationMS int64 `json:"animationMs,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Random) State(_, _, _, _ int) device.State {
|
func (e Random) State(_, _, _ int) device.State {
|
||||||
if len(e.States) == 0 {
|
if len(e.States) == 0 {
|
||||||
return device.State{}
|
return device.State{}
|
||||||
}
|
}
|
||||||
|
|
||||||
indexFactor := rand.Float64()
|
return gradientStateFactor(e.States, e.Interpolate, rand.Float64())
|
||||||
stateIncrement := 1.0 / float64(len(e.States)-1)
|
|
||||||
|
|
||||||
for i := range e.States {
|
|
||||||
a := float64(i) * stateIncrement
|
|
||||||
if indexFactor >= a {
|
|
||||||
si := e.States[i]
|
|
||||||
sj := e.States[(i+1)%len(e.States)]
|
|
||||||
f := (indexFactor - a) / stateIncrement
|
|
||||||
|
|
||||||
if f < 0 || f > 1 {
|
|
||||||
panic(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.Interpolate {
|
|
||||||
return si.Interpolate(sj, f)
|
|
||||||
} else if f < 0.5 {
|
|
||||||
return si
|
|
||||||
} else {
|
|
||||||
return sj
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return e.States[len(e.States)-1]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Random) Frequency() time.Duration {
|
func (e Random) Frequency() time.Duration {
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package effects
|
package effects
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"git.aiterp.net/lucifer3/server/device"
|
"git.aiterp.net/lucifer3/server/device"
|
||||||
|
"math"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -21,3 +23,41 @@ func statesDescription(states []device.State) string {
|
|||||||
|
|
||||||
return sb.String()
|
return sb.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func gradientState(states []device.State, interpolate bool, index, length int) device.State {
|
||||||
|
indexFactor := math.Min(float64(index)/float64(length-1), 1)
|
||||||
|
|
||||||
|
return gradientStateFactor(states, interpolate, indexFactor)
|
||||||
|
}
|
||||||
|
|
||||||
|
func gradientStateFactor(states []device.State, interpolate bool, factor float64) device.State {
|
||||||
|
var stateIncrement float64
|
||||||
|
if interpolate {
|
||||||
|
stateIncrement = 1.0 / float64(len(states)-1)
|
||||||
|
} else {
|
||||||
|
stateIncrement = 1.0 / float64(len(states))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range states {
|
||||||
|
a := float64(i) * stateIncrement
|
||||||
|
b := float64(i+1) * stateIncrement
|
||||||
|
|
||||||
|
if factor >= a && factor < b {
|
||||||
|
si := states[i]
|
||||||
|
if !interpolate || i+1 == len(states) {
|
||||||
|
return si
|
||||||
|
}
|
||||||
|
sj := states[i+1]
|
||||||
|
|
||||||
|
f := (factor - a) / stateIncrement
|
||||||
|
|
||||||
|
if f < 0 || f > 1 {
|
||||||
|
panic(fmt.Sprintf("assert(0 <= f <= 1) f = %.2f (if = %.2f, a = %.2f, si = %.2f)", f, factor, a, stateIncrement))
|
||||||
|
}
|
||||||
|
|
||||||
|
return si.Interpolate(sj, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return states[len(states)-1]
|
||||||
|
}
|
||||||
|
|||||||
+1
-2
@@ -10,8 +10,7 @@ type Effect interface {
|
|||||||
// index: The position of this ID;
|
// index: The position of this ID;
|
||||||
// len: The total length of the effect's IDs;
|
// len: The total length of the effect's IDs;
|
||||||
// round: Increases by one for each run of the effect if Frequency > 0;
|
// round: Increases by one for each run of the effect if Frequency > 0;
|
||||||
// random: A random positive int in the full 31-bit range.
|
State(index, len, round int) device.State
|
||||||
State(index, len, round, random int) device.State
|
|
||||||
Frequency() time.Duration
|
Frequency() time.Duration
|
||||||
EffectDescription() string
|
EffectDescription() string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
lucifer3 "git.aiterp.net/lucifer3/server"
|
lucifer3 "git.aiterp.net/lucifer3/server"
|
||||||
"git.aiterp.net/lucifer3/server/commands"
|
"git.aiterp.net/lucifer3/server/commands"
|
||||||
"git.aiterp.net/lucifer3/server/device"
|
"git.aiterp.net/lucifer3/server/device"
|
||||||
"math/rand"
|
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
@@ -58,7 +57,7 @@ func (s *effectEnforcer) HandleCommand(bus *lucifer3.EventBus, command lucifer3.
|
|||||||
}
|
}
|
||||||
s.list = append(s.list, newRun)
|
s.list = append(s.list, newRun)
|
||||||
|
|
||||||
// Remove the ids from any old run.
|
// Switch over the indices.
|
||||||
for _, id := range allowedIDs {
|
for _, id := range allowedIDs {
|
||||||
if oldRun := s.index[id]; oldRun != nil {
|
if oldRun := s.index[id]; oldRun != nil {
|
||||||
oldRun.remove(id)
|
oldRun.remove(id)
|
||||||
@@ -75,11 +74,12 @@ func (s *effectEnforcer) HandleCommand(bus *lucifer3.EventBus, command lucifer3.
|
|||||||
|
|
||||||
func (s *effectEnforcer) runLoop(bus *lucifer3.EventBus) {
|
func (s *effectEnforcer) runLoop(bus *lucifer3.EventBus) {
|
||||||
deleteList := make([]int, 0, 8)
|
deleteList := make([]int, 0, 8)
|
||||||
commandQueue := make([]commands.SetState, 0, 32)
|
batch := make(commands.SetStateBatch, 64)
|
||||||
|
|
||||||
for now := range time.NewTicker(time.Millisecond * 100).C {
|
for now := range time.NewTicker(time.Millisecond * 100).C {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
for i, run := range s.list {
|
for i, run := range s.list {
|
||||||
|
|
||||||
if run.dead {
|
if run.dead {
|
||||||
deleteList = append(deleteList, i-len(deleteList))
|
deleteList = append(deleteList, i-len(deleteList))
|
||||||
continue
|
continue
|
||||||
@@ -88,17 +88,13 @@ func (s *effectEnforcer) runLoop(bus *lucifer3.EventBus) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
r := rand.Int()
|
|
||||||
for j, id := range run.ids {
|
for j, id := range run.ids {
|
||||||
if id == "" {
|
if id == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
state := run.effect.State(j, len(run.ids), run.round, r)
|
state := run.effect.State(j, len(run.ids), run.round)
|
||||||
commandQueue = append(commandQueue, commands.SetState{
|
batch[id] = state
|
||||||
ID: id,
|
|
||||||
State: state,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if freq := run.effect.Frequency(); freq > 0 {
|
if freq := run.effect.Frequency(); freq > 0 {
|
||||||
@@ -123,12 +119,9 @@ func (s *effectEnforcer) runLoop(bus *lucifer3.EventBus) {
|
|||||||
}
|
}
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
|
|
||||||
if len(commandQueue) > 0 {
|
if len(batch) > 0 {
|
||||||
for _, command := range commandQueue {
|
bus.RunCommand(batch)
|
||||||
bus.RunCommand(command)
|
batch = make(commands.SetStateBatch, 64)
|
||||||
}
|
|
||||||
|
|
||||||
commandQueue = commandQueue[:0]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-32
@@ -8,6 +8,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
lucifer3 "git.aiterp.net/lucifer3/server"
|
lucifer3 "git.aiterp.net/lucifer3/server"
|
||||||
|
"git.aiterp.net/lucifer3/server/commands"
|
||||||
"git.aiterp.net/lucifer3/server/device"
|
"git.aiterp.net/lucifer3/server/device"
|
||||||
"git.aiterp.net/lucifer3/server/events"
|
"git.aiterp.net/lucifer3/server/events"
|
||||||
"git.aiterp.net/lucifer3/server/internal/color"
|
"git.aiterp.net/lucifer3/server/internal/color"
|
||||||
@@ -168,45 +169,28 @@ func (b *bridge) URL(resource ...string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *bridge) Update(id string, change device.State) {
|
func (b *bridge) Update(id string, change device.State) {
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
transitionTime := time.Now().Add(time.Millisecond * 255)
|
transitionTime := time.Now().Add(time.Millisecond * 255)
|
||||||
|
|
||||||
|
b.mu.Lock()
|
||||||
for _, panel := range b.panels {
|
for _, panel := range b.panels {
|
||||||
if panel.FullID == id {
|
if panel.FullID == id {
|
||||||
if change.Intensity != nil {
|
panel.apply(change, transitionTime)
|
||||||
panel.Intensity = *change.Intensity
|
|
||||||
}
|
|
||||||
|
|
||||||
if change.Color != nil {
|
|
||||||
rgbColor, ok := change.Color.ToRGB()
|
|
||||||
if !ok {
|
|
||||||
newColor := [4]byte{255, 255, 255, 255}
|
|
||||||
if newColor != panel.ColorRGBA {
|
|
||||||
panel.update(newColor, transitionTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
rgb := rgbColor.RGB.AtIntensity(panel.Intensity)
|
|
||||||
red := byte(rgb.Red * 255.0001)
|
|
||||||
green := byte(rgb.Green * 255.0001)
|
|
||||||
blue := byte(rgb.Blue * 255.0001)
|
|
||||||
newColor := [4]byte{red, green, blue, 255}
|
|
||||||
if newColor != panel.ColorRGBA {
|
|
||||||
panel.update(newColor, time.Now().Add(time.Millisecond*220))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if change.Power != nil {
|
|
||||||
panel.On = *change.Power
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
b.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *bridge) UpdateBatch(batch commands.SetStateBatch) {
|
||||||
|
transitionTime := time.Now().Add(time.Millisecond * 255)
|
||||||
|
|
||||||
|
b.mu.Lock()
|
||||||
|
for _, panel := range b.panels {
|
||||||
|
if change, ok := batch[panel.FullID]; ok {
|
||||||
|
panel.apply(change, transitionTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bridge) Run(ctx context.Context, bus *lucifer3.EventBus) error {
|
func (b *bridge) Run(ctx context.Context, bus *lucifer3.EventBus) error {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package nanoleaf
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"git.aiterp.net/lucifer3/server/device"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -208,6 +209,42 @@ func (p *panel) update(colorRGBA [4]byte, transitionAt time.Time) {
|
|||||||
p.TransitionAt = transitionAt
|
p.TransitionAt = transitionAt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *panel) apply(change device.State, transitionTime time.Time) {
|
||||||
|
if change.Power != nil {
|
||||||
|
p.On = *change.Power
|
||||||
|
}
|
||||||
|
|
||||||
|
if change.Intensity != nil {
|
||||||
|
p.Intensity = *change.Intensity
|
||||||
|
}
|
||||||
|
|
||||||
|
if change.Color != nil {
|
||||||
|
if !p.On {
|
||||||
|
newColor := [4]byte{0, 0, 0, 0}
|
||||||
|
if newColor != p.ColorRGBA {
|
||||||
|
p.update(newColor, transitionTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rgbColor, ok := change.Color.ToRGB()
|
||||||
|
if !ok {
|
||||||
|
newColor := [4]byte{255, 255, 255, 255}
|
||||||
|
if newColor != p.ColorRGBA {
|
||||||
|
p.update(newColor, transitionTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rgb := rgbColor.RGB.AtIntensity(p.Intensity)
|
||||||
|
red := byte(rgb.Red * 255.0001)
|
||||||
|
green := byte(rgb.Green * 255.0001)
|
||||||
|
blue := byte(rgb.Blue * 255.0001)
|
||||||
|
newColor := [4]byte{red, green, blue, 255}
|
||||||
|
if newColor != p.ColorRGBA {
|
||||||
|
p.update(newColor, transitionTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type panelUpdate []byte
|
type panelUpdate []byte
|
||||||
|
|
||||||
func (u *panelUpdate) Add(message [8]byte) {
|
func (u *panelUpdate) Add(message [8]byte) {
|
||||||
|
|||||||
@@ -35,6 +35,11 @@ func (s *service) HandleCommand(bus *lucifer3.EventBus, command lucifer3.Command
|
|||||||
s.bridges[sub].Update(command.ID, command.State)
|
s.bridges[sub].Update(command.ID, command.State)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case commands.SetStateBatch:
|
||||||
|
for _, b := range s.bridges {
|
||||||
|
b.UpdateBatch(command)
|
||||||
|
}
|
||||||
|
|
||||||
case commands.SearchDevices:
|
case commands.SearchDevices:
|
||||||
if sub, ok := command.Matches("nanoleaf"); ok {
|
if sub, ok := command.Matches("nanoleaf"); ok {
|
||||||
if s.bridges[sub] != nil {
|
if s.bridges[sub] != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user