gobot.io/x/gobot/v2@v2.1.0/drivers/i2c/sht3x_driver.go (about) 1 /* 2 * Copyright (c) 2016-2017 Weston Schmidt <weston_schmidt@alumni.purdue.edu> 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package i2c 18 19 // SHT3xDriver is a driver for the SHT3x-D based devices. 20 // 21 // This module was tested with AdaFruit Sensiron SHT32-D Breakout. 22 // https://www.adafruit.com/products/2857 23 24 import ( 25 "errors" 26 "time" 27 28 "github.com/sigurn/crc8" 29 ) 30 31 // SHT3xAddressA is the default address of device 32 const SHT3xAddressA = 0x44 33 34 // SHT3xAddressB is the optional address of device 35 const SHT3xAddressB = 0x45 36 37 // SHT3xAccuracyLow is the faster, but lower accuracy sample setting 38 const SHT3xAccuracyLow = 0x16 39 40 // SHT3xAccuracyMedium is the medium accuracy and speed sample setting 41 const SHT3xAccuracyMedium = 0x0b 42 43 // SHT3xAccuracyHigh is the high accuracy and slowest sample setting 44 const SHT3xAccuracyHigh = 0x00 45 46 var ( 47 crc8Params = crc8.Params{ 48 Poly: 0x31, Init: 0xff, RefIn: false, RefOut: false, XorOut: 0x00, Check: 0xf7, Name: "CRC-8/SENSIRON", 49 } 50 ErrInvalidAccuracy = errors.New("Invalid accuracy") 51 ErrInvalidCrc = errors.New("Invalid crc") 52 ErrInvalidTemp = errors.New("Invalid temperature units") 53 ) 54 55 // SHT3xDriver is a Driver for a SHT3x humidity and temperature sensor 56 type SHT3xDriver struct { 57 *Driver 58 Units string 59 accuracy byte 60 delay time.Duration 61 crcTable *crc8.Table 62 } 63 64 // NewSHT3xDriver creates a new driver with specified i2c interface 65 // Params: 66 // c Connector - the Adaptor to use with this Driver 67 // 68 // Optional params: 69 // i2c.WithBus(int): bus to use with this driver 70 // i2c.WithAddress(int): address to use with this driver 71 // 72 func NewSHT3xDriver(c Connector, options ...func(Config)) *SHT3xDriver { 73 s := &SHT3xDriver{ 74 Driver: NewDriver(c, "SHT3x", SHT3xAddressA), 75 Units: "C", 76 crcTable: crc8.MakeTable(crc8Params), 77 } 78 s.SetAccuracy(SHT3xAccuracyHigh) 79 80 for _, option := range options { 81 option(s) 82 } 83 84 return s 85 } 86 87 // Accuracy returns the accuracy of the sampling 88 func (s *SHT3xDriver) Accuracy() byte { return s.accuracy } 89 90 // SetAccuracy sets the accuracy of the sampling 91 func (s *SHT3xDriver) SetAccuracy(a byte) (err error) { 92 switch a { 93 case SHT3xAccuracyLow: 94 s.delay = 5 * time.Millisecond // Actual max is 4, wait 1 ms longer 95 case SHT3xAccuracyMedium: 96 s.delay = 7 * time.Millisecond // Actual max is 6, wait 1 ms longer 97 case SHT3xAccuracyHigh: 98 s.delay = 16 * time.Millisecond // Actual max is 15, wait 1 ms longer 99 default: 100 err = ErrInvalidAccuracy 101 return 102 } 103 104 s.accuracy = a 105 106 return 107 } 108 109 // SerialNumber returns the serial number of the chip 110 func (s *SHT3xDriver) SerialNumber() (sn uint32, err error) { 111 ret, err := s.sendCommandDelayGetResponse([]byte{0x37, 0x80}, nil, 2) 112 if nil == err { 113 sn = (uint32(ret[0]) << 16) | uint32(ret[1]) 114 } 115 116 return 117 } 118 119 // Heater returns true if the heater is enabled 120 func (s *SHT3xDriver) Heater() (status bool, err error) { 121 sr, err := s.getStatusRegister() 122 if err == nil { 123 if (1 << 13) == (sr & (1 << 13)) { 124 status = true 125 } 126 } 127 return 128 } 129 130 // SetHeater enables or disables the heater on the device 131 func (s *SHT3xDriver) SetHeater(enabled bool) (err error) { 132 out := []byte{0x30, 0x66} 133 if enabled { 134 out[1] = 0x6d 135 } 136 _, err = s.connection.Write(out) 137 return 138 } 139 140 // Sample returns the temperature in celsius and relative humidity for one sample 141 func (s *SHT3xDriver) Sample() (temp float32, rh float32, err error) { 142 ret, err := s.sendCommandDelayGetResponse([]byte{0x24, s.accuracy}, &s.delay, 2) 143 if nil != err { 144 return 145 } 146 147 // From the datasheet: 148 // RH = 100 * Srh / (2^16 - 1) 149 rhSample := uint64(ret[1]) 150 rh = float32((uint64(1000000)*rhSample)/uint64(0xffff)) / 10000.0 151 152 tempSample := uint64(ret[0]) 153 switch s.Units { 154 case "C": 155 // From the datasheet: 156 // T[C] = -45 + 175 * (St / (2^16 - 1)) 157 temp = float32((uint64(1750000)*tempSample)/uint64(0xffff)-uint64(450000)) / 10000.0 158 case "F": 159 // From the datasheet: 160 // T[F] = -49 + 315 * (St / (2^16 - 1)) 161 temp = float32((uint64(3150000)*tempSample)/uint64(0xffff)-uint64(490000)) / 10000.0 162 default: 163 err = ErrInvalidTemp 164 } 165 166 return 167 } 168 169 // getStatusRegister returns the device status register 170 func (s *SHT3xDriver) getStatusRegister() (status uint16, err error) { 171 ret, err := s.sendCommandDelayGetResponse([]byte{0xf3, 0x2d}, nil, 1) 172 if nil == err { 173 status = ret[0] 174 } 175 return 176 } 177 178 // sendCommandDelayGetResponse is a helper function to reduce duplicated code 179 func (s *SHT3xDriver) sendCommandDelayGetResponse(send []byte, delay *time.Duration, expect int) (read []uint16, err error) { 180 if _, err = s.connection.Write(send); err != nil { 181 return 182 } 183 184 if nil != delay { 185 time.Sleep(*delay) 186 } 187 188 buf := make([]byte, 3*expect) 189 got, err := s.connection.Read(buf) 190 if err != nil { 191 return 192 } 193 if got != (3 * expect) { 194 err = ErrNotEnoughBytes 195 return 196 } 197 198 read = make([]uint16, expect) 199 for i := 0; i < expect; i++ { 200 crc := crc8.Checksum(buf[i*3:i*3+2], s.crcTable) 201 if buf[i*3+2] != crc { 202 err = ErrInvalidCrc 203 return 204 } 205 read[i] = uint16(buf[i*3])<<8 | uint16(buf[i*3+1]) 206 } 207 208 return 209 }