github.com/martinohmann/rfoutlet@v1.2.1-0.20220707195255-8a66aa411105/internal/statedrift/detector.go (about)

     1  // Package statedrift provides a detector for listening to rf codes sent out by
     2  // anything else than rfoutlet (e.g. the physical remote control for the
     3  // outlet).
     4  package statedrift
     5  
     6  import (
     7  	"github.com/martinohmann/rfoutlet/internal/command"
     8  	"github.com/martinohmann/rfoutlet/internal/outlet"
     9  	"github.com/martinohmann/rfoutlet/pkg/gpio"
    10  	"github.com/sirupsen/logrus"
    11  )
    12  
    13  var log = logrus.WithField("component", "statedrift")
    14  
    15  // Detector sniffs for sent out rf codes using the receiver and pushes state
    16  // correction commands into the command queue if necessary. This allows for the
    17  // detection of codes sent out by pressing buttons on a physical outlet remote
    18  // control.
    19  type Detector struct {
    20  	Registry     *outlet.Registry
    21  	Receiver     gpio.CodeReceiver
    22  	CommandQueue chan<- command.Command
    23  }
    24  
    25  // NewDetector creates a new *Detector.
    26  func NewDetector(registry *outlet.Registry, receiver gpio.CodeReceiver, queue chan<- command.Command) *Detector {
    27  	return &Detector{
    28  		Registry:     registry,
    29  		Receiver:     receiver,
    30  		CommandQueue: queue,
    31  	}
    32  }
    33  
    34  // Run runs the state drift detection loop until stopCh is closed.
    35  func (d *Detector) Run(stopCh <-chan struct{}) {
    36  	for {
    37  		select {
    38  		case <-stopCh:
    39  			log.Info("shutting down state drift detector")
    40  			return
    41  		case result, ok := <-d.Receiver.Receive():
    42  			if !ok {
    43  				log.Error("receiver was closed unexpectedly, shutting down state drift detector")
    44  				return
    45  			}
    46  
    47  			var found bool
    48  
    49  			for _, o := range d.Registry.GetOutlets() {
    50  				if result.Code == o.CodeOn && o.GetState() != outlet.StateOn {
    51  					found = true
    52  					d.CommandQueue <- command.StateCorrectionCommand{
    53  						Outlet:       o,
    54  						DesiredState: outlet.StateOn,
    55  					}
    56  				} else if result.Code == o.CodeOff && o.GetState() != outlet.StateOff {
    57  					found = true
    58  					d.CommandQueue <- command.StateCorrectionCommand{
    59  						Outlet:       o,
    60  						DesiredState: outlet.StateOff,
    61  					}
    62  				}
    63  
    64  				if found {
    65  					break
    66  				}
    67  			}
    68  		}
    69  	}
    70  }