Skip to content

Commit

Permalink
Merge pull request hybridgroup#352 from schmidtw/dev
Browse files Browse the repository at this point in the history
Add a driver for the sht3x chip.
  • Loading branch information
deadprogram authored Jan 3, 2017
2 parents dacb2e5 + 2fde08f commit 94207b4
Show file tree
Hide file tree
Showing 6 changed files with 498 additions and 0 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,4 @@ deps:
go get -d -v github.com/lazywei/go-opencv
go get -d -v github.com/donovanhide/eventsource
go get -d -v github.com/hashicorp/go-multierror
go get -d -v github.com/sigurn/crc8
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ drivers provided using the `gobot/drivers/i2c` package:
- MMA7660 3-Axis Accelerometer
- MPL115A2 Barometer
- MPU6050 Accelerometer/Gyroscope
- SHT3x-D Temperature/Humidity
- Wii Nunchuck Controller

More platforms and drivers are coming soon...
Expand Down
1 change: 1 addition & 0 deletions drivers/i2c/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Gobot has a extensible system for connecting to hardware devices. The following
- MMA7660 3-Axis Accelerometer
- MPL115A2 Barometer
- MPU6050 Accelerometer/Gyroscope
- SHT3x-D Temperature/Humidity
- Wii Nunchuck Controller

More drivers are coming soon...
218 changes: 218 additions & 0 deletions drivers/i2c/sht3x_driver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
/*
* Copyright (c) 2016-2017 Weston Schmidt <[email protected]>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package i2c

// SHT3xDriver is a driver for the SHT3x-D based devices.
//
// This module was tested with AdaFruit Sensiron SHT32-D Breakout.
// https://www.adafruit.com/products/2857

import (
"errors"
"github.com/sigurn/crc8"
"gobot.io/x/gobot"
"time"
)

// SHT3xAddressA is the default address of device
const SHT3xAddressA = 0x44

// SHT3xAddressB is the optional address of device
const SHT3xAddressB = 0x45

// SHT3xAccuracyLow is the faster, but lower accuracy sample setting
const SHT3xAccuracyLow = 0x16

// SHT3xAccuracyMedium is the medium accuracy and speed sample setting
const SHT3xAccuracyMedium = 0x0b

// SHT3xAccuracyHigh is the high accuracy and slowest sample setting
const SHT3xAccuracyHigh = 0x00

var (
crc8Params = crc8.Params{0x31, 0xff, false, false, 0x00, 0xf7, "CRC-8/SENSIRON"}
ErrInvalidAccuracy = errors.New("Invalid accuracy")
ErrInvalidCrc = errors.New("Invalid crc")
ErrInvalidTemp = errors.New("Invalid temperature units")
)

// SHT3xDriver is a Driver for a SHT3x humidity and temperature sensor
type SHT3xDriver struct {
Units string

name string
connection I2c
sht3xAddress int
accuracy byte
delay time.Duration
crcTable *crc8.Table
}

// NewSHT3xDriver creates a new driver with specified i2c interface
func NewSHT3xDriver(a I2c) *SHT3xDriver {
s := &SHT3xDriver{
Units: "C",
name: "SHT3x",
connection: a,
sht3xAddress: SHT3xAddressA,
crcTable: crc8.MakeTable(crc8Params),
}
s.SetAccuracy(SHT3xAccuracyHigh)
return s
}

// Name returns the name for this Driver
func (s *SHT3xDriver) Name() string { return s.name }

// SetName sets the name for this Driver
func (s *SHT3xDriver) SetName(n string) { s.name = n }

// Connection returns the connection for this Driver
func (s *SHT3xDriver) Connection() gobot.Connection { return s.connection.(gobot.Connection) }

// Start initializes the SHT3x
func (s *SHT3xDriver) Start() (err error) {
err = s.connection.I2cStart(s.sht3xAddress)
return
}

// Halt returns true if devices is halted successfully
func (s *SHT3xDriver) Halt() (err error) { return }

// SetAddress sets the address of the device
func (s *SHT3xDriver) SetAddress(address int) { s.sht3xAddress = address }

// Accuracy returns the accuracy of the sampling
func (s *SHT3xDriver) Accuracy() byte { return s.accuracy }

// SetAccuracy sets the accuracy of the sampling
func (s *SHT3xDriver) SetAccuracy(a byte) (err error) {
switch a {
case SHT3xAccuracyLow:
s.delay = 5 * time.Millisecond // Actual max is 4, wait 1 ms longer
case SHT3xAccuracyMedium:
s.delay = 7 * time.Millisecond // Actual max is 6, wait 1 ms longer
case SHT3xAccuracyHigh:
s.delay = 16 * time.Millisecond // Actual max is 15, wait 1 ms longer
default:
err = ErrInvalidAccuracy
return
}

s.accuracy = a

return
}

// SerialNumber returns the serial number of the chip
func (s *SHT3xDriver) SerialNumber() (sn uint32, err error) {
ret, err := s.sendCommandDelayGetResponse([]byte{0x37, 0x80}, nil, 2)
if nil == err {
sn = (uint32(ret[0]) << 16) | uint32(ret[1])
}

return
}

// Heater returns true if the heater is enabled
func (s *SHT3xDriver) Heater() (status bool, err error) {
sr, err := s.getStatusRegister()
if err == nil {
if (1 << 13) == (sr & (1 << 13)) {
status = true
}
}
return
}

// SetHeater enables or disables the heater on the device
func (s *SHT3xDriver) SetHeater(enabled bool) (err error) {
out := []byte{0x30, 0x66}
if true == enabled {
out[1] = 0x6d
}
return s.connection.I2cWrite(s.sht3xAddress, out)
}

// Sample returns the temperature in celsius and relative humidity for one sample
func (s *SHT3xDriver) Sample() (temp float32, rh float32, err error) {
ret, err := s.sendCommandDelayGetResponse([]byte{0x24, s.accuracy}, &s.delay, 2)
if nil != err {
return
}

// From the datasheet:
// RH = 100 * Srh / (2^16 - 1)
rhSample := uint64(ret[1])
rh = float32((uint64(1000000)*rhSample)/uint64(0xffff)) / 10000.0

tempSample := uint64(ret[0])
switch s.Units {
case "C":
// From the datasheet:
// T[C] = -45 + 175 * (St / (2^16 - 1))
temp = float32((uint64(1750000)*tempSample)/uint64(0xffff)-uint64(450000)) / 10000.0
case "F":
// From the datasheet:
// T[F] = -49 + 315 * (St / (2^16 - 1))
temp = float32((uint64(3150000)*tempSample)/uint64(0xffff)-uint64(490000)) / 10000.0
default:
err = ErrInvalidTemp
}

return
}

// getStatusRegister returns the device status register
func (s *SHT3xDriver) getStatusRegister() (status uint16, err error) {
ret, err := s.sendCommandDelayGetResponse([]byte{0xf3, 0x2d}, nil, 1)
if nil == err {
status = ret[0]
}
return
}

// sendCommandDelayGetResponse is a helper function to reduce duplicated code
func (s *SHT3xDriver) sendCommandDelayGetResponse(send []byte, delay *time.Duration, expect int) (read []uint16, err error) {
if err = s.connection.I2cWrite(s.sht3xAddress, send); err != nil {
return
}

if nil != delay {
time.Sleep(*delay)
}

got, err := s.connection.I2cRead(s.sht3xAddress, 3*expect)
if err != nil {
return
}
if len(got) != (3 * expect) {
err = ErrNotEnoughBytes
return
}

read = make([]uint16, expect)
for i := 0; i < expect; i++ {
crc := crc8.Checksum(got[i*3:i*3+2], s.crcTable)
if got[i*3+2] != crc {
err = ErrInvalidCrc
return
}
read[i] = uint16(got[i*3])<<8 | uint16(got[i*3+1])
}

return
}
Loading

0 comments on commit 94207b4

Please sign in to comment.