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

     1  package aio
     2  
     3  import (
     4  	"math"
     5  	"time"
     6  
     7  	"gobot.io/x/gobot/v2"
     8  )
     9  
    10  const kelvinOffset = 273.15
    11  
    12  // TemperatureSensorNtcConf contains all attributes to calculate key parameters of a NTC thermistor.
    13  type TemperatureSensorNtcConf struct {
    14  	TC0 int     // °C
    15  	R0  float64 // same unit as resistance of NTC (Ohm is recommended)
    16  	B   float64 // 2000..5000K
    17  	TC1 int     // used if B is not given, °C
    18  	R1  float64 // used if B is not given, same unit as R0 needed
    19  	t0  float64
    20  	r   float64
    21  }
    22  
    23  // TemperatureSensorDriver represents an Analog Sensor
    24  type TemperatureSensorDriver struct {
    25  	*AnalogSensorDriver
    26  }
    27  
    28  // NewTemperatureSensorDriver is a gobot driver for analog temperature sensors
    29  // with a polling interval 10 Milliseconds given an AnalogReader and pin.
    30  // For further details please refer to AnalogSensorDriver.
    31  // Linear scaling and NTC scaling is supported.
    32  //
    33  // Optionally accepts:
    34  //
    35  //	time.Duration: Interval at which the sensor is polled for new information (given 0 switch the polling off)
    36  //
    37  // Adds the following API Commands:
    38  //
    39  //	"Read"      - See AnalogDriverSensor.Read
    40  //	"ReadValue" - See AnalogDriverSensor.ReadValue
    41  func NewTemperatureSensorDriver(a AnalogReader, pin string, v ...time.Duration) *TemperatureSensorDriver {
    42  	ad := NewAnalogSensorDriver(a, pin, v...)
    43  
    44  	d := &TemperatureSensorDriver{AnalogSensorDriver: ad}
    45  	d.SetName(gobot.DefaultName("TemperatureSensor"))
    46  
    47  	return d
    48  }
    49  
    50  // SetNtcScaler sets a function for typical NTC scaling the read value.
    51  // The read value is related to the voltage over the thermistor in an series connection to a resistor.
    52  // If the thermistor is connected to ground, the reverse flag must be set to true.
    53  // This means the voltage decreases when temperature gets higher.
    54  // Currently no negative values for voltage are supported.
    55  func (t *TemperatureSensorDriver) SetNtcScaler(vRef uint, rOhm uint, reverse bool, ntc TemperatureSensorNtcConf) {
    56  	t.SetScaler(TemperatureSensorNtcScaler(vRef, rOhm, reverse, ntc))
    57  }
    58  
    59  // SetLinearScaler sets a function for linear scaling the read value.
    60  // This can be applied for some silicon based PTC sensors or e.g. PT100,
    61  // and in a small temperature range also for NTC.
    62  func (t *TemperatureSensorDriver) SetLinearScaler(fromMin, fromMax int, toMin, toMax float64) {
    63  	t.SetScaler(AnalogSensorLinearScaler(fromMin, fromMax, toMin, toMax))
    64  }
    65  
    66  // TemperatureSensorNtcScaler creates a function for typical NTC scaling the read value.
    67  // The read value is related to the voltage over the thermistor in an series connection to a resistor.
    68  // If the thermistor is connected to ground, the reverse flag must be set to true.
    69  // This means the voltage decreases when temperature gets higher.
    70  // Currently no negative values for voltage are supported.
    71  func TemperatureSensorNtcScaler(vRef uint, rOhm uint, reverse bool, ntc TemperatureSensorNtcConf) func(input int) (value float64) {
    72  	ntc.initialize()
    73  	return (func(input int) (value float64) {
    74  		if input < 0 {
    75  			input = 0
    76  		}
    77  		rTherm := temperaturSensorGetResistance(uint(input), vRef, rOhm, reverse)
    78  		temp := ntc.getTemp(rTherm)
    79  		return temp
    80  	})
    81  }
    82  
    83  // getResistance calculates the value of the series thermistor by given value
    84  // and reference value (e.g. the voltage value over the complete series circuit)
    85  // The unit of the returned thermistor value equals the given series resistor unit.
    86  func temperaturSensorGetResistance(value uint, vRef uint, rSeries uint, reverse bool) float64 {
    87  	if value > vRef {
    88  		value = vRef
    89  	}
    90  	valDiff := vRef - value
    91  	if reverse {
    92  		//        rSeries  thermistor
    93  		// vRef o--|==|--o--|=/=|----| GND
    94  		//               |-> value <-|
    95  		if value == 0 {
    96  			// prevent jump to -273.15
    97  			value = 1
    98  		}
    99  		return float64(rSeries*value) / float64(valDiff)
   100  	}
   101  
   102  	//      thermistor  rSeries
   103  	// vRef o--|=/=|--o--|==|-----| GND
   104  	//                |-> value <-|
   105  	if valDiff == 0 {
   106  		// prevent jump to -273.15
   107  		valDiff = 1
   108  	}
   109  	return float64(rSeries*valDiff) / float64(value)
   110  }
   111  
   112  // getTemp calculates the temperature from the given resistance of the NTC resistor
   113  func (n *TemperatureSensorNtcConf) getTemp(rntc float64) float64 {
   114  	// 1/T = 1/T0 + 1/B * ln(R/R0)
   115  	//
   116  	// B/T = B/T0 + ln(R/R0) = k, B/T0 = r
   117  	// T = B/k, Tc = T - 273
   118  
   119  	k := n.r + math.Log(rntc/n.R0)
   120  	return n.B/k - kelvinOffset
   121  }
   122  
   123  // initialize is used to calculate some constants for the NTC algorithm.
   124  // If B is unknown (given as 0), the function needs a second pair to calculate
   125  // B from the both pairs (R1, TC1), (R0, TC0)
   126  func (n *TemperatureSensorNtcConf) initialize() {
   127  	n.t0 = float64(n.TC0) + kelvinOffset
   128  	if n.B <= 0 {
   129  		//B=[ln(R0)-ln(R1)]/(1/T0-1/T1)
   130  		T1 := float64(n.TC1) + kelvinOffset
   131  		n.B = (1/n.t0 - 1/T1)
   132  		n.B = (math.Log(n.R0) - math.Log(n.R1)) / n.B // 2000K...5000K
   133  	}
   134  	n.r = n.B / n.t0
   135  }