tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/dht/timesafethermometer.go (about) 1 //go:build tinygo 2 3 // Package dht provides a driver for DHTXX family temperature and humidity sensors. 4 // 5 // [1] Datasheet DHT11: https://www.mouser.com/datasheet/2/758/DHT11-Technical-Data-Sheet-Translated-Version-1143054.pdf 6 // [2] Datasheet DHT22: https://cdn-shop.adafruit.com/datasheets/Digital+humidity+and+temperature+sensor+AM2302.pdf 7 // Adafruit C++ driver: https://github.com/adafruit/DHT-sensor-library 8 9 package dht // import "tinygo.org/x/drivers/dht" 10 11 import ( 12 "machine" 13 "time" 14 ) 15 16 // Device interface provides main functionality of the DHTXX sensors. 17 type Device interface { 18 DummyDevice 19 Configure(policy UpdatePolicy) 20 } 21 22 // managedDevice struct provides time control and optional automatic data retrieval from the sensor. 23 // It delegates all the functionality to device 24 type managedDevice struct { 25 t device 26 lastUpdate time.Time 27 policy UpdatePolicy 28 } 29 30 // Measurements returns both measurements: temperature and humidity as they sent by the device. 31 // Depending on the UpdatePolicy of the device may update cached measurements. 32 func (m *managedDevice) Measurements() (temperature int16, humidity uint16, err error) { 33 err = m.checkForUpdateOnDataRequest() 34 if err != nil { 35 return 0, 0, err 36 } 37 return m.t.Measurements() 38 } 39 40 // Getter for temperature. Temperature method returns temperature as it is sent by device. 41 // The temperature is measured temperature in Celsius multiplied by 10. 42 // Depending on the UpdatePolicy of the device may update cached measurements. 43 func (m *managedDevice) Temperature() (temp int16, err error) { 44 err = m.checkForUpdateOnDataRequest() 45 if err != nil { 46 return 0, err 47 } 48 temp, err = m.t.Temperature() 49 return 50 } 51 52 func (m *managedDevice) checkForUpdateOnDataRequest() (err error) { 53 // update if necessary 54 if m.policy.UpdateAutomatically { 55 err = m.ReadMeasurements() 56 } 57 // ignore error if the data was updated recently 58 // interface comparison does not work in tinygo. Therefore need to cast to explicit type 59 if code, ok := err.(ErrorCode); ok && code == UpdateError { 60 err = nil 61 } 62 // add error if the data is not initialized 63 if !m.t.initialized { 64 err = UninitializedDataError 65 } 66 return err 67 } 68 69 // Getter for temperature. TemperatureFloat returns temperature in a given scale. 70 // Depending on the UpdatePolicy of the device may update cached measurements. 71 func (m *managedDevice) TemperatureFloat(scale TemperatureScale) (float32, error) { 72 err := m.checkForUpdateOnDataRequest() 73 if err != nil { 74 return 0, err 75 } 76 return m.t.TemperatureFloat(scale) 77 } 78 79 // Getter for humidity. Humidity returns humidity as it is sent by device. 80 // The humidity is measured in percentages multiplied by 10. 81 // Depending on the UpdatePolicy of the device may update cached measurements. 82 func (m *managedDevice) Humidity() (hum uint16, err error) { 83 err = m.checkForUpdateOnDataRequest() 84 if err != nil { 85 return 0, err 86 } 87 return m.t.Humidity() 88 } 89 90 // Getter for humidity. HumidityFloat returns humidity in percentages. 91 // Depending on the UpdatePolicy of the device may update cached measurements. 92 func (m *managedDevice) HumidityFloat() (float32, error) { 93 err := m.checkForUpdateOnDataRequest() 94 if err != nil { 95 return 0, err 96 } 97 return m.t.HumidityFloat() 98 } 99 100 // ReadMeasurements reads data from the sensor. 101 // The function will return UpdateError if it is called more frequently than specified in UpdatePolicy 102 func (m *managedDevice) ReadMeasurements() (err error) { 103 timestamp := time.Now() 104 if !m.t.initialized || timestamp.Sub(m.lastUpdate) > m.policy.UpdateTime { 105 err = m.t.ReadMeasurements() 106 } else { 107 err = UpdateError 108 } 109 if err == nil { 110 m.lastUpdate = timestamp 111 } 112 return 113 } 114 115 // Configure configures UpdatePolicy for Device. 116 // Configure checks for policy.UpdateTime and prevent from updating more frequently than specified in [1][2] 117 // to prevent undefined behaviour of the sensor. 118 func (m *managedDevice) Configure(policy UpdatePolicy) { 119 if policy.UpdateAutomatically && policy.UpdateTime < time.Second*2 { 120 policy.UpdateTime = time.Second * 2 121 } 122 m.policy = policy 123 } 124 125 // Constructor of the Device implementation. 126 // This implementation updates data every 2 seconds during data access. 127 func New(pin machine.Pin, deviceType DeviceType) Device { 128 pin.High() 129 return &managedDevice{ 130 t: device{ 131 pin: pin, 132 measurements: deviceType, 133 initialized: false, 134 }, 135 lastUpdate: time.Time{}, 136 policy: UpdatePolicy{ 137 UpdateTime: time.Second * 2, 138 UpdateAutomatically: true, 139 }, 140 } 141 } 142 143 // Constructor of the Device implementation with given UpdatePolicy 144 func NewWithPolicy(pin machine.Pin, deviceType DeviceType, updatePolicy UpdatePolicy) Device { 145 pin.High() 146 result := &managedDevice{ 147 t: device{ 148 pin: pin, 149 measurements: deviceType, 150 initialized: false, 151 }, 152 lastUpdate: time.Time{}, 153 } 154 result.Configure(updatePolicy) 155 return result 156 }