github.com/e154/smart-home@v0.17.2-0.20240311175135-e530a6e5cd45/plugins/zigbee2mqtt/actor.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 zigbee2mqtt
    20  
    21  import (
    22  	"context"
    23  	"sync"
    24  
    25  	"github.com/pkg/errors"
    26  
    27  	"github.com/e154/smart-home/common/events"
    28  	m "github.com/e154/smart-home/models"
    29  	"github.com/e154/smart-home/system/mqtt"
    30  	"github.com/e154/smart-home/system/supervisor"
    31  )
    32  
    33  // Actor ...
    34  type Actor struct {
    35  	*supervisor.BaseActor
    36  	zigbee2mqttDevice *m.Zigbee2mqttDevice
    37  	mqttMessageQueue  chan *Message
    38  	actionPool        chan events.EventCallEntityAction
    39  	newMsgMu          *sync.Mutex
    40  	stateMu           *sync.Mutex
    41  }
    42  
    43  // NewActor ...
    44  func NewActor(entity *m.Entity,
    45  	service supervisor.Service) (actor *Actor, err error) {
    46  
    47  	var zigbee2mqttDevice *m.Zigbee2mqttDevice
    48  	if zigbee2mqttDevice, err = service.Adaptors().Zigbee2mqttDevice.GetById(context.Background(), entity.Id.Name()); err != nil {
    49  		return
    50  	}
    51  
    52  	actor = &Actor{
    53  		BaseActor:         supervisor.NewBaseActor(entity, service),
    54  		mqttMessageQueue:  make(chan *Message, 10),
    55  		actionPool:        make(chan events.EventCallEntityAction, 1000),
    56  		newMsgMu:          &sync.Mutex{},
    57  		stateMu:           &sync.Mutex{},
    58  		zigbee2mqttDevice: zigbee2mqttDevice,
    59  	}
    60  
    61  	// mqtt worker
    62  	go func() {
    63  		for message := range actor.mqttMessageQueue {
    64  			actor.mqttNewMessage(message)
    65  		}
    66  	}()
    67  
    68  	// action worker
    69  	go func() {
    70  		for msg := range actor.actionPool {
    71  			actor.runAction(msg)
    72  		}
    73  	}()
    74  
    75  	return
    76  }
    77  
    78  func (e *Actor) Destroy() {
    79  
    80  }
    81  
    82  // SetState ...
    83  func (e *Actor) SetState(params supervisor.EntityStateParams) error {
    84  
    85  	e.SetActorState(params.NewState)
    86  	e.DeserializeAttr(params.AttributeValues)
    87  	e.SaveState(false, params.StorageSave)
    88  
    89  	return nil
    90  }
    91  
    92  func (e *Actor) mqttOnPublish(client mqtt.MqttCli, msg mqtt.Message) {
    93  	message := NewMessage()
    94  	message.Payload = string(msg.Payload)
    95  	message.Topic = msg.Topic
    96  	message.Qos = msg.Qos
    97  	message.Duplicate = msg.Dup
    98  
    99  	e.mqttMessageQueue <- message
   100  }
   101  
   102  func (e *Actor) mqttNewMessage(message *Message) {
   103  	e.newMsgMu.Lock()
   104  	defer e.newMsgMu.Unlock()
   105  
   106  	if _, err := e.ScriptsEngine.AssertFunction(FuncZigbee2mqttEvent, message); err != nil {
   107  		log.Error(err.Error())
   108  		return
   109  	}
   110  }
   111  
   112  func (e *Actor) addAction(event events.EventCallEntityAction) {
   113  	e.actionPool <- event
   114  }
   115  
   116  func (e *Actor) runAction(msg events.EventCallEntityAction) {
   117  	if action, ok := e.Actions[msg.ActionName]; ok {
   118  		if action.ScriptEngine != nil && action.ScriptEngine.Engine() != nil {
   119  			if _, err := action.ScriptEngine.Engine().AssertFunction(FuncEntityAction, e.Id, action.Name, msg.Args); err != nil {
   120  				log.Error(errors.Wrapf(err, "entity id: %s ", e.Id).Error())
   121  			}
   122  			return
   123  		}
   124  	}
   125  	if e.ScriptsEngine != nil && e.ScriptsEngine.Engine() != nil {
   126  		if _, err := e.ScriptsEngine.AssertFunction(FuncEntityAction, e.Id, msg.ActionName, msg.Args); err != nil {
   127  			log.Error(errors.Wrapf(err, "entity id: %s ", e.Id).Error())
   128  		}
   129  	}
   130  }