├── readme.md └── dht22.go /readme.md: -------------------------------------------------------------------------------- 1 | Greetings do it yourselfers! 2 | 3 | It's AM2302/DHT22 library. No external c libraries. 4 | 5 | ## installation 6 | `go get github.com/morus12/dht22` 7 | 8 | ## usage 9 | ``` 10 | import "github.com/morus12/dht22" 11 | 12 | sensor := dht22.New("GPIO_17") 13 | temperature, err := sensor.Temperature() 14 | humidity, err := sensor.Humidity() 15 | ``` 16 | 17 | ## testing environmnet 18 | - Raspberry Pi 3 19 | - two DHT22 sensors 20 | - go1.7.5 linux/arm 21 | - Raspbian GNU/Linux 8 22 | 23 | Pi3 has 64 bit CPU, but system was setup on 32bit. Currently (Feb 2016) there is no official linux/arm64 kernel for Pi 3. -------------------------------------------------------------------------------- /dht22.go: -------------------------------------------------------------------------------- 1 | package dht22 2 | 3 | import ( 4 | "errors" 5 | "time" 6 | 7 | "github.com/kidoman/embd" 8 | _ "github.com/kidoman/embd/host/rpi" 9 | ) 10 | 11 | // AM2302/DHT22 - digital relative humidity and temperature sensor 12 | // https://cdn-shop.adafruit.com/datasheets/Digital+humidity+and+temperature+sensor+AM2302.pdf 13 | 14 | const ( 15 | COLLECTING_PERIOD = 2 * time.Second 16 | LOGICAL_1_TRESHOLD = 50 * time.Microsecond 17 | ) 18 | 19 | var ( 20 | ChecksumError = errors.New("checksum error") 21 | HumidityError = errors.New("humidity range error") 22 | TemperatureError = errors.New("temperature range error") 23 | ) 24 | 25 | type DHT22 struct { 26 | pin string 27 | temperature float32 28 | humidity float32 29 | readAt time.Time 30 | err error 31 | } 32 | 33 | func New(pin string) *DHT22 { 34 | return &DHT22{pin: pin} 35 | } 36 | 37 | func (d *DHT22) Temperature() (float32, error) { 38 | if err := d.read(); err != nil { 39 | d.err = err 40 | return 0, err 41 | } 42 | 43 | return d.temperature, nil 44 | } 45 | 46 | func (d *DHT22) Humidity() (float32, error) { 47 | if err := d.read(); err != nil { 48 | d.err = err 49 | return 0, err 50 | } 51 | 52 | return d.humidity, nil 53 | } 54 | 55 | func (d *DHT22) read() error { 56 | if d.readAt.Add(COLLECTING_PERIOD).After(time.Now()) { 57 | return d.err 58 | } 59 | 60 | d.err = nil 61 | 62 | d.readAt = time.Now() 63 | 64 | // early allocations before time critical code 65 | lengths := make([]time.Duration, 40) 66 | iterator := 0 67 | 68 | embd.InitGPIO() 69 | defer embd.CloseGPIO() 70 | 71 | pin, err := embd.NewDigitalPin(d.pin) 72 | if err != nil { 73 | return err 74 | } 75 | 76 | defer pin.Close() 77 | 78 | if err := pin.SetDirection(embd.Out); err != nil { 79 | return err 80 | } 81 | 82 | if err := pin.Write(embd.High); err != nil { 83 | return err 84 | } 85 | 86 | // send init values 87 | time.Sleep(250 * time.Millisecond) 88 | if err := pin.Write(embd.Low); err != nil { 89 | return err 90 | } 91 | 92 | time.Sleep(5 * time.Millisecond) 93 | 94 | if err := pin.Write(embd.High); err != nil { 95 | return err 96 | } 97 | 98 | time.Sleep(20 * time.Microsecond) 99 | 100 | if err := pin.SetDirection(embd.In); err != nil { 101 | return err 102 | } 103 | 104 | // read data 105 | for { 106 | duration, err := pin.TimePulse(embd.High) 107 | if err != nil { 108 | return err 109 | } 110 | lengths[iterator] = duration 111 | iterator++ 112 | if iterator >= 40 { 113 | break 114 | } 115 | } 116 | 117 | // convert to bytes 118 | bytes := make([]uint8, 5) 119 | 120 | for i := range bytes { 121 | for j := 0; j < 8; j++ { 122 | bytes[i] <<= 1 123 | if lengths[i*8+j] > LOGICAL_1_TRESHOLD { 124 | bytes[i] |= 0x01 125 | } 126 | } 127 | } 128 | 129 | if err := d.checksum(bytes); err != nil { 130 | if err != nil { 131 | return err 132 | } 133 | } 134 | 135 | var ( 136 | humidity uint16 137 | temperature uint16 138 | ) 139 | 140 | // calculate humidity 141 | 142 | humidity |= uint16(bytes[0]) 143 | humidity <<= 8 144 | humidity |= uint16(bytes[1]) 145 | 146 | if humidity < 0 || humidity > 1000 { 147 | return HumidityError 148 | } 149 | 150 | d.humidity = float32(humidity) / 10 151 | 152 | // calculate temperature 153 | temperature |= uint16(bytes[2]) 154 | temperature <<= 8 155 | temperature |= uint16(bytes[3]) 156 | 157 | // check for negative temperature 158 | if temperature&0x8000 > 0 { 159 | d.temperature = float32(temperature&0x7FFF) / -10 160 | } else { 161 | d.temperature = float32(temperature) / 10 162 | } 163 | 164 | // datasheet operating range 165 | if d.temperature < -40 || d.temperature > 80 { 166 | return TemperatureError 167 | } 168 | 169 | return nil 170 | } 171 | 172 | func (d *DHT22) checksum(bytes []uint8) error { 173 | var sum uint8 174 | 175 | for i := 0; i < 4; i++ { 176 | sum += bytes[i] 177 | } 178 | 179 | if sum != bytes[4] { 180 | return ChecksumError 181 | } 182 | 183 | return nil 184 | } 185 | --------------------------------------------------------------------------------