PKGBUILD/vendor/github.com/MichaelS11/go-dht/dht.go
2018-12-07 20:42:30 +01:00

197 lines
4.9 KiB
Go

package dht
import (
"fmt"
"time"
"periph.io/x/periph/host"
)
// HostInit calls periph.io host.Init(). This needs to be done before DHT can be used.
func HostInit() error {
_, err := host.Init()
return err
}
// Read reads the sensor once, returing humidity and temperature, or an error.
// Note that Read will sleep for at least 2 seconds between last call.
// Each reads error adds a half second to sleep time to max of 30 seconds.
func (dht *DHT) Read() (humidity float64, temperature float64, err error) {
// set sleepTime
var sleepTime time.Duration
if dht.numErrors < 57 {
sleepTime = (2 * time.Second) + (time.Duration(dht.numErrors) * 500 * time.Millisecond)
} else {
// sleep max of 30 seconds
sleepTime = 30 * time.Second
}
sleepTime -= time.Since(dht.lastRead)
// sleep between 2 and 30 seconds
time.Sleep(sleepTime)
// read bits from sensor
var bits []int
bits, err = dht.readBits()
if err != nil {
return
}
// covert bits to humidity and temperature
humidity, temperature, err = dht.bitsToValues(bits)
return
}
// bitsToValues will convert the bits into humidity and temperature values
func (dht *DHT) bitsToValues(bits []int) (humidity float64, temperature float64, err error) {
var sum8 uint8
var sumTotal uint8
var checkSum uint8
var i int
var humidityInt int
var temperatureInt int
// get humidityInt value
for i = 0; i < 16; i++ {
humidityInt = humidityInt << 1
humidityInt += bits[i]
// sum 8 bits for checkSum
sum8 = sum8 << 1
sum8 += uint8(bits[i])
if i == 7 || i == 15 {
// got 8 bits, add to sumTotal for checkSum
sumTotal += sum8
sum8 = 0
}
}
// get temperatureInt value
for i = 16; i < 32; i++ {
temperatureInt = temperatureInt << 1
temperatureInt += bits[i]
// sum 8 bits for checkSum
sum8 = sum8 << 1
sum8 += uint8(bits[i])
if i == 23 || i == 31 {
// got 8 bits, add to sumTotal for checkSum
sumTotal += sum8
sum8 = 0
}
}
// if high 16 bit is set, value is negtive
// 1000000000000000 = 0x8000
if (temperatureInt & 0x8000) > 0 {
// flip bits 16 and lower to get negtive number for int
// 1111111111111111 = 0xffff
temperatureInt |= ^0xffff
}
// get checkSum value
for i = 32; i < 40; i++ {
checkSum = checkSum << 1
checkSum += uint8(bits[i])
}
if dht.sensorType != "dht11" {
// humidity is between 0 % to 100 %
if humidityInt < 0 || humidityInt > 1000 {
err = fmt.Errorf("bad data - humidity: %v", humidityInt)
return
}
// temperature between -40 C to 80 C
if temperatureInt < -400 || temperatureInt > 800 {
err = fmt.Errorf("bad data - temperature: %v", temperatureInt)
return
}
// check checkSum
if checkSum != sumTotal {
err = fmt.Errorf("bad data - check sum fail")
}
humidity = float64(humidityInt) / 10.0
if dht.temperatureUnit == Celsius {
temperature = float64(temperatureInt) / 10.0
} else {
temperature = float64(temperatureInt)*9.0/50.0 + 32.0
}
return
}
// humidity is between 0 % to 100 %
if humidityInt < 0 || humidityInt > 100 {
err = fmt.Errorf("bad data - humidity: %v", humidityInt)
return
}
// temperature between 0 C to 50 C
if temperatureInt < 0 || temperatureInt > 50 {
err = fmt.Errorf("bad data - temperature: %v", temperatureInt)
return
}
// check checkSum
if checkSum != sumTotal {
err = fmt.Errorf("bad data - check sum fail")
}
humidity = float64(humidityInt)
if dht.temperatureUnit == Celsius {
temperature = float64(temperatureInt)
} else {
temperature = float64(temperatureInt)*9.0/5.0 + 32.0
}
return
}
// ReadRetry will call Read until there is no errors or the maxRetries is hit.
// Suggest maxRetries to be set around 11.
func (dht *DHT) ReadRetry(maxRetries int) (humidity float64, temperature float64, err error) {
for i := 0; i < maxRetries; i++ {
humidity, temperature, err = dht.Read()
if err == nil {
return
}
}
return
}
// ReadBackground it meant to be run in the background, run as a Goroutine.
// sleepDuration is how long it will try to sleep between reads.
// If there is ongoing read errors there will be no notice except that the values will not be updated.
// Will continue to read sensor until stop is closed.
// After it has been stopped, the stopped chan will be closed.
// Will panic if humidity, temperature, or stop are nil.
func (dht *DHT) ReadBackground(humidity *float64, temperature *float64, sleepDuration time.Duration, stop chan struct{}, stopped chan struct{}) {
var humidityTemp float64
var temperatureTemp float64
var err error
var startTime time.Time
Loop:
for {
startTime = time.Now()
humidityTemp, temperatureTemp, err = dht.Read()
if err == nil {
// no read error, save result
*humidity = humidityTemp
*temperature = temperatureTemp
// wait for sleepDuration or stop
select {
case <-time.After(sleepDuration - time.Since(startTime)):
case <-stop:
break Loop
}
} else {
// read error, just check for stop
select {
case <-stop:
break Loop
default:
}
}
}
close(stopped)
}