github.com/martinohmann/rfoutlet@v1.2.1-0.20220707195255-8a66aa411105/cmd/transmit.go (about)

     1  package cmd
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strconv"
     7  	"time"
     8  
     9  	"github.com/martinohmann/rfoutlet/internal/config"
    10  	"github.com/martinohmann/rfoutlet/pkg/gpio"
    11  	log "github.com/sirupsen/logrus"
    12  	"github.com/spf13/cobra"
    13  )
    14  
    15  func NewTransmitCommand() *cobra.Command {
    16  	options := &TransmitOptions{
    17  		PulseLength: config.DefaultPulseLength,
    18  		Pin:         config.DefaultTransmitPin,
    19  		Protocol:    config.DefaultProtocol,
    20  		Count:       gpio.DefaultTransmissionCount,
    21  	}
    22  
    23  	cmd := &cobra.Command{
    24  		Use:   "transmit [codes...]",
    25  		Short: "Send out codes to remote controlled outlets",
    26  		Long:  "The transmit command can be used send out codes to remote controlled outlets.",
    27  		Args:  cobra.MinimumNArgs(1),
    28  		RunE: func(cmd *cobra.Command, args []string) error {
    29  			return options.Run(cmd, args)
    30  		},
    31  	}
    32  
    33  	options.AddFlags(cmd)
    34  
    35  	return cmd
    36  }
    37  
    38  type TransmitOptions struct {
    39  	config.Config
    40  	PulseLength uint
    41  	Pin         uint
    42  	Protocol    int
    43  	Count       int
    44  	Delay       time.Duration
    45  	Infinite    bool
    46  }
    47  
    48  func (o *TransmitOptions) AddFlags(cmd *cobra.Command) {
    49  	cmd.Flags().UintVar(&o.PulseLength, "pulse-length", o.PulseLength, "pulse length")
    50  	cmd.Flags().UintVar(&o.Pin, "pin", o.Pin, "gpio pin to transmit on")
    51  	cmd.Flags().IntVar(&o.Protocol, "protocol", o.Protocol, "protocol to use for the transmission")
    52  	cmd.Flags().IntVar(&o.Count, "count", o.Count, "number of times a code should be transmitted in a row. The higher the value, the more likely it is that an outlet actually received the code")
    53  	cmd.Flags().DurationVar(&o.Delay, "delay", o.Delay, "delay between code transmissions")
    54  	cmd.Flags().BoolVar(&o.Infinite, "infinite", o.Infinite, "restart the transmission of codes after the last one was sent")
    55  }
    56  
    57  func (o *TransmitOptions) Run(cmd *cobra.Command, args []string) error {
    58  	if o.Protocol < 1 || o.Protocol > len(gpio.DefaultProtocols) {
    59  		return fmt.Errorf("protocol %d does not exist", o.Protocol)
    60  	}
    61  
    62  	proto := gpio.DefaultProtocols[o.Protocol-1]
    63  
    64  	codes := make([]uint64, len(args))
    65  
    66  	for i, arg := range args {
    67  		var err error
    68  		codes[i], err = strconv.ParseUint(arg, 10, 64)
    69  		if err != nil {
    70  			return fmt.Errorf("failed to parse code: %v", err)
    71  		}
    72  	}
    73  
    74  	device, err := openGPIODevice(cmd)
    75  	if err != nil {
    76  		return err
    77  	}
    78  	defer device.Close()
    79  
    80  	transmitter, err := gpio.NewTransmitter(device.Chip, int(o.Pin), gpio.TransmissionCount(o.Count))
    81  	if err != nil {
    82  		return fmt.Errorf("failed to create gpio transmitter: %v", err)
    83  	}
    84  	defer transmitter.Close()
    85  
    86  	ctx, cancel := context.WithCancel(context.Background())
    87  	defer cancel()
    88  
    89  	go handleSignals(cancel)
    90  
    91  	log.WithFields(log.Fields{
    92  		"pulseLength": o.PulseLength,
    93  		"protocol":    o.Protocol,
    94  		"delay":       o.Delay,
    95  		"count":       o.Count,
    96  	}).Infof("starting transmission")
    97  
    98  Loop:
    99  	for _, code := range codes {
   100  		log.Infof("transmitting code %d", code)
   101  
   102  		select {
   103  		case <-transmitter.Transmit(code, proto, o.PulseLength):
   104  			select {
   105  			case <-time.After(o.Delay):
   106  			case <-ctx.Done():
   107  				return nil
   108  			}
   109  
   110  		case <-ctx.Done():
   111  			return nil
   112  		}
   113  	}
   114  
   115  	if o.Infinite {
   116  		goto Loop
   117  	}
   118  
   119  	return nil
   120  }