#-----------------------------------------------------------------------------
# qwiic_bme280.py
#
# Python library for the SparkFun qwiic BME280 sensor.
#
# This sensor is available on the SparkFun Environmental Combo Breakout board.
# https://www.sparkfun.com/products/14348
#
#------------------------------------------------------------------------
#
# Written by SparkFun Electronics, May 2019
#
# This python library supports the SparkFun Electroncis qwiic
# qwiic sensor/board ecosystem
#
# More information on qwiic is at https:// www.sparkfun.com/qwiic
#
# Do you like this library? Help support SparkFun. Buy a board!
#==================================================================================
# Copyright (c) 2019 SparkFun Electronics
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#==================================================================================
#
# This is mostly a port of existing Arduino functionaly, so pylint is sad.
# The goal is to keep the public interface pthonic, but internal is internal
#
# pylint: disable=line-too-long, bad-whitespace, invalid-name, too-many-public-methods
#
"""
qwiic_bme280
============
Python module for the qwiic bme280 sensor, which is part of the [SparkFun Qwiic Environmental Combo Breakout](https://www.sparkfun.com/products/14348)
This python package is a port of the existing [SparkFun BME280 Arduino Library](https://github.com/sparkfun/SparkFun_BME280_Arduino_Library)
This package can be used in conjunction with the overall [SparkFun qwiic Python Package](https://github.com/sparkfun/Qwiic_Py)
New to qwiic? Take a look at the entire [SparkFun qwiic ecosystem](https://www.sparkfun.com/qwiic).
"""
#-----------------------------------------------------------------------------
from __future__ import print_function
import math
import qwiic_i2c
# Define the device name and I2C addresses. These are set in the class defintion
# as class variables, making them avilable without having to create a class instance.
# This allows higher level logic to rapidly create a index of qwiic devices at
# runtine
#
# The name of this device
_DEFAULT_NAME = "Qwiic BME280"
# Some devices have multiple availabel addresses - this is a list of these addresses.
# NOTE: The first address in this list is considered the default I2C address for the
# device.
_AVAILABLE_I2C_ADDRESS = [0x77, 0x76]
# Default Setting Values
_settings = {"runMode" : 3, \
"tStandby" : 0, \
"filter" : 0, \
"tempOverSample" : 1, \
"pressOverSample" : 1, \
"humidOverSample" : 1, \
"tempCorrection" : 0.0}
# define our valid chip IDs
_validChipIDs = [0x58, 0x60]
# define the class that encapsulates the device being created. All information associated with this
# device is encapsulated by this class. The device class should be the only value exported
# from this module.
[docs]class QwiicBme280(object):
"""
QwiicBme280
:param address: The I2C address to use for the device.
If not provided, the default address is used.
:param i2c_driver: An existing i2c driver object. If not provided
a driver object is created.
:return: The BME280 device object.
:rtype: Object
"""
# Constructor
device_name =_DEFAULT_NAME
available_addresses = _AVAILABLE_I2C_ADDRESS
# mode flags for the device - user exposed
MODE_SLEEP = 0b00
MODE_FORCED = 0b01
MODE_NORMAL = 0b11
# Register names for the BME280
BME280_DIG_T1_LSB_REG = 0x88
BME280_DIG_T1_MSB_REG = 0x89
BME280_DIG_T2_LSB_REG = 0x8A
BME280_DIG_T2_MSB_REG = 0x8B
BME280_DIG_T3_LSB_REG = 0x8C
BME280_DIG_T3_MSB_REG = 0x8D
BME280_DIG_P1_LSB_REG = 0x8E
BME280_DIG_P1_MSB_REG = 0x8F
BME280_DIG_P2_LSB_REG = 0x90
BME280_DIG_P2_MSB_REG = 0x91
BME280_DIG_P3_LSB_REG = 0x92
BME280_DIG_P3_MSB_REG = 0x93
BME280_DIG_P4_LSB_REG = 0x94
BME280_DIG_P4_MSB_REG = 0x95
BME280_DIG_P5_LSB_REG = 0x96
BME280_DIG_P5_MSB_REG = 0x97
BME280_DIG_P6_LSB_REG = 0x98
BME280_DIG_P6_MSB_REG = 0x99
BME280_DIG_P7_LSB_REG = 0x9A
BME280_DIG_P7_MSB_REG = 0x9B
BME280_DIG_P8_LSB_REG = 0x9C
BME280_DIG_P8_MSB_REG = 0x9D
BME280_DIG_P9_LSB_REG = 0x9E
BME280_DIG_P9_MSB_REG = 0x9F
BME280_DIG_H1_REG = 0xA1
BME280_CHIP_ID_REG = 0xD0 # Chip ID
BME280_RST_REG = 0xE0 # Softreset Reg
BME280_DIG_H2_LSB_REG = 0xE1
BME280_DIG_H2_MSB_REG = 0xE2
BME280_DIG_H3_REG = 0xE3
BME280_DIG_H4_MSB_REG = 0xE4
BME280_DIG_H4_LSB_REG = 0xE5
BME280_DIG_H5_MSB_REG = 0xE6
BME280_DIG_H6_REG = 0xE7
BME280_CTRL_HUMIDITY_REG = 0xF2 # Ctrl Humidity Reg
BME280_STAT_REG = 0xF3 # Status Reg
BME280_CTRL_MEAS_REG = 0xF4 # Ctrl Measure Reg
BME280_CONFIG_REG = 0xF5 # Configuration Reg
BME280_PRESSURE_MSB_REG = 0xF7 # Pressure MSB
BME280_PRESSURE_LSB_REG = 0xF8 # Pressure LSB
BME280_PRESSURE_XLSB_REG = 0xF9 # Pressure XLSB
BME280_TEMPERATURE_MSB_REG = 0xFA # Temperature MSB
BME280_TEMPERATURE_LSB_REG = 0xFB # Temperature LSB
BME280_TEMPERATURE_XLSB_REG = 0xFC # Temperature XLSB
BME280_HUMIDITY_MSB_REG = 0xFD # Humidity MSB
BME280_HUMIDITY_LSB_REG = 0xFE # Humidity LSB
# Constructor
def __init__(self, address=None, i2c_driver=None):
# Did the user specify an I2C address?
self.address = self.available_addresses[0] if address is None else address
# load the I2C driver if one isn't provided
if i2c_driver is None:
self._i2c = qwiic_i2c.getI2CDriver()
if self._i2c is None:
print("Unable to load I2C driver for this platform.")
return
else:
self._i2c = i2c_driver
# create a dictionary to stash our calibration data for the sensor
self.calibration={}
self.t_fine=0
self._referencePressure = 101325.0
# ----------------------------------
# is_connected()
#
# Is an actual board connected to our system?
[docs] def is_connected(self):
"""
Determine if a BME280 device is conntected to the system..
:return: True if the device is connected, otherwise False.
:rtype: bool
"""
return qwiic_i2c.isDeviceConnected(self.address)
connected = property(is_connected)
# ----------------------------------
# begin()
#
# Initialize the system/validate the board.
[docs] def begin(self):
"""
Initialize the operation of the BME280 module
:return: Returns true of the initializtion was successful, otherwise False.
:rtype: bool
"""
# are we who we need to be?
chipID = self._i2c.readByte(self.address, self.BME280_CHIP_ID_REG)
if chipID not in _validChipIDs:
print("Invalid Chip ID: 0x%.2X" % chipID)
return False
# Reading all compensation data, range 0x88:A1, 0xE1:E7
self.calibration["dig_T1"] = (self._i2c.readByte(self.address, self.BME280_DIG_T1_MSB_REG) << 8) + self._i2c.readByte(self.address, self.BME280_DIG_T1_LSB_REG)
self.calibration["dig_T2"] = (self._i2c.readByte(self.address, self.BME280_DIG_T2_MSB_REG) << 8) + self._i2c.readByte(self.address, self.BME280_DIG_T2_LSB_REG)
self.calibration["dig_T3"] = (self._i2c.readByte(self.address, self.BME280_DIG_T3_MSB_REG) << 8) + self._i2c.readByte(self.address, self.BME280_DIG_T3_LSB_REG)
self.calibration["dig_P1"] = (self._i2c.readByte(self.address, self.BME280_DIG_P1_MSB_REG) << 8) + self._i2c.readByte(self.address, self.BME280_DIG_P1_LSB_REG)
self.calibration["dig_P2"] = (self._i2c.readByte(self.address, self.BME280_DIG_P2_MSB_REG) << 8) + self._i2c.readByte(self.address, self.BME280_DIG_P2_LSB_REG)
self.calibration["dig_P3"] = (self._i2c.readByte(self.address, self.BME280_DIG_P3_MSB_REG) << 8) + self._i2c.readByte(self.address, self.BME280_DIG_P3_LSB_REG)
self.calibration["dig_P4"] = (self._i2c.readByte(self.address, self.BME280_DIG_P4_MSB_REG) << 8) + self._i2c.readByte(self.address, self.BME280_DIG_P4_LSB_REG)
self.calibration["dig_P5"] = (self._i2c.readByte(self.address, self.BME280_DIG_P5_MSB_REG) << 8) + self._i2c.readByte(self.address, self.BME280_DIG_P5_LSB_REG)
self.calibration["dig_P6"] = (self._i2c.readByte(self.address, self.BME280_DIG_P6_MSB_REG) << 8) + self._i2c.readByte(self.address, self.BME280_DIG_P6_LSB_REG)
self.calibration["dig_P7"] = (self._i2c.readByte(self.address, self.BME280_DIG_P7_MSB_REG) << 8) + self._i2c.readByte(self.address, self.BME280_DIG_P7_LSB_REG)
self.calibration["dig_P8"] = (self._i2c.readByte(self.address, self.BME280_DIG_P8_MSB_REG) << 8) + self._i2c.readByte(self.address, self.BME280_DIG_P8_LSB_REG)
self.calibration["dig_P9"] = (self._i2c.readByte(self.address, self.BME280_DIG_P9_MSB_REG) << 8) + self._i2c.readByte(self.address, self.BME280_DIG_P9_LSB_REG)
self.calibration["dig_H1"] = self._i2c.readByte(self.address, self.BME280_DIG_H1_REG)
self.calibration["dig_H2"] = (self._i2c.readByte(self.address, self.BME280_DIG_H2_MSB_REG) << 8) + self._i2c.readByte(self.address, self.BME280_DIG_H2_LSB_REG)
self.calibration["dig_H3"] = self._i2c.readByte(self.address, self.BME280_DIG_H3_REG)
self.calibration["dig_H4"] = (self._i2c.readByte(self.address, self.BME280_DIG_H4_MSB_REG) << 4) + (self._i2c.readByte(self.address, self.BME280_DIG_H4_LSB_REG) & 0x0F)
self.calibration["dig_H5"] = (self._i2c.readByte(self.address, self.BME280_DIG_H5_MSB_REG) << 4) + ((self._i2c.readByte(self.address, self.BME280_DIG_H4_LSB_REG) >> 4) & 0x0F)
self.calibration["dig_H6"] = self._i2c.readByte(self.address, self.BME280_DIG_H6_REG)
# Most of the time the sensor will be init with default values
# But in case user has old/deprecated code, use the _settings.x values
self.set_standby_time(_settings["tStandby"])
self.set_filter(_settings["filter"])
self.set_pressure_oversample(_settings["pressOverSample"]) # Default of 1x oversample
self.set_humidity_oversample(_settings["humidOverSample"]) # Default of 1x oversample
self.set_tempature_oversample(_settings["tempOverSample"]) # Default of 1x oversample
self.set_mode(self.MODE_NORMAL) #Go!
return True
#----------------------------------------------------------------
# Mode of the sensor
[docs] def set_mode(self, mode):
"""
Set the operational mode of the sensor.
:param mode: One of the class constant values.
MODE_SLEEP, MODE_FORCED, MODE_NORMAL
:return: No return value
"""
if mode > 0b11:
mode = 0 # Error check. Default to sleep mode
controlData = self._i2c.readByte(self.address, self.BME280_CTRL_MEAS_REG)
controlData &= (~( (1<<1) | (1<<0) ) ) & 0xFF # Clear the mode[1:0] bits - note we just want a byte
controlData |= mode # Set
self._i2c.writeByte(self.address, self.BME280_CTRL_MEAS_REG, controlData)
[docs] def get_mode(self):
"""
Returns the operational mode of the sensor.
:return: The current operational mode
:rtype: MODE_SLEEP, MODE_FORCED, or MODE_NORMAL
"""
controlData = self._i2c.readByte(self.address, self.BME280_CTRL_MEAS_REG)
return controlData & 0b00000011
# Make the mode a property of this object
mode = property(get_mode, set_mode)
#----------------------------------------------------------------
# Set the standby bits in the config register
# tStandby can be:
# 0, 0.5ms
# 1, 62.5ms
# 2, 125ms
# 3, 250ms
# 4, 500ms
# 5, 1000ms
# 6, 10ms
# 7, 20ms
[docs] def set_standby_time(self, timeSetting):
"""
Set the standby bits in the BME280s config register
:param timeSetting: The standby time bits - acceptable values
0 = 0.5ms
1 = 62.5ms
2 = 125ms
3 = 250ms
4 = 500ms
5 = 1000ms
6 = 10ms
7 = 20ms
:return: No return value
"""
if timeSetting > 0b111 :
timeSetting = 0 # Error check. Default to 0.5ms
controlData = self._i2c.readByte(self.address, self.BME280_CONFIG_REG)
controlData &= ( ~( (1<<7) | (1<<6) | (1<<5) )) & 0xff # Clear the 7/6/5 bits
controlData |= (timeSetting << 5) # Align with bits 7/6/5
self._i2c.writeByte(self.address, self.BME280_CONFIG_REG, controlData)
# Make standby time a property
standby_time = property()
standby_time = standby_time.setter(set_standby_time)
#----------------------------------------------------------------
# Set the filter bits in the config register
# filter can be off or number of FIR coefficients to use:
# 0, filter off
# 1, coefficients = 2
# 2, coefficients = 4
# 3, coefficients = 8
# 4, coefficients = 16
[docs] def set_filter(self, filterSetting):
"""
Set the filter bits in the BME280s config register
:param filterSetting: The filter bits for the BME280. Acceptable values
0 = filter off
1 = coefficients = 2
2 = coefficients = 4
3 = coefficients = 8
4 = coefficients = 16
:return: No return value
"""
if filterSetting > 0b111 :
filterSetting = 0 # Error check. Default to filter off
controlData = self._i2c.readByte(self.address, self.BME280_CONFIG_REG)
controlData &= (~( (1<<4) | (1<<3) | (1<<2) ) ) & 0xFF # Clear the 4/3/2 bits
controlData |= (filterSetting << 2) # Align with bits 4/3/2
self._i2c.writeByte(self.address, self.BME280_CONFIG_REG, controlData)
filter = property()
filter = filter.setter(set_filter)
#----------------------------------------------------------------
# Set the temperature oversample value
# 0 turns off temp sensing
# 1 to 16 are valid over sampling values
[docs] def set_tempature_oversample(self, overSampleAmount):
"""
Set the temperature oversample value
:param overSampleAmount: The temperature oversample value. Acceptable values
0 = turns off temp sensing
1 to 16 are valid over sampling values
:return: No return value
"""
overSampleAmount = self.check_sample_value(overSampleAmount) # Error check
originalMode = self.get_mode() # Get the current mode so we can go back to it at the end
self.set_mode(self.MODE_SLEEP) # Config will only be writeable in sleep mode, so first go to sleep mode
# Set the osrs_t bits (7, 6, 5) to overSampleAmount
controlData = self._i2c.readByte(self.address, self.BME280_CTRL_MEAS_REG)
controlData &= (~( (1<<7) | (1<<6) | (1<<5) )) & 0xFF # Clear bits 765
controlData |= overSampleAmount << 5 # Align overSampleAmount to bits 7/6/5
self._i2c.writeByte(self.address, self.BME280_CTRL_MEAS_REG, controlData)
self.set_mode(originalMode) # Return to the original user's choice
tempature_oversample = property()
tempature_oversample = tempature_oversample.setter(set_tempature_oversample)
# Set the pressure oversample value
# 0 turns off pressure sensing
# 1 to 16 are valid over sampling values
[docs] def set_pressure_oversample(self, overSampleAmount):
"""
Set the pressure oversample value
:param overSampleAmount: The pressure oversample value. Acceptable values
0 = turns off pressure sensing
1 to 16 are valid over sampling values
:return: No return value
"""
overSampleAmount = self.check_sample_value(overSampleAmount) # Error check
originalMode = self.get_mode() # Get the current mode so we can go back to it at the end
self.set_mode(self.MODE_SLEEP) # Config will only be writeable in sleep mode, so first go to sleep mode
# Set the osrs_p bits (4, 3, 2) to overSampleAmount
controlData = self._i2c.readByte(self.address, self.BME280_CTRL_MEAS_REG)
controlData &= (~( (1<<4) | (1<<3) | (1<<2) )) & 0xFF # Clear bits 432
controlData |= overSampleAmount << 2 # Align overSampleAmount to bits 4/3/2
self._i2c.writeByte(self.address, self.BME280_CTRL_MEAS_REG, controlData)
self.set_mode(originalMode) # Return to the original user's choice
pressure_oversample = property()
pressure_oversample = pressure_oversample.setter(set_pressure_oversample)
#----------------------------------------------------------------
# Set the humidity oversample value
# 0 turns off humidity sensing
# 1 to 16 are valid over sampling values
[docs] def set_humidity_oversample(self, overSampleAmount):
"""
Set the humidity oversample value
:param overSampleAmount: The humidity oversample value. Acceptable values
0 = turns off humidity sensing
1 to 16 are valid over sampling values
:return: No return value
"""
overSampleAmount = self.check_sample_value(overSampleAmount) # Error check
originalMode = self.get_mode() # Get the current mode so we can go back to it at the end
self.set_mode(self.MODE_SLEEP) # Config will only be writeable in sleep mode, so first go to sleep mode
# Set the osrs_h bits (2, 1, 0) to overSampleAmount
controlData = self._i2c.readByte(self.address, self.BME280_CTRL_HUMIDITY_REG)
controlData &= (~( (1<<2) | (1<<1) | (1<<0) )) & 0xFF # Clear bits 2/1/0
controlData |= overSampleAmount << 0 # Align overSampleAmount to bits 2/1/0
self._i2c.writeByte(self.address, self.BME280_CTRL_HUMIDITY_REG, controlData)
self.set_mode(originalMode) # Return to the original user's choice
humidity_oversample = property()
humidity_oversample = humidity_oversample.setter(set_humidity_oversample)
#----------------------------------------------------------------
# Validates an over sample value
# Allowed values are 0 to 16
# These are used in the humidty, pressure, and temp oversample functions
#
# pylint: disable=no-self-use
[docs] def check_sample_value(self, userValue):
"""
Validates an over sample value
:param userValue: The oversample value to check.
Allowed values are 0 to 16
These are used in the humidty, pressure, and temp oversample functions
:return: Valid oversample value
:rtype: int
"""
_valueMap = { 0: 0, 1: 1, 2: 2, 4: 3, 8: 4, 16: 5}
return _valueMap[userValue] if userValue in _valueMap.keys() else 1
# pylint: enable=no-self-use
# Check the measuring bit and return true while device is taking measurement
[docs] def is_measuring(self):
"""
Return if the sensor is measuring or not
:return: True if the sensor is measuring, else False
:rvalue: boolean
"""
stat = self._i2c.readByte(self.address, self.BME280_STAT_REG)
return True if stat & (1<<3) else False # If the measuring bit (3) is set, return true
# Strictly resets. Run .begin() afterwards
[docs] def reset( self ):
"""
Resets the sensor. If called, the begin method must be called before
using the sensor.
"""
self._i2c.writeByte(self.address, self.BME280_RST_REG, 0xB6)
# ****************************************************************************#
#
# Pressure Section
#
# ****************************************************************************#
[docs] def read_pressure( self ):
"""
Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 integer bits and 8 fractional bits).
Output value of "24674867" represents 24674867/256 = 96386.2 Pa = 963.862 hPa
:return: Pressure in Pa
:rtype: integer
"""
# Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 integer bits and 8 fractional bits).
# Output value of "24674867" represents 24674867/256 = 96386.2 Pa = 963.862 hPa
data_buffer = self._i2c.readBlock(self.address, self.BME280_PRESSURE_MSB_REG, 3)
adc_P = (data_buffer[0] << 12) | (data_buffer[1] << 4) | ((data_buffer[2] >> 4) & 0x0F)
var1 = self.t_fine - 128000
var2 = var1 * var1 * self.calibration["dig_P6"]
var2 = var2 + ((var1 * self.calibration["dig_P5"])<<17)
var2 = var2 + (self.calibration["dig_P4"] <<35)
var1 = ((var1 * var1 * self.calibration["dig_P3"])>>8) + ((var1 * self.calibration["dig_P2"])<<12)
var1 = ( (1 << 47) + var1 )*(self.calibration["dig_P1"])>>33
if var1 == 0:
return 0 # avoid exception caused by division by zero
p_acc = 1048576 - adc_P
p_acc = (((p_acc<<31) - var2)*3125)//var1
var1 = ((self.calibration["dig_P9"]) * (p_acc>>13) * (p_acc>>13)) >> 25
var2 = ((self.calibration["dig_P8"]) * p_acc) >> 19
p_acc = ((p_acc + var1 + var2) >> 8) + ((self.calibration["dig_P7"])<<4)
return p_acc / 256.0
pressure = property(read_pressure)
#----------------------------------------------------------------
# Sets the internal variable _referencePressure so the
[docs] def set_reference_pressure(self, refPressure):
"""
Sets the referance pressure for the sensor measurments.
:param refPressure: The referance pressure to use.
:return: No return value
"""
self._referencePressure = float(refPressure)
# Return the local reference pressure
[docs] def get_reference_pressure(self):
"""
Get the current reference pressure for the sensor.
:return: The current reference pressure.
:rtype: float
"""
return self._referencePressure
reference_pressure = property(get_reference_pressure, set_reference_pressure)
#----------------------------------------------------------------
[docs] def get_altitude_meters( self ):
"""
Return the current Altitude in meters
:return: The current altitude in meters
:rtype: float
"""
# heightOutput = ((float)-45846.2)*(pow(((float)readFloatPressure()/(float)_referencePressure), 0.190263) - (float)1);
return (-44330.77)*(math.pow((self.pressure/self._referencePressure), 0.190263) - 1.0) # Corrected, see issue 30
altitude_meters = property(get_altitude_meters)
#----------------------------------------------------------------
[docs] def get_altitude_feet( self ):
"""
Return the current Altitude in feet
:return: The current altitude in feets
:rtype: float
"""
return self.get_altitude_meters() * 3.28084
altitude_feet = property(get_altitude_feet)
# ****************************************************************************#
#
# Humidity Section
#
# ****************************************************************************#
[docs] def read_humidity( self ):
"""
Returns humidity in %RH as unsigned 32 bit integer in Q22. 10 format (22 integer and 10 fractional bits).
Output value of "47445" represents 47445/1024 = 46. 33 %RH
:return: The current humidity value
:rtype: float
"""
# Returns humidity in %RH as unsigned 32 bit integer in Q22. 10 format (22 integer and 10 fractional bits).
# Output value of "47445" represents 47445/1024 = 46. 33 %RH
data_buffer = self._i2c.readBlock(self.address, self.BME280_HUMIDITY_MSB_REG, 2)
adc_H = (data_buffer[0] << 8) | data_buffer[1]
var1 = (self.t_fine - 76800)
var1 = (((((adc_H << 14) - ((self.calibration["dig_H4"]) << 20) - ((self.calibration["dig_H5"]) * var1)) + \
(16384)) >> 15) * (((((((var1 * (self.calibration["dig_H6"])) >> 10) * (((var1 * (self.calibration["dig_H3"])) >> 11) + (32768))) >> 10) + (2097152)) * \
(self.calibration["dig_H2"]) + 8192) >> 14))
var1 = (var1 - (((((var1 >> 15) * (var1 >> 15)) >> 7) * (self.calibration["dig_H1"])) >> 4))
var1 = 0 if var1 < 0 else var1
var1 = 419430400 if var1 > 419430400 else var1
return (var1>>12) / 1024.0
humidity = property(read_humidity)
# ****************************************************************************#
#
# Temperature Section
#
# ****************************************************************************#
[docs] def get_temperature_celsius( self ):
"""
Returns temperature in DegC, resolution is 0.01 DegC. Output value of "5123" equals 51.23 DegC.
t_fine carries fine temperature as global value
:return: The current temperature in C.
:rtype: float
"""
# Returns temperature in DegC, resolution is 0.01 DegC. Output value of "5123" equals 51.23 DegC.
# t_fine carries fine temperature as global value
# get the reading (adc_T);
data_buffer = self._i2c.readBlock(self.address, self.BME280_TEMPERATURE_MSB_REG, 3)
adc_T = (data_buffer[0] << 12) | (data_buffer[1] << 4) | ((data_buffer[2] >> 4) & 0x0F)
# By datasheet, calibrate
var1 = ((((adc_T>>3) - (self.calibration["dig_T1"]<<1))) * (self.calibration["dig_T2"])) >> 11
var2 = (((((adc_T>>4) - (self.calibration["dig_T1"])) * ((adc_T>>4) - (self.calibration["dig_T1"]))) >> 12) * \
(self.calibration["dig_T3"])) >> 14
self.t_fine = var1 + var2
output = (self.t_fine * 5 + 128) >> 8
return output / 100 + _settings["tempCorrection"]
temperature_celsius = property(get_temperature_celsius)
#----------------------------------------------------------------
[docs] def get_temperature_fahrenheit( self ):
"""
Returns temperature in Deg F, resolution is 0.01 DegF. Output value of "5123" equals 51.23 DegF.
t_fine carries fine temperature as global value
:return: The current temperature in F.
:rtype: float
"""
output = self.temperature_celsius
return (output * 9) / 5 + 32
temperature_fahrenheit = property(get_temperature_fahrenheit)
# ****************************************************************************#
#
# Dew point Section
#
# ****************************************************************************#
# Returns Dew point in DegC
[docs] def get_dewpoint_celsius(self):
"""
Returns the Dew point in degrees C.
:return: The current dewpoint in C.
:rtype: float
"""
celsius = self.get_temperature_celsius()
humidity = self.read_humidity()
# (1) Saturation Vapor Pressure = ESGG(T)
RATIO = 373.15 / (273.15 + celsius)
RHS = -7.90298 * (RATIO - 1)
RHS += 5.02808 * math.log10(RATIO)
RHS += -1.3816e-7 * (math.pow(10, (11.344 * (1 - 1/RATIO ))) - 1)
RHS += 8.1328e-3 * (math.pow(10, (-3.49149 * (RATIO - 1))) - 1)
RHS += math.log10(1013.246)
# factor -3 is to adjust units - Vapor Pressure SVP * humidity
VP = math.pow(10, RHS - 3) * humidity
# (2) DEWPOINT = F(Vapor Pressure)
T = math.log(VP/0.61078) # temp var
return (241.88 * T) / (17.558 - T)
dewpoint_celsius = property(get_dewpoint_celsius)
#----------------------------------------------------------------
# Returns Dew point in DegF
[docs] def get_dewpoint_fahrenheit(self):
"""
Returns the Dew point in degrees F.
:return: The current dewpoint in F.
:rtype: float
"""
return self.get_dewpoint_celsius() * 1.8 + 32 # Convert C to F
dewpoint_fahrenheit = property(get_dewpoint_fahrenheit)