In this guide you’ll learn how to use the BME280 sensor module with the ESP32 and ESP8266 to get pressure, temperature and humidity readings using MicroPython firmware. We’ll build a simple example to get you familiar with the sensor and a web server to display your sensor readings.
Prerequisites
To follow this tutorial you need MicroPython firmware installed in your ESP32 or ESP8266 boards. You also need an IDE to write and upload the code to your board. We suggest using Thonny IDE or uPyCraft IDE:
- Thonny IDE:
- uPyCraft IDE:
- Getting Started with uPyCraft IDE
- Install uPyCraft IDE (Windows, Mac OS X, Linux)
- Flash/Upload MicroPython Firmware to ESP32 and ESP8266
Learn more about MicroPython: MicroPython Programming with ESP32 and ESP8266 eBook.
You might also like reading other BME280 guides:
- ESP32 with BME280 Sensor using Arduino IDE
- ESP32 Web Server with BME280 – Weather Station
- ESP8266 with BME280 using Arduino IDE
- Arduino Board with BME280
Introducing the BME280 Sensor Module
The BME280 sensor module reads barometric pressure, temperature and humidity. Because pressure changes with altitude, you can also estimate altitude. There are several versions of this sensor module, but we’re using the one shown in the figure below.
This sensor communicates using I2C communication protocol, so the wiring is very simple. You can use the default ESP32 or ESP8266 I2C pins as shown in the following table:
BME280 | ESP32 | ESP8266 |
Vin | 3.3V | 3.3V |
GND | GND | GND |
SCL | GPIO 22 | GPIO 5 (D1) |
SDA | GPIO 21 | GPIO 4 (D2) |
Parts Required
For this project you need to wire the BME280 sensor module to the ESP32 or ESP8266 I2C pins. Here’s a list of parts you need for this tutorial:
You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!
Schematic – ESP32
Follow the next schematic diagram if you’re using an ESP32 board:
Recommended reading: ESP32 Pinout Reference Guide
Schematic – ESP8266
Follow the next schematic diagram if you’re using an ESP8266 board:
Recommended reading: ESP8266 Pinout Reference Guide
BME280 MicroPython Library
The library to read from the BME280 sensor isn’t part of the standard MicroPython library by default. So, you need to upload the following library to your ESP32/ESP8266 board (save it with the name BME280.py).
from machine import I2C
import time
# BME280 default address.
BME280_I2CADDR = 0x76
# Operating Modes
BME280_OSAMPLE_1 = 1
BME280_OSAMPLE_2 = 2
BME280_OSAMPLE_4 = 3
BME280_OSAMPLE_8 = 4
BME280_OSAMPLE_16 = 5
# BME280 Registers
BME280_REGISTER_DIG_T1 = 0x88 # Trimming parameter registers
BME280_REGISTER_DIG_T2 = 0x8A
BME280_REGISTER_DIG_T3 = 0x8C
BME280_REGISTER_DIG_P1 = 0x8E
BME280_REGISTER_DIG_P2 = 0x90
BME280_REGISTER_DIG_P3 = 0x92
BME280_REGISTER_DIG_P4 = 0x94
BME280_REGISTER_DIG_P5 = 0x96
BME280_REGISTER_DIG_P6 = 0x98
BME280_REGISTER_DIG_P7 = 0x9A
BME280_REGISTER_DIG_P8 = 0x9C
BME280_REGISTER_DIG_P9 = 0x9E
BME280_REGISTER_DIG_H1 = 0xA1
BME280_REGISTER_DIG_H2 = 0xE1
BME280_REGISTER_DIG_H3 = 0xE3
BME280_REGISTER_DIG_H4 = 0xE4
BME280_REGISTER_DIG_H5 = 0xE5
BME280_REGISTER_DIG_H6 = 0xE6
BME280_REGISTER_DIG_H7 = 0xE7
BME280_REGISTER_CHIPID = 0xD0
BME280_REGISTER_VERSION = 0xD1
BME280_REGISTER_SOFTRESET = 0xE0
BME280_REGISTER_CONTROL_HUM = 0xF2
BME280_REGISTER_CONTROL = 0xF4
BME280_REGISTER_CONFIG = 0xF5
BME280_REGISTER_PRESSURE_DATA = 0xF7
BME280_REGISTER_TEMP_DATA = 0xFA
BME280_REGISTER_HUMIDITY_DATA = 0xFD
class Device:
"""Class for communicating with an I2C device.
Allows reading and writing 8-bit, 16-bit, and byte array values to
registers on the device."""
def __init__(self, address, i2c):
"""Create an instance of the I2C device at the specified address using
the specified I2C interface object."""
self._address = address
self._i2c = i2c
def writeRaw8(self, value):
"""Write an 8-bit value on the bus (without register)."""
value = value & 0xFF
self._i2c.writeto(self._address, value)
def write8(self, register, value):
"""Write an 8-bit value to the specified register."""
b=bytearray(1)
b[0]=value & 0xFF
self._i2c.writeto_mem(self._address, register, b)
def write16(self, register, value):
"""Write a 16-bit value to the specified register."""
value = value & 0xFFFF
b=bytearray(2)
b[0]= value & 0xFF
b[1]= (value>>8) & 0xFF
self.i2c.writeto_mem(self._address, register, value)
def readRaw8(self):
"""Read an 8-bit value on the bus (without register)."""
return int.from_bytes(self._i2c.readfrom(self._address, 1),'little') & 0xFF
def readU8(self, register):
"""Read an unsigned byte from the specified register."""
return int.from_bytes(
self._i2c.readfrom_mem(self._address, register, 1),'little') & 0xFF
def readS8(self, register):
"""Read a signed byte from the specified register."""
result = self.readU8(register)
if result > 127:
result -= 256
return result
def readU16(self, register, little_endian=True):
"""Read an unsigned 16-bit value from the specified register, with the
specified endianness (default little endian, or least significant byte
first)."""
result = int.from_bytes(
self._i2c.readfrom_mem(self._address, register, 2),'little') & 0xFFFF
if not little_endian:
result = ((result << 8) & 0xFF00) + (result >> 8)
return result
def readS16(self, register, little_endian=True):
"""Read a signed 16-bit value from the specified register, with the
specified endianness (default little endian, or least significant byte
first)."""
result = self.readU16(register, little_endian)
if result > 32767:
result -= 65536
return result
def readU16LE(self, register):
"""Read an unsigned 16-bit value from the specified register, in little
endian byte order."""
return self.readU16(register, little_endian=True)
def readU16BE(self, register):
"""Read an unsigned 16-bit value from the specified register, in big
endian byte order."""
return self.readU16(register, little_endian=False)
def readS16LE(self, register):
"""Read a signed 16-bit value from the specified register, in little
endian byte order."""
return self.readS16(register, little_endian=True)
def readS16BE(self, register):
"""Read a signed 16-bit value from the specified register, in big
endian byte order."""
return self.readS16(register, little_endian=False)
class BME280:
def __init__(self, mode=BME280_OSAMPLE_1, address=BME280_I2CADDR, i2c=None,
**kwargs):
# Check that mode is valid.
if mode not in [BME280_OSAMPLE_1, BME280_OSAMPLE_2, BME280_OSAMPLE_4,
BME280_OSAMPLE_8, BME280_OSAMPLE_16]:
raise ValueError(
'Unexpected mode value {0}. Set mode to one of '
'BME280_ULTRALOWPOWER, BME280_STANDARD, BME280_HIGHRES, or '
'BME280_ULTRAHIGHRES'.format(mode))
self._mode = mode
# Create I2C device.
if i2c is None:
raise ValueError('An I2C object is required.')
self._device = Device(address, i2c)
# Load calibration values.
self._load_calibration()
self._device.write8(BME280_REGISTER_CONTROL, 0x3F)
self.t_fine = 0
def _load_calibration(self):
self.dig_T1 = self._device.readU16LE(BME280_REGISTER_DIG_T1)
self.dig_T2 = self._device.readS16LE(BME280_REGISTER_DIG_T2)
self.dig_T3 = self._device.readS16LE(BME280_REGISTER_DIG_T3)
self.dig_P1 = self._device.readU16LE(BME280_REGISTER_DIG_P1)
self.dig_P2 = self._device.readS16LE(BME280_REGISTER_DIG_P2)
self.dig_P3 = self._device.readS16LE(BME280_REGISTER_DIG_P3)
self.dig_P4 = self._device.readS16LE(BME280_REGISTER_DIG_P4)
self.dig_P5 = self._device.readS16LE(BME280_REGISTER_DIG_P5)
self.dig_P6 = self._device.readS16LE(BME280_REGISTER_DIG_P6)
self.dig_P7 = self._device.readS16LE(BME280_REGISTER_DIG_P7)
self.dig_P8 = self._device.readS16LE(BME280_REGISTER_DIG_P8)
self.dig_P9 = self._device.readS16LE(BME280_REGISTER_DIG_P9)
self.dig_H1 = self._device.readU8(BME280_REGISTER_DIG_H1)
self.dig_H2 = self._device.readS16LE(BME280_REGISTER_DIG_H2)
self.dig_H3 = self._device.readU8(BME280_REGISTER_DIG_H3)
self.dig_H6 = self._device.readS8(BME280_REGISTER_DIG_H7)
h4 = self._device.readS8(BME280_REGISTER_DIG_H4)
h4 = (h4 << 24) >> 20
self.dig_H4 = h4 | (self._device.readU8(BME280_REGISTER_DIG_H5) & 0x0F)
h5 = self._device.readS8(BME280_REGISTER_DIG_H6)
h5 = (h5 << 24) >> 20
self.dig_H5 = h5 | (
self._device.readU8(BME280_REGISTER_DIG_H5) >> 4 & 0x0F)
def read_raw_temp(self):
"""Reads the raw (uncompensated) temperature from the sensor."""
meas = self._mode
self._device.write8(BME280_REGISTER_CONTROL_HUM, meas)
meas = self._mode << 5 | self._mode << 2 | 1
self._device.write8(BME280_REGISTER_CONTROL, meas)
sleep_time = 1250 + 2300 * (1 << self._mode)
sleep_time = sleep_time + 2300 * (1 << self._mode) + 575
sleep_time = sleep_time + 2300 * (1 << self._mode) + 575
time.sleep_us(sleep_time) # Wait the required time
msb = self._device.readU8(BME280_REGISTER_TEMP_DATA)
lsb = self._device.readU8(BME280_REGISTER_TEMP_DATA + 1)
xlsb = self._device.readU8(BME280_REGISTER_TEMP_DATA + 2)
raw = ((msb << 16) | (lsb << 8) | xlsb) >> 4
return raw
def read_raw_pressure(self):
"""Reads the raw (uncompensated) pressure level from the sensor."""
"""Assumes that the temperature has already been read """
"""i.e. that enough delay has been provided"""
msb = self._device.readU8(BME280_REGISTER_PRESSURE_DATA)
lsb = self._device.readU8(BME280_REGISTER_PRESSURE_DATA + 1)
xlsb = self._device.readU8(BME280_REGISTER_PRESSURE_DATA + 2)
raw = ((msb << 16) | (lsb << 8) | xlsb) >> 4
return raw
def read_raw_humidity(self):
"""Assumes that the temperature has already been read """
"""i.e. that enough delay has been provided"""
msb = self._device.readU8(BME280_REGISTER_HUMIDITY_DATA)
lsb = self._device.readU8(BME280_REGISTER_HUMIDITY_DATA + 1)
raw = (msb << 8) | lsb
return raw
def read_temperature(self):
"""Get the compensated temperature in 0.01 of a degree celsius."""
adc = self.read_raw_temp()
var1 = ((adc >> 3) - (self.dig_T1 << 1)) * (self.dig_T2 >> 11)
var2 = ((
(((adc >> 4) - self.dig_T1) * ((adc >> 4) - self.dig_T1)) >> 12) *
self.dig_T3) >> 14
self.t_fine = var1 + var2
return (self.t_fine * 5 + 128) >> 8
def read_pressure(self):
"""Gets the compensated pressure in Pascals."""
adc = self.read_raw_pressure()
var1 = self.t_fine - 128000
var2 = var1 * var1 * self.dig_P6
var2 = var2 + ((var1 * self.dig_P5) << 17)
var2 = var2 + (self.dig_P4 << 35)
var1 = (((var1 * var1 * self.dig_P3) >> 8) +
((var1 * self.dig_P2) >> 12))
var1 = (((1 << 47) + var1) * self.dig_P1) >> 33
if var1 == 0:
return 0
p = 1048576 - adc
p = (((p << 31) - var2) * 3125) // var1
var1 = (self.dig_P9 * (p >> 13) * (p >> 13)) >> 25
var2 = (self.dig_P8 * p) >> 19
return ((p + var1 + var2) >> 8) + (self.dig_P7 << 4)
def read_humidity(self):
adc = self.read_raw_humidity()
# print 'Raw humidity = {0:d}'.format (adc)
h = self.t_fine - 76800
h = (((((adc << 14) - (self.dig_H4 << 20) - (self.dig_H5 * h)) +
16384) >> 15) * (((((((h * self.dig_H6) >> 10) * (((h *
self.dig_H3) >> 11) + 32768)) >> 10) + 2097152) *
self.dig_H2 + 8192) >> 14))
h = h - (((((h >> 15) * (h >> 15)) >> 7) * self.dig_H1) >> 4)
h = 0 if h < 0 else h
h = 419430400 if h > 419430400 else h
return h >> 12
@property
def temperature(self):
"Return the temperature in degrees."
t = self.read_temperature()
ti = t // 100
td = t - ti * 100
return "{}.{:02d}C".format(ti, td)
@property
def pressure(self):
"Return the temperature in hPa."
p = self.read_pressure() // 256
pi = p // 100
pd = p - pi * 100
return "{}.{:02d}hPa".format(pi, pd)
@property
def humidity(self):
"Return the humidity in percent."
h = self.read_humidity()
hi = h // 1024
hd = h * 100 // 1024 - hi * 100
return "{}.{:02d}%".format(hi, hd)
Follow the next set of instructions for the IDE you’re using:
- A. Upload BME280 library with uPyCraft IDE
- B. Upload BME280 library with Thonny IDE
A. Upload BME280 library with uPyCraft IDE
This section shows how to upload a library using uPyCraft IDE. If you’re using Thonny IDE, read the next section.
1. Create a new file by pressing the New File button (1).
2. Copy the BME280 library code into that file. The BME280 library code can be found here.
3. After copying the code, save the file by pressing the Save button (2).
4. Call this new file “BME280.py” and press ok.
5. Click the Download and Run button.
The file should be saved on the device folder with the name “BME280.py” as highlighted in the following figure.
Now, you can use the library functionalities in your code by importing the library.
B. Upload BME280 library with Thonny IDE
If you’re using Thonny IDE, follow the next steps:
1. Copy the library code to a new file. The BME280 library code can be found here.
2. Go to File > Save as…
3. Select save to “MicroPython device“:
4. Name your file as BME280.py and press the OK button:
And that’s it. The library was uploaded to your board. To make sure that it was uploaded successfully, go to File > Save as… and select the MicroPython device. Your file should be listed there:
After uploading the library to your board, you can use the library functionalities in your code by importing the library.
Code – BME280 Pressure, Temperature, and Humidity
After uploading the library to the ESP32 or ESP8266, copy the following code to the main.py or boot.py file. It simply prints the temperature, humidity and pressure into the shell every 5 seconds.
# Complete project details at https://RandomNerdTutorials.com
from machine import Pin, I2C
from time import sleep
import BME280
# ESP32 - Pin assignment
i2c = I2C(scl=Pin(22), sda=Pin(21), freq=10000)
# ESP8266 - Pin assignment
#i2c = I2C(scl=Pin(5), sda=Pin(4), freq=10000)
while True:
bme = BME280.BME280(i2c=i2c)
temp = bme.temperature
hum = bme.humidity
pres = bme.pressure
# uncomment for temperature in Fahrenheit
#temp = (bme.read_temperature()/100) * (9/5) + 32
#temp = str(round(temp, 2)) + 'F'
print('Temperature: ', temp)
print('Humidity: ', hum)
print('Pressure: ', pres)
sleep(5)
How the Code Works
First, you need to import the necessary libraries, including the BME280 module you’ve imported previously.
from machine import Pin, I2C
from time import sleep
import BME280
Set the I2C pins. In this case, we’re using the default I2C pins. If you’re using the ESP32, set the pins as follows:
i2c = I2C(scl=Pin(22), sda=Pin(21), freq=10000)
If you’re using the ESP8266, comment the previous line and uncomment the following so that you have:
i2c = I2C(scl=Pin(5), sda=Pin(4), freq=10000)
In the while loop, create a BME280 object called bme with the I2C pins defined earlier:
bme = BME280.BME280(i2c=i2c)
Reading temperature, humidity and pressure is as simple as using the temperature, humidity and pressure methods on the bme object.
temp = bme.temperature
hum = bme.humidity
pres = bme.pressure
Finally, print the readings on the shell:
print('Temperature: ', temp)
print('Humidity: ', hum)
print('Pressure: ', pres)
In the end, we add a delay of 5 seconds:
sleep(5)
Demonstration
After uploading the code to your board, press the RST button to run the code. New BME280 sensor readings should be displayed every 5 seconds.
Display BME280 Readings on Web Server
Now that you know how to get pressure, temperature and humidity from the BME280 sensor, we’ll display the sensor readings on a web server that you can access on your local network.
For this example, you need three files:
- BME280.py: this is the file that contains all the methods to use the BME280 sensor. That’s the file you’ve uploaded previously.
- boot.py: runs when the device starts and sets up several configuration options like your network credentials, importing libraries, setting the pins, etc.
- main.py: this is the main script where we’ll handle the web server. It executes immediately after the boot.py.
Note: It is a good practice to include the boot.py and main.py files. However, if you prefer, you can include all the code in the main.py file.
boot.py
Create a new file in your IDE called boot.py and copy the following code.
# Complete project details at https://RandomNerdTutorials.com
try:
import usocket as socket
except:
import socket
from time import sleep
from machine import Pin, I2C
import network
import esp
esp.osdebug(None)
import gc
gc.collect()
import BME280
# ESP32 - Pin assignment
i2c = I2C(scl=Pin(22), sda=Pin(21), freq=10000)
# ESP8266 - Pin assignment
#i2c = I2C(scl=Pin(5), sda=Pin(4), freq=10000)
ssid = 'REPLACE_WITH_YOUR_SSID'
password = 'REPLACE_WITH_YOUR_PASSWORD'
station = network.WLAN(network.STA_IF)
station.active(True)
station.connect(ssid, password)
while station.isconnected() == False:
pass
print('Connection successful')
print(station.ifconfig())
This file imports the necessary libraries, defines the I2C pins to connect to the sensor and connects to your network.
In the code, we’re using the ESP32 I2C pins:
i2c = I2C(scl=Pin(5), sda=Pin(4), freq=10000)
If you’re using the ESP8266, comment the previous line and uncomment the following:
i2c = I2C(scl=Pin(22), sda=Pin(21), freq=10000)
Then, insert your network credentials in the following variables:
ssid = 'REPLACE_WITH_YOUR_SSID'
password = 'REPLACE_WITH_YOUR_PASSWORD'
main.py
In the main.py file is where we’ll create the web server and handle the requests. Copy the following code to your main.py file.
# Complete project details at https://RandomNerdTutorials.com
def web_page():
bme = BME280.BME280(i2c=i2c)
html = """<html><head><meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,"><style>body { text-align: center; font-family: "Trebuchet MS", Arial;}
table { border-collapse: collapse; width:35%; margin-left:auto; margin-right:auto; }
th { padding: 12px; background-color: #0043af; color: white; }
tr { border: 1px solid #ddd; padding: 12px; }
tr:hover { background-color: #bcbcbc; }
td { border: none; padding: 12px; }
.sensor { color:white; font-weight: bold; background-color: #bcbcbc; padding: 1px;
</style></head><body><h1>ESP with BME280</h1>
<table><tr><th>MEASUREMENT</th><th>VALUE</th></tr>
<tr><td>Temp. Celsius</td><td><span class="sensor">""" + str(bme.temperature) + """</span></td></tr>
<tr><td>Temp. Fahrenheit</td><td><span class="sensor">""" + str(round((bme.read_temperature()/100.0) * (9/5) + 32, 2)) + """F</span></td></tr>
<tr><td>Pressure</td><td><span class="sensor">""" + str(bme.pressure) + """</span></td></tr>
<tr><td>Humidity</td><td><span class="sensor">""" + str(bme.humidity) + """</span></td></tr></body></html>"""
return html
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 80))
s.listen(5)
while True:
try:
if gc.mem_free() < 102000:
gc.collect()
conn, addr = s.accept()
conn.settimeout(3.0)
print('Got a connection from %s' % str(addr))
request = conn.recv(1024)
conn.settimeout(None)
request = str(request)
print('Content = %s' % request)
response = web_page()
conn.send('HTTP/1.1 200 OK\n')
conn.send('Content-Type: text/html\n')
conn.send('Connection: close\n\n')
conn.sendall(response)
conn.close()
except OSError as e:
conn.close()
print('Connection closed')
This code creates a socket server that sends an HTML page with the latest sensor readings when it receives a request on the ESP32 or ESP8266 IP address.
Basically, we have a function called web_page() that returns the HTML to build up the web page with the latest sensor readings. This HMTL text builds a table to display the readings:
html = """<html><head><meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,"><style>body { text-align: center; font-family: "Trebuchet MS", Arial;}
table { border-collapse: collapse; width:35%; margin-left:auto; margin-right:auto; }
th { padding: 12px; background-color: #0043af; color: white; }
tr { border: 1px solid #ddd; padding: 12px; }
tr:hover { background-color: #bcbcbc; }
td { border: none; padding: 12px; }
.sensor { color:white; font-weight: bold; background-color: #bcbcbc; padding: 1px;
</style></head><body><h1>ESP with BME280</h1>
<table><tr><th>MEASUREMENT</th><th>VALUE</th></tr>
<tr><td>Temp. Celsius</td><td><span class="sensor">""" + str(bme.temperature) + """</span></td></tr>
<tr><td>Temp. Fahrenheit</td><td><span class="sensor">""" + str(round((bme.read_temperature()/100.0) * (9/5) + 32, 2)) + """F</span></td></tr>
<tr><td>Pressure</td><td><span class="sensor">""" + str(bme.pressure) + """</span></td></tr>
<tr><td>Humidity</td><td><span class="sensor">""" + str(bme.humidity) + """</span></td></tr>
</body></html>"""
Then, we create a socket server that sends the HTML when it gets a request. The HTML text is then saved on the response variable:
response = web_page()
And sent to the client:
conn.sendall(response)
We’ve explained in great detail how these kind of web servers work in previous tutorials. So, if you want to learn how it works, you can read the following articles:
- MicroPython: ESP32/ESP8266 with DHT11/DHT22 Web Server
- ESP32/ESP8266 MicroPython Web Server – Control Outputs
Web Server Demonstration
Upload all the previous files to your ESP32 or ESP8266 board in the following order:
- BME280.py
- boot.py
- main.py
If you don’t know how to upload code, you can read our getting started guides with uPyCraft IDE, or Thonny IDE:
- Getting Started with Thonny MicroPython (Python) IDE for ESP32 and ESP8266
- Getting Started with MicroPython on ESP32 and ESP8266 (uPyCraft IDE)
After uploading the code, your ESP32 or ESP8266 IP address should be displayed on the Serial Monitor.
Open a web browser in your local network and type your ESP IP address (in our example the IP is http://192.168.1.71). You should get a page with the latest sensor readings as shown in the following figure.
Auto refresh web page
With the web server script provided in this project, you need to refresh the web page to see the latest readings. If add the next meta tag inside the HTML <head></head> tags, your web page will auto refresh every 10 seconds:
<meta http-equiv="refresh" content="10">
Wrapping Up
We hope you’ve found this tutorial useful. We have other projects and tutorials with MicroPython that you may like:
- Low Power Weather Station Datalogger using ESP8266 and BME280 with MicroPython
- MicroPython: OLED Display with ESP32 and ESP8266
- MicroPython: ESP32/ESP8266 with DHT11/DHT22 Web Server
- MicroPython: WS2812B Addressable RGB LEDs with ESP32 and ESP8266
If you want to learn more about programming the ESP32 and ESP8266 boards with MicroPython, get access to our eBook: MicroPython Programming with ESP32 and ESP8266.
Thanks for reading.
That is a must for me, thanks for the guide
Hello, thanks for the tutorial! However I’m having a bit of troubles, since the values being read from the bme are all zeroes… It might just be a faulty sensor, but i figured there may be more people with this problem. For example in letscontrolit.com/forum/viewtopic.php?t=2142#top, he had the same problem but managed to solve changing the IDX/var for something other than 0. Do you know what this is?
Thanks for the help and all the knowledge you’re passing!
Hi Francisco.
It seems they are talking about some configuration for ESPEasy firmware.
I don’t know if you can change that with MicroPython.
You can also try using an example from Arduino IDE to check if the sensor is working properly. Also, make sure that your sensor is wired correctly.
Regards,
Sara
Hi, thank you for the tutorial… it’s way easier than others I’ve encountered over the internet.
I’ve created the BME280.py library and flashed it in the ESP32 and after that, I’ve copied and pasted the code inside the main.py file and, hopefully (I’m a real newbie), connected the BME280 correctly to the esp32 via a breadboard.
I get this error:
Traceback (most recent call last):
File “main.py”, line 13, in
File “BME280.py”, line 153, in init
File “BME280.py”, line 159, in _load_calibration
File “BME280.py”, line 119, in readU16LE
File “BME280.py”, line 102, in readU16
OSError: [Errno 19] ENODEV
Same error if the BME280 is connected directly to the esp32 and if the code is moved from the main.py to the boot.py
Can you help me, please? Reading the web, this kind of error happens when somehow the device is not recognized.
Key: 19
Code: ENODEV
Meaning: No such device
(extracted from https :// nodeswitch . com/micropython-programming-for-ESP32-part7)
Thanks a lot!
Regards,
Stefano
Same for me, I just get a different error: OSError: [Errno 110] ETIMEDOUT. It seems to be related to readfrom_mem() calls. Did you find a solution?
Thanks in advance.
Regards,
Andrea
Hi Andrea,
yep, I did it. My problem was in the library, I had a wrong address associated to the BME280. 0x77 instead of 0x76.
FIxing that solved the problem.
Yeup. …Solved my problem. I am learning that you have to check out these driver scripts !
I2C scan showed a 119 (ie: 0X77)… I shoulda known to read the driver code to check if the i2c assignment was the same as the i2c scan value.
Many Thanks !
Hello i had this issu and it work for me changing this:
bme = bme280.BME280(i2c=i2c, address=119) it seems like the default addres is 118 whereas the addres sensor is 119
Hallo, i did all, the first tutorial worked perfectly, the sensor reading every 5 secs showed in my thonny..
But the 2nd tutorial that need the boot.py and then connect to the router, after saving bme280, boot and main…i tried to run the main but i got the following issue:
i dont know why.. can you pls help me? thanks
Hi.
Are you sure you have the boot.py saved in your board?
On the upper left corner of uPyCraft IDE, under the device folder, check that you have boot.py with the right content.
That error means that it can’t find the socket library that should be uploaded in boot.py. If it can’t find it, it probably means it wasn’t uploaded successfully.
Regards,
Sara
Hi Sarah, I am trying despertly to learn this MicroPython. This project is very interesting but I cannot get it to work.
Trying to follow you. The code, I copied the RAW code and pasted it in uPycraft. I saved is at BME280.py and the other code that reads and prints out the information I named it “main.py”. Im sure thats wrong but I lost you at this point. I have a pin BME280 IC, that make a difference with the extra pins?
Both loads ok however after the main.py file loads I get the following errors.
exec(open(‘main.py’)read(),globals()
Traceback (most recent call last):
File “”, line 1, in
File “”, line 13, in
File “BME280.py”, line 153, in_int_
File “BME280.py”, line 159, in_load_calibration
File “BME280.py”, line 119, in_readU16LE
File “BME280.py”, line 102, in_readU16
OSError:[Errno 19] ENODEV
This is what I see.. If you can help me out I greatly appreciate it.
Hi Tim,
I”ve had the same problem.
All I needed to do was to change I2C address to 0x77
and then restart ESP32. It works fine.
Hi,
I’m running into the following issue when running my boot.py file for the BME280 Pressure, Temperature, and Humidity code.
Traceback (most recent call last):
File “”, line 13, in
File “BME280.py”, line 153, in init
File “BME280.py”, line 159, in _load_calibration
File “BME280.py”, line 119, in readU16LE
File “BME280.py”, line 102, in readU16
OSError: [Errno 19] ENODEV
I tried following previous suggestions for changing BME280_I2CADDR = 0x76 to BME280_I2CADDR = 0x77 on line 5 of the BME280.py file but that did not work.
Any suggestions?
Same problem still exists despite changing the i2c address?
I am having the same problem, although my error is:
Warning: I2C(-1, …) is deprecated, use SoftI2C(…) instead
Traceback (most recent call last):
File “”, line 13, in
File “BME280.py”, line 153, in init
File “BME280.py”, line 159, in _load_calibration
File “BME280.py”, line 119, in readU16LE
File “BME280.py”, line 102, in readU16
OSError: [Errno 110] ETIMEDOUT
Is this a problem with using I2C versus SoftI2C? What is the proper way to update this example code?
Thanks, Seth
Hi Seth.
I haven’t faced that error yet.
did you try replacing “I2C” with “SoftI2C”?
Regards,
Sara
from machine import Pin, SoftI2C
from time import sleep
import BME280
ESP32 – Pin assignment
i2c = SoftI2C(scl=Pin(22), sda=Pin(21), freq=10000)
ho, I changed the address too:
from machine import I2C
import time
BME280 default address.
BME280_I2CADDR = 0x77
Hi Sara,
It turns out that the newest release of MicroPython, e.g., v1.14, requires the use of SoftI2C bit banging, and yes, my code now works.
Unfortunately, I think that this new MicroPython release for the ESP series of processors is likely to break many of your excellent MicroPython examples where the old I2C library methods are used, including the MQTT examples. Lots more updating work for you and Ruis… Sorry!
Keep up the great work!
Hi Seth.
Thanks for letting us know.
We’ll wait to see if there are any more changes before we start updating our examples.
We have lots of examples using I2C :'(
Regards,
Sara
Apart from using the SoftI2C what else did you do to make it work? I tried changing the address to 0x77 and still it gave out zeros. Using 1.14 like you
Hello i had this issu and it work for me changing this:
bme = bme280.BME280(i2c=i2c, address=119) it seems like the default addres is 118 whereas the addres sensor is 119
Runs but always gives zeros. I used SoftI2C on v1.14 uPython
I used the web code and it looks like you have the pin assignments backwards
the 8266 uses pin 4 and 5
Shouldn’t the examples say:
In the code, we’re using the ESP32 I2C pins:
i2c = I2C(scl=Pin(22), sda=Pin(21), freq=10000)
If you’re using the ESP8266, comment the previous line and uncomment the following:
i2c = I2C(scl=Pin(5), sda=Pin(4), freq=10000)
Also – I have the three files – I have to run boot – then run main to get it to work – should’t boot run at powerup – and call main?
After playing around a while I got it more or less working BY:
1)power off the D1 then power back up and wait – evetuually it will connect –
-or-
2)pushing reset button will most of the time start it going …
Just concerned about mains power drops and this thing being outside and all …
Hi,
The original BME280.py gives random +-2C temperature spikes under 0C.
Library from https://github.com/robert-hh/BME280 works OK.
Thanks for sharing.
Regards,
Sara
hello, it works with bmp280 sensor, interesting, probably bmp280 and bme280 have same similar register definitions, after looking for most micropython for bmp280, only this lib works for me.
Dear Rui Santos,
it seems to me that there is a typing error in file BME280.py.
In method read_pressure (see code lines below) the right-shift operator >>12 in line 9 should be replaced by a left-shift operator <<12. This can be easily seen when comparing the coding with the coding in the original Bosch data sheet on page 25 (Document number: BST-BME280-DS002-15, Revision_1.6_092018).
In my test case the error mentioned above and as shown below caused a pressure decay of about 150 Pa when I increased the sensor temperature by about 8 K via touching the sensor with my finger. From a physical point of view the pressure decay observed seems to be unreasonable and fortunately it vanishes, when the left-shift operator is used.
def read_pressure(self):
“””Gets the compensated pressure in Pascals.”””
adc = self.read_raw_pressure()
var1 = self.t_fine – 128000
var2 = var1 * var1 * self.dig_P6
var2 = var2 + ((var1 * self.dig_P5) << 17)
var2 = var2 + (self.dig_P4 << 35)
var1 = (((var1 * var1 * self.dig_P3) >> 8) +
((var1 * self.dig_P2) >> 12))
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
var1 = (((1 << 47) + var1) * self.dig_P1) >> 33
if var1 == 0:
return 0
p = 1048576 – adc
p = (((p << 31) – var2) * 3125) // var1
var1 = (self.dig_P9 * (p >> 13) * (p >> 13)) >> 25
var2 = (self.dig_P8 * p) >> 19
return ((p + var1 + var2) >> 8) + (self.dig_P7 << 4)
I also opened an issue at github with same contents as above, but, as I have seen that there are already some untreated open issues I place this info also here. If other users experienced similar problems, this might be the appropriate place. If I am wrong, please correct me and apologize for confusion and for taking your time.
Best regards
Ebi
PS:
Here is the Bosch coding:
// 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
BME280_U32_t BME280_compensate_P_int64(BME280_S32_t adc_P)
{
BME280_S64_t var1, var2, p;
var1 = ((BME280_S64_t)t_fine) – 128000;
var2 = var1 * var1 * (BME280_S64_t)dig_P6;
var2 = var2 + ((var1(BME280_S64_t)dig_P5)<<17);
var2 = var2 + (((BME280_S64_t)dig_P4)<<35);
var1 = ((var1 * var1 * (BME280_S64_t)dig_P3)>>8) + ((var1 * (BME280_S64_t)dig_P2)<<12);
var1 = (((((BME280_S64_t)1)<<47)+var1))((BME280_S64_t)dig_P1)>>33;
if (var1 == 0)
{
return 0; // avoid exception caused by division by zero
}
p = 1048576-adc_P;
p = (((p<<31)-var2)*3125)/var1;
var1 = (((BME280_S64_t)dig_P9) * (p>>13) * (p>>13)) >> 25;
var2 = (((BME280_S64_t)dig_P8) * p) >> 19;
p = ((p + var1 + var2) >> 8) + (((BME280_S64_t)dig_P7)<<4);
return (BME280_U32_t)p;
Dear Rui Santos,
it seems to me that there is a typing error in file BME280.py.
In method read_pressure (see code lines below) the right-shift operator >>12 in line 9 should be replaced by a left-shift operator <<12. This can be easily seen when comparing the coding with the coding in the original Bosch data sheet on page 25 (Document number: BST-BME280-DS002-15, Revision_1.6_092018).
In my test case the error mentioned above and as shown below caused a pressure decay of about 150 Pa when I increased the sensor temperature by about 8 K via touching the sensor with my finger. From a physical point of view the pressure decay observed seems to be unreasonable and fortunately it vanishes, when the left-shift operator is used.
def read_pressure(self):
“””Gets the compensated pressure in Pascals.”””
adc = self.read_raw_pressure()
var1 = self.t_fine – 128000
var2 = var1 * var1 * self.dig_P6
var2 = var2 + ((var1 * self.dig_P5) << 17)
var2 = var2 + (self.dig_P4 << 35)
var1 = (((var1 * var1 * self.dig_P3) >> 8) +
((var1 * self.dig_P2) >> 12))
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
var1 = (((1 << 47) + var1) * self.dig_P1) >> 33
if var1 == 0:
return 0
p = 1048576 – adc
p = (((p << 31) – var2) * 3125) // var1
var1 = (self.dig_P9 * (p >> 13) * (p >> 13)) >> 25
var2 = (self.dig_P8 * p) >> 19
return ((p + var1 + var2) >> 8) + (self.dig_P7 << 4)
I also opened an issue at github with same contents as above, but, as I have seen that there are already some untreated open issues I place this info also here. If other users experienced similar problems, this might be the appropriate place. If I am wrong, please correct me and apologize for confusion and for taking your time.
Best regards
Ebi
PS:
Here is the Bosch coding:
// 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
BME280_U32_t BME280_compensate_P_int64(BME280_S32_t adc_P)
{
BME280_S64_t var1, var2, p;
var1 = ((BME280_S64_t)t_fine) – 128000;
var2 = var1 * var1 * (BME280_S64_t)dig_P6;
var2 = var2 + ((var1(BME280_S64_t)dig_P5)<<17);
var2 = var2 + (((BME280_S64_t)dig_P4)<<35);
var1 = ((var1 * var1 * (BME280_S64_t)dig_P3)>>8) + ((var1 * (BME280_S64_t)dig_P2)<<12);
var1 = (((((BME280_S64_t)1)<<47)+var1))((BME280_S64_t)dig_P1)>>33;
if (var1 == 0)
{
return 0; // avoid exception caused by division by zero
}
p = 1048576-adc_P;
p = (((p<<31)-var2)*3125)/var1;
var1 = (((BME280_S64_t)dig_P9) * (p>>13) * (p>>13)) >> 25;
var2 = (((BME280_S64_t)dig_P8) * p) >> 19;
p = ((p + var1 + var2) >> 8) + (((BME280_S64_t)dig_P7)<<4);
return (BME280_U32_t)p;
Hi,
I would like to make a small correction to my previous comment. The spurious pressure decay observed is not 150 Pa, but instead 1500 Pa or 15 hPa, which is even worse. Sorry for this mistake.
Best regards
Eberhard
Hi,
Thanks for this tutorial.
Unfortunately, after uploading BME280.py code and main.py code to my ESP8266 board and press the RST button to run the code, I get the following message :
Traceback (most recent call last):
File “”, line 11, in
File “BME280.py”, line 153, in init
File “BME280.py”, line 159 in load calibration
File “BME280.py”, line119, in readU16LE
File “BME280.py”, line 102, in readU16
OSError : [Erno 110] ETIMEDOUT
I just start programming with MicroPython and don’t know how to fix it
Thank you and best regards
Gerard
Hi.
Check your I2C connections.
Regards,
Sara
Hi Sara,
Thank you.
The “SCL” jumper wire” did not conduct.
After replacing, I get the same message, but the last line become :
OSError: [Errno 19] ENODEV
Thank you and best regards
Hi Sara,
It is working well now after shifting the GND wire jumper (from the one near “3v3” on the board to the one near “vin” on the board.
Thank you and regards
Hi.
I’m glad everything is working fine.
Usually those errors mean that the I2C connection is not properly establish, which is probably caused by bad wiring.
Regards,
Sara
Hi, thank you for the tutorial.
I would like to extand the script to estimate the altitude.
from
github.com/robert-hh/BME680-Micropython/blob/master/bme680.py
I add to Library BME280.py
import math
self.sea_level_pressure = 1013.25
@property
def altitude(self):
pressure = self.pressure
return 44330 * (1.0 – math.pow(pressure / self.sea_level_pressure, 0.1903))
add to the main.py script
while True:
alt = bme.altitude
print(‘Altitude: ‘, alt)
But now I get the Error:
MPY: soft reboo
Traceback (most recent call last):
File “”, line 28, in
File “BME280.py”, line 294, in altitude
TypeError: unsupported types for truediv: ‘str’, ‘float’
How can I solve this issue?
Thanks a lot!
Regards,
Hanspeter