gobot.io/x/gobot@v1.16.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 "gobot.io/x/gobot" 30 ) 31 32 // SHT3xAddressA is the default address of device 33 const SHT3xAddressA = 0x44 34 35 // SHT3xAddressB is the optional address of device 36 const SHT3xAddressB = 0x45 37 38 // SHT3xAccuracyLow is the faster, but lower accuracy sample setting 39 const SHT3xAccuracyLow = 0x16 40 41 // SHT3xAccuracyMedium is the medium accuracy and speed sample setting 42 const SHT3xAccuracyMedium = 0x0b 43 44 // SHT3xAccuracyHigh is the high accuracy and slowest sample setting 45 const SHT3xAccuracyHigh = 0x00 46 47 var ( 48 crc8Params = crc8.Params{0x31, 0xff, false, false, 0x00, 0xf7, "CRC-8/SENSIRON"} 49 ErrInvalidAccuracy = errors.New("Invalid accuracy") 50 ErrInvalidCrc = errors.New("Invalid crc") 51 ErrInvalidTemp = errors.New("Invalid temperature units") 52 ) 53 54 // SHT3xDriver is a Driver for a SHT3x humidity and temperature sensor 55 type SHT3xDriver struct { 56 Units string 57 58 name string 59 connector Connector 60 connection Connection 61 Config 62 sht3xAddress int 63 accuracy byte 64 delay time.Duration 65 crcTable *crc8.Table 66 } 67 68 // NewSHT3xDriver creates a new driver with specified i2c interface 69 // Params: 70 // conn Connector - the Adaptor to use with this Driver 71 // 72 // Optional params: 73 // i2c.WithBus(int): bus to use with this driver 74 // i2c.WithAddress(int): address to use with this driver 75 // 76 func NewSHT3xDriver(a Connector, options ...func(Config)) *SHT3xDriver { 77 s := &SHT3xDriver{ 78 Units: "C", 79 name: gobot.DefaultName("SHT3x"), 80 connector: a, 81 Config: NewConfig(), 82 sht3xAddress: SHT3xAddressA, 83 crcTable: crc8.MakeTable(crc8Params), 84 } 85 s.SetAccuracy(SHT3xAccuracyHigh) 86 87 for _, option := range options { 88 option(s) 89 } 90 91 return s 92 } 93 94 // Name returns the name for this Driver 95 func (s *SHT3xDriver) Name() string { return s.name } 96 97 // SetName sets the name for this Driver 98 func (s *SHT3xDriver) SetName(n string) { s.name = n } 99 100 // Connection returns the connection for this Driver 101 func (s *SHT3xDriver) Connection() gobot.Connection { return s.connector.(gobot.Connection) } 102 103 // Start initializes the SHT3x 104 func (s *SHT3xDriver) Start() (err error) { 105 bus := s.GetBusOrDefault(s.connector.GetDefaultBus()) 106 address := s.GetAddressOrDefault(s.sht3xAddress) 107 108 s.connection, err = s.connector.GetConnection(address, bus) 109 return 110 } 111 112 // Halt returns true if devices is halted successfully 113 func (s *SHT3xDriver) Halt() (err error) { return } 114 115 // SetAddress sets the address of the device 116 func (s *SHT3xDriver) SetAddress(address int) { s.sht3xAddress = address } 117 118 // Accuracy returns the accuracy of the sampling 119 func (s *SHT3xDriver) Accuracy() byte { return s.accuracy } 120 121 // SetAccuracy sets the accuracy of the sampling 122 func (s *SHT3xDriver) SetAccuracy(a byte) (err error) { 123 switch a { 124 case SHT3xAccuracyLow: 125 s.delay = 5 * time.Millisecond // Actual max is 4, wait 1 ms longer 126 case SHT3xAccuracyMedium: 127 s.delay = 7 * time.Millisecond // Actual max is 6, wait 1 ms longer 128 case SHT3xAccuracyHigh: 129 s.delay = 16 * time.Millisecond // Actual max is 15, wait 1 ms longer 130 default: 131 err = ErrInvalidAccuracy 132 return 133 } 134 135 s.accuracy = a 136 137 return 138 } 139 140 // SerialNumber returns the serial number of the chip 141 func (s *SHT3xDriver) SerialNumber() (sn uint32, err error) { 142 ret, err := s.sendCommandDelayGetResponse([]byte{0x37, 0x80}, nil, 2) 143 if nil == err { 144 sn = (uint32(ret[0]) << 16) | uint32(ret[1]) 145 } 146 147 return 148 } 149 150 // Heater returns true if the heater is enabled 151 func (s *SHT3xDriver) Heater() (status bool, err error) { 152 sr, err := s.getStatusRegister() 153 if err == nil { 154 if (1 << 13) == (sr & (1 << 13)) { 155 status = true 156 } 157 } 158 return 159 } 160 161 // SetHeater enables or disables the heater on the device 162 func (s *SHT3xDriver) SetHeater(enabled bool) (err error) { 163 out := []byte{0x30, 0x66} 164 if true == enabled { 165 out[1] = 0x6d 166 } 167 _, err = s.connection.Write(out) 168 return 169 } 170 171 // Sample returns the temperature in celsius and relative humidity for one sample 172 func (s *SHT3xDriver) Sample() (temp float32, rh float32, err error) { 173 ret, err := s.sendCommandDelayGetResponse([]byte{0x24, s.accuracy}, &s.delay, 2) 174 if nil != err { 175 return 176 } 177 178 // From the datasheet: 179 // RH = 100 * Srh / (2^16 - 1) 180 rhSample := uint64(ret[1]) 181 rh = float32((uint64(1000000)*rhSample)/uint64(0xffff)) / 10000.0 182 183 tempSample := uint64(ret[0]) 184 switch s.Units { 185 case "C": 186 // From the datasheet: 187 // T[C] = -45 + 175 * (St / (2^16 - 1)) 188 temp = float32((uint64(1750000)*tempSample)/uint64(0xffff)-uint64(450000)) / 10000.0 189 case "F": 190 // From the datasheet: 191 // T[F] = -49 + 315 * (St / (2^16 - 1)) 192 temp = float32((uint64(3150000)*tempSample)/uint64(0xffff)-uint64(490000)) / 10000.0 193 default: 194 err = ErrInvalidTemp 195 } 196 197 return 198 } 199 200 // getStatusRegister returns the device status register 201 func (s *SHT3xDriver) getStatusRegister() (status uint16, err error) { 202 ret, err := s.sendCommandDelayGetResponse([]byte{0xf3, 0x2d}, nil, 1) 203 if nil == err { 204 status = ret[0] 205 } 206 return 207 } 208 209 // sendCommandDelayGetResponse is a helper function to reduce duplicated code 210 func (s *SHT3xDriver) sendCommandDelayGetResponse(send []byte, delay *time.Duration, expect int) (read []uint16, err error) { 211 if _, err = s.connection.Write(send); err != nil { 212 return 213 } 214 215 if nil != delay { 216 time.Sleep(*delay) 217 } 218 219 buf := make([]byte, 3*expect) 220 got, err := s.connection.Read(buf) 221 if err != nil { 222 return 223 } 224 if got != (3 * expect) { 225 err = ErrNotEnoughBytes 226 return 227 } 228 229 read = make([]uint16, expect) 230 for i := 0; i < expect; i++ { 231 crc := crc8.Checksum(buf[i*3:i*3+2], s.crcTable) 232 if buf[i*3+2] != crc { 233 err = ErrInvalidCrc 234 return 235 } 236 read[i] = uint16(buf[i*3])<<8 | uint16(buf[i*3+1]) 237 } 238 239 return 240 }