-
-
Notifications
You must be signed in to change notification settings - Fork 1k
/
bme280_driver.go
171 lines (143 loc) · 4.48 KB
/
bme280_driver.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
package i2c
import (
"bytes"
"encoding/binary"
"errors"
)
const bme280RegisterControlHumidity = 0xF2
const bme280RegisterHumidityMSB = 0xFD
const bme280RegisterCalibDigH1 = 0xa1
const bme280RegisterCalibDigH2LSB = 0xe1
type bmeHumidityCalibrationCoefficients struct {
h1 uint8
h2 int16
h3 uint8
h4 int16
h5 int16
h6 int8
}
// BME280Driver is a driver for the BME280 temperature/humidity sensor.
// It implements all of the same functions as the BMP280Driver, but also
// adds the Humidity() function by reading the BME280's humidity sensor.
// For details on the BMP280Driver please see:
// https://godoc.org/gobot.io/x/gobot/drivers/i2c#BMP280Driver
//
type BME280Driver struct {
*BMP280Driver
hc *bmeHumidityCalibrationCoefficients
}
// NewBME280Driver creates a new driver with specified i2c interface.
// Params:
// conn Connector - the Adaptor to use with this Driver
//
// Optional params:
// i2c.WithBus(int): bus to use with this driver
// i2c.WithAddress(int): address to use with this driver
//
func NewBME280Driver(c Connector, options ...func(Config)) *BME280Driver {
b := &BME280Driver{
BMP280Driver: NewBMP280Driver(c),
hc: &bmeHumidityCalibrationCoefficients{},
}
for _, option := range options {
option(b)
}
// TODO: expose commands to API
return b
}
// Start initializes the BME280 and loads the calibration coefficients.
func (d *BME280Driver) Start() (err error) {
bus := d.GetBusOrDefault(d.connector.GetDefaultBus())
address := d.GetAddressOrDefault(bmp180Address)
if d.connection, err = d.connector.GetConnection(address, bus); err != nil {
return err
}
if err := d.initialization(); err != nil {
return err
}
if err := d.initHumidity(); err != nil {
return err
}
return nil
}
// Humidity returns the current humidity in percentage of relative humidity
func (d *BME280Driver) Humidity() (humidity float32, err error) {
var rawH uint32
if rawH, err = d.rawHumidity(); err != nil {
return 0.0, err
}
humidity = d.calculateHumidity(rawH)
return
}
// read the humidity calibration coefficients.
func (d *BME280Driver) initHumidity() (err error) {
var coefficients []byte
if coefficients, err = d.read(bme280RegisterCalibDigH1, 1); err != nil {
return err
}
buf := bytes.NewBuffer(coefficients)
binary.Read(buf, binary.BigEndian, &d.hc.h1)
if coefficients, err = d.read(bme280RegisterCalibDigH2LSB, 7); err != nil {
return err
}
buf = bytes.NewBuffer(coefficients)
// H4 and H5 laid out strangely on the bme280
var addrE4 byte
var addrE5 byte
var addrE6 byte
binary.Read(buf, binary.LittleEndian, &d.hc.h2) // E1 ...
binary.Read(buf, binary.BigEndian, &d.hc.h3) // E3
binary.Read(buf, binary.BigEndian, &addrE4) // E4
binary.Read(buf, binary.BigEndian, &addrE5) // E5
binary.Read(buf, binary.BigEndian, &addrE6) // E6
binary.Read(buf, binary.BigEndian, &d.hc.h6) // ... E7
d.hc.h4 = 0 + (int16(addrE4) << 4) | (int16(addrE5 & 0x0F))
d.hc.h5 = 0 + (int16(addrE6) << 4) | (int16(addrE5) >> 4)
d.connection.WriteByteData(bme280RegisterControlHumidity, 0x3F)
// The 'ctrl_hum' register sets the humidity data acquisition options of
// the device. Changes to this register only become effective after a write
// operation to 'ctrl_meas'. Read the current value in, then write it back
var cmr uint8
cmr, err = d.connection.ReadByteData(bmp280RegisterControl)
if err == nil {
err = d.connection.WriteByteData(bmp280RegisterControl, cmr)
}
return err
}
func (d *BME280Driver) rawHumidity() (uint32, error) {
ret, err := d.read(bme280RegisterHumidityMSB, 2)
if err != nil {
return 0, err
}
if ret[0] == 0x80 && ret[1] == 0x00 {
return 0, errors.New("Humidity disabled")
}
buf := bytes.NewBuffer(ret)
var rawH uint16
binary.Read(buf, binary.BigEndian, &rawH)
return uint32(rawH), nil
}
// Adapted from https://github.com/BoschSensortec/BME280_driver/blob/master/bme280.c
// function bme280_compensate_humidity_double(s32 v_uncom_humidity_s32)
func (d *BME280Driver) calculateHumidity(rawH uint32) float32 {
var rawT int32
var err error
var h float32
rawT, err = d.rawTemp()
if err != nil {
return 0
}
_, tFine := d.calculateTemp(rawT)
h = float32(tFine) - 76800
if h == 0 {
return 0 // TODO err is 'invalid data' from Bosch - include errors or not?
}
x := float32(rawH) - (float32(d.hc.h4)*64.0 +
(float32(d.hc.h5) / 16384.0 * h))
y := float32(d.hc.h2) / 65536.0 *
(1.0 + float32(d.hc.h6)/67108864.0*h*
(1.0+float32(d.hc.h3)/67108864.0*h))
h = x * y
h = h * (1 - float32(d.hc.h1)*h/524288)
return h
}