Giter Club home page Giter Club logo

go-dht's Introduction

DHTxx temperature and humidity sensors

Build Status Go Report Card GoDoc MIT License

Preamble

All sensors supported by this library communicate with Raspberry PI via "single-wire digital interface". This approach is require very accurate synchronous timing. Raspberry PI hardware and its clones equipped with Linux - most massive and useful operating system (Linux is my favorite OS) - but not a real time system strictly speaking. It cannot guaranty that code (particularly user, not kernel layer code) might provide exact microsecond switching necessary to meet "single-wire digital interface" specification. Especially when you run this code from language whose runtime is based on background garbage collector processes, which might additionally raise "stop the world" phenomenon, when running code might unexpectedly freeze for a moment. Starting from Go 1.5 GC STW significantly improved, but still can affect millisecond/microsecond world.

So here is my recommendation - if you want to control sensors and peripheral devices from Golang environment running on Linux OS, go and buy sensors with I2C interface. I personally support such sensors in my hobby projects via I2C library (you can go and find list of supported devices in the middle).

But if you want to learn how signal processing algorithm attempt to work with "sinlge-wire digital interface" from not real time user code layer, go and find it!

About

DHT11 (pdf reference), AM2302/DHT22 (pdf reference) and DHT12 (pdf reference) sensors, which quite popular among Arduino, Raspberry PI developers (here you will find comparison DHT11 vs DHT22): dht11 and dht22

They are cheap enough and affordable. So, here is a code written in Go programming language for Raspberry PI and clones, which gives you at the output temperature and humidity values (making all necessary signal processing via their own 1-wire bus protocol behind the scene).

Technology overview

There are 2 methods how we can drive such devices which require special pins switch from low to high level and back (employing specific "1-wire protocol" described in pdf documentation):

  1. First approach implies to work on the most lower layer to handle pins via GPIO chip registers using Linux "memory mapped" device (/dev/mem). This approach is most reliable (until you move to other RPI clone) and fastest with regard to the transmission speed. Disadvantage of this method is explained by the fact that each RPI-clone have their own GPIO registers set to drive device GPIO pins.
  2. Second option implies to access GPIO pins via special layer based on Linux "device tree" approach (/sys/class/gpio/... virtual file system), which translate such operations to direct register writes and reads described in 1st approach. In some sense it is more compatible when you move from original Raspberry PI to RPI-clones, but may have some issues in stability of specific implementations. As it was found some clones don't implement this layer at all from the box (Beaglebone for instance).

So, here I'm using second approach.

Compatibility

Tested on Raspberry PI 1/2 (model B), Banana PI (model M1), Orange PI One.

Golang usage

func main() {
	// Read DHT11 sensor data from pin 4, retrying 10 times in case of failure.
	// You may enable "boost GPIO performance" parameter, if your device is old
	// as Raspberry PI 1 (this will require root privileges). You can switch off
	// "boost GPIO performance" parameter for old devices, but it may increase
	// retry attempts. Play with this parameter.
	// Note: "boost GPIO performance" parameter is not work anymore from some
	// specific Go release. Never put true value here.
	temperature, humidity, retried, err :=
		dht.ReadDHTxxWithRetry(dht.DHT11, 4, false, 10)
	if err != nil {
		log.Fatal(err)
	}
	// Print temperature and humidity
	fmt.Printf("Temperature = %v*C, Humidity = %v%% (retried %d times)\n",
		temperature, humidity, retried)
}

Installation

$ go get -u github.com/d2r2/go-dht

Quick start

There are two functions you could use: ReadDHTxx(...) and ReadDHTxxWithRetry(...). They both do exactly same thing - activate sensor then read and decode temperature and humidity values. The only thing which distinguish one from another - "retry count" parameter as additional argument in ReadDHTxxWithRetry(...). So, it's highly recommended to utilize ReadDHTxxWithRetry(...) with "retry count" not less than 7, since sensor asynchronous protocol is not very stable causing errors time to time. Each additional retry attempt takes 1.5-2 seconds (according to specification before repeated attempt you should wait 1-2 seconds).

This functionality works not only with Raspberry PI, but with counterparts as well (tested with Raspberry PI and Banana PI).

Note: This package does not have dependency on any sensor-specific 3-rd party C-code or library.

Tutorial

The library consists of 2 parts: low level C-code to send queries and read raw data from sensor and front-end Golang functions with raw data decoding.

Originally attempt was made to write whole library in Golang, but during debugging it was found that Garbage Collector (GC) "stop the world" characteristic in early version of Golang noticeably freeze library in the middle of sensor reading process, which lead to unpredictable mistakes when some signals from sensor just have been lost. Starting from Go 1.5 version GC behavior was improved significantly, but original design left as is, since it been tested and works reliably in most cases.

To install library on your Raspberry PI device you should execute console command go get -u github.com/d2r2/go-dht to download and install/update package to you device $GOPATH/src path.

You may start from simple test with DHTxx sensor using ./examples/example1/example1.go application which will interact with the sensor connected to some specific physical hardware pin (you may google pinout of any Raspberry PI version either its clones).

Also you can use cross compile technique, to build ARM application from x86/64bit system. For this your should install GCC tool-chain for ARM target platform. So, your x86/64bit Linux system should have specific gcc compiler installed: in case of Debian or Ubuntu arm-linux-gnueabi-gcc (in case of Arch Linux arm-linux-gnueabihf-gcc). After all, for instance, for cross compiling test application "./examples/example1/example1.go" to ARM target platform in Ubuntu/Debian you should run CC=arm-linux-gnueabi-gcc CGO_ENABLED=1 GOOS=linux GOARCH=arm GOARM=6 go build ./examples/example1/example1.go.

GoDoc documentation.

For detailed explanation read great article "Golang with Raspberry Pi : Read RH and Temperature from DHT22 or AM2302" written by Joseph Mathew. Thanks Joseph!

Contribute authors

Contact

Please use Github issue tracker for filing bugs or feature requests.

License

Go-dht is licensed under MIT License.

go-dht's People

Contributors

d2r2 avatar fank avatar gdunstone avatar ztc1997 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-dht's Issues

golint warnings

dht.go:19: exported type SensorType should have comment or be unexported
dht.go:22: receiver name should be a reflection of its identity; don't use generic
           names such as "this" or "self"
dht.go:35: comment on exported const DHT11 should be of the form "DHT11 ..."
dht.go:37: comment on exported const DHT22 should be of the form "DHT22 ..."
dht.go:39: comment on exported const AM2302 should be of the form "AM2302 ..."
dht.go:43: comment on exported type Pulse should be of the form "Pulse ..."
           (with optional leading article)
dht.go:55: should drop = 0 from declaration of var boost; it is the zero value
dht.go:83: should drop = 0 from declaration of var value; it is the zero value
dht.go:99: should drop = 0 from declaration of var b; it is the zero value
dht.go:109: don't use ALL_CAPS in Go names; use CamelCase
dht.go:112: don't use ALL_CAPS in Go names; use CamelCase
dht.go:175: if block ends with a return statement, so drop this else and outdent
            its block
dht.go:212: comment on exported function ReadDHTxx should be of the form
            "ReadDHTxx ..."
dht.go:243: comment on exported function ReadDHTxxWithRetry should be of the form 
            "ReadDHTxxWithRetry ..."
dht.go:280: error strings should not be capitalized or end with punctuation or a newline

These seem to be easy fixes, mind if I just do them?

Ubuntu Server 20.04.1 on Raspberry Pi 3B V2.1: "NewDHT error: pin out high error: sysfs-gpio (GPIO17): sysfs gpio is not initialized"

Hello!

I have been trying to use the first reading example in the code.

As said in the title I am using Ubuntu server 20.04 64bits. I have tested this on Ubuntu 20.10 also. Checked in all 64 and 32 bits editions.

The thermometer works on Raspbian just fine using this library but it doesn't on Ubuntu. This is the error:

[     dht] WARN  Error during call C.dial_DHTxx_and_read(): failed to open GPIO export for writing

The thermometer model is AOSONG AM2302

Do you know how this could be fixed?

Thanks a lot!

RPI Zero-W using pin 5..

First time posting so hopefully properly. Am experimenting w/RPI3s + several Zero Ws. Using DS18B20s on pin 4 (GPIO4) so DHT22 is connected to pin 5. Code snippet is:
humSensor := dht.DHT22
dht22Temp, dht22Humidity, _, err := dht.ReadDHTxxWithRetry (humSensor, 5, false, 10)

Code runs fine in RPI3 but errors on Zero. have swapped Zeros, 22s, all connector wires betw RPIs & breadboards, tried several resistor values. Errors I see are:
Failed to open gpio direction for writing!
2017-08-13T04:36:51.860 [dht] WARN Error during call C.dial_DHTxx_and_read()
2017-08-13T04:36:54.080 [dht] WARN Can't decode pulse array received from DHTxx sensor, since incorrect length: 79
2017-08-13T04:36:56.293 [dht] WARN High edge value duration 100µs exceed expected maximum amount 97µs
2017-08-13T04:36:58.502 [dht] WARN Control sum 221 doesn't match 115 (130+235+1+5)
2017-08-13T04:37:00.719 [dht] WARN Control sum 220 doesn't match 141 (129+214+17+37)
2017-08-13T04:37:02.937 [dht] WARN Humidity value exceed 100%: 149.4
2017-08-13T04:37:05.154 [dht] WARN High edge value duration 107µs exceed expected maximum amount 97µs
2017-08-13T04:37:07.361 [dht] WARN Control sum 158 doesn't match 0 (3+247+1+5)

Have lotsa experience w/various languages, etc, etc. But do not understand what the problem w/the Zeros is. Both Zeros do the same thing, so I'd guess it's cockpit error or (perhaps?) difference in Zero using the lib. Thanks in advance for your help and kindness.

Can't compile if set env for raspberry pi

If set env to
GOOS=linux GOARCH=arm GOARM=5
ind try to compile
go build ./examples/example1/example1.go
got error:
build command-line-arguments: cannot find module for path github.com/d2r2/go-shell

./dht.go.h:73:23: error: unknown type name 'int32_t'

Unable to build this in an alpine docker image.
Adding following "stdint.h" will fix it like redis/redis#336

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <sched.h>
#include <time.h>
#include <unistd.h>

Golang compiler warnings for functions

dht.go.h:304: warning: implicit declaration of function 'sched_setscheduler' is
              invalid in C99 [-Wimplicit-function-declaration]
dht.go.h:317: warning: implicit declaration of function 'sched_setscheduler' is
              invalid in C99 [-Wimplicit-function-declaration]

Code fails on RPI-Zero but not on RPI-3

Hi,

Tested on RPI 3B+, tried running on RPI-Zero and it fails with the following error:

Error during call C.dial_DHTxx_and_read(): failed to export pin 4

Any help much appreciated.

The driver would suddenly fatally exit after ten or more hours.

Hi. I tried to use the driver to detect the temperature in the indoor environment for days. However, it would always suddenly throw a fatal message after collecting the temperature data for ten or more hours. Is there anyway for ignoring this kind of outlier?

Error during call C.dial_DHTxx_and_read(): failed to open pin 22 direction for writing on Raspberry PI3

$ go version
go version go1.12.6 linux/arm

I've tried code from example1:

	sensorType := dht.AM2302
	pin := 22
	temperature, humidity, retried, err :=
		dht.ReadDHTxxWithRetry(sensorType, pin, false, 10)
	if err != nil {
		fmt.Println(err)
	}

	fmt.Println("Sensor = %v: Temperature = %v*C, Humidity = %v%% (retried %d times)",
		sensorType, temperature, humidity, retried)

compiled and run by:

GOARM=7 GOARCH=arm GOOS=linux go build -o main & ./main

got error:

Error during call C.dial_DHTxx_and_read(): failed to open pin 22 direction for writing

in the same time tried to use DHT from https://github.com/adafruit/Adafruit_Python_DHT (python lib) and it worked fine.

Also I've tried to connect to different pins, but got the same result -- works fine on python and doesn't work on golang lib :(.

Beaglebone question

Hi, I made small temperature service for my own use on beaglebone https://github.com/Gonzih/temperature-service. Originaly i wanted ot use your library but it did not work. I looked at Adafruit labrary https://github.com/adafruit/Adafruit_Python_DHT and main difference that I saw is /dev/gpiomem usage instead of /dev/mem on beaglebone. Do you think it is possible to adjust this labriary in a way that it will work on Beaglebone also? Their implementation should work on beaglebone black, but also works on my beaglebone white board.

Thanks!

fix compiler warnings

Hi, thanks for the lib - works great!
here's a patch to get rid of compiler warnings - I see these when cross-compiling to arm with
CC=arm-linux-gnueabi-gcc CGO_ENABLED=1 GOOS=linux GOARCH=arm GOARM=6 go build <app.go>

----------------------------------- dht.go.h -----------------------------------
index 6cda1e0..fc05c70 100644
@@ -7,6 +7,7 @@
#include <fcntl.h>
#include <sched.h>
#include <time.h>
+#include <unistd.h>

// GPIO direction: receive either output data to specific GPIO pin.
#define IN 0
@@ -52,7 +53,9 @@ static int gpio_export(int port, Pin *pin) {
}
(*pin).pin = port;
bytes_written = snprintf(buffer, BUFFER_MAX, "%d", (*pin).pin);

  • write(fd, buffer, bytes_written);
  • if (-1 == write(fd, buffer, bytes_written)){

  •    fprintf(stderr, "Failed to export pin!\n");
    
  • }
    close(fd);

    #define DIRECTION_MAX 35
    @@ -92,7 +95,9 @@ static int gpio_unexport(Pin *pin) {
    }

    bytes_written = snprintf(buffer, BUFFER_MAX, "%d", (*pin).pin);

  • write(fd, buffer, bytes_written);
  • if (-1 == write(fd, buffer, bytes_written)){
  •    fprintf(stderr, "Failed to unexport pin!\n");
    
  • }
    close(fd);
    return 0;
    }

On app termination long output of "2018/10/01 11:18:47 Signal received, cancel context" messages

As @jnovack report, app termination produce long output, which can contains hundreds/thousands of lines:

2018/10/01 11:18:47 Signal received, cancel context
2018/10/01 11:18:47 Signal received, cancel context
2018/10/01 11:18:47 Signal received, cancel context
2018/10/01 11:18:47 Signal received, cancel context

As it found each call to ReadDHTxxWithRetry left goroutine live and running inside of shell.CloseContextOnKillSignal(cancel) waiting for termination event.

pins could be 4 characters on 64bit RPIs

On my Raspberry Pi 3 (64bit kernel and userland) the pins are in the 4 character range (e.g. 2017 for GPIO23) according to kernel debug interface. But the library only uses the first two digits:

bytes_written = snprintf(buffer, BUFFER_MAX, "%d", pin->pin);

Writing manual a 2 digit number in the kernel interface with echo does not work (creates an error), but the "2017" does work.
Will fork the code and try to increase the buffer the next days when I have time again.

Installation failure on macOS

As documentation, I executed:
go get -u github.com/d2r2/go-dht

# github.com/d2r2/go-dht
In file included from ../../go/src/github.com/d2r2/go-dht/dht.go:3:
../../go/src/github.com/d2r2/go-dht/dht.go.h:304:15: warning: implicit declaration of function 'sched_setscheduler' is invalid in C99 [-Wimplicit-function-declaration]
# github.com/d2r2/go-dht
ld: library not found for -lrt
clang: error: linker command failed with exit code 1 (use -v to see invocation)

cross compilations techniques compile error

I try to read out the data of my DHT11 sensor using the example. My Golang code looks like this:

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/d2r2/go-dht"
)

func main() {
	temperature, humidity, err := dht.ReadDHTxx(dht.DHT11, 4, true)
	if err != nil {
		log.Fatal(err)
		os.Exit(1)
	}
	// Print temperature and humidity
	fmt.Printf("Temperature = %v*C, Humidity = %v%%\n", temperature, humidity)
}

I downloaded the lib via go get -u github.com/d2r2/go-dht.

Thereby compile the binary on my Arch Linux system. Therefore I give the ARM, OS and ARCH variables so that the binary is executable on the Pi. When compelling I get the following error:

markus@markus-pc:~/go/src/dht11-example$ GOARM=7 GOOS=linux GOARCH=arm go build
./main.go:17:32: undefined: dht.ReadDHTxx
./main.go:17:46: undefined: dht.DHT11

Does anyone have any idea what I'm doing wrong?

DHT11 Compatibility

So I created a fork of this project in an attempt to achieve a completely "go-only" implementatiton (I know, sue me, but I have my reasons).

I got everything working, but noticed that the errors I had periodically received warning of invalid array lengths were now much more frequent. When I started digging through the code, I noticed that the function gpio_read_seq_until_timeout sleeps for times not quite on par with the DHT11 single-wire communication bus specification, though mostly compatible with it's DHT22 counterpart.

My question is this: do these functions actually support the DHT11 communication bus? Are the delays in place somehow calculated to work for both DHTxx models?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.