Lucy handler add
This commit is contained in:
+2
-20
@@ -6,29 +6,11 @@ import (
|
|||||||
"git.aiterp.net/lucifer/new-server/models"
|
"git.aiterp.net/lucifer/new-server/models"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"log"
|
"log"
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func fetchDevices(ctx context.Context, fetchStr string) ([]models.Device, error) {
|
func fetchDevices(ctx context.Context, fetchStr string) ([]models.Device, error) {
|
||||||
if strings.HasPrefix(fetchStr, "tag:") {
|
kind, value := models.ParseFetchString(fetchStr)
|
||||||
return config.DeviceRepository().FetchByReference(ctx, models.RKTag, fetchStr[4:])
|
return config.DeviceRepository().FetchByReference(ctx, kind, value)
|
||||||
} else if strings.HasPrefix(fetchStr, "bridge:") {
|
|
||||||
return config.DeviceRepository().FetchByReference(ctx, models.RKBridgeID, fetchStr[7:])
|
|
||||||
} else if strings.HasPrefix(fetchStr, "id:") {
|
|
||||||
return config.DeviceRepository().FetchByReference(ctx, models.RKDeviceID, fetchStr[7:])
|
|
||||||
} else if strings.HasPrefix(fetchStr, "name:") {
|
|
||||||
return config.DeviceRepository().FetchByReference(ctx, models.RKName, fetchStr[7:])
|
|
||||||
}else if fetchStr == "all" {
|
|
||||||
return config.DeviceRepository().FetchByReference(ctx, models.RKAll, "")
|
|
||||||
} else {
|
|
||||||
_, err := strconv.Atoi(fetchStr)
|
|
||||||
if err != nil {
|
|
||||||
return config.DeviceRepository().FetchByReference(ctx, models.RKName, fetchStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return config.DeviceRepository().FetchByReference(ctx, models.RKDeviceID, fetchStr)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Devices(r gin.IRoutes) {
|
func Devices(r gin.IRoutes) {
|
||||||
|
|||||||
+11
-1
@@ -6,7 +6,7 @@ import (
|
|||||||
"git.aiterp.net/lucifer/new-server/models"
|
"git.aiterp.net/lucifer/new-server/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (client *Client) GetHandlers(ctx context.Context, fetchStr string) ([]models.EventHandler, error) {
|
func (client *Client) GetHandlers(ctx context.Context) ([]models.EventHandler, error) {
|
||||||
handlers := make([]models.EventHandler, 0, 16)
|
handlers := make([]models.EventHandler, 0, 16)
|
||||||
err := client.Fetch(ctx, "GET", "/api/event-handlers", &handlers, nil)
|
err := client.Fetch(ctx, "GET", "/api/event-handlers", &handlers, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -16,6 +16,16 @@ func (client *Client) GetHandlers(ctx context.Context, fetchStr string) ([]model
|
|||||||
return handlers, nil
|
return handlers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (client *Client) AddHandler(ctx context.Context, handler models.EventHandler) (*models.EventHandler, error) {
|
||||||
|
var result models.EventHandler
|
||||||
|
err := client.Fetch(ctx, "POST", "/api/event-handlers", &result, handler)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (client *Client) DeleteHandler(ctx context.Context, id int) (*models.EventHandler, error) {
|
func (client *Client) DeleteHandler(ctx context.Context, id int) (*models.EventHandler, error) {
|
||||||
var handler models.EventHandler
|
var handler models.EventHandler
|
||||||
err := client.Fetch(ctx, "DELETE", fmt.Sprintf("/api/event-handlers/%d", id), &handler, nil)
|
err := client.Fetch(ctx, "DELETE", fmt.Sprintf("/api/event-handlers/%d", id), &handler, nil)
|
||||||
|
|||||||
@@ -144,6 +144,10 @@ func handleEvent(event models.Event) (responses []models.Event) {
|
|||||||
newState.Intensity = &newIntensity
|
newState.Intensity = &newIntensity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if action.SetTemperature != nil {
|
||||||
|
newState.Temperature = action.SetTemperature
|
||||||
|
}
|
||||||
|
|
||||||
err = allDevices[i].SetState(newState)
|
err = allDevices[i].SetState(newState)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error updating state for device", device.ID, "err:", err)
|
log.Println("Error updating state for device", device.ID, "err:", err)
|
||||||
|
|||||||
+67
-8
@@ -1,15 +1,17 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"git.aiterp.net/lucifer/new-server/models"
|
||||||
"log"
|
"log"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Param struct {
|
type Param struct {
|
||||||
Index int
|
Index int
|
||||||
Key string
|
Key string
|
||||||
Value string
|
Value string
|
||||||
|
Operator string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Param) String() *string {
|
func (p *Param) String() *string {
|
||||||
@@ -28,7 +30,6 @@ func (p *Param) StringOr(fallback string) string {
|
|||||||
return p.Value
|
return p.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (p *Param) Int() *int {
|
func (p *Param) Int() *int {
|
||||||
if p == nil {
|
if p == nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -42,6 +43,15 @@ func (p *Param) Int() *int {
|
|||||||
return &n
|
return &n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Param) IntOr(other int) int {
|
||||||
|
val := p.Int()
|
||||||
|
if val == nil {
|
||||||
|
return other
|
||||||
|
}
|
||||||
|
|
||||||
|
return *val
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Param) Float() *float64 {
|
func (p *Param) Float() *float64 {
|
||||||
if p == nil {
|
if p == nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -108,7 +118,7 @@ func (p Params) Subset(prefix string) Params {
|
|||||||
|
|
||||||
for _, param := range p {
|
for _, param := range p {
|
||||||
if param.Index == -1 && strings.HasPrefix(param.Key, prefix) {
|
if param.Index == -1 && strings.HasPrefix(param.Key, prefix) {
|
||||||
res = append(res, Param{Index: -1, Key: param.Key[len(prefix):], Value: param.Value})
|
res = append(res, Param{Index: -1, Key: param.Key[len(prefix):], Value: param.Value, Operator: param.Operator})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,6 +162,34 @@ func (p Params) Strings(minIndex int) []string {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p Params) EventConditions() map[string]models.EventCondition {
|
||||||
|
ecMap := make(map[string]models.EventCondition, len(p))
|
||||||
|
|
||||||
|
for _, param := range p {
|
||||||
|
element, ok := ecMap[param.Key]
|
||||||
|
if !ok {
|
||||||
|
element = models.EventCondition{}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch param.Operator {
|
||||||
|
case "<":
|
||||||
|
element.LT = param.Value
|
||||||
|
case "<=":
|
||||||
|
element.LTE = param.Value
|
||||||
|
case ">=":
|
||||||
|
element.GTE = param.Value
|
||||||
|
case ">":
|
||||||
|
element.GT = param.Value
|
||||||
|
default:
|
||||||
|
element.EQ = param.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
ecMap[param.Key] = element
|
||||||
|
}
|
||||||
|
|
||||||
|
return ecMap
|
||||||
|
}
|
||||||
|
|
||||||
type Command struct {
|
type Command struct {
|
||||||
Name string
|
Name string
|
||||||
Params Params
|
Params Params
|
||||||
@@ -169,10 +207,22 @@ func parseCommand(args []string) Command {
|
|||||||
|
|
||||||
nextIndex := 0
|
nextIndex := 0
|
||||||
for _, arg := range args[1:] {
|
for _, arg := range args[1:] {
|
||||||
kv := strings.SplitN(arg, "=", 2)
|
kvle := strings.SplitN(arg, "<=", 2)
|
||||||
|
kvge := strings.SplitN(arg, ">=", 2)
|
||||||
|
kvl := strings.SplitN(arg, "<", 2)
|
||||||
|
kvg := strings.SplitN(arg, ">", 2)
|
||||||
|
kve := strings.SplitN(arg, "=", 2)
|
||||||
|
|
||||||
if len(kv) == 2 {
|
if len(kvle) == 2 {
|
||||||
cmd.Params = append(cmd.Params, Param{Index: -1, Key: kv[0], Value: kv[1]})
|
cmd.Params = append(cmd.Params, Param{Index: -1, Key: kvle[0], Value: kvle[1], Operator: "<="})
|
||||||
|
} else if len(kvge) == 2 {
|
||||||
|
cmd.Params = append(cmd.Params, Param{Index: -1, Key: kvge[0], Value: kvge[1], Operator: ">="})
|
||||||
|
} else if len(kvl) == 2 {
|
||||||
|
cmd.Params = append(cmd.Params, Param{Index: -1, Key: kvl[0], Value: kvl[1], Operator: "<"})
|
||||||
|
} else if len(kvg) == 2 {
|
||||||
|
cmd.Params = append(cmd.Params, Param{Index: -1, Key: kvg[0], Value: kvg[1], Operator: ">"})
|
||||||
|
} else if len(kve) == 2 {
|
||||||
|
cmd.Params = append(cmd.Params, Param{Index: -1, Key: kve[0], Value: kve[1], Operator: "="})
|
||||||
} else {
|
} else {
|
||||||
cmd.Params = append(cmd.Params, Param{Index: nextIndex, Value: arg})
|
cmd.Params = append(cmd.Params, Param{Index: nextIndex, Value: arg})
|
||||||
nextIndex += 1
|
nextIndex += 1
|
||||||
@@ -181,3 +231,12 @@ func parseCommand(args []string) Command {
|
|||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cmd Command) NewDeviceState(prefix string) models.NewDeviceState {
|
||||||
|
return models.NewDeviceState{
|
||||||
|
Power: cmd.Params.Get(prefix + "power").Bool(),
|
||||||
|
Color: cmd.Params.Get(prefix + "color").String(),
|
||||||
|
Intensity: cmd.Params.Get(prefix + "intensity").Float(),
|
||||||
|
Temperature: cmd.Params.Get(prefix + "temperature").Int(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+57
-1
@@ -17,12 +17,68 @@ func handlerCmd(
|
|||||||
|
|
||||||
switch cmd.Name {
|
switch cmd.Name {
|
||||||
case "list":
|
case "list":
|
||||||
handlers, err := c.GetHandlers(ctx, cmd.Params.Get(0).StringOr("all"))
|
handlers, err := c.GetHandlers(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteHandlerInfoTable(os.Stdout, handlers)
|
WriteHandlerInfoTable(os.Stdout, handlers)
|
||||||
|
case "add":
|
||||||
|
model := models.EventHandler{}
|
||||||
|
|
||||||
|
// Event name
|
||||||
|
model.EventName = cmd.Params.Get(0).StringOr("")
|
||||||
|
if len(model.EventName) == 0 {
|
||||||
|
log.Fatalln("Event name needed!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search
|
||||||
|
fetchStr := cmd.Params.Get(1).String()
|
||||||
|
if fetchStr == nil {
|
||||||
|
log.Fatalln("Search filter needed!")
|
||||||
|
}
|
||||||
|
model.TargetKind, model.TargetValue = models.ParseFetchString(*fetchStr)
|
||||||
|
|
||||||
|
// One shot
|
||||||
|
model.OneShot = cmd.Params.Get("one-shot").StringOr("false") == "true"
|
||||||
|
|
||||||
|
// Priority
|
||||||
|
model.Priority = cmd.Params.Get("priority").IntOr(100)
|
||||||
|
|
||||||
|
// Conditions
|
||||||
|
model.Conditions = cmd.Params.Subset("conditions").EventConditions()
|
||||||
|
|
||||||
|
// Power, Color, Intensity, Temperature
|
||||||
|
nds := cmd.NewDeviceState("set-")
|
||||||
|
model.Actions.SetPower = nds.Power
|
||||||
|
model.Actions.SetColor = nds.Color
|
||||||
|
model.Actions.SetIntensity = nds.Intensity
|
||||||
|
|
||||||
|
// Add intensity
|
||||||
|
model.Actions.AddIntensity = cmd.Params.Get("add-intensity").Float()
|
||||||
|
|
||||||
|
// Fire
|
||||||
|
fireParams := cmd.Params.Subset("fire")
|
||||||
|
fireName := fireParams.Get("name").String()
|
||||||
|
if fireName != nil {
|
||||||
|
firePayloadParams := fireParams.Subset("payload")
|
||||||
|
|
||||||
|
model.Actions.FireEvent = &models.Event{
|
||||||
|
Name: *fireName,
|
||||||
|
Payload: make(map[string]string, len(firePayloadParams)),
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, value := range firePayloadParams.StringMap() {
|
||||||
|
model.Actions.FireEvent.Payload[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newHandler, err := c.AddHandler(ctx, model)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteHandlerInfoTable(os.Stdout, []models.EventHandler{*newHandler})
|
||||||
case "delete":
|
case "delete":
|
||||||
id := cmd.Params.Get(0).Int()
|
id := cmd.Params.Get(0).Int()
|
||||||
if id == nil {
|
if id == nil {
|
||||||
|
|||||||
+13
-4
@@ -7,16 +7,25 @@ EXAMPLES
|
|||||||
lucy set tag:Hexagon color=hs:35,1 intensity=0.3
|
lucy set tag:Hexagon color=hs:35,1 intensity=0.3
|
||||||
lucy run SetProfile name=evening
|
lucy run SetProfile name=evening
|
||||||
|
|
||||||
EVENT HANDLER COMMANDS
|
|
||||||
handler list
|
|
||||||
handler delete <id>
|
|
||||||
|
|
||||||
DEVICE COMMANDS
|
DEVICE COMMANDS
|
||||||
list <search>
|
list <search>
|
||||||
set <search> <power=B> <color=C> <intensity=F> <temperature=N>
|
set <search> <power=B> <color=C> <intensity=F> <temperature=N>
|
||||||
tag <search> <[+/-]tag-name>
|
tag <search> <[+/-]tag-name>
|
||||||
update <search> <name=S> <icon=S> <prop.*=S/NULL>
|
update <search> <name=S> <icon=S> <prop.*=S/NULL>
|
||||||
|
|
||||||
|
EVENT HANDLER COMMANDS
|
||||||
|
handler list
|
||||||
|
handler add <event> <search> \
|
||||||
|
<one-shot=B> \
|
||||||
|
<priority=N> \
|
||||||
|
<conditions.[any.*|all.*|*][<|<=|=|=>|>]*> \
|
||||||
|
<set-power=B> <set-color=C> <set-intensity=F> <set-temperature=N> \
|
||||||
|
<add-intensity=F> \
|
||||||
|
<fire.name=S> <fire.payload.*=S>
|
||||||
|
handler delete <id>
|
||||||
|
|
||||||
EVENT COMMANDS
|
EVENT COMMANDS
|
||||||
run <event name> <*=S>
|
run <event name> <*=S>
|
||||||
|
|
||||||
|
NOTE: You may have to surround arguments including < or > with quotation marks!
|
||||||
`
|
`
|
||||||
|
|||||||
+7
-7
@@ -37,16 +37,15 @@ func main() {
|
|||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteDeviceStateTable(os.Stdout, devices)
|
if cmd.Params.Get("info").StringOr("false") == "true" {
|
||||||
|
WriteDeviceInfoTable(os.Stdout, devices)
|
||||||
|
} else {
|
||||||
|
WriteDeviceStateTable(os.Stdout, devices)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case "set":
|
case "set":
|
||||||
{
|
{
|
||||||
devices, err := c.PutDeviceState(ctx, cmd.Params.Get(0).StringOr("all"), models.NewDeviceState{
|
devices, err := c.PutDeviceState(ctx, cmd.Params.Get(0).StringOr("all"), cmd.NewDeviceState(""))
|
||||||
Power: cmd.Params.Get("power").Bool(),
|
|
||||||
Color: cmd.Params.Get("color").String(),
|
|
||||||
Intensity: cmd.Params.Get("intensity").Float(),
|
|
||||||
Temperature: cmd.Params.Get("temperature").Int(),
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
@@ -124,3 +123,4 @@ func main() {
|
|||||||
_, _ = fmt.Fprintln(os.Stderr, helpString[1:])
|
_, _ = fmt.Fprintln(os.Stderr, helpString[1:])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -95,6 +95,9 @@ func WriteHandlerInfoTable(w io.Writer, handlers []models.EventHandler) {
|
|||||||
if h.Actions.SetIntensity != nil {
|
if h.Actions.SetIntensity != nil {
|
||||||
actionStr += fmt.Sprintf("setIntensity=%.02f ", *h.Actions.SetIntensity)
|
actionStr += fmt.Sprintf("setIntensity=%.02f ", *h.Actions.SetIntensity)
|
||||||
}
|
}
|
||||||
|
if h.Actions.SetTemperature != nil {
|
||||||
|
actionStr += fmt.Sprintf("setTemperature=%d ", *h.Actions.SetTemperature)
|
||||||
|
}
|
||||||
if h.Actions.AddIntensity != nil {
|
if h.Actions.AddIntensity != nil {
|
||||||
actionStr += fmt.Sprintf("addIntensity=%.02f ", *h.Actions.AddIntensity)
|
actionStr += fmt.Sprintf("addIntensity=%.02f ", *h.Actions.AddIntensity)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -196,11 +196,12 @@ func (c *EventCondition) matches(value string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type EventAction struct {
|
type EventAction struct {
|
||||||
SetPower *bool `json:"setPower"`
|
SetPower *bool `json:"setPower"`
|
||||||
SetColor *string `json:"setColor"`
|
SetColor *string `json:"setColor"`
|
||||||
SetIntensity *float64 `json:"setIntensity"`
|
SetIntensity *float64 `json:"setIntensity"`
|
||||||
AddIntensity *float64 `json:"addIntensity"`
|
SetTemperature *int `json:"setTemperature"`
|
||||||
FireEvent *Event `json:"fireEvent"`
|
AddIntensity *float64 `json:"addIntensity"`
|
||||||
|
FireEvent *Event `json:"fireEvent"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (action *EventAction) Apply(other EventAction) {
|
func (action *EventAction) Apply(other EventAction) {
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
type ReferenceKind string
|
type ReferenceKind string
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -9,3 +14,24 @@ var (
|
|||||||
RKAll ReferenceKind = "All"
|
RKAll ReferenceKind = "All"
|
||||||
RKName ReferenceKind = "Name"
|
RKName ReferenceKind = "Name"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func ParseFetchString(fetchStr string) (ReferenceKind, string) {
|
||||||
|
if strings.HasPrefix(fetchStr, "tag:") {
|
||||||
|
return RKTag, fetchStr[4:]
|
||||||
|
} else if strings.HasPrefix(fetchStr, "bridge:") {
|
||||||
|
return RKBridgeID, fetchStr[7:]
|
||||||
|
} else if strings.HasPrefix(fetchStr, "id:") {
|
||||||
|
return RKDeviceID, fetchStr[7:]
|
||||||
|
} else if strings.HasPrefix(fetchStr, "name:") {
|
||||||
|
return RKName, fetchStr[7:]
|
||||||
|
} else if fetchStr == "all" {
|
||||||
|
return RKAll, ""
|
||||||
|
} else {
|
||||||
|
_, err := strconv.Atoi(fetchStr)
|
||||||
|
if err != nil {
|
||||||
|
return RKName, fetchStr
|
||||||
|
}
|
||||||
|
|
||||||
|
return RKDeviceID, fetchStr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user