Stian Fredrik Aune
3 years ago
5 changed files with 304 additions and 3 deletions
-
42app/services/handlerfactory/config.go
-
169app/services/handlerfactory/factory.go
-
71cmd/lucy/factorycmd.go
-
17cmd/lucy/help.go
-
4cmd/lucy/main.go
@ -0,0 +1,42 @@ |
|||
package handlerfactory |
|||
|
|||
import ( |
|||
"gopkg.in/yaml.v2" |
|||
"io" |
|||
"io/ioutil" |
|||
"strings" |
|||
) |
|||
|
|||
type FactoryConfig struct { |
|||
Mode FCMOde `yaml:"mode"` |
|||
Target string `yaml:"target"` |
|||
SceneNames []string `yaml:"scenes"` |
|||
TriggerDeviceID string `yaml:"trigger_device_id"` |
|||
} |
|||
|
|||
type FCMOde string |
|||
|
|||
var ( |
|||
SceneDimmer FCMOde = "SceneDimmer" |
|||
) |
|||
|
|||
func ParseConfigs(reader io.Reader) ([]FactoryConfig, error) { |
|||
readAll, err := ioutil.ReadAll(reader) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
splits := strings.Split(string(readAll), "\n---\n") |
|||
configs := make([]FactoryConfig, 0, 8) |
|||
for _, split := range splits { |
|||
var factoryConfig FactoryConfig |
|||
err := yaml.NewDecoder(strings.NewReader(split)).Decode(&factoryConfig) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
configs = append(configs, factoryConfig) |
|||
} |
|||
|
|||
return configs, nil |
|||
} |
@ -0,0 +1,169 @@ |
|||
package handlerfactory |
|||
|
|||
import ( |
|||
"fmt" |
|||
"git.aiterp.net/lucifer/new-server/models" |
|||
) |
|||
|
|||
func CreateHandlers( |
|||
config FactoryConfig, |
|||
scenes []models.Scene, |
|||
existing []models.EventHandler, |
|||
) ([]models.EventHandler, []models.EventHandler) { |
|||
switch config.Mode { |
|||
case SceneDimmer: |
|||
return sceneDimmer(config, scenes, existing) |
|||
default: |
|||
return []models.EventHandler{}, []models.EventHandler{} |
|||
} |
|||
} |
|||
|
|||
func sceneDimmer( |
|||
config FactoryConfig, |
|||
scenes []models.Scene, |
|||
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.Conditions["deviceId"].EQ == config.TriggerDeviceID { |
|||
toRemove = append(toRemove, old) |
|||
} |
|||
} |
|||
|
|||
resolvedScenes := make([]models.Scene, 0, len(config.SceneNames)) |
|||
for _, name := range config.SceneNames { |
|||
for _, scene := range scenes { |
|||
if name == scene.Name { |
|||
resolvedScenes = append(resolvedScenes, scene) |
|||
break |
|||
} |
|||
} |
|||
} |
|||
|
|||
if len(scenes) < 2 { |
|||
return []models.EventHandler{}, []models.EventHandler{} |
|||
} |
|||
|
|||
handlers := make([]models.EventHandler, 0, len(scenes)+4) |
|||
|
|||
handlers = append(handlers, models.EventHandler{ |
|||
EventName: "ButtonPressed", |
|||
Conditions: map[string]models.EventCondition{ |
|||
"deviceId": {EQ: config.TriggerDeviceID}, |
|||
"buttonName": {EQ: "On"}, |
|||
}, |
|||
OneShot: false, |
|||
Priority: 100, |
|||
TargetKind: kind, |
|||
TargetValue: refValue, |
|||
Actions: models.EventAction{SetPower: &myTrue}, |
|||
From: -1, |
|||
To: -1, |
|||
}) |
|||
|
|||
handlers = append(handlers, models.EventHandler{ |
|||
EventName: "ButtonPressed", |
|||
Conditions: map[string]models.EventCondition{ |
|||
"deviceId": {EQ: config.TriggerDeviceID}, |
|||
"buttonName": {EQ: "Off"}, |
|||
}, |
|||
OneShot: false, |
|||
Priority: 100, |
|||
TargetKind: kind, |
|||
TargetValue: refValue, |
|||
Actions: models.EventAction{SetPower: &myFalse}, |
|||
From: -1, |
|||
To: -1, |
|||
}) |
|||
|
|||
for i, scene := range resolvedScenes { |
|||
if i > 0 { |
|||
handlers = append(handlers, models.EventHandler{ |
|||
EventName: "ButtonPressed", |
|||
Conditions: map[string]models.EventCondition{ |
|||
"deviceId": {EQ: config.TriggerDeviceID}, |
|||
"buttonName": {EQ: "DimDown"}, |
|||
"any.scene": {EQ: fmt.Sprintf("%d", scene.ID)}, |
|||
}, |
|||
OneShot: false, |
|||
Priority: 100, |
|||
TargetKind: kind, |
|||
TargetValue: refValue, |
|||
Actions: models.EventAction{SetScene: &models.DeviceSceneAssignment{ |
|||
SceneID: resolvedScenes[i-1].ID, |
|||
Group: refValue, |
|||
DurationMS: 0, |
|||
}}, |
|||
From: -1, |
|||
To: -1, |
|||
}) |
|||
} |
|||
|
|||
if i < len(resolvedScenes)-1 { |
|||
handlers = append(handlers, models.EventHandler{ |
|||
EventName: "ButtonPressed", |
|||
Conditions: map[string]models.EventCondition{ |
|||
"deviceId": {EQ: config.TriggerDeviceID}, |
|||
"buttonName": {EQ: "DimUp"}, |
|||
"any.scene": {EQ: fmt.Sprintf("%d", scene.ID)}, |
|||
}, |
|||
OneShot: false, |
|||
Priority: 100, |
|||
TargetKind: kind, |
|||
TargetValue: refValue, |
|||
Actions: models.EventAction{SetScene: &models.DeviceSceneAssignment{ |
|||
SceneID: resolvedScenes[i+1].ID, |
|||
Group: refValue, |
|||
DurationMS: 0, |
|||
}}, |
|||
From: -1, |
|||
To: -1, |
|||
}) |
|||
} |
|||
} |
|||
|
|||
handlers = append(handlers, models.EventHandler{ |
|||
EventName: "ButtonPressed", |
|||
Conditions: map[string]models.EventCondition{ |
|||
"deviceId": {EQ: config.TriggerDeviceID}, |
|||
"buttonName": {EQ: "DimDown"}, |
|||
}, |
|||
OneShot: false, |
|||
Priority: 90, |
|||
TargetKind: kind, |
|||
TargetValue: refValue, |
|||
Actions: models.EventAction{SetScene: &models.DeviceSceneAssignment{ |
|||
SceneID: scenes[len(scenes)-1].ID, |
|||
Group: refValue, |
|||
DurationMS: 0, |
|||
}}, |
|||
From: -1, |
|||
To: -1, |
|||
}) |
|||
|
|||
handlers = append(handlers, models.EventHandler{ |
|||
EventName: "ButtonPressed", |
|||
Conditions: map[string]models.EventCondition{ |
|||
"deviceId": {EQ: config.TriggerDeviceID}, |
|||
"buttonName": {EQ: "DimUp"}, |
|||
}, |
|||
OneShot: false, |
|||
Priority: 90, |
|||
TargetKind: kind, |
|||
TargetValue: refValue, |
|||
Actions: models.EventAction{SetScene: &models.DeviceSceneAssignment{ |
|||
SceneID: scenes[0].ID, |
|||
Group: refValue, |
|||
DurationMS: 0, |
|||
}}, |
|||
From: -1, |
|||
To: -1, |
|||
}) |
|||
|
|||
return handlers, toRemove |
|||
} |
|||
|
|||
var myTrue = true |
|||
var myFalse = false |
@ -0,0 +1,71 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"context" |
|||
"fmt" |
|||
"git.aiterp.net/lucifer/new-server/app/client" |
|||
"git.aiterp.net/lucifer/new-server/app/services/handlerfactory" |
|||
"log" |
|||
"os" |
|||
) |
|||
|
|||
func factoryCmd( |
|||
ctx context.Context, |
|||
c client.Client, |
|||
) { |
|||
cmd := parseCommand(os.Args[2:]) |
|||
|
|||
switch cmd.Name { |
|||
case "run": |
|||
fileName := cmd.Params.Get(0).String() |
|||
if fileName == nil { |
|||
log.Fatalln("Missing filename") |
|||
} |
|||
|
|||
scenes, err := c.GetScenes(ctx) |
|||
if err != nil { |
|||
log.Fatalln(err.Error()) |
|||
} |
|||
|
|||
handlers, err := c.GetHandlers(ctx) |
|||
if err != nil { |
|||
log.Fatalln(err.Error()) |
|||
} |
|||
|
|||
file, err := os.Open(*fileName) |
|||
if err != nil { |
|||
log.Fatalln("Failed to open file:", err) |
|||
} |
|||
defer file.Close() |
|||
|
|||
configs, err := handlerfactory.ParseConfigs(file) |
|||
for _, config := range configs { |
|||
toAdd, toRemove := handlerfactory.CreateHandlers(config, scenes, handlers) |
|||
|
|||
for _, removing := range toRemove { |
|||
_, err := c.DeleteHandler(ctx, removing.ID) |
|||
if err != nil { |
|||
log.Fatalln(err.Error()) |
|||
} |
|||
|
|||
log.Printf("Removed handler %d", removing.ID) |
|||
} |
|||
|
|||
for _, adding := range toAdd { |
|||
res, err := c.AddHandler(ctx, adding) |
|||
if err != nil { |
|||
log.Fatalln(err.Error()) |
|||
} |
|||
|
|||
log.Printf("Added handler %d", res.ID) |
|||
} |
|||
} |
|||
|
|||
default: |
|||
if cmd.Name != "help" { |
|||
log.Println("Unknown command:", cmd.Name) |
|||
} |
|||
|
|||
_, _ = fmt.Fprintln(os.Stderr, helpString[1:]) |
|||
} |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue