lucy factory - sensor support
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package handlerfactory
|
||||
|
||||
import (
|
||||
"git.aiterp.net/lucifer/new-server/models"
|
||||
"gopkg.in/yaml.v2"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
@@ -12,14 +13,23 @@ type FactoryConfig struct {
|
||||
Target string `yaml:"target"`
|
||||
SceneNames []string `yaml:"scenes"`
|
||||
TriggerDeviceID string `yaml:"trigger_device_id"`
|
||||
After []After `yaml:"after"`
|
||||
From string `yaml:"from"`
|
||||
To string `yaml:"to"`
|
||||
}
|
||||
|
||||
type FCMOde string
|
||||
|
||||
var (
|
||||
SceneDimmer FCMOde = "SceneDimmer"
|
||||
SceneDimmer FCMOde = "SceneDimmer"
|
||||
MotionSensor FCMOde = "MotionSensor"
|
||||
)
|
||||
|
||||
type After struct {
|
||||
Minutes int `yaml:"minutes"`
|
||||
NewState models.NewDeviceState `yaml:"new_state"`
|
||||
}
|
||||
|
||||
func ParseConfigs(reader io.Reader) ([]FactoryConfig, error) {
|
||||
readAll, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
@@ -40,3 +50,13 @@ func ParseConfigs(reader io.Reader) ([]FactoryConfig, error) {
|
||||
|
||||
return configs, nil
|
||||
}
|
||||
|
||||
func (f *FactoryConfig) FromTime() models.TimeOfDay {
|
||||
tod, _ := models.ParseTimeOfDay(f.From)
|
||||
return tod
|
||||
}
|
||||
|
||||
func (f *FactoryConfig) ToTime() models.TimeOfDay {
|
||||
tod, _ := models.ParseTimeOfDay(f.To)
|
||||
return tod
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ func CreateHandlers(
|
||||
switch config.Mode {
|
||||
case SceneDimmer:
|
||||
return sceneDimmer(config, scenes, existing)
|
||||
case MotionSensor:
|
||||
return motionSensor(config, existing)
|
||||
default:
|
||||
return []models.EventHandler{}, []models.EventHandler{}
|
||||
}
|
||||
@@ -59,8 +61,8 @@ func sceneDimmer(
|
||||
TargetKind: kind,
|
||||
TargetValue: refValue,
|
||||
Actions: models.EventAction{SetPower: &myTrue},
|
||||
From: -1,
|
||||
To: -1,
|
||||
From: config.FromTime(),
|
||||
To: config.ToTime(),
|
||||
})
|
||||
|
||||
handlers = append(handlers, models.EventHandler{
|
||||
@@ -74,8 +76,8 @@ func sceneDimmer(
|
||||
TargetKind: kind,
|
||||
TargetValue: refValue,
|
||||
Actions: models.EventAction{SetPower: &myFalse},
|
||||
From: -1,
|
||||
To: -1,
|
||||
From: config.FromTime(),
|
||||
To: config.ToTime(),
|
||||
})
|
||||
|
||||
for i, scene := range resolvedScenes {
|
||||
@@ -96,8 +98,8 @@ func sceneDimmer(
|
||||
Group: refValue,
|
||||
DurationMS: 0,
|
||||
}},
|
||||
From: -1,
|
||||
To: -1,
|
||||
From: config.FromTime(),
|
||||
To: config.ToTime(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -118,8 +120,8 @@ func sceneDimmer(
|
||||
Group: refValue,
|
||||
DurationMS: 0,
|
||||
}},
|
||||
From: -1,
|
||||
To: -1,
|
||||
From: config.FromTime(),
|
||||
To: config.ToTime(),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -139,8 +141,8 @@ func sceneDimmer(
|
||||
Group: refValue,
|
||||
DurationMS: 0,
|
||||
}},
|
||||
From: -1,
|
||||
To: -1,
|
||||
From: config.FromTime(),
|
||||
To: config.ToTime(),
|
||||
})
|
||||
|
||||
handlers = append(handlers, models.EventHandler{
|
||||
@@ -158,11 +160,75 @@ func sceneDimmer(
|
||||
Group: refValue,
|
||||
DurationMS: 0,
|
||||
}},
|
||||
From: -1,
|
||||
To: -1,
|
||||
From: config.FromTime(),
|
||||
To: config.ToTime(),
|
||||
})
|
||||
|
||||
return handlers, toRemove
|
||||
return optimizeLists(handlers, toRemove)
|
||||
}
|
||||
|
||||
func motionSensor(
|
||||
config FactoryConfig,
|
||||
existing []models.EventHandler,
|
||||
) ([]models.EventHandler, []models.EventHandler) {
|
||||
kind, refValue := models.ParseFetchString(config.Target)
|
||||
|
||||
toRemove := make([]models.EventHandler, 0, 8)
|
||||
for _, old := range existing {
|
||||
if old.From != config.FromTime() || old.To != config.ToTime() {
|
||||
continue
|
||||
}
|
||||
|
||||
if old.Conditions["deviceId"].EQ == config.TriggerDeviceID {
|
||||
toRemove = append(toRemove, old)
|
||||
}
|
||||
}
|
||||
|
||||
handlers := make([]models.EventHandler, 0, len(config.After))
|
||||
for _, after := range config.After {
|
||||
if after.Minutes == 0 {
|
||||
handlers = append(handlers, models.EventHandler{
|
||||
EventName: "SensorPresenceStarted",
|
||||
Conditions: map[string]models.EventCondition{
|
||||
"deviceId": {EQ: config.TriggerDeviceID},
|
||||
},
|
||||
OneShot: false,
|
||||
Priority: 100,
|
||||
TargetKind: kind,
|
||||
TargetValue: refValue,
|
||||
Actions: models.EventAction{
|
||||
SetPower: after.NewState.Power,
|
||||
SetColor: after.NewState.Color,
|
||||
SetIntensity: after.NewState.Intensity,
|
||||
SetTemperature: after.NewState.Temperature,
|
||||
},
|
||||
From: config.FromTime(),
|
||||
To: config.ToTime(),
|
||||
})
|
||||
} else {
|
||||
handlers = append(handlers, models.EventHandler{
|
||||
EventName: "SensorPresenceEnded",
|
||||
Conditions: map[string]models.EventCondition{
|
||||
"deviceId": {EQ: config.TriggerDeviceID},
|
||||
"minutesElapsed": {EQ: fmt.Sprintf("%d", after.Minutes)},
|
||||
},
|
||||
OneShot: false,
|
||||
Priority: 100,
|
||||
TargetKind: kind,
|
||||
TargetValue: refValue,
|
||||
Actions: models.EventAction{
|
||||
SetPower: after.NewState.Power,
|
||||
SetColor: after.NewState.Color,
|
||||
SetIntensity: after.NewState.Intensity,
|
||||
SetTemperature: after.NewState.Temperature,
|
||||
},
|
||||
From: config.FromTime(),
|
||||
To: config.ToTime(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return optimizeLists(handlers, toRemove)
|
||||
}
|
||||
|
||||
var myTrue = true
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
package handlerfactory
|
||||
|
||||
import (
|
||||
"git.aiterp.net/lucifer/new-server/models"
|
||||
)
|
||||
|
||||
func optimizeLists(
|
||||
add []models.EventHandler,
|
||||
del []models.EventHandler,
|
||||
) ([]models.EventHandler, []models.EventHandler) {
|
||||
newAdd := make([]models.EventHandler, 0, len(add))
|
||||
newDel := make([]models.EventHandler, 0, len(del))
|
||||
|
||||
OptimizeLoop1:
|
||||
for _, addItem := range add {
|
||||
for _, delItem := range del {
|
||||
if checkDuplicate(&addItem, &delItem) {
|
||||
continue OptimizeLoop1
|
||||
}
|
||||
}
|
||||
|
||||
newAdd = append(newAdd, addItem)
|
||||
}
|
||||
|
||||
OptimizeLoop2:
|
||||
for _, delItem := range del {
|
||||
for _, addItem := range add {
|
||||
if checkDuplicate(&addItem, &delItem) {
|
||||
continue OptimizeLoop2
|
||||
}
|
||||
}
|
||||
|
||||
newDel = append(newDel, delItem)
|
||||
}
|
||||
|
||||
return newAdd, newDel
|
||||
}
|
||||
|
||||
func checkDuplicate(a *models.EventHandler, b *models.EventHandler) bool {
|
||||
check := true
|
||||
check = check && a.EventName == b.EventName
|
||||
check = check && len(a.Conditions) == len(b.Conditions)
|
||||
for k := range a.Conditions {
|
||||
check = check && a.Conditions[k] == b.Conditions[k]
|
||||
}
|
||||
check = check && a.OneShot == b.OneShot
|
||||
check = check && a.Priority == b.Priority
|
||||
check = check && a.TargetKind == b.TargetKind
|
||||
check = check && a.TargetValue == b.TargetValue
|
||||
check = check && a.From == b.From
|
||||
check = check && a.To == b.To
|
||||
|
||||
aPower := a.Actions.SetPower
|
||||
bPower := b.Actions.SetPower
|
||||
powerEq := (aPower == nil && bPower == nil) || (aPower != nil && bPower != nil && *aPower == *bPower)
|
||||
|
||||
aColor := a.Actions.SetColor
|
||||
bColor := b.Actions.SetColor
|
||||
colorEq := (aColor == nil && bColor == nil) || (aColor != nil && bColor != nil && *aColor == *bColor)
|
||||
|
||||
aInt := a.Actions.SetIntensity
|
||||
bInt := b.Actions.SetIntensity
|
||||
intEq := (aInt == nil && bInt == nil) || (aInt != nil && bInt != nil && *aInt == *bInt)
|
||||
|
||||
aTemp := a.Actions.SetTemperature
|
||||
bTemp := b.Actions.SetTemperature
|
||||
tempEq := (aTemp == nil && bTemp == nil) || (aTemp != nil && bTemp != nil && *aTemp == *bTemp)
|
||||
|
||||
check = check && powerEq && colorEq && intEq && tempEq
|
||||
|
||||
return check
|
||||
}
|
||||
Reference in New Issue
Block a user