moar stuff.
This commit is contained in:
@@ -21,6 +21,7 @@ func NewService(resolver device.Resolver) lucifer3.ActiveService {
|
||||
|
||||
supportFlags: make(map[string]device.SupportFlags),
|
||||
colorFlags: make(map[string]device.ColorFlags),
|
||||
ctRanges: make(map[string]*[2]int),
|
||||
temperatures: make(map[string]float64),
|
||||
motions: make(map[string]float64),
|
||||
}
|
||||
@@ -39,8 +40,9 @@ type effectEnforcer struct {
|
||||
|
||||
started uint32
|
||||
|
||||
list []*effectEnforcerRun
|
||||
index map[string]*effectEnforcerRun
|
||||
list []*effectEnforcerRun
|
||||
index map[string]*effectEnforcerRun
|
||||
ctRanges map[string]*[2]int
|
||||
}
|
||||
|
||||
func (s *effectEnforcer) Active() bool {
|
||||
@@ -53,6 +55,7 @@ func (s *effectEnforcer) HandleEvent(bus *lucifer3.EventBus, event lucifer3.Even
|
||||
s.mu.Lock()
|
||||
colorFlags := s.colorFlags
|
||||
supportFlags := s.supportFlags
|
||||
ctRanges := s.ctRanges
|
||||
s.mu.Unlock()
|
||||
|
||||
colorFlags = gentools.CopyMap(colorFlags)
|
||||
@@ -60,9 +63,15 @@ func (s *effectEnforcer) HandleEvent(bus *lucifer3.EventBus, event lucifer3.Even
|
||||
colorFlags[event.ID] = event.ColorFlags
|
||||
supportFlags[event.ID] = event.SupportFlags
|
||||
|
||||
if event.ColorKelvinRange != nil {
|
||||
ctRanges = gentools.CopyMap(ctRanges)
|
||||
ctRanges[event.ID] = event.ColorKelvinRange
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
s.colorFlags = colorFlags
|
||||
s.supportFlags = supportFlags
|
||||
s.ctRanges = ctRanges
|
||||
s.mu.Unlock()
|
||||
|
||||
case events.DeviceReady:
|
||||
@@ -237,6 +246,7 @@ func (s *effectEnforcer) runLoop(bus *lucifer3.EventBus) {
|
||||
s.mu.Lock()
|
||||
colorFlags := s.colorFlags
|
||||
supportFlags := s.supportFlags
|
||||
ctRanges := s.ctRanges
|
||||
|
||||
for i, run := range s.list {
|
||||
if run.dead {
|
||||
@@ -307,11 +317,18 @@ func (s *effectEnforcer) runLoop(bus *lucifer3.EventBus) {
|
||||
state.Color = nil
|
||||
} else if state.Color != nil {
|
||||
cf := colorFlags[id]
|
||||
|
||||
invalid := (state.Color.K != nil && !cf.HasAll(device.CFlagKelvin)) ||
|
||||
(state.Color.XY != nil && !cf.HasAll(device.CFlagXY)) ||
|
||||
(state.Color.RGB != nil && !cf.HasAll(device.CFlagRGB)) ||
|
||||
(state.Color.HS != nil && !cf.HasAll(device.CFlagHS))
|
||||
|
||||
if state.Color.K != nil && cf.IsColor() && ctRanges[id] != nil {
|
||||
if *state.Color.K < ctRanges[id][0] || *state.Color.K >= ctRanges[id][1] {
|
||||
invalid = true
|
||||
}
|
||||
}
|
||||
|
||||
if invalid {
|
||||
var converted color.Color
|
||||
var ok bool
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"git.aiterp.net/lucifer3/server/commands"
|
||||
"git.aiterp.net/lucifer3/server/effects"
|
||||
"git.aiterp.net/lucifer3/server/events"
|
||||
"git.aiterp.net/lucifer3/server/internal/color"
|
||||
"git.aiterp.net/lucifer3/server/services/script"
|
||||
"git.aiterp.net/lucifer3/server/services/uistate"
|
||||
"github.com/google/uuid"
|
||||
@@ -38,6 +39,24 @@ func New(addr string) (lucifer3.Service, error) {
|
||||
e.HidePort = true
|
||||
e.Use(middleware.CORS())
|
||||
|
||||
e.GET("/color/:value", func(c echo.Context) error {
|
||||
col, err := color.Parse(c.Param("value"))
|
||||
if err != nil {
|
||||
return c.String(400, err.Error())
|
||||
}
|
||||
|
||||
rgb, _ := col.ToRGB()
|
||||
xy, _ := col.ToXY()
|
||||
hs, _ := col.ToHS()
|
||||
|
||||
return c.JSON(200, color.Color{
|
||||
K: col.K,
|
||||
RGB: rgb.RGB,
|
||||
HS: hs.HS,
|
||||
XY: xy.XY,
|
||||
})
|
||||
})
|
||||
|
||||
e.GET("/state", func(c echo.Context) error {
|
||||
svc.mu.Lock()
|
||||
data := svc.data
|
||||
|
||||
+34
-8
@@ -18,6 +18,7 @@ import (
|
||||
|
||||
func NewBridge(host string, client *Client) *Bridge {
|
||||
return &Bridge{
|
||||
mu: sync.Mutex{},
|
||||
client: client,
|
||||
host: host,
|
||||
ctx: context.Background(),
|
||||
@@ -26,6 +27,7 @@ func NewBridge(host string, client *Client) *Bridge {
|
||||
activeStates: map[string]device.State{},
|
||||
desiredStates: map[string]device.State{},
|
||||
colorFlags: map[string]device.ColorFlags{},
|
||||
reachable: nil,
|
||||
hasSeen: map[string]bool{},
|
||||
triggerCongruenceCheckCh: make(chan struct{}, 2),
|
||||
}
|
||||
@@ -46,6 +48,7 @@ type Bridge struct {
|
||||
reachable map[string]bool
|
||||
hasSeen map[string]bool
|
||||
lastMotion map[string]time.Time
|
||||
lastPresence map[string]bool
|
||||
lastButton map[string]time.Time
|
||||
|
||||
triggerCongruenceCheckCh chan struct{}
|
||||
@@ -115,12 +118,14 @@ func (b *Bridge) RefreshAll() ([]lucifer3.Event, error) {
|
||||
hasSeen := b.hasSeen
|
||||
reachable := b.reachable
|
||||
lastMotion := b.lastMotion
|
||||
lastPresence := b.lastPresence
|
||||
b.mu.Unlock()
|
||||
|
||||
oldHasSeen := hasSeen
|
||||
hasSeen = gentools.CopyMap(hasSeen)
|
||||
reachable = gentools.CopyMap(reachable)
|
||||
lastMotion = gentools.CopyMap(lastMotion)
|
||||
lastPresence = gentools.CopyMap(lastPresence)
|
||||
|
||||
colorFlags := make(map[string]device.ColorFlags)
|
||||
activeStates := make(map[string]device.State)
|
||||
@@ -144,13 +149,17 @@ func (b *Bridge) RefreshAll() ([]lucifer3.Event, error) {
|
||||
})
|
||||
|
||||
lastMotion[b.fullId(*res)] = time.Now()
|
||||
lastPresence[b.fullId(*res)] = true
|
||||
} else {
|
||||
extraEvents = append(extraEvents, events.MotionSensed{
|
||||
ID: b.fullId(*res),
|
||||
SecondsSince: 301,
|
||||
})
|
||||
if lastMotion[b.fullId(*res)].IsZero() {
|
||||
extraEvents = append(extraEvents, events.MotionSensed{
|
||||
ID: b.fullId(*res),
|
||||
SecondsSince: 301,
|
||||
})
|
||||
|
||||
lastMotion[b.fullId(*res)] = time.Now().Add(-time.Millisecond * 301)
|
||||
lastMotion[b.fullId(*res)] = time.Now().Add(-time.Millisecond * 301)
|
||||
}
|
||||
lastPresence[b.fullId(*res)] = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -180,6 +189,7 @@ func (b *Bridge) RefreshAll() ([]lucifer3.Event, error) {
|
||||
b.activeStates = activeStates
|
||||
b.reachable = reachable
|
||||
b.lastMotion = lastMotion
|
||||
b.lastPresence = lastPresence
|
||||
b.mu.Unlock()
|
||||
|
||||
return append(newEvents, extraEvents...), nil
|
||||
@@ -193,6 +203,7 @@ func (b *Bridge) ApplyPatches(date time.Time, resources []ResourceData) (eventLi
|
||||
colorFlags := b.colorFlags
|
||||
lastMotion := b.lastMotion
|
||||
lastButton := b.lastButton
|
||||
lastPresence := b.lastPresence
|
||||
b.mu.Unlock()
|
||||
|
||||
mapCopy := gentools.CopyMap(resourceMap)
|
||||
@@ -201,6 +212,7 @@ func (b *Bridge) ApplyPatches(date time.Time, resources []ResourceData) (eventLi
|
||||
colorFlagsCopy := gentools.CopyMap(colorFlags)
|
||||
lastMotionCopy := gentools.CopyMap(lastMotion)
|
||||
lastButtonCopy := gentools.CopyMap(lastButton)
|
||||
lastPresenceCopy := gentools.CopyMap(lastPresence)
|
||||
|
||||
for _, resource := range resources {
|
||||
if mapCopy[resource.ID] != nil {
|
||||
@@ -218,6 +230,8 @@ func (b *Bridge) ApplyPatches(date time.Time, resources []ResourceData) (eventLi
|
||||
}
|
||||
|
||||
for _, resource := range resources {
|
||||
fullID := b.fullId(resource)
|
||||
|
||||
if resource.Owner != nil && resource.Owner.Kind == "device" {
|
||||
if parent, ok := mapCopy[resource.Owner.ID]; ok && !strings.HasPrefix(parent.Metadata.Archetype, "bridge") {
|
||||
hwState, _ := parent.GenerateEvent(b.host, mapCopy)
|
||||
@@ -231,18 +245,24 @@ func (b *Bridge) ApplyPatches(date time.Time, resources []ResourceData) (eventLi
|
||||
|
||||
if resource.Temperature != nil {
|
||||
eventList = append(eventList, events.TemperatureChanged{
|
||||
ID: b.fullId(resource),
|
||||
ID: fullID,
|
||||
Temperature: resource.Temperature.Temperature,
|
||||
})
|
||||
}
|
||||
if resource.Motion != nil {
|
||||
lastMotionCopy[fullID] = time.Now()
|
||||
|
||||
if resource.Motion.Motion {
|
||||
eventList = append(eventList, events.MotionSensed{
|
||||
ID: b.fullId(resource),
|
||||
ID: fullID,
|
||||
SecondsSince: 0,
|
||||
})
|
||||
|
||||
lastMotionCopy[b.fullId(resource)] = time.Now()
|
||||
lastMotion[fullID] = time.Now()
|
||||
lastPresenceCopy[fullID] = true
|
||||
} else if lastPresenceCopy[fullID] {
|
||||
lastMotion[fullID] = time.Now()
|
||||
lastPresenceCopy[fullID] = false
|
||||
}
|
||||
}
|
||||
if resource.Button != nil {
|
||||
@@ -285,6 +305,7 @@ func (b *Bridge) ApplyPatches(date time.Time, resources []ResourceData) (eventLi
|
||||
b.colorFlags = colorFlagsCopy
|
||||
b.lastMotion = lastMotionCopy
|
||||
b.lastButton = lastButtonCopy
|
||||
b.lastPresence = lastPresenceCopy
|
||||
b.mu.Unlock()
|
||||
|
||||
return
|
||||
@@ -382,9 +403,14 @@ func (b *Bridge) Run(ctx context.Context, bus *lucifer3.EventBus) interface{} {
|
||||
case <-quickStep.C:
|
||||
b.mu.Lock()
|
||||
lastMotion := b.lastMotion
|
||||
lastPresence := b.lastPresence
|
||||
b.mu.Unlock()
|
||||
|
||||
for id, value := range lastMotion {
|
||||
if lastPresence[id] {
|
||||
continue
|
||||
}
|
||||
|
||||
since := time.Since(value)
|
||||
sinceMod := since % (time.Second * 30)
|
||||
if (since > time.Second*20) && (sinceMod >= time.Second*27 || sinceMod <= time.Second*3) {
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
ALTER TABLE script_trigger ADD COLUMN name VARCHAR(255) NOT NULL DEFAULT '';
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
ALTER TABLE script_trigger DROP COLUMN IF EXISTS name;
|
||||
-- +goose StatementEnd
|
||||
@@ -49,6 +49,7 @@ type ScriptTrigger struct {
|
||||
ScriptName string
|
||||
ScriptPre json.RawMessage
|
||||
ScriptPost json.RawMessage
|
||||
Name string
|
||||
}
|
||||
|
||||
type ScriptVariable struct {
|
||||
|
||||
@@ -22,7 +22,7 @@ func (q *Queries) DeleteScriptTrigger(ctx context.Context, id uuid.UUID) error {
|
||||
}
|
||||
|
||||
const listScriptTriggers = `-- name: ListScriptTriggers :many
|
||||
SELECT id, event, device_match, parameter, script_target, script_name, script_pre, script_post FROM script_trigger
|
||||
SELECT id, event, device_match, parameter, script_target, script_name, script_pre, script_post, name FROM script_trigger
|
||||
`
|
||||
|
||||
func (q *Queries) ListScriptTriggers(ctx context.Context) ([]ScriptTrigger, error) {
|
||||
@@ -43,6 +43,7 @@ func (q *Queries) ListScriptTriggers(ctx context.Context) ([]ScriptTrigger, erro
|
||||
&i.ScriptName,
|
||||
&i.ScriptPre,
|
||||
&i.ScriptPost,
|
||||
&i.Name,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -112,12 +113,13 @@ func (q *Queries) ListScripts(ctx context.Context) ([]Script, error) {
|
||||
}
|
||||
|
||||
const replaceScriptTrigger = `-- name: ReplaceScriptTrigger :exec
|
||||
REPLACE INTO script_trigger (id, event, device_match, parameter, script_target, script_name, script_pre, script_post)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
REPLACE INTO script_trigger (id, name, event, device_match, parameter, script_target, script_name, script_pre, script_post)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`
|
||||
|
||||
type ReplaceScriptTriggerParams struct {
|
||||
ID uuid.UUID
|
||||
Name string
|
||||
Event string
|
||||
DeviceMatch string
|
||||
Parameter string
|
||||
@@ -130,6 +132,7 @@ type ReplaceScriptTriggerParams struct {
|
||||
func (q *Queries) ReplaceScriptTrigger(ctx context.Context, arg ReplaceScriptTriggerParams) error {
|
||||
_, err := q.exec(ctx, q.replaceScriptTriggerStmt, replaceScriptTrigger,
|
||||
arg.ID,
|
||||
arg.Name,
|
||||
arg.Event,
|
||||
arg.DeviceMatch,
|
||||
arg.Parameter,
|
||||
|
||||
@@ -14,8 +14,8 @@ REPLACE INTO script_variable (scope, name, value) VALUES (?, ?, ?);
|
||||
SELECT * FROM script_trigger;
|
||||
|
||||
-- name: ReplaceScriptTrigger :exec
|
||||
REPLACE INTO script_trigger (id, event, device_match, parameter, script_target, script_name, script_pre, script_post)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?);
|
||||
REPLACE INTO script_trigger (id, name, event, device_match, parameter, script_target, script_name, script_pre, script_post)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||
|
||||
-- name: DeleteScriptTrigger :exec
|
||||
DELETE FROM script_trigger WHERE id = ?;
|
||||
@@ -34,7 +34,7 @@ func (d *database) HandleEvent(bus *lucifer3.EventBus, event lucifer3.Event) {
|
||||
|
||||
switch event := event.(type) {
|
||||
case events.Started:
|
||||
timeout, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
||||
timeout, cancel := context.WithTimeout(context.Background(), time.Second*90)
|
||||
defer cancel()
|
||||
|
||||
// Fetch all aliases first
|
||||
@@ -185,6 +185,7 @@ func (d *database) HandleEvent(bus *lucifer3.EventBus, event lucifer3.Event) {
|
||||
for _, trig := range scriptTriggers {
|
||||
bus.RunCommand(script.UpdateTrigger{
|
||||
ID: trig.ID,
|
||||
Name: trig.Name,
|
||||
Event: script.TriggerEvent(trig.Event),
|
||||
DeviceMatch: trig.DeviceMatch,
|
||||
Parameter: trig.Parameter,
|
||||
@@ -389,6 +390,7 @@ func (d *database) HandleCommand(bus *lucifer3.EventBus, command lucifer3.Comman
|
||||
ScriptName: command.ScriptName,
|
||||
ScriptPre: toJSON(command.ScriptPre),
|
||||
ScriptPost: toJSON(command.ScriptPost),
|
||||
Name: command.Name,
|
||||
})
|
||||
if err != nil {
|
||||
bus.RunEvent(events.Log{
|
||||
|
||||
@@ -141,15 +141,15 @@ var shapeTypeMap = map[int]string{
|
||||
}
|
||||
|
||||
var shapeIconMap = map[int]string{
|
||||
0: "triangle",
|
||||
1: "triangle",
|
||||
2: "square",
|
||||
3: "square",
|
||||
4: "square",
|
||||
7: "hexagon",
|
||||
8: "triangle",
|
||||
9: "triangle",
|
||||
12: "hexagon",
|
||||
0: "shape_triangle",
|
||||
1: "shape_triangle",
|
||||
2: "shape_square",
|
||||
3: "shape_square",
|
||||
4: "shape_square",
|
||||
7: "shape_hexagon",
|
||||
8: "shape_triangle",
|
||||
9: "shape_triangle",
|
||||
12: "shape_hexagon",
|
||||
}
|
||||
|
||||
var shapeWidthMap = map[int]int{
|
||||
|
||||
@@ -20,6 +20,7 @@ const (
|
||||
|
||||
type Trigger struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Event TriggerEvent `json:"event"`
|
||||
DeviceMatch string `json:"deviceMatch"`
|
||||
Parameter string `json:"parameter"`
|
||||
|
||||
@@ -53,7 +53,15 @@ func (d *Data) WithPatch(patches ...Patch) Data {
|
||||
}
|
||||
|
||||
if patch.Device.HWMetadata != nil {
|
||||
if pd.Icon == "" {
|
||||
hasIconAlias := false
|
||||
for _, a := range pd.Aliases {
|
||||
if strings.HasPrefix(a, "lucifer:icon") {
|
||||
hasIconAlias = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !hasIconAlias {
|
||||
pd.Icon = patch.Device.HWMetadata.Icon
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user