From e827e5d622fd70df2aee6a68ebac626cf539ee55 Mon Sep 17 00:00:00 2001 From: Giampiero Baggiani Date: Mon, 10 Dec 2018 10:55:07 +0100 Subject: [PATCH 1/6] added check on constants.__dict__ for micropython support (#18) * added check on constants.__dict__ for micropython support --- library/bme680/__init__.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/library/bme680/__init__.py b/library/bme680/__init__.py index 62aa7ea..61641ec 100644 --- a/library/bme680/__init__.py +++ b/library/bme680/__init__.py @@ -10,10 +10,11 @@ __version__ = '1.0.5' # Export constants to global namespace # so end-users can "from BME680 import NAME" -for key in constants.__dict__: - value = constants.__dict__[key] - if key not in globals(): - globals()[key] = value +if hasattr(constants, '__dict__'): + for key in constants.__dict__: + value = constants.__dict__[key] + if key not in globals(): + globals()[key] = value class BME680(BME680Data): From 5a5dd139c3e02ead0ac00a47a1e9dd436bb989c9 Mon Sep 17 00:00:00 2001 From: Sandy Macdonald Date: Sun, 9 Jun 2019 13:11:35 +0100 Subject: [PATCH 2/6] Tidying up and adding examples --- examples/compensated-temperature.py | 59 +++++++++++++++++++ examples/indoor-air-quality.py | 5 +- examples/read-all.py | 5 +- .../{temp-offset.py => temperature-offset.py} | 8 ++- ...um.py => temperature-pressure-humidity.py} | 5 +- 5 files changed, 72 insertions(+), 10 deletions(-) create mode 100755 examples/compensated-temperature.py rename examples/{temp-offset.py => temperature-offset.py} (89%) rename examples/{temp-press-hum.py => temperature-pressure-humidity.py} (90%) diff --git a/examples/compensated-temperature.py b/examples/compensated-temperature.py new file mode 100755 index 0000000..d3901ca --- /dev/null +++ b/examples/compensated-temperature.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python + +import time +import bme680 +from subprocess import PIPE, Popen + +try: + from smbus2 import SMBus +except ImportError: + from smbus import SMBus + +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) diff --git a/examples/indoor-air-quality.py b/examples/indoor-air-quality.py index 0a60643..a762e49 100755 --- a/examples/indoor-air-quality.py +++ b/examples/indoor-air-quality.py @@ -1,14 +1,15 @@ #!/usr/bin/env python + import bme680 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 combination of relative humidity and gas resistance to estimate indoor air quality as a percentage. -Press Ctrl+C to exit +Press Ctrl+C to exit! """) diff --git a/examples/read-all.py b/examples/read-all.py index 1c23ed0..b0d31d2 100755 --- a/examples/read-all.py +++ b/examples/read-all.py @@ -1,10 +1,11 @@ #!/usr/bin/env python + import bme680 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! """) diff --git a/examples/temp-offset.py b/examples/temperature-offset.py similarity index 89% rename from examples/temp-offset.py rename to examples/temperature-offset.py index 2ccd73d..7f298cd 100755 --- a/examples/temp-offset.py +++ b/examples/temperature-offset.py @@ -1,7 +1,11 @@ #!/usr/bin/env python + 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: @@ -18,7 +22,6 @@ sensor.set_pressure_oversample(bme680.OS_4X) sensor.set_temperature_oversample(bme680.OS_8X) sensor.set_filter(bme680.FILTER_SIZE_3) - def display_data(offset=0): sensor.set_temp_offset(offset) sensor.get_sensor_data() @@ -29,7 +32,6 @@ def display_data(offset=0): print(output) print('') - print('Initial readings') display_data() diff --git a/examples/temp-press-hum.py b/examples/temperature-pressure-humidity.py similarity index 90% rename from examples/temp-press-hum.py rename to examples/temperature-pressure-humidity.py index 8a2702d..ae3321e 100755 --- a/examples/temp-press-hum.py +++ b/examples/temperature-pressure-humidity.py @@ -1,7 +1,8 @@ #!/usr/bin/env python + 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, pressure and humidity quickly. @@ -28,12 +29,10 @@ print('Polling:') try: while True: if sensor.get_sensor_data(): - output = '{0:.2f} C,{1:.2f} hPa,{2:.3f} %RH'.format( sensor.data.temperature, sensor.data.pressure, sensor.data.humidity) - print(output) except KeyboardInterrupt: From 3a48112445a012b4ec38105b750d27f9591cdc75 Mon Sep 17 00:00:00 2001 From: Philip Howard Date: Fri, 8 Nov 2019 11:53:07 +0000 Subject: [PATCH 3/6] Fix learn link for #25 (#26) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index deee6f4..2cea030 100644 --- a/README.md +++ b/README.md @@ -52,5 +52,5 @@ In all cases you will have to enable the i2c bus. ## 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 From 90fabf53fa6b4ce774fb153047fa591169278dd3 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 20 Mar 2020 15:38:22 +0000 Subject: [PATCH 4/6] Expand test coverage and improve tests --- library/setup.cfg | 1 + library/tests/conftest.py | 101 +++++++++++++++++++++++++++++ library/tests/test_compensation.py | 41 ++++++++++++ library/tests/test_setup.py | 48 +------------- 4 files changed, 145 insertions(+), 46 deletions(-) create mode 100644 library/tests/conftest.py create mode 100644 library/tests/test_compensation.py diff --git a/library/setup.cfg b/library/setup.cfg index 81dc0bf..bdbc6ef 100644 --- a/library/setup.cfg +++ b/library/setup.cfg @@ -12,3 +12,4 @@ ignore = E501 F403 F405 + W504 diff --git a/library/tests/conftest.py b/library/tests/conftest.py new file mode 100644 index 0000000..bbe4939 --- /dev/null +++ b/library/tests/conftest.py @@ -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 diff --git a/library/tests/test_compensation.py b/library/tests/test_compensation.py new file mode 100644 index 0000000..30b7156 --- /dev/null +++ b/library/tests/test_compensation.py @@ -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 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 diff --git a/library/tests/test_setup.py b/library/tests/test_setup.py index 95b7391..b401d91 100644 --- a/library/tests/test_setup.py +++ b/library/tests/test_setup.py @@ -1,57 +1,13 @@ -import sys -import mock import pytest import bme680 -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] - - -def test_setup_not_present(): +def test_setup_not_present(smbus_notpresent): """Mock the adbsence of a BME680 and test initialisation.""" - sys.modules['smbus'] = mock.MagicMock() - sys.modules['smbus'].SMBus = MockSMBus - with pytest.raises(RuntimeError): 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.""" - sys.modules['smbus'] = mock.MagicMock() - sys.modules['smbus'].SMBus = MockSMBusPresent - sensor = bme680.BME680() # noqa F841 From 45eeba9bb4883312197f04aa06c44e6d28e1f628 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 20 Mar 2020 15:38:31 +0000 Subject: [PATCH 5/6] Minor linting fixes to examples --- examples/compensated-temperature.py | 6 ++---- examples/temperature-offset.py | 2 ++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/compensated-temperature.py b/examples/compensated-temperature.py index d3901ca..071bbfb 100755 --- a/examples/compensated-temperature.py +++ b/examples/compensated-temperature.py @@ -4,10 +4,6 @@ import time import bme680 from subprocess import PIPE, Popen -try: - from smbus2 import SMBus -except ImportError: - from smbus import SMBus print("""compensated-temperature.py - Use the CPU temperature to compensate temperature readings from the BME680 sensor. Method adapted from Initial State's Enviro pHAT @@ -31,12 +27,14 @@ 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 diff --git a/examples/temperature-offset.py b/examples/temperature-offset.py index 7f298cd..c39700e 100755 --- a/examples/temperature-offset.py +++ b/examples/temperature-offset.py @@ -22,6 +22,7 @@ sensor.set_pressure_oversample(bme680.OS_4X) sensor.set_temperature_oversample(bme680.OS_8X) sensor.set_filter(bme680.FILTER_SIZE_3) + def display_data(offset=0): sensor.set_temp_offset(offset) sensor.get_sensor_data() @@ -32,6 +33,7 @@ def display_data(offset=0): print(output) print('') + print('Initial readings') display_data() From 580646673960899ae577ea05b5b88abf740bf16d Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Fri, 20 Mar 2020 15:44:06 +0000 Subject: [PATCH 6/6] Fix for test in py3 --- library/tests/test_compensation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/tests/test_compensation.py b/library/tests/test_compensation.py index 30b7156..89b0cd9 100644 --- a/library/tests/test_compensation.py +++ b/library/tests/test_compensation.py @@ -29,7 +29,7 @@ def test_calc_gas_resistance(smbus, calibration): """Validate gas calculation against mock calibration data.""" sensor = bme680.BME680() sensor.calibration_data = calibration - assert sensor._calc_gas_resistance(0, 0) == 12946860 + assert int(sensor._calc_gas_resistance(0, 0)) == 12946860 def test_temp_offset(smbus, calibration):