You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
277 lines
5.1 KiB
277 lines
5.1 KiB
package main
|
|
|
|
import (
|
|
"git.aiterp.net/lucifer/new-server/models"
|
|
"log"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type Param struct {
|
|
Index int
|
|
Key string
|
|
Value string
|
|
Operator string
|
|
}
|
|
|
|
func (p *Param) String() *string {
|
|
if p == nil {
|
|
return nil
|
|
}
|
|
|
|
return &p.Value
|
|
}
|
|
|
|
func (p *Param) TimeOfDay() *models.TimeOfDay {
|
|
if p == nil {
|
|
return nil
|
|
}
|
|
|
|
tod, err := models.ParseTimeOfDay(p.Value)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
return &tod
|
|
}
|
|
|
|
func (p *Param) TimeOfDayOr(fallback models.TimeOfDay) models.TimeOfDay {
|
|
tod := p.TimeOfDay()
|
|
if tod == nil {
|
|
return fallback
|
|
}
|
|
|
|
return *tod
|
|
}
|
|
|
|
func (p *Param) StringOr(fallback string) string {
|
|
if p == nil {
|
|
return fallback
|
|
}
|
|
|
|
return p.Value
|
|
}
|
|
|
|
func (p *Param) Int() *int {
|
|
if p == nil {
|
|
return nil
|
|
}
|
|
|
|
n, err := strconv.Atoi(p.Value)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
return &n
|
|
}
|
|
|
|
func (p *Param) IntOr(other int) int {
|
|
val := p.Int()
|
|
if val == nil {
|
|
return other
|
|
}
|
|
|
|
return *val
|
|
}
|
|
|
|
func (p *Param) Float() *float64 {
|
|
if p == nil {
|
|
return nil
|
|
}
|
|
|
|
n, err := strconv.ParseFloat(p.Value, 64)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
return &n
|
|
}
|
|
|
|
func (p *Param) Bool() *bool {
|
|
if p == nil {
|
|
return nil
|
|
}
|
|
|
|
v := strings.ToLower(p.Value)
|
|
if v == "yes" || v == "true" || v == "on" {
|
|
r := true
|
|
return &r
|
|
} else if v == "no" || v == "false" || v == "off" {
|
|
r := false
|
|
return &r
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type Params []Param
|
|
|
|
func (p Params) Get(key interface{}) *Param {
|
|
switch key := key.(type) {
|
|
case string:
|
|
for _, p := range p {
|
|
if p.Key == key {
|
|
return &p
|
|
}
|
|
}
|
|
case int:
|
|
for _, p := range p {
|
|
if p.Index == key {
|
|
return &p
|
|
}
|
|
}
|
|
default:
|
|
log.Panicf("Incorrect key type %T", key)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p Params) Subset(prefix string) Params {
|
|
if len(p) == 0 {
|
|
return Params{}
|
|
}
|
|
|
|
if len(prefix) > 0 && !strings.HasSuffix(prefix, ".") {
|
|
prefix += "."
|
|
}
|
|
|
|
res := make(Params, 0, len(p))
|
|
|
|
for _, param := range p {
|
|
if param.Index == -1 && strings.HasPrefix(param.Key, prefix) {
|
|
res = append(res, Param{Index: -1, Key: param.Key[len(prefix):], Value: param.Value, Operator: param.Operator})
|
|
}
|
|
}
|
|
|
|
return res
|
|
}
|
|
|
|
func (p Params) StringMap() map[string]string {
|
|
res := make(map[string]string)
|
|
for _, param := range p {
|
|
if param.Index == -1 {
|
|
res[param.Key] = param.Value
|
|
}
|
|
}
|
|
|
|
return res
|
|
}
|
|
|
|
func (p Params) StringPtrMap() map[string]*string {
|
|
res := make(map[string]*string)
|
|
for _, param := range p {
|
|
if param.Index == -1 {
|
|
if param.Value == "NULL" {
|
|
res[param.Key] = nil
|
|
} else {
|
|
res[param.Key] = ¶m.Value
|
|
}
|
|
}
|
|
}
|
|
|
|
return res
|
|
}
|
|
|
|
func (p Params) Strings(minIndex int) []string {
|
|
res := make([]string, 0, len(p))
|
|
for _, param := range p {
|
|
if param.Index >= minIndex {
|
|
res = append(res, param.Value)
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
func (p Params) DeviceState(prefix string) models.NewDeviceState {
|
|
return models.NewDeviceState{
|
|
Power: p.Get(prefix + "power").Bool(),
|
|
Color: p.Get(prefix + "color").String(),
|
|
Intensity: p.Get(prefix + "intensity").Float(),
|
|
Temperature: p.Get(prefix + "temperature").Int(),
|
|
}
|
|
}
|
|
|
|
func (p Params) SceneAssignment(prefix string) *models.DeviceSceneAssignment {
|
|
if p.Get(prefix+"scene") == nil {
|
|
return nil
|
|
}
|
|
|
|
return &models.DeviceSceneAssignment{
|
|
SceneID: p.Get(prefix+"scene").IntOr(-1),
|
|
Group: p.Get(prefix+"scene.group").StringOr(time.Now().Format(time.RFC3339)),
|
|
DurationMS: int64(p.Get(prefix+"scene.duration").IntOr(0)),
|
|
}
|
|
}
|
|
|
|
type Command struct {
|
|
Name string
|
|
Params Params
|
|
}
|
|
|
|
func parseCommand(args []string) Command {
|
|
if len(args) == 0 {
|
|
return Command{Name: "help"}
|
|
}
|
|
|
|
cmd := Command{
|
|
Name: args[0],
|
|
Params: make(Params, 0, len(args)-1),
|
|
}
|
|
|
|
nextIndex := 0
|
|
for _, arg := range args[1:] {
|
|
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(kvle) == 2 {
|
|
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 {
|
|
cmd.Params = append(cmd.Params, Param{Index: nextIndex, Value: arg})
|
|
nextIndex += 1
|
|
}
|
|
}
|
|
|
|
return cmd
|
|
}
|