Публикация репозитория

This commit is contained in:
Victor Chapaev 2024-09-23 10:31:57 +03:00
commit eeb6ec46be
Signed by: victor
GPG Key ID: 05ACE065D1EC5CA4
10 changed files with 378 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
go.sum

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Chapvic
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

1
README.md Normal file
View File

@ -0,0 +1 @@
# Библиотека Go для чтения показаний датчиков DHT-11/22

9
cmd/check/main.go Normal file
View File

@ -0,0 +1,9 @@
package main
import (
"gitfox.ru/victor/go-dht"
)
func main() {
dht.ReadDHT_check(dht.GPIO_4)
}

15
cmd/example/main.go Normal file
View File

@ -0,0 +1,15 @@
package main
import (
"fmt"
"gitfox.ru/victor/go-dht"
"gitfox.ru/victor/go-wiringpi"
)
func main() {
if temp, hum, err := dht.ReadDHT(wiringpi.GPIO_4); err != nil {
fmt.Println(err)
} else {
fmt.Printf("Temperature: %.1f\nHumidity: %.1f\n", temp, hum)
}
}

99
dht.go Normal file
View File

@ -0,0 +1,99 @@
// Read temperature and humidity data from a DHT11/22 sensors on a Raspberry PI
package dht
import (
"errors"
"gitfox.ru/victor/go-wiringpi"
)
const (
ERR_SETUP_FAILED = "WiringPi setup failed!"
ERR_BAD_VALUE = "Bad value!"
MAX_TIMINGS = 85
BAD_VALUE = 999
DATA_SIZE = 5
DATA_BITS = DATA_SIZE * 8
)
var (
IterationCount = 10
QueryTimeout = uint(500)
)
/*
* Signal Sensor we're ready to read by pulling pin UP for 10 milliseconds,
* pulling pin down for 18 milliseconds and then back up for 40 microseconds
*/
func initDHT(pin int) {
/* Initialize sensor */
wiringpi.PinMode(pin, wiringpi.OUTPUT)
wiringpi.DigitalWrite(pin, wiringpi.HIGH)
wiringpi.Delay(10)
wiringpi.DigitalWrite(pin, wiringpi.LOW)
wiringpi.Delay(18)
wiringpi.DigitalWrite(pin, wiringpi.HIGH)
wiringpi.DelayMicroseconds(40)
/* Read data from pin. Look for a change in state. */
wiringpi.PinMode(pin, wiringpi.INPUT)
}
/*
* Check we read 40 bits (8bit x 5) + verify checksum in the last byte.
* Return it if data is good
*/
func decodeData(data [DATA_SIZE]int, bits int) (temperature float64, humidity float64, err error) {
if ((bits >= DATA_BITS) && (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF))) {
humidity = float64(((data[0] << 8) + data[1])) / 10
if (humidity > 100) {
humidity = float64(data[0]) // for DHT11
}
temperature = float64((((data[2] & 0x7F) << 8) + data[3])) / 10
if (temperature > 125) {
temperature = float64(data[2]) // for DHT11
}
if (data[2] & 0x80 == 0x80) {
temperature *= -1
}
return
}
return BAD_VALUE, BAD_VALUE, errors.New(ERR_BAD_VALUE)
}
func ReadDHT(pin int) (temperature float64, humidity float64, err error) {
/*
* Initialize WiringPi
*/
if err = wiringpi.Setup(); err != nil {
return 0, 0, errors.New(ERR_SETUP_FAILED)
}
data := [DATA_SIZE]int{} // Sensor data
bits := 0 // Bits read from sensor
/*
* Calling sequentially two algorithms with a repeat call if an error occurs.
* The maximum number of call iterations is 10 (IterationCount) with a delay of 100 ms (QueryTimeout)
*/
for n := 0; n < IterationCount; n++ {
if data, bits, err = read_dht_1(pin); err == nil {
if temperature, humidity, err = decodeData(data, bits); err == nil {
return
}
}
wiringpi.Delay(QueryTimeout)
if data, bits, err = read_dht_2(pin); err == nil {
if temperature, humidity, err = decodeData(data, bits); err == nil {
return
}
}
wiringpi.Delay(QueryTimeout)
}
return decodeData(data, bits)
}

44
dht_1.go Normal file
View File

@ -0,0 +1,44 @@
package dht
import (
"errors"
"gitfox.ru/victor/go-wiringpi"
)
func read_dht_1(pin int) (data [DATA_SIZE]int, bits int, err error) {
laststate := wiringpi.HIGH
counter := 0
initDHT(pin)
/* detect change and read data */
for i := 0; i < MAX_TIMINGS; i++ {
counter = 0
for (wiringpi.DigitalRead(pin) == laststate) {
counter++
wiringpi.DelayMicroseconds(2)
if (counter == 255) {
break
}
}
laststate = wiringpi.DigitalRead(pin)
if (counter == 255) {
break
}
/* ignore first 3 transitions */
if ((i >= 4) && (i % 2 == 0)) {
/* shove each bit into the storage bytes */
data[bits / 8] <<= 1
if (counter > 16) {
data[bits / 8] |= 1
}
bits++
}
}
if ((bits >= DATA_BITS) && (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF))) {
return
}
return data, bits, errors.New(ERR_BAD_VALUE)
}

136
dht_2.go Normal file
View File

@ -0,0 +1,136 @@
package dht
import (
"errors"
"gitfox.ru/victor/go-wiringpi"
)
func btoi(b bool) int {
if b {
return 1
}
return 0
}
func abs(n int) int {
if n < 0 {
n *= -1
}
return n
}
func decode_signals(duration [DATA_BITS]int) (result [DATA_BITS]bool) {
// The initial values for the centroids are the minimum and maximum
min := 0
max := 0
for i := range duration {
if (duration[i] < min) {
min = duration[i]
}
if (duration[i] > max) {
max = duration[i]
}
}
// This will always converge, so won't run infinitely
// Assignment step: assign each observation to the nearest centroid
for true {
nMap := [DATA_BITS]bool{}
for j := range nMap {
if ((abs(min - duration[j]) > abs(max - duration[j]))) {
nMap[j] = true
} else {
nMap[j] = false
}
}
// Update step: update the centroid location with the mean of the assigned observations
nMin := 0
nMax := 0
observations := 0
for j := range nMap {
observations += btoi(nMap[j])
if (nMap[j]) {
nMax += duration[j]
} else {
nMin += duration[j]
}
}
// Check for devision by zero
if observations == 0 {
nMax = 0
} else {
nMax /= observations
}
if (DATA_BITS - observations) == 0 {
nMin = 0
} else {
nMin /= DATA_BITS - observations
}
// Check convergence: k-means has converged if no assignments have changed
if nMap == result {
break
}
// Iterate: new values are now old
min = nMin
max = nMax
result = nMap
}
return
}
func read_dht_2(pin int) (data [DATA_SIZE]int, bits int, err error) {
lastState := wiringpi.HIGH
stateDuration := 0
stateChanges := 0
// Saved state duration
signalState := [DATA_BITS]int{}
initDHT(pin)
for stateChanges = 0; (stateChanges < MAX_TIMINGS) && (stateDuration < 255) && (bits < DATA_BITS); stateChanges++ {
stateDuration = 0
for true {
if ((wiringpi.DigitalRead(pin) == lastState) && (stateDuration < 255)) {
stateDuration++
wiringpi.DelayMicroseconds(1)
} else {
break
}
}
lastState = wiringpi.DigitalRead(pin)
// First 2 state changes are sensor signaling ready to send, ignore
// them. Each bit is preceeded by a state change to mark its
// beginning, ignore it too.
if ((stateChanges > 2) && (stateChanges % 2 == 0)) {
signalState[bits] = stateDuration
bits++
}
}
// Make sure if all 40 bits are read, otherwise return with a bad read
if (bits >= DATA_BITS) {
// Use the k-means decoder instead of the split one, as it's slightly more robust with neglible
// runtime increase
signalData := decode_signals(signalState)
for j := range signalData {
data[j / 8] <<= 1 // Each array element has 8 bits. Shift Left 1 bit.
if (signalData[j]) { // A state with a duration assigned to an upper cluster is a '1'
data[j / 8] |= 1
}
}
if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) {
return
}
}
return data, bits, errors.New(ERR_BAD_VALUE)
}

47
dht_check.go Normal file
View File

@ -0,0 +1,47 @@
package dht
import (
"fmt"
"errors"
"gitfox.ru/victor/go-wiringpi"
)
func ReadDHT_check(pin int) {
/*
* Initialize WiringPi
*/
if err := wiringpi.Setup(); err != nil {
return
}
data := [DATA_SIZE]int{} // Sensor data
bits := 0 // Bits read from sensor
temperature := float64(0)
humidity := float64(0)
err := error(nil)
/*
* Calling sequentially two algorithms with a repeat call if an error occurs.
* The maximum number of call iterations is 10 (IterationCount) with a delay of 100 ms (QueryTimeout)
*/
fmt.Printf("BEGIN\n")
for n := 1; n <= IterationCount; n++ {
data, bits, err = read_dht_1(pin)
temperature, humidity, err = decodeData(data, bits)
if err == nil {
err = errors.New("OK")
}
fmt.Printf("ITER: %d of %d, FN: 1 -> T: %.1f, H: %.1f (bits: %02d, error: %s)\n", n, IterationCount, temperature, humidity, bits, err)
wiringpi.Delay(QueryTimeout)
data, bits, err = read_dht_2(pin)
temperature, humidity, err = decodeData(data, bits)
if err == nil {
err = errors.New("OK")
}
fmt.Printf("ITER: %d of %d, FN: 2 -> T: %.1f, H: %.1f (bits: %02d, error: %s)\n", n, IterationCount, temperature, humidity, bits, err)
wiringpi.Delay(QueryTimeout)
}
fmt.Printf("END\n")
}

5
go.mod Normal file
View File

@ -0,0 +1,5 @@
module gitfox.ru/victor/go-dht
go 1.22
require gitfox.ru/victor/go-wiringpi v1.0.0