some more stuffs.
This commit is contained in:
+50
-58
@@ -443,68 +443,60 @@ func (b *Bridge) makeCongruentLoop(ctx context.Context) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Handle power first
|
||||
if desired.Power != nil && active.Power != nil && *desired.Power != *active.Power {
|
||||
updates["light/"+*lightID] = ResourceUpdate{
|
||||
Power: gentools.Ptr(*desired.Power),
|
||||
TransitionDuration: gentools.Ptr(time.Millisecond * 101),
|
||||
}
|
||||
|
||||
newActiveState := activeStates[id]
|
||||
newActiveState.Power = gentools.Ptr(*desired.Power)
|
||||
|
||||
continue
|
||||
}
|
||||
if active.Power != nil && !*active.Power {
|
||||
// Don't do more with shut-off-light.
|
||||
continue
|
||||
}
|
||||
|
||||
updated := false
|
||||
update := ResourceUpdate{}
|
||||
|
||||
if active.Color != nil && desired.Color != nil {
|
||||
ac := *active.Color
|
||||
dc := *desired.Color
|
||||
|
||||
if !dc.IsKelvin() || !colorFlags[id].IsWarmWhite() {
|
||||
dc, _ = dc.ToXY()
|
||||
dc.XY = gentools.Ptr(light.Color.Gamut.Conform(*dc.XY))
|
||||
}
|
||||
|
||||
if dc.XY != nil {
|
||||
if ac.K != nil {
|
||||
ac.K = gentools.Ptr(1000000 / (1000000 / *ac.K))
|
||||
}
|
||||
|
||||
acXY, _ := ac.ToXY()
|
||||
dist := dc.XY.DistanceTo(*acXY.XY)
|
||||
if dist > 0.0002 {
|
||||
update.ColorXY = gentools.Ptr(*dc.XY)
|
||||
updated = true
|
||||
}
|
||||
} else {
|
||||
dcMirek := 1000000 / *dc.K
|
||||
if dcMirek < light.ColorTemperature.MirekSchema.MirekMinimum {
|
||||
dcMirek = light.ColorTemperature.MirekSchema.MirekMinimum
|
||||
} else if dcMirek > light.ColorTemperature.MirekSchema.MirekMaximum {
|
||||
dcMirek = light.ColorTemperature.MirekSchema.MirekMaximum
|
||||
}
|
||||
acMirek := 0
|
||||
if ac.K != nil {
|
||||
acMirek = 1000000 / *ac.K
|
||||
}
|
||||
if acMirek != dcMirek {
|
||||
update.Mirek = &dcMirek
|
||||
updated = true
|
||||
}
|
||||
}
|
||||
// Handle power first
|
||||
if desired.Power != nil && active.Power != nil && *desired.Power != *active.Power {
|
||||
update.Power = gentools.Ptr(*desired.Power)
|
||||
updated = true
|
||||
}
|
||||
|
||||
if active.Intensity != nil && desired.Intensity != nil {
|
||||
if math.Abs(*active.Intensity-*desired.Intensity) >= 0.01 {
|
||||
update.Brightness = gentools.Ptr(*desired.Intensity * 100)
|
||||
updated = true
|
||||
// Only do the rest if there's power.
|
||||
if desired.Power == nil || *desired.Power {
|
||||
if active.Color != nil && desired.Color != nil {
|
||||
ac := *active.Color
|
||||
dc := *desired.Color
|
||||
|
||||
if !dc.IsKelvin() || !colorFlags[id].IsWarmWhite() {
|
||||
dc, _ = dc.ToXY()
|
||||
dc.XY = gentools.Ptr(light.Color.Gamut.Conform(*dc.XY))
|
||||
}
|
||||
|
||||
if dc.XY != nil {
|
||||
if ac.K != nil {
|
||||
ac.K = gentools.Ptr(1000000 / (1000000 / *ac.K))
|
||||
}
|
||||
|
||||
acXY, _ := ac.ToXY()
|
||||
dist := dc.XY.DistanceTo(*acXY.XY)
|
||||
if dist > 0.0002 {
|
||||
update.ColorXY = gentools.Ptr(*dc.XY)
|
||||
updated = true
|
||||
}
|
||||
} else {
|
||||
dcMirek := 1000000 / *dc.K
|
||||
if dcMirek < light.ColorTemperature.MirekSchema.MirekMinimum {
|
||||
dcMirek = light.ColorTemperature.MirekSchema.MirekMinimum
|
||||
} else if dcMirek > light.ColorTemperature.MirekSchema.MirekMaximum {
|
||||
dcMirek = light.ColorTemperature.MirekSchema.MirekMaximum
|
||||
}
|
||||
acMirek := 0
|
||||
if ac.K != nil {
|
||||
acMirek = 1000000 / *ac.K
|
||||
}
|
||||
if acMirek != dcMirek {
|
||||
update.Mirek = &dcMirek
|
||||
updated = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if active.Intensity != nil && desired.Intensity != nil {
|
||||
if math.Abs(*active.Intensity-*desired.Intensity) >= 0.01 {
|
||||
update.Brightness = gentools.Ptr(*desired.Intensity * 100)
|
||||
updated = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -515,7 +507,7 @@ func (b *Bridge) makeCongruentLoop(ctx context.Context) {
|
||||
}
|
||||
|
||||
if len(updates) > 0 {
|
||||
timeout, cancel := context.WithTimeout(ctx, time.Second)
|
||||
timeout, cancel := context.WithTimeout(ctx, time.Millisecond*500*time.Duration(len(updates)))
|
||||
|
||||
eg, ctx := errgroup.WithContext(timeout)
|
||||
for key := range updates {
|
||||
|
||||
@@ -210,8 +210,10 @@ func (res *ResourceData) GenerateEvent(hostname string, resources map[string]*Re
|
||||
hwMeta.Icon = "hue_lightbulb_e14"
|
||||
case "sultan_bulb":
|
||||
hwMeta.Icon = "hue_lightbulb_e27"
|
||||
case "hue_signe":
|
||||
hwMeta.Icon = "hue_signe"
|
||||
case "hue_play":
|
||||
hwMeta.Icon = "hue_playbar"
|
||||
case "hue_signe", "hue_go":
|
||||
hwMeta.Icon = res.ProductData.ProductArchetype
|
||||
case "unknown_archetype":
|
||||
switch res.ProductData.ProductName {
|
||||
case "Hue motion sensor":
|
||||
|
||||
+13
-10
@@ -3,6 +3,7 @@ package nanoleaf
|
||||
import (
|
||||
"encoding/binary"
|
||||
"git.aiterp.net/lucifer3/server/device"
|
||||
"git.aiterp.net/lucifer3/server/internal/color"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -141,13 +142,13 @@ var shapeTypeMap = map[int]string{
|
||||
|
||||
var shapeIconMap = map[int]string{
|
||||
0: "triangle",
|
||||
1: "rhythm",
|
||||
2: "Square",
|
||||
1: "triangle",
|
||||
2: "square",
|
||||
3: "square",
|
||||
4: "square",
|
||||
7: "hexagon",
|
||||
8: "triangle",
|
||||
9: "triangle-small",
|
||||
9: "triangle",
|
||||
12: "hexagon",
|
||||
}
|
||||
|
||||
@@ -218,14 +219,16 @@ func (p *panel) apply(change device.State, transitionTime time.Time) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
if change.Color == nil {
|
||||
change.Color = &color.Color{RGB: &color.RGB{Red: 255, Green: 255, Blue: 255}}
|
||||
}
|
||||
|
||||
if !p.On {
|
||||
newColor := [4]byte{0, 0, 0, 0}
|
||||
if newColor != p.ColorRGBA {
|
||||
p.update(newColor, transitionTime)
|
||||
}
|
||||
} else {
|
||||
rgbColor, ok := change.Color.ToRGB()
|
||||
if !ok {
|
||||
newColor := [4]byte{255, 255, 255, 255}
|
||||
|
||||
@@ -13,6 +13,7 @@ type Line struct {
|
||||
If *LineIf `json:"if,omitempty"`
|
||||
Assign *LineAssign `json:"assign,omitempty"`
|
||||
Set *LineSet `json:"set,omitempty"`
|
||||
Select *LineSelect `json:"select,omitempty"`
|
||||
}
|
||||
|
||||
type LineSet struct {
|
||||
@@ -31,3 +32,8 @@ type LineIf struct {
|
||||
Then []Line `json:"then,omitempty"`
|
||||
Else []Line `json:"else,omitempty"`
|
||||
}
|
||||
|
||||
type LineSelect struct {
|
||||
Match string `json:"match"`
|
||||
Then []Line `json:"then"`
|
||||
}
|
||||
|
||||
+38
-24
@@ -1,6 +1,7 @@
|
||||
package script
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
lucifer3 "git.aiterp.net/lucifer3/server"
|
||||
"git.aiterp.net/lucifer3/server/commands"
|
||||
"git.aiterp.net/lucifer3/server/device"
|
||||
@@ -37,7 +38,9 @@ func (s *service) HandleEvent(bus *lucifer3.EventBus, event lucifer3.Event) {
|
||||
return devices[i].ID < devices[j].ID
|
||||
})
|
||||
|
||||
s.runScript(bus, script.Lines, trig.ScriptTarget, map[string]bool{}, devices, variables)
|
||||
fmt.Println("[TRIGGER] Running", trig.ID, "for", len(devices), "devices:", event.EventDescription())
|
||||
|
||||
s.runScript(bus, lines, trig.ScriptTarget, map[string]bool{}, devices, variables)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,7 +100,7 @@ func (s *service) runScript(bus *lucifer3.EventBus, lines []Line, match string,
|
||||
continue
|
||||
}
|
||||
|
||||
if dev.Matches(matcher) {
|
||||
if line.Assign.Match == "*" || dev.Matches(matcher) {
|
||||
matchedDevices[dev.ID] = true
|
||||
matched = append(matched, dev.ID)
|
||||
}
|
||||
@@ -109,30 +112,41 @@ func (s *service) runScript(bus *lucifer3.EventBus, lines []Line, match string,
|
||||
Effect: line.Assign.Effect.Effect,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if line.Set != nil {
|
||||
switch line.Set.Scope {
|
||||
case "devices":
|
||||
bus.RunCommand(SetVariable{
|
||||
Devices: gentools.Map(devices, func(d device.Pointer) string {
|
||||
return d.ID
|
||||
}),
|
||||
Key: line.Set.Key,
|
||||
Value: line.Set.Value,
|
||||
})
|
||||
case "match":
|
||||
bus.RunCommand(SetVariable{
|
||||
Match: gentools.Ptr(match),
|
||||
Key: line.Set.Key,
|
||||
Value: line.Set.Value,
|
||||
})
|
||||
case "global":
|
||||
bus.RunCommand(SetVariable{
|
||||
Key: line.Set.Key,
|
||||
Value: line.Set.Value,
|
||||
})
|
||||
} else if line.Set != nil {
|
||||
switch line.Set.Scope {
|
||||
case "devices":
|
||||
bus.RunCommand(SetVariable{
|
||||
Devices: gentools.Map(devices, func(d device.Pointer) string {
|
||||
return d.ID
|
||||
}),
|
||||
Key: line.Set.Key,
|
||||
Value: line.Set.Value,
|
||||
})
|
||||
case "match":
|
||||
bus.RunCommand(SetVariable{
|
||||
Match: gentools.Ptr(match),
|
||||
Key: line.Set.Key,
|
||||
Value: line.Set.Value,
|
||||
})
|
||||
case "global":
|
||||
bus.RunCommand(SetVariable{
|
||||
Key: line.Set.Key,
|
||||
Value: line.Set.Value,
|
||||
})
|
||||
}
|
||||
} else if line.Select != nil {
|
||||
matcher := s.resolver.CompileMatcher(line.Select.Match)
|
||||
|
||||
matched := make([]device.Pointer, 0)
|
||||
for _, dev := range devices {
|
||||
if dev.Matches(matcher) {
|
||||
matched = append(matched, dev)
|
||||
}
|
||||
}
|
||||
|
||||
if len(matched) > 0 {
|
||||
s.runScript(bus, line.Select.Then, match, matchedDevices, matched, variables)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,10 +60,12 @@ func (s *service) HandleCommand(bus *lucifer3.EventBus, command lucifer3.Command
|
||||
})
|
||||
}
|
||||
case commands.SearchDevices:
|
||||
bus.RunEvent(events.DeviceFailed{
|
||||
ID: command.ID,
|
||||
Error: "Please follow instructions in IKEA app; they will appear here after pairing.",
|
||||
})
|
||||
if _, ok := command.Matches("tradfri"); ok {
|
||||
bus.RunEvent(events.DeviceFailed{
|
||||
ID: command.ID,
|
||||
Error: "Please follow instructions in IKEA app; they will appear here after pairing.",
|
||||
})
|
||||
}
|
||||
case commands.SetState:
|
||||
if _, ok := command.Matches("tradfri"); ok {
|
||||
bridge, ok := s.findBridge(command.ID)
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"git.aiterp.net/lucifer3/server/internal/gentools"
|
||||
"git.aiterp.net/lucifer3/server/services/script"
|
||||
"github.com/google/uuid"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Data struct {
|
||||
@@ -22,7 +23,6 @@ func (d *Data) WithPatch(patches ...Patch) Data {
|
||||
if patch.Device != nil {
|
||||
pd := d.ensureDevice(patch.Device.ID)
|
||||
|
||||
gentools.ApplyUpdateSlice(&pd.Aliases, patch.Device.SetAliases)
|
||||
gentools.ApplyUpdate(&pd.Name, patch.Device.Name)
|
||||
gentools.ApplyUpdatePtr(&pd.HWState, patch.Device.HWState)
|
||||
gentools.ApplyUpdatePtr(&pd.HWMetadata, patch.Device.HWMetadata)
|
||||
@@ -32,18 +32,31 @@ func (d *Data) WithPatch(patches ...Patch) Data {
|
||||
gentools.ApplyUpdatePtr(&pd.DesiredColorRGB, patch.Device.DesiredColorRGB)
|
||||
|
||||
if patch.Device.AddAlias != nil {
|
||||
pd.Aliases = append(pd.Aliases[:0:0], pd.Aliases...)
|
||||
pd.Aliases = append(pd.Aliases, *patch.Device.AddAlias)
|
||||
ptr := device.Pointer{ID: "dummy", Aliases: pd.Aliases}
|
||||
ptr.AddAlias(*patch.Device.AddAlias)
|
||||
|
||||
if strings.HasPrefix(*patch.Device.AddAlias, "lucifer:name:") {
|
||||
pd.Name = (*patch.Device.AddAlias)[len("lucifer:name:"):]
|
||||
}
|
||||
if strings.HasPrefix(*patch.Device.AddAlias, "lucifer:icon:") {
|
||||
pd.Icon = (*patch.Device.AddAlias)[len("lucifer:icon:"):]
|
||||
}
|
||||
|
||||
pd.Aliases = ptr.Aliases
|
||||
}
|
||||
if patch.Device.RemoveAlias != nil {
|
||||
for i, alias := range pd.Aliases {
|
||||
if alias == *patch.Device.RemoveAlias {
|
||||
pd.Aliases = append(pd.Aliases[:0:0], pd.Aliases...)
|
||||
pd.Aliases = append(pd.Aliases[:i], pd.Aliases[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if patch.Device.HWMetadata != nil {
|
||||
if pd.Icon == "" {
|
||||
pd.Icon = patch.Device.HWMetadata.Icon
|
||||
}
|
||||
}
|
||||
if patch.Device.ClearAssignment {
|
||||
pd.Assignment = nil
|
||||
}
|
||||
@@ -136,6 +149,7 @@ type Device struct {
|
||||
Aliases []string `json:"aliases"`
|
||||
Assignment *uuid.UUID `json:"assignment"`
|
||||
Sensors DeviceSensors `json:"sensors"`
|
||||
Icon string `json:"icon"`
|
||||
}
|
||||
|
||||
type DeviceSensors struct {
|
||||
|
||||
@@ -32,9 +32,9 @@ func (e Patch) EventDescription() string {
|
||||
case e.Device.HWMetadata != nil:
|
||||
return fmt.Sprintf("uistate.Patch(device=%s, hwMetadata)", e.Device.ID)
|
||||
case e.Device.AddAlias != nil:
|
||||
return fmt.Sprintf("uistate.Patch(device=%s, addAlias=%s)", e.Device.ID, *e.Device.AddAlias)
|
||||
return fmt.Sprintf("uistate.Patch(device=%s, addAlias)", e.Device.ID)
|
||||
case e.Device.RemoveAlias != nil:
|
||||
return fmt.Sprintf("uistate.Patch(device=%s, removeAlias=%s)", e.Device.ID, *e.Device.RemoveAlias)
|
||||
return fmt.Sprintf("uistate.Patch(device=%s, removeAlias)", e.Device.ID)
|
||||
case e.Device.ActiveColorRGB != nil:
|
||||
col := color.Color{RGB: e.Device.ActiveColorRGB}
|
||||
return fmt.Sprintf("uistate.Patch(device=%s, activeColorRgb=%s)", e.Device.ID, col.String())
|
||||
@@ -59,7 +59,6 @@ type DevicePatch struct {
|
||||
HWMetadata *events.HardwareMetadata `json:"hwMetadata,omitempty"`
|
||||
HWState *events.HardwareState `json:"hwState,omitempty"`
|
||||
DesiredState *device.State `json:"desiredState,omitempty"`
|
||||
SetAliases []string `json:"setAliases,omitempty"`
|
||||
AddAlias *string `json:"addAlias,omitempty"`
|
||||
RemoveAlias *string `json:"removeAlias,omitempty"`
|
||||
Assignment *uuid.UUID `json:"assignment,omitempty"`
|
||||
|
||||
Reference in New Issue
Block a user