mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-07-26 10:38:41 +00:00
158 lines
4.8 KiB
Go
158 lines
4.8 KiB
Go
//go:build tinygo
|
|
// +build tinygo
|
|
|
|
// 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"
|
|
)
|
|
|
|
// 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. Temperature method returns temperature as it is sent by device.
|
|
// The temperature is measured temperature in Celsius multiplied by 10.
|
|
// Depending on the UpdatePolicy of the device may update cached measurements.
|
|
func (m *managedDevice) Temperature() (temp int16, 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 temperature. TemperatureFloat returns temperature in a given scale.
|
|
// Depending on the UpdatePolicy of the device may update cached measurements.
|
|
func (m *managedDevice) TemperatureFloat(scale TemperatureScale) (float32, error) {
|
|
err := m.checkForUpdateOnDataRequest()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return m.t.TemperatureFloat(scale)
|
|
}
|
|
|
|
// 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
|
|
}
|