This commit is contained in:
@@ -76,9 +76,10 @@ func (b *Bridge) Refresh(ctx context.Context) error {
|
|||||||
|
|
||||||
if state == nil {
|
if state == nil {
|
||||||
state = &hueSensorState{
|
state = &hueSensorState{
|
||||||
index: index,
|
index: index,
|
||||||
uniqueID: sensor.UniqueID,
|
uniqueID: sensor.UniqueID,
|
||||||
externalID: -1,
|
externalID: -1,
|
||||||
|
presenceCooldown: -2,
|
||||||
}
|
}
|
||||||
|
|
||||||
b.sensorStates = append(b.sensorStates, state)
|
b.sensorStates = append(b.sensorStates, state)
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ type hueSensorState struct {
|
|||||||
uniqueID string
|
uniqueID string
|
||||||
prevData *SensorData
|
prevData *SensorData
|
||||||
prevTime time.Time
|
prevTime time.Time
|
||||||
presenceCooldown bool
|
presenceCooldown int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (state *hueSensorState) Update(newData SensorData) *models.Event {
|
func (state *hueSensorState) Update(newData SensorData) *models.Event {
|
||||||
@@ -153,26 +153,36 @@ func (state *hueSensorState) Update(newData SensorData) *models.Event {
|
|||||||
case "ZLLPresence":
|
case "ZLLPresence":
|
||||||
{
|
{
|
||||||
if state.prevData != nil && state.prevData.State.Presence != newData.State.Presence {
|
if state.prevData != nil && state.prevData.State.Presence != newData.State.Presence {
|
||||||
name := models.ENSensorPresenceStarted
|
if newData.State.Presence {
|
||||||
if !newData.State.Presence {
|
state.presenceCooldown = -1
|
||||||
name = models.ENSensorPresenceEnding
|
|
||||||
state.presenceCooldown = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return &models.Event{
|
return &models.Event{
|
||||||
Name: name,
|
Name: models.ENSensorPresenceStarted,
|
||||||
Payload: map[string]string{
|
Payload: map[string]string{
|
||||||
"deviceId": strconv.Itoa(state.externalID),
|
"deviceId": strconv.Itoa(state.externalID),
|
||||||
"deviceInternalId": newData.UniqueID,
|
"deviceInternalId": newData.UniqueID,
|
||||||
},
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
state.presenceCooldown = 0
|
||||||
}
|
}
|
||||||
} else if state.presenceCooldown && !newData.State.Presence && time.Since(stateTime) > time.Minute {
|
}
|
||||||
state.presenceCooldown = false
|
|
||||||
|
if state.presenceCooldown == -2 {
|
||||||
|
state.presenceCooldown = int(time.Since(stateTime) / time.Minute)
|
||||||
|
}
|
||||||
|
|
||||||
|
nextEventWait := time.Minute * time.Duration(state.presenceCooldown)
|
||||||
|
if state.presenceCooldown != -1 && !newData.State.Presence && time.Since(stateTime) > nextEventWait {
|
||||||
|
state.presenceCooldown += 1
|
||||||
|
|
||||||
return &models.Event{
|
return &models.Event{
|
||||||
Name: models.ENSensorPresenceEnded,
|
Name: models.ENSensorPresenceEnded,
|
||||||
Payload: map[string]string{
|
Payload: map[string]string{
|
||||||
"deviceId": strconv.Itoa(state.externalID),
|
"deviceId": strconv.Itoa(state.externalID),
|
||||||
"deviceInternalId": newData.UniqueID,
|
"deviceInternalId": newData.UniqueID,
|
||||||
|
"minutesElapsed": strconv.Itoa(state.presenceCooldown - 1),
|
||||||
|
"secondsElapsed": strconv.Itoa((state.presenceCooldown - 1) * 60),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -173,11 +173,11 @@ func (c *EventCondition) checkDevice(key string, device Device) (matches bool, s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var numRegex = regexp.MustCompile("^{-[0-9].}+$")
|
var numRegex = regexp.MustCompile("^-*[0-9]+(.[0-9]+)*$")
|
||||||
|
|
||||||
func (c *EventCondition) matches(value string) bool {
|
func (c *EventCondition) matches(value string) bool {
|
||||||
if numRegex.MatchString(value) {
|
if numRegex.MatchString(value) {
|
||||||
numValue, _ := strconv.ParseFloat(c.LT, 64)
|
numValue, _ := strconv.ParseFloat(value, 64)
|
||||||
stillAlive := true
|
stillAlive := true
|
||||||
|
|
||||||
if c.LT != "" {
|
if c.LT != "" {
|
||||||
@@ -197,7 +197,7 @@ func (c *EventCondition) matches(value string) bool {
|
|||||||
|
|
||||||
if stillAlive && c.GTE != "" {
|
if stillAlive && c.GTE != "" {
|
||||||
gte, _ := strconv.ParseFloat(c.GTE, 64)
|
gte, _ := strconv.ParseFloat(c.GTE, 64)
|
||||||
stillAlive = numValue == gte
|
stillAlive = numValue >= gte
|
||||||
}
|
}
|
||||||
|
|
||||||
if stillAlive && c.GT != "" {
|
if stillAlive && c.GT != "" {
|
||||||
|
|||||||
+1
-1
@@ -75,7 +75,7 @@ func (t TimeOfDay) IsBetween(from TimeOfDay, to TimeOfDay) bool {
|
|||||||
if from == to {
|
if from == to {
|
||||||
return t == from
|
return t == from
|
||||||
} else if from > to {
|
} else if from > to {
|
||||||
return t >= to || t <= from
|
return t >= from || t <= to
|
||||||
} else {
|
} else {
|
||||||
return t >= from && t <= to
|
return t >= from && t <= to
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func tod(s string) TimeOfDay {
|
||||||
|
tod, err := ParseTimeOfDay(s)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tod
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTimeOfDay_IsBetween(t *testing.T) {
|
||||||
|
table := []struct{
|
||||||
|
Value TimeOfDay
|
||||||
|
From TimeOfDay
|
||||||
|
To TimeOfDay
|
||||||
|
Expected bool
|
||||||
|
}{
|
||||||
|
{ tod("16:13:11"), tod("07"), tod("21:30"), true },
|
||||||
|
{ tod("16:13:31"), tod("21:30"), tod("07"), false },
|
||||||
|
{ tod("23:15:32"), tod("21:30"), tod("07"), true },
|
||||||
|
{ tod("04:13:57"), tod("21:30"), tod("07"), true },
|
||||||
|
{ tod("16:14:43"), tod("15:30"), tod("16:00"), false },
|
||||||
|
{ tod("16:14:43"), tod("15:30"), tod("16:15"), true },
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, row := range table {
|
||||||
|
t.Run(fmt.Sprintf("row_%d", i), func (t *testing.T) {
|
||||||
|
if row.Value.IsBetween(row.From, row.To) != row.Expected {
|
||||||
|
t.Log(row.Value, row.From, row.To)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user