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
/
dhtNotWindows.go
153 lines (132 loc) · 4.19 KB
/
dhtNotWindows.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
//go:build !windows
// +build !windows
package dht
import (
"fmt"
"runtime/debug"
"strings"
"time"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/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)
// 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 than 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
}