package main import ( "fmt" "errors" "github.com/warthog618/gpio" "math" "time" ) const Timeout = math.MaxInt32 const TimeoutErrInitial string = "timed out waiting for sensor's initial %s reading" var oneSecondInCycles = (func() int { result := cyclesInAMillisecond() for i := 0; i < 100; i++ { result += cyclesInAMillisecond() } return result / 100 })() func cyclesInAMillisecond() int { count := 0 start := time.Now().UnixNano() for { count++ if time.Now().UnixNano() - start >= 1000000 { break } } return count } func main() { err := gpio.Open() if err != nil { panic(err) } defer gpio.Close() pinNumber := gpio.GPIO4 pin := gpio.NewPin(pinNumber) dhtData, err := readDataFromDHT(pin) if err != nil { fmt.Println(fmt.Sprintf("Bad read! Reason: %s!", err.Error())) } else { fmt.Println(convertToRhAndTemp(dhtData)) } } func readDataFromDHT(pin *gpio.Pin) ([5]byte, error) { // Setup pin.PullUp() time.Sleep(time.Second) // Send start signal pin.Low() pin.Output() time.Sleep(1100 * time.Microsecond) pin.Input() time.Sleep(40 * time.Microsecond) // Wait for high low signal if cyclesForReading(pin, gpio.Low) == Timeout { return [5]byte{}, errors.New(fmt.Sprintf(TimeoutErrInitial, "low")) } if cyclesForReading(pin, gpio.High) == Timeout { return [5]byte{}, errors.New(fmt.Sprintf(TimeoutErrInitial, "high")) } pulsesAsCycles := readPulsesAsCycles(pin) receivedInput, err := storeCycleCountsAsBinarySequence(&pulsesAsCycles) if err != nil { return [5]byte{}, err } return receivedInput, nil } func cyclesForReading(pin *gpio.Pin, level gpio.Level) int { count := 0 for pin.Read() == level { count++ if count >= oneSecondInCycles { return Timeout } } return count } func readPulsesAsCycles(pin *gpio.Pin) [80]int { cycles := [80]int{} for i := 0; i < 80; i += 2 { cycles[i] = cyclesForReading(pin, gpio.Low) cycles[i + 1] = cyclesForReading(pin, gpio.High) } return cycles } func storeCycleCountsAsBinarySequence(cycles *[80]int) ([5]byte, error) { data := [5]byte{} for i := 0; i < 40; i++ { lowCycles := cycles[2 * i] highCycles := cycles[2 * i + 1] if (lowCycles == Timeout) || (highCycles == Timeout) { return [5]byte{}, errors.New("timed out waiting for sensor pulse") } data[i / 8] <<= 1 if highCycles > lowCycles { data[i / 8] |= 1 } } return data, nil } func convertToRhAndTemp(data [5]byte) (float32, float32) { rh := float32(data[0]) + float32(int(data[1]) << 4) temp := float32(data[2]) + float32(int(data[3]) << 4) return rh/10, temp/10 }