mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-03 06:27:47 +00:00
6763521eff
This type should be used whenever a sensor (or actuator?) works with a
temperature. For example, this commit changes the signature:
ReadTemperature() (int32, error)
to the following:
ReadTemperature() (drivers.Temperature, error)
I believe this is much clearer in intent. It also makes it trivial to
introduce common conversions. For example, there are already Celsius()
and Fahrenheit() methods to convert to the given units, as a floating
point. More units could be added as needed, for example a CelsiusInt().
146 lines
4.3 KiB
Go
146 lines
4.3 KiB
Go
// Package dht provides a driver for DHTXX family temperature and humidity sensors.
|
|
//
|
|
// [1] Datasheet DHT11: https://www.mouser.com/datasheet/2/758/DHT11-Technical-Data-Sheet-Translated-Version-1143054.pdf
|
|
// [2] Datasheet DHT22: https://cdn-shop.adafruit.com/datasheets/Digital+humidity+and+temperature+sensor+AM2302.pdf
|
|
// Adafruit C++ driver: https://github.com/adafruit/DHT-sensor-library
|
|
|
|
package dht // import "tinygo.org/x/drivers/dht"
|
|
|
|
import (
|
|
"machine"
|
|
"time"
|
|
|
|
"tinygo.org/x/drivers"
|
|
)
|
|
|
|
// Device interface provides main functionality of the DHTXX sensors.
|
|
type Device interface {
|
|
DummyDevice
|
|
Configure(policy UpdatePolicy)
|
|
}
|
|
|
|
// managedDevice struct provides time control and optional automatic data retrieval from the sensor.
|
|
// It delegates all the functionality to device
|
|
type managedDevice struct {
|
|
t device
|
|
lastUpdate time.Time
|
|
policy UpdatePolicy
|
|
}
|
|
|
|
// Measurements returns both measurements: temperature and humidity as they sent by the device.
|
|
// Depending on the UpdatePolicy of the device may update cached measurements.
|
|
func (m *managedDevice) Measurements() (temperature int16, humidity uint16, err error) {
|
|
err = m.checkForUpdateOnDataRequest()
|
|
if err != nil {
|
|
return 0, 0, err
|
|
}
|
|
return m.t.Measurements()
|
|
}
|
|
|
|
// Getter for temperature. The temperature is returned in milli degrees Celsius.
|
|
// Depending on the UpdatePolicy of the device may update cached measurements.
|
|
func (m *managedDevice) Temperature() (temp drivers.Temperature, err error) {
|
|
err = m.checkForUpdateOnDataRequest()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
temp, err = m.t.Temperature()
|
|
return
|
|
}
|
|
|
|
func (m *managedDevice) checkForUpdateOnDataRequest() (err error) {
|
|
// update if necessary
|
|
if m.policy.UpdateAutomatically {
|
|
err = m.ReadMeasurements()
|
|
}
|
|
// ignore error if the data was updated recently
|
|
// interface comparison does not work in tinygo. Therefore need to cast to explicit type
|
|
if code, ok := err.(ErrorCode); ok && code == UpdateError {
|
|
err = nil
|
|
}
|
|
// add error if the data is not initialized
|
|
if !m.t.initialized {
|
|
err = UninitializedDataError
|
|
}
|
|
return err
|
|
}
|
|
|
|
// Getter for humidity. Humidity returns humidity as it is sent by device.
|
|
// The humidity is measured in percentages multiplied by 10.
|
|
// Depending on the UpdatePolicy of the device may update cached measurements.
|
|
func (m *managedDevice) Humidity() (hum uint16, err error) {
|
|
err = m.checkForUpdateOnDataRequest()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return m.t.Humidity()
|
|
}
|
|
|
|
// Getter for humidity. HumidityFloat returns humidity in percentages.
|
|
// Depending on the UpdatePolicy of the device may update cached measurements.
|
|
func (m *managedDevice) HumidityFloat() (float32, error) {
|
|
err := m.checkForUpdateOnDataRequest()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return m.t.HumidityFloat()
|
|
}
|
|
|
|
// ReadMeasurements reads data from the sensor.
|
|
// The function will return UpdateError if it is called more frequently than specified in UpdatePolicy
|
|
func (m *managedDevice) ReadMeasurements() (err error) {
|
|
timestamp := time.Now()
|
|
if !m.t.initialized || timestamp.Sub(m.lastUpdate) > m.policy.UpdateTime {
|
|
err = m.t.ReadMeasurements()
|
|
} else {
|
|
err = UpdateError
|
|
}
|
|
if err == nil {
|
|
m.lastUpdate = timestamp
|
|
}
|
|
return
|
|
}
|
|
|
|
// Configure configures UpdatePolicy for Device.
|
|
// Configure checks for policy.UpdateTime and prevent from updating more frequently than specified in [1][2]
|
|
// to prevent undefined behaviour of the sensor.
|
|
func (m *managedDevice) Configure(policy UpdatePolicy) {
|
|
if policy.UpdateAutomatically && policy.UpdateTime < time.Second*2 {
|
|
policy.UpdateTime = time.Second * 2
|
|
}
|
|
m.policy = policy
|
|
}
|
|
|
|
// Constructor of the Device implementation.
|
|
// This implementation updates data every 2 seconds during data access.
|
|
func New(pin machine.Pin, deviceType DeviceType) Device {
|
|
pin.High()
|
|
return &managedDevice{
|
|
t: device{
|
|
pin: pin,
|
|
measurements: deviceType,
|
|
initialized: false,
|
|
},
|
|
lastUpdate: time.Time{},
|
|
policy: UpdatePolicy{
|
|
UpdateTime: time.Second * 2,
|
|
UpdateAutomatically: true,
|
|
},
|
|
}
|
|
}
|
|
|
|
// Constructor of the Device implementation with given UpdatePolicy
|
|
func NewWithPolicy(pin machine.Pin, deviceType DeviceType, updatePolicy UpdatePolicy) Device {
|
|
pin.High()
|
|
result := &managedDevice{
|
|
t: device{
|
|
pin: pin,
|
|
measurements: deviceType,
|
|
initialized: false,
|
|
},
|
|
lastUpdate: time.Time{},
|
|
}
|
|
result.Configure(updatePolicy)
|
|
return result
|
|
}
|