github.com/e154/smart-home@v0.17.2-0.20240311175135-e530a6e5cd45/system/automation/condition_group.go (about) 1 // This file is part of the Smart Home 2 // Program complex distribution https://github.com/e154/smart-home 3 // Copyright (C) 2016-2023, Filippov Alex 4 // 5 // This library is free software: you can redistribute it and/or 6 // modify it under the terms of the GNU Lesser General Public 7 // License as published by the Free Software Foundation; either 8 // version 3 of the License, or (at your option) any later version. 9 // 10 // This library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 // Library General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public 16 // License along with this library. If not, see 17 // <https://www.gnu.org/licenses/>. 18 19 package automation 20 21 import ( 22 "context" 23 "sync" 24 "time" 25 26 "go.uber.org/atomic" 27 28 "github.com/e154/smart-home/common" 29 ) 30 31 // NewConditionGroup ... 32 func NewConditionGroup(t common.ConditionType) *ConditionGroup { 33 return &ConditionGroup{ 34 t: t, 35 lastStatus: atomic.NewBool(false), 36 Mutex: sync.Mutex{}, 37 } 38 } 39 40 // ConditionGroup ... 41 type ConditionGroup struct { 42 rules []*Condition 43 t common.ConditionType 44 lastStatus *atomic.Bool 45 sync.Mutex 46 } 47 48 // AddCondition ... 49 func (c *ConditionGroup) AddCondition(condition *Condition) { 50 c.rules = append(c.rules, condition) 51 } 52 53 func (c *ConditionGroup) Stop() { 54 for _, condition := range c.rules { 55 condition.Stop() 56 } 57 } 58 59 // Check ... 60 func (c *ConditionGroup) Check(entityId *common.EntityId) (state bool, err error) { 61 c.Lock() 62 defer func() { 63 c.lastStatus.Store(state) 64 c.Unlock() 65 }() 66 67 var total = len(c.rules) 68 if total == 0 { 69 state = true 70 return 71 } 72 73 wg := &sync.WaitGroup{} 74 wg.Add(total) 75 76 for _, r := range c.rules { 77 go func(condition *Condition) { 78 defer wg.Done() 79 bg, _ := context.WithTimeout(context.Background(), time.Second) 80 ctx := context.WithValue(bg, "entityId", entityId) 81 if _, err = condition.Check(ctx); err != nil { 82 log.Error(err.Error()) 83 } 84 }(r) 85 } 86 87 wg.Wait() 88 89 switch c.t { 90 case common.ConditionOr: 91 for _, r := range c.rules { 92 if r.Status() { 93 state = true 94 return 95 } 96 } 97 98 case common.ConditionAnd: 99 state = true 100 for _, r := range c.rules { 101 if !r.Status() { 102 state = false 103 } 104 if !state { 105 return 106 } 107 } 108 } 109 110 return 111 }