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  }