gobot.io/x/gobot@v1.16.0/drivers/i2c/sht2x_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  // SHT2xDriver is a driver for the SHT2x based devices.
    20  //
    21  // This module was tested with Sensirion SHT21 Breakout.
    22  
    23  import (
    24  	"errors"
    25  	"time"
    26  
    27  	"github.com/sigurn/crc8"
    28  	"gobot.io/x/gobot"
    29  )
    30  
    31  const (
    32  	// SHT2xDefaultAddress is the default I2C address for SHT2x
    33  	SHT2xDefaultAddress = 0x40
    34  
    35  	// SHT2xAccuracyLow is the faster, but lower accuracy sample setting
    36  	//  0/1 = 8bit RH, 12bit Temp
    37  	SHT2xAccuracyLow = byte(0x01)
    38  
    39  	// SHT2xAccuracyMedium is the medium accuracy and speed sample setting
    40  	//  1/0 = 10bit RH, 13bit Temp
    41  	SHT2xAccuracyMedium = byte(0x80)
    42  
    43  	// SHT2xAccuracyHigh is the high accuracy and slowest sample setting
    44  	//  0/0 = 12bit RH, 14bit Temp
    45  	//  Power on default is 0/0
    46  	SHT2xAccuracyHigh = byte(0x00)
    47  
    48  	// SHT2xTriggerTempMeasureHold is the command for measureing temperature in hold master mode
    49  	SHT2xTriggerTempMeasureHold = 0xe3
    50  
    51  	// SHT2xTriggerHumdMeasureHold is the command for measureing humidity in hold master mode
    52  	SHT2xTriggerHumdMeasureHold = 0xe5
    53  
    54  	// SHT2xTriggerTempMeasureNohold is the command for measureing humidity in no hold master mode
    55  	SHT2xTriggerTempMeasureNohold = 0xf3
    56  
    57  	// SHT2xTriggerHumdMeasureNohold is the command for measureing humidity in no hold master mode
    58  	SHT2xTriggerHumdMeasureNohold = 0xf5
    59  
    60  	// SHT2xWriteUserReg is the command for writing user register
    61  	SHT2xWriteUserReg = 0xe6
    62  
    63  	// SHT2xReadUserReg is the command for reading user register
    64  	SHT2xReadUserReg = 0xe7
    65  
    66  	// SHT2xReadUserReg is the command for reading user register
    67  	SHT2xSoftReset = 0xfe
    68  )
    69  
    70  // SHT2xDriver is a Driver for a SHT2x humidity and temperature sensor
    71  type SHT2xDriver struct {
    72  	Units string
    73  
    74  	name       string
    75  	connector  Connector
    76  	connection Connection
    77  	Config
    78  	sht2xAddress int
    79  	accuracy     byte
    80  	delay        time.Duration
    81  	crcTable     *crc8.Table
    82  }
    83  
    84  // NewSHT2xDriver creates a new driver with specified i2c interface
    85  // Params:
    86  //		conn Connector - the Adaptor to use with this Driver
    87  //
    88  // Optional params:
    89  //		i2c.WithBus(int):	bus to use with this driver
    90  //		i2c.WithAddress(int):	address to use with this driver
    91  //
    92  func NewSHT2xDriver(a Connector, options ...func(Config)) *SHT2xDriver {
    93  	// From the document "CRC Checksum Calculation -- For Safe Communication with SHT2x Sensors":
    94  	crc8Params := crc8.Params{0x31, 0x00, false, false, 0x00, 0x00, "CRC-8/SENSIRION-SHT2x"}
    95  	s := &SHT2xDriver{
    96  		Units:     "C",
    97  		name:      gobot.DefaultName("SHT2x"),
    98  		connector: a,
    99  		Config:    NewConfig(),
   100  		crcTable:  crc8.MakeTable(crc8Params),
   101  	}
   102  
   103  	for _, option := range options {
   104  		option(s)
   105  	}
   106  
   107  	return s
   108  }
   109  
   110  // Name returns the name for this Driver
   111  func (d *SHT2xDriver) Name() string { return d.name }
   112  
   113  // SetName sets the name for this Driver
   114  func (d *SHT2xDriver) SetName(n string) { d.name = n }
   115  
   116  // Connection returns the connection for this Driver
   117  func (d *SHT2xDriver) Connection() gobot.Connection { return d.connector.(gobot.Connection) }
   118  
   119  // Start initializes the SHT2x
   120  func (d *SHT2xDriver) Start() (err error) {
   121  	bus := d.GetBusOrDefault(d.connector.GetDefaultBus())
   122  	address := d.GetAddressOrDefault(SHT2xDefaultAddress)
   123  
   124  	if d.connection, err = d.connector.GetConnection(address, bus); err != nil {
   125  		return
   126  	}
   127  
   128  	if err = d.Reset(); err != nil {
   129  		return
   130  	}
   131  
   132  	d.sendAccuracy()
   133  
   134  	return
   135  }
   136  
   137  // Halt returns true if devices is halted successfully
   138  func (d *SHT2xDriver) Halt() (err error) { return }
   139  
   140  func (d *SHT2xDriver) Accuracy() byte { return d.accuracy }
   141  
   142  // SetAccuracy sets the accuracy of the sampling
   143  func (d *SHT2xDriver) SetAccuracy(acc byte) (err error) {
   144  	d.accuracy = acc
   145  
   146  	if d.connection != nil {
   147  		err = d.sendAccuracy()
   148  	}
   149  
   150  	return
   151  }
   152  
   153  // Reset does a software reset of the device
   154  func (d *SHT2xDriver) Reset() (err error) {
   155  	if err = d.connection.WriteByte(SHT2xSoftReset); err != nil {
   156  		return
   157  	}
   158  
   159  	time.Sleep(15 * time.Millisecond) // 15ms delay (from the datasheet 5.5)
   160  
   161  	return
   162  }
   163  
   164  // Temperature returns the current temperature, in celsius degrees.
   165  func (d *SHT2xDriver) Temperature() (temp float32, err error) {
   166  	var rawT uint16
   167  	if rawT, err = d.readSensor(SHT2xTriggerTempMeasureNohold); err != nil {
   168  		return
   169  	}
   170  
   171  	// From the datasheet 6.2:
   172  	// T[C] = -46.85 + 175.72 * St / 2^16
   173  	temp = -46.85 + 175.72/65536.0*float32(rawT)
   174  
   175  	return
   176  }
   177  
   178  // Humidity returns the current humidity in percentage of relative humidity
   179  func (d *SHT2xDriver) Humidity() (humidity float32, err error) {
   180  	var rawH uint16
   181  	if rawH, err = d.readSensor(SHT2xTriggerHumdMeasureNohold); err != nil {
   182  		return
   183  	}
   184  
   185  	// From the datasheet 6.1:
   186  	// RH = -6 + 125 * Srh / 2^16
   187  	humidity = -6.0 + 125.0/65536.0*float32(rawH)
   188  
   189  	return
   190  }
   191  
   192  // sendCommandDelayGetResponse is a helper function to reduce duplicated code
   193  func (d *SHT2xDriver) readSensor(cmd byte) (read uint16, err error) {
   194  	if err = d.connection.WriteByte(cmd); err != nil {
   195  		return
   196  	}
   197  
   198  	//Hang out while measurement is taken. 85ms max, page 9 of datasheet.
   199  	time.Sleep(85 * time.Millisecond)
   200  
   201  	//Comes back in three bytes, data(MSB) / data(LSB) / Checksum
   202  	buf := make([]byte, 3)
   203  	counter := 0
   204  	for {
   205  		var got int
   206  		got, err = d.connection.Read(buf)
   207  		counter++
   208  		if counter > 50 {
   209  			return
   210  		}
   211  		if err == nil {
   212  			if got != 3 {
   213  				err = ErrNotEnoughBytes
   214  				return
   215  			}
   216  			break
   217  		}
   218  		time.Sleep(1 * time.Millisecond)
   219  	}
   220  
   221  	//Store the result
   222  	crc := crc8.Checksum(buf[0:2], d.crcTable)
   223  	if buf[2] != crc {
   224  		err = errors.New("Invalid crc")
   225  		return
   226  	}
   227  	read = uint16(buf[0])<<8 | uint16(buf[1])
   228  	read &= 0xfffc // clear two low bits (status bits)
   229  
   230  	return
   231  }
   232  
   233  func (d *SHT2xDriver) sendAccuracy() (err error) {
   234  	if err = d.connection.WriteByte(SHT2xReadUserReg); err != nil {
   235  		return
   236  	}
   237  	userRegister, err := d.connection.ReadByte()
   238  	if err != nil {
   239  		return
   240  	}
   241  
   242  	userRegister &= 0x7e //Turn off the resolution bits
   243  	acc := d.accuracy
   244  	acc &= 0x81         //Turn off all other bits but resolution bits
   245  	userRegister |= acc //Mask in the requested resolution bits
   246  
   247  	//Request a write to user register
   248  	_, err = d.connection.Write([]byte{SHT2xWriteUserReg, userRegister})
   249  	if err != nil {
   250  		return
   251  	}
   252  
   253  	userRegister, err = d.connection.ReadByte()
   254  	if err != nil {
   255  		return
   256  	}
   257  
   258  	return
   259  }