add: humidity (WIP)

This commit is contained in:
2018-12-04 19:11:50 +01:00
parent ba9f0c59f3
commit 81600154f0
141 changed files with 18562 additions and 4 deletions

21
vendor/github.com/MichaelS11/go-dht/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 MichaelS11
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

144
vendor/github.com/MichaelS11/go-dht/README.md generated vendored Normal file
View File

@ -0,0 +1,144 @@
# Go DHT22 / AM2302 / DHT11 interface
Golang DHT22 / AM2302 / DHT11 interface using periph.io driver
[![GoDoc Reference](https://godoc.org/github.com/MichaelS11/go-dht?status.svg)](http://godoc.org/github.com/MichaelS11/go-dht)
[![Go Report Card](https://goreportcard.com/badge/github.com/MichaelS11/go-dht)](https://goreportcard.com/report/github.com/MichaelS11/go-dht)
## Please note
Please make sure to setup your DHT22 / AM2302 / DHT11 correctly. Do a search on the internet to find guide. Here is an example of a guide:
https://learn.adafruit.com/dht/connecting-to-a-dhtxx-sensor
The examples below are from using a Raspberry Pi 3 with GPIO 19 for the pin. Your setup may be different, if so, your pin names would need to change in each example.
Side note, in my testing the sensor has a fairly high level of read errors, suggest using ReadRetry or ReadBackground rather then just Read.
Tested on Raspberry Pi 3 with AM2302. Please open an issue if there are any issues.
## Get
go get github.com/MichaelS11/go-dht
## ReadRetry example
```go
package main
import (
"fmt"
"github.com/MichaelS11/go-dht"
)
func main() {
err := dht.HostInit()
if err != nil {
fmt.Println("HostInit error:", err)
return
}
dht, err := dht.NewDHT("GPIO19", dht.Fahrenheit, "")
if err != nil {
fmt.Println("NewDHT error:", err)
return
}
humidity, temperature, err := dht.ReadRetry(11)
if err != nil {
fmt.Println("Read error:", err)
return
}
fmt.Printf("humidity: %v\n", humidity)
fmt.Printf("temperature: %v\n", temperature)
}
```
## ReadBackground example
```go
package main
import (
"fmt"
"time"
"github.com/MichaelS11/go-dht"
)
func main() {
err := dht.HostInit()
if err != nil {
fmt.Println("HostInit error:", err)
return
}
dht, err := dht.NewDHT("GPIO19", dht.Fahrenheit, "")
if err != nil {
fmt.Println("NewDHT error:", err)
return
}
stop := make(chan struct{})
stopped := make(chan struct{})
var humidity float64
var temperature float64
// get sensor reading every 20 seconds in background
go dht.ReadBackground(&humidity, &temperature, 20*time.Second, stop, stopped)
// should have at least read the sensor twice after 30 seconds
time.Sleep(30 * time.Second)
fmt.Printf("humidity: %v\n", humidity)
fmt.Printf("temperature: %v\n", temperature)
// to stop ReadBackground after done with reading, close the stop channel
close(stop)
// can check stopped channel to know when ReadBackground has stopped
<-stopped
}
```
## Read example
```go
package main
import (
"fmt"
"github.com/MichaelS11/go-dht"
)
func main() {
err := dht.HostInit()
if err != nil {
fmt.Println("HostInit error:", err)
return
}
dht, err := dht.NewDHT("GPIO19", dht.Fahrenheit, "")
if err != nil {
fmt.Println("NewDHT error:", err)
return
}
humidity, temperature, err := dht.Read()
if err != nil {
fmt.Println("Read error:", err)
return
}
fmt.Printf("humidity: %v\n", humidity)
fmt.Printf("temperature: %v\n", temperature)
}
```

196
vendor/github.com/MichaelS11/go-dht/dht.go generated vendored Normal file
View File

@ -0,0 +1,196 @@
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)
}

155
vendor/github.com/MichaelS11/go-dht/dhtNotWindows.go generated vendored Normal file
View File

@ -0,0 +1,155 @@
// +build !windows
package dht
import (
"fmt"
"log"
"runtime/debug"
"strings"
"time"
"periph.io/x/periph/conn/gpio"
"periph.io/x/periph/conn/gpio/gpioreg"
)
// NewDHT to create a new DHT struct.
// sensorType is dht11 for DHT11, anything else for AM2302 / DHT22.
func NewDHT(pinName string, temperatureUnit TemperatureUnit, sensorType string) (*DHT, error) {
dht := &DHT{temperatureUnit: temperatureUnit}
// set sensorType
sensorType = strings.ToLower(sensorType)
if sensorType == "dht11" {
dht.sensorType = "dht11"
}
// get pin
dht.pin = gpioreg.ByName(pinName)
if dht.pin == nil {
return nil, fmt.Errorf("pin is nill")
}
// set pin to high so ready for first read
err := dht.pin.Out(gpio.High)
if err != nil {
return nil, fmt.Errorf("pin out high error: %v", err)
}
// set lastRead a second before to give the pin a second to warm up
dht.lastRead = time.Now().Add(-1 * time.Second)
return dht, nil
}
// readBits will get the bits for humidity and temperature
func (dht *DHT) readBits() ([]int, error) {
// create variables ahead of time before critical timing part
var i int
var startTime time.Time
var levelPrevious gpio.Level
var level gpio.Level
levels := make([]gpio.Level, 0, 84)
durations := make([]time.Duration, 0, 84)
// set lastRead so do not read more than once every 2 seconds
dht.lastRead = time.Now()
// disable garbage collection during critical timing part
gcPercent := debug.SetGCPercent(-1)
// send start low
err := dht.pin.Out(gpio.Low)
if err != nil {
dht.pin.Out(gpio.High)
return nil, fmt.Errorf("pin out low error: %v", err)
}
time.Sleep(time.Millisecond)
// send start high
err = dht.pin.In(gpio.PullUp, gpio.NoEdge)
if err != nil {
dht.pin.Out(gpio.High)
return nil, fmt.Errorf("pin in error: %v", err)
}
// read levels and durations with busy read
// hope there is a better way in the future
// tried to use WaitForEdge but seems to miss edges and/or take too long to detect them
// note that pin read takes around .2 microsecond (us) on Raspberry PI 3
// note that 1000 microsecond (us) = 1 millisecond (ms)
levelPrevious = dht.pin.Read()
level = levelPrevious
for i = 0; i < 84; i++ {
startTime = time.Now()
for levelPrevious == level && time.Since(startTime) < time.Millisecond {
level = dht.pin.Read()
}
durations = append(durations, time.Since(startTime))
levels = append(levels, levelPrevious)
levelPrevious = level
}
// enable garbage collection, done with critical part
debug.SetGCPercent(gcPercent)
log.Printf("%v\n", levels)
// set pin to high so ready for next time
err = dht.pin.Out(gpio.High)
if err != nil {
return nil, fmt.Errorf("pin out high error: %v", err)
}
// get last low reading so know start of data
var endNumber int
for i = len(levels) - 1; ; i-- {
if levels[i] == gpio.Low {
endNumber = i
break
}
if i < 80 {
// not enough readings, i = 79 means endNumber is 78 or less
return nil, fmt.Errorf("missing some readings - low level not found")
}
}
startNumber := endNumber - 79
// covert pulses into bits and check high levels
bits := make([]int, 40)
index := 0
for i = startNumber; i < endNumber; i += 2 {
// check high levels
if levels[i] != gpio.High {
return nil, fmt.Errorf("missing some readings - level not high")
}
// high should not be longer then 90 microseconds
if durations[i] > 90*time.Microsecond {
return nil, fmt.Errorf("missing some readings - high level duration too long: %v", durations[i])
}
// bit is 0 if less than or equal to 30 microseconds
if durations[i] > 30*time.Microsecond {
// bit is 1 if more than 30 microseconds
bits[index] = 1
}
index++
}
// check low levels
for i = startNumber + 1; i < endNumber+1; i += 2 {
// check low levels
if levels[i] != gpio.Low {
return nil, fmt.Errorf("missing some readings - level not low")
}
// low should not be longer then 70 microseconds
if durations[i] > 70*time.Microsecond {
return nil, fmt.Errorf("missing some readings - low level duration too long: %v", durations[i])
}
// low should not be shorter then 35 microseconds
if durations[i] < 35*time.Microsecond {
return nil, fmt.Errorf("missing some readings - low level duration too short: %v", durations[i])
}
}
return bits, nil
}

35
vendor/github.com/MichaelS11/go-dht/dhtWindows.go generated vendored Normal file
View File

@ -0,0 +1,35 @@
// +build windows
package dht
import (
"strings"
"time"
)
// NewDHT to create a new DHT struct.
// sensorType is dht11 for DHT11, anything else for AM2302 / DHT22.
func NewDHT(pinName string, temperatureUnit TemperatureUnit, sensorType string) (*DHT, error) {
dht := &DHT{temperatureUnit: temperatureUnit}
// set sensorType
sensorType = strings.ToLower(sensorType)
if sensorType == "dht11" {
dht.sensorType = "dht11"
}
// set lastRead a second before to give the pin a second to warm up
dht.lastRead = time.Now().Add(-1 * time.Second)
return dht, nil
}
// readBits will get the bits for humidity and temperature
func (dht *DHT) readBits() ([]int, error) {
// set lastRead so do not read more than once every 2 seconds
dht.lastRead = time.Now()
bits := make([]int, 40)
return bits, nil
}

27
vendor/github.com/MichaelS11/go-dht/globals.go generated vendored Normal file
View File

@ -0,0 +1,27 @@
package dht
import (
"time"
"periph.io/x/periph/conn/gpio"
)
// TemperatureUnit is the temperature unit wanted, either Celsius or Fahrenheit
type TemperatureUnit int
const (
// Celsius temperature unit
Celsius TemperatureUnit = iota
// Fahrenheit temperature unit
Fahrenheit
)
// DHT struct to interface with the sensor.
// Call NewDHT to create a new one.
type DHT struct {
pin gpio.PinIO
temperatureUnit TemperatureUnit
sensorType string
numErrors int
lastRead time.Time
}