diff --git a/drivers/i2c/th02_driver.go b/drivers/i2c/th02_driver.go new file mode 100644 index 00000000..efa87389 --- /dev/null +++ b/drivers/i2c/th02_driver.go @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2018 Nicholas Potts + * + * 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 + +// TH02Driver is a driver for the TH02-D based devices. +// +// This module was tested with a Grove Temperature and Humidty Sensor (High Accuracy) +// https://www.seeedstudio.com/Grove-Temperature-Humidity-Sensor-High-Accuracy-Min-p-1921.html + +import ( + "fmt" + "time" + + "gobot.io/x/gobot" +) + +// TH02Address is the default address of device +const TH02Address = 0x40 + +//TH02ConfigReg is the configuration register +const TH02ConfigReg = 0x03 + +// TH02HighAccuracyTemp is the CONFIG write value to start reading temperature +const TH02HighAccuracyTemp = 0x11 + +//TH02HighAccuracyRH is the CONFIG write value to start reading high accuracy RH +const TH02HighAccuracyRH = 0x01 + +// TH02Driver is a Driver for a TH02 humidity and temperature sensor +type TH02Driver struct { + Units string + name string + connector Connector + connection Connection + Config + addr byte + accuracy byte + delay time.Duration +} + +// NewTH02Driver 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 NewTH02Driver(a Connector, options ...func(Config)) *TH02Driver { + s := &TH02Driver{ + Units: "C", + name: gobot.DefaultName("TH02"), + connector: a, + addr: TH02Address, + Config: NewConfig(), + } + // s.SetAccuracy(TH02AccuracyHigh) + + for _, option := range options { + option(s) + } + + return s +} + +// Name returns the name for this Driver +func (s *TH02Driver) Name() string { return s.name } + +// SetName sets the name for this Driver +func (s *TH02Driver) SetName(n string) { s.name = n } + +// Connection returns the connection for this Driver +func (s *TH02Driver) Connection() gobot.Connection { return s.connector.(gobot.Connection) } + +// Start initializes the TH02 +func (s *TH02Driver) Start() (err error) { + bus := s.GetBusOrDefault(s.connector.GetDefaultBus()) + address := s.GetAddressOrDefault(int(s.addr)) + + s.connection, err = s.connector.GetConnection(address, bus) + return err +} + +// Halt returns true if devices is halted successfully +func (s *TH02Driver) Halt() (err error) { return } + +// SetAddress sets the address of the device +func (s *TH02Driver) SetAddress(address int) { s.addr = byte(address) } + +// SerialNumber returns the serial number of the chip +func (s *TH02Driver) SerialNumber() (sn uint32, err error) { + ret, err := s.readRegister(0x11) + return uint32(ret) >> 4, err +} + +// Sample returns the temperature in celsius and relative humidity for one sample +func (s *TH02Driver) Sample() (temp float32, rh float32, err error) { + if err := s.writeRegister(TH02ConfigReg, TH02HighAccuracyRH); err != nil { + return 0, 0, err + } + + rrh, err := s.readData() + if err != nil { + return 0, 0, err + } + rrh = rrh >> 4 + rh = float32(rrh)/16.0 - 24.0 + + if err := s.writeRegister(TH02ConfigReg, TH02HighAccuracyTemp); err != nil { + return 0, 0, err + } + + rt, err := s.readData() + if err != nil { + return 0, rh, err + } + rt = rt / 4 + temp = float32(rt)/32.0 - 50.0 + + switch s.Units { + case "F": + temp = 9.0/5.0 + 32.0 + } + + return temp, rh, nil + +} + +// getStatusRegister returns the device status register +func (s *TH02Driver) getStatusRegister() (status byte, err error) { + return s.readRegister(TH02ConfigReg) +} + +//writeRegister writes the value to the register. +func (s *TH02Driver) writeRegister(reg, value byte) error { + _, err := s.connection.Write([]byte{reg, value}) + return err +} + +//readRegister returns the value of a single regusterm and a non-nil error on problem +func (s *TH02Driver) readRegister(reg byte) (byte, error) { + if _, err := s.connection.Write([]byte{reg}); err != nil { + return 0, err + } + rcvd := make([]byte, 1) + _, err := s.connection.Read(rcvd) + return rcvd[0], err +} + +func (s *TH02Driver) waitForReady() error { + start := time.Now() + for { + if time.Since(start) > 100*time.Millisecond { + return fmt.Errorf("timeout on \\RDY") + } + reg, _ := s.readRegister(0x00) + if reg == 0 { + return nil + } + } +} + +func (s *TH02Driver) readData() (uint16, error) { + if err := s.waitForReady(); err != nil { + return 1, err + } + + if n, err := s.connection.Write([]byte{0x01}); err != nil || n != 1 { + return 0, fmt.Errorf("n=%d not 1, or err = %v", n, err) + } + rcvd := make([]byte, 3) + n, err := s.connection.Read(rcvd) + if err != nil || n != 3 { + return 0, fmt.Errorf("n=%d not 3, or err = %v", n, err) + } + return uint16(rcvd[1])<<8 + uint16(rcvd[2]), nil + +}