1
0
mirror of https://github.com/cmur2/python-bme680.git synced 2024-12-22 12:54:29 +01:00

Merge upstream

This commit is contained in:
cn 2020-08-09 01:44:29 +02:00
commit cd32ec320d
11 changed files with 222 additions and 59 deletions

View File

@ -27,4 +27,5 @@ In all cases you will have to enable the i2c bus.
## Documentation & Support ## Documentation & Support
* Guides and tutorials - https://learn.pimoroni.com/bme680 * Guides and tutorials - https://learn.pimoroni.com/bme680-breakout
* Get help - http://forums.pimoroni.com/c/support

View File

@ -0,0 +1,57 @@
#!/usr/bin/env python
import time
import bme680
from subprocess import PIPE, Popen
print("""compensated-temperature.py - Use the CPU temperature to compensate temperature
readings from the BME680 sensor. Method adapted from Initial State's Enviro pHAT
review: https://medium.com/@InitialState/tutorial-review-enviro-phat-for-raspberry-pi-4cd6d8c63441
Press Ctrl+C to exit!
""")
try:
sensor = bme680.BME680(bme680.I2C_ADDR_PRIMARY)
except IOError:
sensor = bme680.BME680(bme680.I2C_ADDR_SECONDARY)
# These oversampling settings can be tweaked to
# change the balance between accuracy and noise in
# the data.
sensor.set_humidity_oversample(bme680.OS_2X)
sensor.set_pressure_oversample(bme680.OS_4X)
sensor.set_temperature_oversample(bme680.OS_8X)
sensor.set_filter(bme680.FILTER_SIZE_3)
# Gets the CPU temperature in degrees C
def get_cpu_temperature():
process = Popen(['vcgencmd', 'measure_temp'], stdout=PIPE)
output, _error = process.communicate()
return float(output[output.index('=') + 1:output.rindex("'")])
factor = 1.0 # Smaller numbers adjust temp down, vice versa
smooth_size = 10 # Dampens jitter due to rapid CPU temp changes
cpu_temps = []
while True:
if sensor.get_sensor_data():
cpu_temp = get_cpu_temperature()
cpu_temps.append(cpu_temp)
if len(cpu_temps) > smooth_size:
cpu_temps = cpu_temps[1:]
smoothed_cpu_temp = sum(cpu_temps) / float(len(cpu_temps))
raw_temp = sensor.data.temperature
comp_temp = raw_temp - ((smoothed_cpu_temp - raw_temp) / factor)
print("Compensated temperature: {:05.2f} *C".format(comp_temp))
time.sleep(1.0)

View File

@ -1,14 +1,15 @@
#!/usr/bin/env python #!/usr/bin/env python
import bme680 import bme680
import time import time
print("""Estimate indoor air quality print("""indoor-air-quality.py - Estimates indoor air quality.
Runs the sensor for a burn-in period, then uses a Runs the sensor for a burn-in period, then uses a
combination of relative humidity and gas resistance combination of relative humidity and gas resistance
to estimate indoor air quality as a percentage. to estimate indoor air quality as a percentage.
Press Ctrl+C to exit Press Ctrl+C to exit!
""") """)

View File

@ -1,10 +1,11 @@
#!/usr/bin/env python #!/usr/bin/env python
import bme680 import bme680
import time import time
print("""Display Temperature, Pressure, Humidity and Gas print("""read-all.py - Displays temperature, pressure, humidity, and gas.
Press Ctrl+C to exit Press Ctrl+C to exit!
""") """)

View File

@ -1,7 +1,11 @@
#!/usr/bin/env python #!/usr/bin/env python
import bme680 import bme680
print("""Display Temperature, Pressure and Humidity with different offsets. print("""temperature-offset.py - Displays temperature, pressure, and humidity with different offsets.
Press Ctrl+C to exit!
""") """)
try: try:

View File

@ -1,7 +1,8 @@
#!/usr/bin/env python #!/usr/bin/env python
import bme680 import bme680
print("""Display Temperature, Pressure and Humidity print("""temperature-pressure-humidity.py - Displays temperature, pressure, and humidity.
If you don't need gas readings, then you can read temperature, If you don't need gas readings, then you can read temperature,
pressure and humidity quickly. pressure and humidity quickly.
@ -28,12 +29,10 @@ print('Polling:')
try: try:
while True: while True:
if sensor.get_sensor_data(): if sensor.get_sensor_data():
output = '{0:.2f} C,{1:.2f} hPa,{2:.3f} %RH'.format( output = '{0:.2f} C,{1:.2f} hPa,{2:.3f} %RH'.format(
sensor.data.temperature, sensor.data.temperature,
sensor.data.pressure / 100.0, sensor.data.pressure / 100.0,
sensor.data.humidity) sensor.data.humidity)
print(output) print(output)
except KeyboardInterrupt: except KeyboardInterrupt:

View File

@ -10,6 +10,7 @@ __version__ = '1.0.5'
# Export constants to global namespace # Export constants to global namespace
# so end-users can "from BME680 import NAME" # so end-users can "from BME680 import NAME"
if hasattr(constants, '__dict__'):
for key in constants.__dict__: for key in constants.__dict__:
value = constants.__dict__[key] value = constants.__dict__[key]
if key not in globals(): if key not in globals():

View File

@ -12,3 +12,4 @@ ignore =
E501 E501
F403 F403
F405 F405
W504

101
library/tests/conftest.py Normal file
View File

@ -0,0 +1,101 @@
import sys
import mock
import pytest
import bme680
from bme680.constants import CalibrationData
class MockSMBus:
"""Mock a basic non-presence SMBus device to cause BME680 to fail.
Returns 0 in all cases, so that CHIP_ID will never match.
"""
def __init__(self, bus): # noqa D107
pass
def read_byte_data(self, addr, register):
"""Return 0 for all read attempts."""
return 0
class MockSMBusPresent:
"""Mock enough of the BME680 for the library to initialise and test."""
def __init__(self, bus):
"""Initialise with test data."""
self.regs = [0 for _ in range(256)]
self.regs[bme680.CHIP_ID_ADDR] = bme680.CHIP_ID
def read_byte_data(self, addr, register):
"""Read a single byte from fake registers."""
return self.regs[register]
def write_byte_data(self, addr, register, value):
"""Write a single byte to fake registers."""
self.regs[register] = value
def read_i2c_block_data(self, addr, register, length):
"""Read up to length bytes from register."""
return self.regs[register:register + length]
@pytest.fixture(scope='function', autouse=False)
def smbus_notpresent():
"""Mock smbus module."""
smbus = mock.MagicMock()
smbus.SMBus = MockSMBus
sys.modules['smbus'] = smbus
yield smbus
del sys.modules['smbus']
@pytest.fixture(scope='function', autouse=False)
def smbus():
"""Mock smbus module."""
smbus = mock.MagicMock()
smbus.SMBus = MockSMBusPresent
sys.modules['smbus'] = smbus
yield smbus
del sys.modules['smbus']
@pytest.fixture(scope='function', autouse=False)
def calibration():
"""Mock bme680 calibration."""
calibration = CalibrationData()
# Dump of calibration data borrowed from:
# https://github.com/pimoroni/bme680-python/issues/11
data = {
'par_gh1': -30,
'par_gh2': -24754,
'par_gh3': 18,
'par_h1': 676,
'par_h2': 1029,
'par_h3': 0,
'par_h4': 45,
'par_h5': 20,
'par_h6': 120,
'par_h7': -100,
'par_p1': 36673,
'par_p10': 30,
'par_p2': -10515,
'par_p3': 88,
'par_p4': 7310,
'par_p5': -129,
'par_p6': 30,
'par_p7': 46,
'par_p8': -3177,
'par_p9': -2379,
'par_t1': 26041,
'par_t2': 26469,
'par_t3': 3,
'range_sw_err': 0,
'res_heat_range': 1,
'res_heat_val': 48,
't_fine': 136667
}
for k, v in data.items():
setattr(calibration, k, v)
return calibration

View File

@ -0,0 +1,41 @@
import bme680
def test_calc_temperature(smbus, calibration):
"""Validate temperature calculation against mock calibration data."""
sensor = bme680.BME680()
sensor.calibration_data = calibration
assert sensor._calc_temperature(501240) == 2669
assert sensor.calibration_data.t_fine == 136667
def test_calc_pressure(smbus, calibration):
"""Validate pressure calculation against mock calibration data."""
sensor = bme680.BME680()
sensor.calibration_data = calibration
sensor._calc_temperature(501240)
assert sensor._calc_pressure(353485) == 98712
def test_calc_humidity(smbus, calibration):
"""Validate humidity calculation against mock calibration data."""
sensor = bme680.BME680()
sensor.calibration_data = calibration
sensor._calc_temperature(501240)
assert sensor._calc_humidity(19019) == 42402
def test_calc_gas_resistance(smbus, calibration):
"""Validate gas calculation against mock calibration data."""
sensor = bme680.BME680()
sensor.calibration_data = calibration
assert int(sensor._calc_gas_resistance(0, 0)) == 12946860
def test_temp_offset(smbus, calibration):
"""Validate temperature calculation with offset against mock calibration data."""
sensor = bme680.BME680()
sensor.calibration_data = calibration
sensor.set_temp_offset(1.99)
assert sensor._calc_temperature(501240) == 2669 + 199
assert sensor.calibration_data.t_fine == 146830

View File

@ -1,57 +1,13 @@
import sys
import mock
import pytest import pytest
import bme680 import bme680
class MockSMBus: def test_setup_not_present(smbus_notpresent):
"""Mock a basic non-presence SMBus device to cause BME680 to fail.
Returns 0 in all cases, so that CHIP_ID will never match.
"""
def __init__(self, bus): # noqa D107
pass
def read_byte_data(self, addr, register):
"""Return 0 for all read attempts."""
return 0
class MockSMBusPresent:
"""Mock enough of the BME680 for the library to initialise and test."""
def __init__(self, bus):
"""Initialise with test data."""
self.regs = [0 for _ in range(256)]
self.regs[bme680.CHIP_ID_ADDR] = bme680.CHIP_ID
def read_byte_data(self, addr, register):
"""Read a single byte from fake registers."""
return self.regs[register]
def write_byte_data(self, addr, register, value):
"""Write a single byte to fake registers."""
self.regs[register] = value
def read_i2c_block_data(self, addr, register, length):
"""Read up to length bytes from register."""
return self.regs[register:register + length]
def test_setup_not_present():
"""Mock the adbsence of a BME680 and test initialisation.""" """Mock the adbsence of a BME680 and test initialisation."""
sys.modules['smbus'] = mock.MagicMock()
sys.modules['smbus'].SMBus = MockSMBus
with pytest.raises(RuntimeError): with pytest.raises(RuntimeError):
sensor = bme680.BME680() # noqa F841 sensor = bme680.BME680() # noqa F841
def test_setup_mock_present(): def test_setup_mock_present(smbus):
"""Mock the presence of a BME680 and test initialisation.""" """Mock the presence of a BME680 and test initialisation."""
sys.modules['smbus'] = mock.MagicMock()
sys.modules['smbus'].SMBus = MockSMBusPresent
sensor = bme680.BME680() # noqa F841 sensor = bme680.BME680() # noqa F841