This repository has been archived by the owner on Dec 13, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 13
/
dht.go
196 lines (174 loc) · 4.92 KB
/
dht.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
package dht
import (
"fmt"
"time"
"periph.io/x/host/v3"
)
// 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)
}