gobot.io/x/gobot/v2@v2.1.0/drivers/aio/analog_sensor_driver.go (about)

     1  package aio
     2  
     3  import (
     4  	"time"
     5  
     6  	"gobot.io/x/gobot/v2"
     7  )
     8  
     9  // AnalogSensorDriver represents an Analog Sensor
    10  type AnalogSensorDriver struct {
    11  	name       string
    12  	pin        string
    13  	halt       chan bool
    14  	interval   time.Duration
    15  	connection AnalogReader
    16  	gobot.Eventer
    17  	gobot.Commander
    18  	rawValue int
    19  	value    float64
    20  	scale    func(input int) (value float64)
    21  }
    22  
    23  // NewAnalogSensorDriver returns a new AnalogSensorDriver with a polling interval of
    24  // 10 Milliseconds given an AnalogReader and pin.
    25  // The driver supports customizable scaling from read int value to returned float64.
    26  // The default scaling is 1:1. An adjustable linear scaler is provided by the driver.
    27  //
    28  // Optionally accepts:
    29  //
    30  //	time.Duration: Interval at which the AnalogSensor is polled for new information
    31  //
    32  // Adds the following API Commands:
    33  //
    34  //	"Read"    - See AnalogDriverSensor.Read
    35  //	"ReadRaw" - See AnalogDriverSensor.ReadRaw
    36  func NewAnalogSensorDriver(a AnalogReader, pin string, v ...time.Duration) *AnalogSensorDriver {
    37  	d := &AnalogSensorDriver{
    38  		name:       gobot.DefaultName("AnalogSensor"),
    39  		connection: a,
    40  		pin:        pin,
    41  		Eventer:    gobot.NewEventer(),
    42  		Commander:  gobot.NewCommander(),
    43  		interval:   10 * time.Millisecond,
    44  		halt:       make(chan bool),
    45  		scale:      func(input int) (value float64) { return float64(input) },
    46  	}
    47  
    48  	if len(v) > 0 {
    49  		d.interval = v[0]
    50  	}
    51  
    52  	d.AddEvent(Data)
    53  	d.AddEvent(Value)
    54  	d.AddEvent(Error)
    55  
    56  	d.AddCommand("Read", func(params map[string]interface{}) interface{} {
    57  		val, err := d.Read()
    58  		return map[string]interface{}{"val": val, "err": err}
    59  	})
    60  
    61  	d.AddCommand("ReadRaw", func(params map[string]interface{}) interface{} {
    62  		val, err := d.ReadRaw()
    63  		return map[string]interface{}{"val": val, "err": err}
    64  	})
    65  
    66  	return d
    67  }
    68  
    69  // Start starts the AnalogSensorDriver and reads the sensor at the given interval.
    70  // Emits the Events:
    71  //
    72  //	Data int - Event is emitted on change and represents the current raw reading from the sensor.
    73  //	Value float64 - Event is emitted on change and represents the current reading from the sensor.
    74  //	Error error - Event is emitted on error reading from the sensor.
    75  func (a *AnalogSensorDriver) Start() (err error) {
    76  	if a.interval == 0 {
    77  		// cyclic reading deactivated
    78  		return
    79  	}
    80  	var oldRawValue = 0
    81  	var oldValue = 0.0
    82  	go func() {
    83  		timer := time.NewTimer(a.interval)
    84  		timer.Stop()
    85  		for {
    86  			_, err := a.Read()
    87  			if err != nil {
    88  				a.Publish(a.Event(Error), err)
    89  			} else {
    90  				if a.rawValue != oldRawValue && a.rawValue != -1 {
    91  					a.Publish(a.Event(Data), a.rawValue)
    92  					oldRawValue = a.rawValue
    93  				}
    94  				if a.value != oldValue && a.value != -1 {
    95  					a.Publish(a.Event(Value), a.value)
    96  					oldValue = a.value
    97  				}
    98  			}
    99  
   100  			timer.Reset(a.interval)
   101  			select {
   102  			case <-timer.C:
   103  			case <-a.halt:
   104  				timer.Stop()
   105  				return
   106  			}
   107  		}
   108  	}()
   109  	return
   110  }
   111  
   112  // Halt stops polling the analog sensor for new information
   113  func (a *AnalogSensorDriver) Halt() (err error) {
   114  	if a.interval == 0 {
   115  		// cyclic reading deactivated
   116  		return
   117  	}
   118  	a.halt <- true
   119  	return
   120  }
   121  
   122  // Name returns the AnalogSensorDrivers name
   123  func (a *AnalogSensorDriver) Name() string { return a.name }
   124  
   125  // SetName sets the AnalogSensorDrivers name
   126  func (a *AnalogSensorDriver) SetName(n string) { a.name = n }
   127  
   128  // Pin returns the AnalogSensorDrivers pin
   129  func (a *AnalogSensorDriver) Pin() string { return a.pin }
   130  
   131  // Connection returns the AnalogSensorDrivers Connection
   132  func (a *AnalogSensorDriver) Connection() gobot.Connection { return a.connection.(gobot.Connection) }
   133  
   134  // Read returns the current reading from the sensor
   135  func (a *AnalogSensorDriver) Read() (val float64, err error) {
   136  	if a.rawValue, err = a.ReadRaw(); err != nil {
   137  		return
   138  	}
   139  	a.value = a.scale(a.rawValue)
   140  	return a.value, nil
   141  }
   142  
   143  // ReadRaw returns the current reading from the sensor without scaling
   144  func (a *AnalogSensorDriver) ReadRaw() (val int, err error) {
   145  	return a.connection.AnalogRead(a.Pin())
   146  }
   147  
   148  // SetScaler substitute the default 1:1 return value function by a new scaling function
   149  func (a *AnalogSensorDriver) SetScaler(scaler func(int) float64) {
   150  	a.scale = scaler
   151  }
   152  
   153  // Value returns the last read value from the sensor
   154  func (a *AnalogSensorDriver) Value() float64 {
   155  	return a.value
   156  }
   157  
   158  // RawValue returns the last read raw value from the sensor
   159  func (a *AnalogSensorDriver) RawValue() int {
   160  	return a.rawValue
   161  }
   162  
   163  // AnalogSensorLinearScaler creates a linear scaler function from the given values.
   164  func AnalogSensorLinearScaler(fromMin, fromMax int, toMin, toMax float64) func(input int) (value float64) {
   165  	m := (toMax - toMin) / float64(fromMax-fromMin)
   166  	n := toMin - m*float64(fromMin)
   167  	return func(input int) (value float64) {
   168  		if input <= fromMin {
   169  			return toMin
   170  		}
   171  		if input >= fromMax {
   172  			return toMax
   173  		}
   174  		return float64(input)*m + n
   175  	}
   176  }