Class: Denko::Sensor::HTU31D

Inherits:
Object
  • Object
show all
Includes:
Behaviors::Poller, I2C::Peripheral
Defined in:
lib/denko/sensor/htu31d.rb

Constant Summary collapse

RESET =

Commands

0x1E
RESET_TIME =

Reset time in seconds.

0.015
HEATER_ON =
0X04
HEATER_OFF =
0X02
READ_T_AND_H =

Returns 6 bytes: [T_MSB, T_LSB, T_CRC, H_MSB, H_LSB, H_CRC]

0x00
READ_H =

Returns 3 bytes: [H_MSB, H_LSB, H_CRC]

0x10
READ_SERIAL =

Returns 6 bytes: [S1, S1_CRC, S2, S2_CRC, S3, S3_CRC]

0x0A
READ_DIAGNOSTIC =

Returns 1 byte: [HEATER, T_LOW, T_HIGH, T_RUN, H_LOW, H_HIGH, H_RUN, NVM_ERR]

0x08
START_CONVERSION =

HEATER : Bit set if heater is turned on. T_LOW / T_HIGH : Bit set if temperature is outside range of -50 to 150 C. H_LOW / H_HIGH : Bit set if humidity is outside range of -10 to 120 % RH. T_RUN / H_RUN : Bit set if storage register under/overruns, truncated to min or max integer value. NVM_ERR : Bit set if internal CRC failed.

0x40
T_RESOLUTIONS =

User can give resolutions as integer from 0-3, as shown in the datasheet.

{
  0 => 0x00, # LSBIT = 0.040 C
  1 => 0x02, # LSBIT = 0.025 C
  2 => 0x04, # LSBIT = 0.016 C
  3 => 0x06, # LSBIT = 0.012 C
}
H_RESOLUTIONS =

LSBIT = 0.012 C

{
  0 => 0x00, # LSBIT = 0.020%
  1 => 0x08, # LSBIT = 0.014%
  2 => 0x10, # LSBIT = 0.010%
  3 => 0x18, # LSBIT = 0.007%
}
CONVERSION_SAFETY_FACTOR =

Leave some margin for error, since this doesn’t lock the bus during conversion like the HTU21D.

1.2
T_CONVERSION_TIMES =

Conversion times in seconds.

{
  0 => 0.00111 * CONVERSION_SAFETY_FACTOR,
  1 => 0.00214 * CONVERSION_SAFETY_FACTOR,
  2 => 0.00421 * CONVERSION_SAFETY_FACTOR,
  3 => 0.00834 * CONVERSION_SAFETY_FACTOR,
}
H_CONVERSION_TIMES =
{
  0 => 0.00157 * CONVERSION_SAFETY_FACTOR,
  1 => 0.00306 * CONVERSION_SAFETY_FACTOR,
  2 => 0.00603 * CONVERSION_SAFETY_FACTOR,
  3 => 0.01198 * CONVERSION_SAFETY_FACTOR,
}

Instance Attribute Summary

Attributes included from Behaviors::Threaded

#interrupts_enabled, #thread

Attributes included from Behaviors::Callbacks

#callback_mutex

Attributes included from I2C::Peripheral

#i2c_frequency, #i2c_repeated_start

Attributes included from Behaviors::BusPeripheral

#address

Attributes included from Behaviors::Component

#board

Instance Method Summary collapse

Methods included from Behaviors::Poller

#poll, #poll_using, #stop

Methods included from Behaviors::Threaded

#enable_interrupts, included, #stop, #stop_thread, #threaded, #threaded_loop

Methods included from Behaviors::Reader

#read, #read_using, #wait_for_read

Methods included from Behaviors::Callbacks

#add_callback, #callbacks, #initialize, #remove_callback, #update

Methods included from Behaviors::State

#initialize, #state

Methods included from I2C::Peripheral

#i2c_read, #i2c_write

Methods included from Behaviors::BusPeripheral

#atomically

Methods included from Behaviors::Component

#initialize, #micro_delay

Instance Method Details

#[](key) ⇒ Object



114
115
116
117
118
# File 'lib/denko/sensor/htu31d.rb', line 114

def [](key)
  @state_mutex.synchronize do
    return @state[key]
  end
end

#_readObject



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/denko/sensor/htu31d.rb', line 120

def _read
  # Calculate total conversion time.
  conversion_time = T_CONVERSION_TIMES[temperature_resolution] +
                    H_CONVERSION_TIMES[humidity_resolution]

  # Build the conversion command from the set resolutions.
  conversion_command = START_CONVERSION | T_RESOLUTIONS[temperature_resolution] | H_RESOLUTIONS[humidity_resolution]

  # Write it and sleep.
  i2c_write [conversion_command]
  sleep conversion_time

  # Write the read command and read back 6 bytes.
  i2c_read(READ_T_AND_H, 6)
end

#after_initialize(options = {}) ⇒ Object



61
62
63
64
65
66
67
68
69
70
# File 'lib/denko/sensor/htu31d.rb', line 61

def after_initialize(options={})
  super(options)

  # Avoid repeated memory allocation for callback data and state.
  @reading     = { temperature: nil, humidity: nil }
  self.state   = { temperature: nil, humidity: nil }
  @resolutions = { temperature: 0, humidity: 0 }

  reset
end

#before_initialize(options = {}) ⇒ Object



56
57
58
59
# File 'lib/denko/sensor/htu31d.rb', line 56

def before_initialize(options={})
  @i2c_address = 0x40
  super(options)
end

#calculate_crc(value) ⇒ Object

CRC calculation adapted from offical driver, found here: github.com/TEConnectivity/HTU21D_Generic_C_Driver/blob/master/htu21d.c#L275



171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/denko/sensor/htu31d.rb', line 171

def calculate_crc(value)
  polynomial = 0x988000   # x^8 + x^5 + x^4 + 1
  msb        = 0x800000
  mask       = 0xFF8000
  result     = value << 8 # Pad right with length of output CRC

  while msb != 0x80
    result = ((result ^ polynomial) & mask) | (result & ~mask) if (result & msb !=0)
    msb        >>= 1
    mask       >>= 1
    polynomial >>= 1
  end
  result
end

#heater_offObject



91
92
93
94
# File 'lib/denko/sensor/htu31d.rb', line 91

def heater_off
  i2c_write [HEATER_OFF]
  @heater_on = false
end

#heater_off?Boolean

Returns:

  • (Boolean)


82
83
84
# File 'lib/denko/sensor/htu31d.rb', line 82

def heater_off?
  !@heater_on
end

#heater_onObject



86
87
88
89
# File 'lib/denko/sensor/htu31d.rb', line 86

def heater_on
  i2c_write [HEATER_ON]
  @heater_on = true
end

#heater_on?Boolean

Returns:

  • (Boolean)


78
79
80
# File 'lib/denko/sensor/htu31d.rb', line 78

def heater_on?
  @heater_on
end

#humidity_resolutionObject



105
106
107
# File 'lib/denko/sensor/htu31d.rb', line 105

def humidity_resolution
  @resolutions[:humidity]
end

#humidity_resolution=(setting) ⇒ Object

Raises:

  • (ArgumentError)


109
110
111
112
# File 'lib/denko/sensor/htu31d.rb', line 109

def humidity_resolution=(setting)
  raise ArgumentError, "wrong resolution given: #{setting}. Must be in range 0..3" unless (0..3).include?(setting)
  @resolutions[:humidity] = setting
end

#pre_callback_filter(bytes) ⇒ Object



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/denko/sensor/htu31d.rb', line 136

def pre_callback_filter(bytes)
  # Bytes given as: [T_MSB, T_LSB, T_CRC, H_MSB, H_LSB, H_CRC]

  # Temperature
  t_raw = (bytes[0] << 8) | bytes[1]
  if calculate_crc(t_raw) != bytes[2]
    @reading[:temperature] = nil
  else
    @reading[:temperature] = (165 * t_raw.to_f / 65535) - 40
  end

  # Humidity
  h_raw = (bytes[3] << 8) | bytes[4]
  if calculate_crc(h_raw) != bytes[5]
    @reading[:humidity] = nil
  else
    @reading[:humidity] = h_raw.to_f / 655.35
  end

  # Ignore entire reading if either CRC failed.
  return nil unless (@reading[:temperature] && @reading[:humidity])
  @reading
end

#resetObject



72
73
74
75
76
# File 'lib/denko/sensor/htu31d.rb', line 72

def reset
  i2c_write [RESET]
  sleep RESET_TIME
  @heater_on = false
end

#temperature_resolutionObject



96
97
98
# File 'lib/denko/sensor/htu31d.rb', line 96

def temperature_resolution
  @resolutions[:temperature]
end

#temperature_resolution=(setting) ⇒ Object

Raises:

  • (ArgumentError)


100
101
102
103
# File 'lib/denko/sensor/htu31d.rb', line 100

def temperature_resolution=(setting)
  raise ArgumentError, "wrong resolution given: #{setting}. Must be in range 0..3" unless (0..3).include?(setting)
  @resolutions[:temperature] = setting
end

#update_state(reading) ⇒ Object



160
161
162
163
164
165
# File 'lib/denko/sensor/htu31d.rb', line 160

def update_state(reading)
  @state_mutex.synchronize do
    @state[:temperature] = reading[:temperature]
    @state[:humidity]    = reading[:humidity]
  end
end