MicroPython: BME680 с ESP32 и ESP8266 (температура, влажность, давление, газ)
В этом руководстве вы узнаете, как использовать модуль датчика BME680 с ESP32 и ESP8266 для получения показаний температуры, влажности, давления и газа (качества воздуха) с использованием прошивки MicroPython. Мы создадим простой пример для знакомства с датчиком и веб-сервер для отображения показаний.
Предварительные требования
Для выполнения этого руководства вам нужна прошивка MicroPython, установленная на вашу плату ESP32 или ESP8266. Вам также понадобится IDE для написания и загрузки кода на плату. Мы рекомендуем использовать Thonny IDE или uPyCraft IDE:
Thonny IDE:
uPyCraft IDE:
Подробнее о MicroPython: MicroPython Programming with ESP32 and ESP8266 eBook.
Вам также могут быть интересны другие руководства по BME680:
Знакомство с модулем датчика окружающей среды BME680
BME680 — это датчик окружающей среды, который объединяет датчики газа, давления, влажности и температуры. Газовый датчик может обнаруживать широкий спектр газов, таких как летучие органические соединения (VOC). По этой причине BME680 может использоваться для контроля качества воздуха в помещении.
Измерения BME680
BME680 — это цифровой датчик «4 в 1», который измеряет:
Температуру
Влажность
Барометрическое давление
Газ: летучие органические соединения (VOC), такие как этанол и угарный газ
Газовый датчик
BME680 содержит датчик MOX (оксид металла), который обнаруживает VOC в воздухе. Этот датчик даёт качественное представление о сумме VOC/загрязняющих веществ в окружающем воздухе — он не является специфичным для конкретной молекулы газа.
Датчики MOX состоят из поверхности из оксида металла, чувствительного чипа для измерения изменений проводимости и нагревателя. Он обнаруживает VOC путём адсорбции молекул кислорода на чувствительном слое. BME680 реагирует на большинство VOC, загрязняющих воздух в помещении (за исключением CO2).
Когда датчик вступает в контакт с восстанавливающими газами, молекулы кислорода реагируют и увеличивают проводимость поверхности. В качестве необработанного сигнала BME680 выдаёт значения сопротивления. Эти значения изменяются в зависимости от концентрации VOC:
Более высокая концентрация VOC >> Более низкое сопротивление
Более низкая концентрация VOC >> Более высокое сопротивление
Реакции, происходящие на поверхности датчика (а значит, и сопротивление), зависят не только от концентрации VOC, но и от других параметров, таких как температура и влажность.
Важная информация о газовом датчике
Газовый датчик даёт качественное представление о VOC-газах в окружающем воздухе. Таким образом, вы можете отслеживать тенденции, сравнивать результаты и определять, улучшается или ухудшается качество воздуха. Для получения точных измерений необходимо откалибровать датчик по известным источникам и построить калибровочную кривую.
При первом получении датчика рекомендуется запускать его на 48 часов перед началом сбора «реальных» данных. После этого также рекомендуется запускать датчик на 30 минут перед получением показаний газа.
Точность BME680
Вот точность датчиков температуры, влажности и давления BME680:
Датчик |
Точность |
|---|---|
Температура |
+/- 1.0 °C |
Влажность |
+/- 3% |
Давление |
+/- 1 гПа |
Диапазон работы BME680
В следующей таблице показан диапазон работы датчиков температуры, влажности и давления BME680.
Датчик |
Диапазон работы |
|---|---|
Температура |
от -40 до 85 °C |
Влажность |
от 0 до 100% |
Давление |
от 300 до 1100 гПа |
Распиновка BME680
Вот распиновка BME680:
Вывод |
Описание |
|---|---|
VCC |
Питание датчика |
GND |
Общая земля |
SCL |
Вывод SCL для I2C-соединения / Вывод SCK для SPI-соединения |
SDA |
Вывод SDA для I2C-соединения / Вывод SDI (MOSI) для SPI-соединения |
SDO |
Вывод SDO (MISO) для SPI-соединения |
CS |
Вывод выбора чипа для SPI-соединения |
Интерфейс BME680
BME680 поддерживает интерфейсы I2C и SPI.
BME680 I2C
Этот датчик обменивается данными по протоколу I2C, поэтому подключение очень простое. Вы можете использовать пины I2C по умолчанию для ESP32 или ESP8266, как показано в следующей таблице:
BME680 |
ESP32 |
ESP8266 |
|---|---|---|
Vin |
3.3V |
3.3V |
GND |
GND |
GND |
SCL |
GPIO 22 |
GPIO 5 (D1) |
SDA |
GPIO 21 |
GPIO 4 (D2) |
Необходимые компоненты
Для этого проекта вам нужно подключить модуль датчика BME680 к пинам I2C ESP32 или ESP8266. Вот список необходимых компонентов:
Схема подключения — ESP32
Следуйте приведённой ниже схеме, если вы используете плату ESP32:
Рекомендуемое чтение: Справочное руководство по распиновке ESP32
Схема подключения — ESP8266
Следуйте приведённой ниже схеме, если вы используете плату ESP8266:
Рекомендуемое чтение: Справочное руководство по распиновке ESP8266
Библиотека BME680 для MicroPython
Библиотека для чтения данных с датчика BME680 не входит в стандартную библиотеку MicroPython по умолчанию. Поэтому вам нужно загрузить следующую библиотеку на вашу плату ESP32/ESP8266 (сохраните её с именем bme680.py).
# Spaces, comments and some functions have been removed from the original file to save memory
# Original source: https://github.com/adafruit/Adafruit_CircuitPython_BME680/blob/master/adafruit_bme680.py
import time
import math
from micropython import const
from ubinascii import hexlify as hex
try:
import struct
except ImportError:
import ustruct as struct
_BME680_CHIPID = const(0x61)
_BME680_REG_CHIPID = const(0xD0)
_BME680_BME680_COEFF_ADDR1 = const(0x89)
_BME680_BME680_COEFF_ADDR2 = const(0xE1)
_BME680_BME680_RES_HEAT_0 = const(0x5A)
_BME680_BME680_GAS_WAIT_0 = const(0x64)
_BME680_REG_SOFTRESET = const(0xE0)
_BME680_REG_CTRL_GAS = const(0x71)
_BME680_REG_CTRL_HUM = const(0x72)
_BME280_REG_STATUS = const(0xF3)
_BME680_REG_CTRL_MEAS = const(0x74)
_BME680_REG_CONFIG = const(0x75)
_BME680_REG_PAGE_SELECT = const(0x73)
_BME680_REG_MEAS_STATUS = const(0x1D)
_BME680_REG_PDATA = const(0x1F)
_BME680_REG_TDATA = const(0x22)
_BME680_REG_HDATA = const(0x25)
_BME680_SAMPLERATES = (0, 1, 2, 4, 8, 16)
_BME680_FILTERSIZES = (0, 1, 3, 7, 15, 31, 63, 127)
_BME680_RUNGAS = const(0x10)
_LOOKUP_TABLE_1 = (2147483647.0, 2147483647.0, 2147483647.0, 2147483647.0, 2147483647.0,
2126008810.0, 2147483647.0, 2130303777.0, 2147483647.0, 2147483647.0,
2143188679.0, 2136746228.0, 2147483647.0, 2126008810.0, 2147483647.0,
2147483647.0)
_LOOKUP_TABLE_2 = (4096000000.0, 2048000000.0, 1024000000.0, 512000000.0, 255744255.0, 127110228.0,
64000000.0, 32258064.0, 16016016.0, 8000000.0, 4000000.0, 2000000.0, 1000000.0,
500000.0, 250000.0, 125000.0)
def _read24(arr):
ret = 0.0
for b in arr:
ret *= 256.0
ret += float(b & 0xFF)
return ret
class Adafruit_BME680:
def __init__(self, *, refresh_rate=10):
self._write(_BME680_REG_SOFTRESET, [0xB6])
time.sleep(0.005)
chip_id = self._read_byte(_BME680_REG_CHIPID)
if chip_id != _BME680_CHIPID:
raise RuntimeError('Failed 0x%x' % chip_id)
self._read_calibration()
self._write(_BME680_BME680_RES_HEAT_0, [0x73])
self._write(_BME680_BME680_GAS_WAIT_0, [0x65])
self.sea_level_pressure = 1013.25
self._pressure_oversample = 0b011
self._temp_oversample = 0b100
self._humidity_oversample = 0b010
self._filter = 0b010
self._adc_pres = None
self._adc_temp = None
self._adc_hum = None
self._adc_gas = None
self._gas_range = None
self._t_fine = None
self._last_reading = 0
self._min_refresh_time = 1000 / refresh_rate
@property
def pressure_oversample(self):
return _BME680_SAMPLERATES[self._pressure_oversample]
@pressure_oversample.setter
def pressure_oversample(self, sample_rate):
if sample_rate in _BME680_SAMPLERATES:
self._pressure_oversample = _BME680_SAMPLERATES.index(sample_rate)
else:
raise RuntimeError("Invalid")
@property
def humidity_oversample(self):
return _BME680_SAMPLERATES[self._humidity_oversample]
@humidity_oversample.setter
def humidity_oversample(self, sample_rate):
if sample_rate in _BME680_SAMPLERATES:
self._humidity_oversample = _BME680_SAMPLERATES.index(sample_rate)
else:
raise RuntimeError("Invalid")
@property
def temperature_oversample(self):
return _BME680_SAMPLERATES[self._temp_oversample]
@temperature_oversample.setter
def temperature_oversample(self, sample_rate):
if sample_rate in _BME680_SAMPLERATES:
self._temp_oversample = _BME680_SAMPLERATES.index(sample_rate)
else:
raise RuntimeError("Invalid")
@property
def filter_size(self):
return _BME680_FILTERSIZES[self._filter]
@filter_size.setter
def filter_size(self, size):
if size in _BME680_FILTERSIZES:
self._filter = _BME680_FILTERSIZES[size]
else:
raise RuntimeError("Invalid")
@property
def temperature(self):
self._perform_reading()
calc_temp = (((self._t_fine * 5) + 128) / 256)
return calc_temp / 100
@property
def pressure(self):
self._perform_reading()
var1 = (self._t_fine / 2) - 64000
var2 = ((var1 / 4) * (var1 / 4)) / 2048
var2 = (var2 * self._pressure_calibration[5]) / 4
var2 = var2 + (var1 * self._pressure_calibration[4] * 2)
var2 = (var2 / 4) + (self._pressure_calibration[3] * 65536)
var1 = (((((var1 / 4) * (var1 / 4)) / 8192) *
(self._pressure_calibration[2] * 32) / 8) +
((self._pressure_calibration[1] * var1) / 2))
var1 = var1 / 262144
var1 = ((32768 + var1) * self._pressure_calibration[0]) / 32768
calc_pres = 1048576 - self._adc_pres
calc_pres = (calc_pres - (var2 / 4096)) * 3125
calc_pres = (calc_pres / var1) * 2
var1 = (self._pressure_calibration[8] * (((calc_pres / 8) * (calc_pres / 8)) / 8192)) / 4096
var2 = ((calc_pres / 4) * self._pressure_calibration[7]) / 8192
var3 = (((calc_pres / 256) ** 3) * self._pressure_calibration[9]) / 131072
calc_pres += ((var1 + var2 + var3 + (self._pressure_calibration[6] * 128)) / 16)
return calc_pres/100
@property
def humidity(self):
self._perform_reading()
temp_scaled = ((self._t_fine * 5) + 128) / 256
var1 = ((self._adc_hum - (self._humidity_calibration[0] * 16)) -
((temp_scaled * self._humidity_calibration[2]) / 200))
var2 = (self._humidity_calibration[1] *
(((temp_scaled * self._humidity_calibration[3]) / 100) +
(((temp_scaled * ((temp_scaled * self._humidity_calibration[4]) / 100)) /
64) / 100) + 16384)) / 1024
var3 = var1 * var2
var4 = self._humidity_calibration[5] * 128
var4 = (var4 + ((temp_scaled * self._humidity_calibration[6]) / 100)) / 16
var5 = ((var3 / 16384) * (var3 / 16384)) / 1024
var6 = (var4 * var5) / 2
calc_hum = (((var3 + var6) / 1024) * 1000) / 4096
calc_hum /= 1000
if calc_hum > 100:
calc_hum = 100
if calc_hum < 0:
calc_hum = 0
return calc_hum
@property
def altitude(self):
pressure = self.pressure
return 44330 * (1.0 - math.pow(pressure / self.sea_level_pressure, 0.1903))
@property
def gas(self):
self._perform_reading()
var1 = ((1340 + (5 * self._sw_err)) * (_LOOKUP_TABLE_1[self._gas_range])) / 65536
var2 = ((self._adc_gas * 32768) - 16777216) + var1
var3 = (_LOOKUP_TABLE_2[self._gas_range] * var1) / 512
calc_gas_res = (var3 + (var2 / 2)) / var2
return int(calc_gas_res)
def _perform_reading(self):
if (time.ticks_diff(self._last_reading, time.ticks_ms()) * time.ticks_diff(0, 1)
< self._min_refresh_time):
return
self._write(_BME680_REG_CONFIG, [self._filter << 2])
self._write(_BME680_REG_CTRL_MEAS,
[(self._temp_oversample << 5)|(self._pressure_oversample << 2)])
self._write(_BME680_REG_CTRL_HUM, [self._humidity_oversample])
self._write(_BME680_REG_CTRL_GAS, [_BME680_RUNGAS])
ctrl = self._read_byte(_BME680_REG_CTRL_MEAS)
ctrl = (ctrl & 0xFC) | 0x01
self._write(_BME680_REG_CTRL_MEAS, [ctrl])
new_data = False
while not new_data:
data = self._read(_BME680_REG_MEAS_STATUS, 15)
new_data = data[0] & 0x80 != 0
time.sleep(0.005)
self._last_reading = time.ticks_ms()
self._adc_pres = _read24(data[2:5]) / 16
self._adc_temp = _read24(data[5:8]) / 16
self._adc_hum = struct.unpack('>H', bytes(data[8:10]))[0]
self._adc_gas = int(struct.unpack('>H', bytes(data[13:15]))[0] / 64)
self._gas_range = data[14] & 0x0F
var1 = (self._adc_temp / 8) - (self._temp_calibration[0] * 2)
var2 = (var1 * self._temp_calibration[1]) / 2048
var3 = ((var1 / 2) * (var1 / 2)) / 4096
var3 = (var3 * self._temp_calibration[2] * 16) / 16384
self._t_fine = int(var2 + var3)
def _read_calibration(self):
coeff = self._read(_BME680_BME680_COEFF_ADDR1, 25)
coeff += self._read(_BME680_BME680_COEFF_ADDR2, 16)
coeff = list(struct.unpack('<hbBHhbBhhbbHhhBBBHbbbBbHhbb', bytes(coeff[1:39])))
coeff = [float(i) for i in coeff]
self._temp_calibration = [coeff[x] for x in [23, 0, 1]]
self._pressure_calibration = [coeff[x] for x in [3, 4, 5, 7, 8, 10, 9, 12, 13, 14]]
self._humidity_calibration = [coeff[x] for x in [17, 16, 18, 19, 20, 21, 22]]
self._gas_calibration = [coeff[x] for x in [25, 24, 26]]
self._humidity_calibration[1] *= 16
self._humidity_calibration[1] += self._humidity_calibration[0] % 16
self._humidity_calibration[0] /= 16
self._heat_range = (self._read_byte(0x02) & 0x30) / 16
self._heat_val = self._read_byte(0x00)
self._sw_err = (self._read_byte(0x04) & 0xF0) / 16
def _read_byte(self, register):
return self._read(register, 1)[0]
def _read(self, register, length):
raise NotImplementedError()
def _write(self, register, values):
raise NotImplementedError()
class BME680_I2C(Adafruit_BME680):
def __init__(self, i2c, address=0x77, debug=False, *, refresh_rate=10):
self._i2c = i2c
self._address = address
self._debug = debug
super().__init__(refresh_rate=refresh_rate)
def _read(self, register, length):
result = bytearray(length)
self._i2c.readfrom_mem_into(self._address, register & 0xff, result)
if self._debug:
print("\t${:x} read ".format(register), " ".join(["{:02x}".format(i) for i in result]))
return result
def _write(self, register, values):
if self._debug:
print("\t${:x} write".format(register), " ".join(["{:02x}".format(i) for i in values]))
for value in values:
self._i2c.writeto_mem(self._address, register, bytearray([value & 0xFF]))
register += 1
Следуйте следующему набору инструкций для IDE, которую вы используете:
Загрузка библиотеки BME680 с помощью uPyCraft IDE
Загрузка библиотеки BME680 с помощью Thonny IDE
A. Загрузка библиотеки BME680 с помощью uPyCraft IDE
В этом разделе показано, как загрузить библиотеку с помощью uPyCraft IDE. Если вы используете Thonny IDE, читайте следующий раздел.
1. Создайте новый файл, нажав кнопку New File (1).
2. Скопируйте код библиотеки BME680 в этот файл. Код библиотеки BME680 можно найти здесь.
3. После копирования кода сохраните файл, нажав кнопку Save (2).
4. Назовите этот новый файл «bme680.py» и нажмите ok.
5. Нажмите кнопку Download and Run.
Файл должен быть сохранён в папке устройства с именем «bme680.py», как выделено на следующем рисунке.
Теперь вы можете использовать функции библиотеки в своём коде, импортировав библиотеку.
B. Загрузка библиотеки BME680 с помощью Thonny IDE
Если вы используете Thonny IDE, выполните следующие шаги:
1. Скопируйте код библиотеки в новый файл. Код библиотеки BME680 можно найти здесь.
2. Перейдите в File > Save as…
3. Выберите сохранение на «MicroPython device»:
4. Назовите файл bme680.py и нажмите кнопку OK:
Вот и всё. Библиотека загружена на вашу плату. Чтобы убедиться, что она была успешно загружена, перейдите в File > Save as… и выберите MicroPython device. Ваш файл должен быть указан там:
После загрузки библиотеки на плату вы можете использовать функции библиотеки в своём коде, импортировав библиотеку.
Код — температура, влажность, давление и газ (качество воздуха) BME680
После загрузки библиотеки на ESP32 или ESP8266, скопируйте следующий код в файл main.py или boot.py. Он просто выводит температуру, влажность, давление и сопротивление газа в консоль каждые 5 секунд.
# Complete project details at https://RandomNerdTutorials.com/micropython-bme680-esp32-esp8266/
from machine import Pin, I2C
from time import sleep
from bme680 import *
# ESP32 - Pin assignment
i2c = I2C(scl=Pin(22), sda=Pin(21))
# ESP8266 - Pin assignment
#i2c = I2C(scl=Pin(5), sda=Pin(4))
bme = BME680_I2C(i2c=i2c)
while True:
try:
temp = str(round(bme.temperature, 2)) + ' C'
#temp = (bme.temperature) * (9/5) + 32
#temp = str(round(temp, 2)) + 'F'
hum = str(round(bme.humidity, 2)) + ' %'
pres = str(round(bme.pressure, 2)) + ' hPa'
gas = str(round(bme.gas/1000, 2)) + ' KOhms'
print('Temperature:', temp)
print('Humidity:', hum)
print('Pressure:', pres)
print('Gas:', gas)
print('-------')
except OSError as e:
print('Failed to read sensor.')
sleep(5)
Как работает код
Сначала вам нужно импортировать необходимые библиотеки, включая модуль BME680, который вы загрузили ранее.
from machine import Pin, I2C
from time import sleep
from bme680 import *
Установите пины I2C. В данном случае мы используем пины I2C по умолчанию. Если вы используете ESP32, установите пины следующим образом:
i2c = I2C(scl=Pin(22), sda=Pin(21))
Если вы используете ESP8266, закомментируйте предыдущую строку и раскомментируйте следующую, чтобы получилось:
i2c = I2C(scl=Pin(5), sda=Pin(4))
В цикле while создайте объект BME680 с именем bme с пинами I2C, определёнными ранее:
bme = BME680_I2C(i2c=i2c)
Чтение температуры, влажности, давления и сопротивления газа так же просто, как использование методов temperature, humidity, pressure и gas объекта bme.
temp = str(round(bme.temperature, 2)) + ' C'
#temp = (bme.temperature) * (9/5) + 32
#temp = str(round(temp, 2)) + 'F'
hum = str(round(bme.humidity, 2)) + ' %'
pres = str(round(bme.pressure, 2)) + ' hPa'
gas = str(round(bme.gas/1000, 2)) + ' KOhms'
Наконец, выведите показания в консоль:
print('Temperature: ', temp)
print('Humidity: ', hum)
print('Pressure: ', pres)
print('Gas:', gas)
В конце мы добавляем задержку в 5 секунд:
sleep(5)
Демонстрация
После загрузки кода на плату нажмите кнопку RST для запуска кода. Новые показания датчика BME680 должны отображаться каждые 5 секунд.
Отображение показаний BME680 на веб-сервере
Теперь, когда вы знаете, как получить температуру, влажность, давление и газ с датчика BME680, мы отобразим показания датчика на веб-сервере, к которому можно получить доступ в вашей локальной сети.
Для этого примера вам нужны три файла:
bme680.py: это файл, содержащий все методы для работы с датчиком BME680. Это файл, который вы загрузили ранее.
boot.py: запускается при старте устройства и устанавливает несколько параметров конфигурации, таких как учётные данные сети, импорт библиотек, настройка пинов и т.д.
main.py: это основной скрипт, в котором мы будем обрабатывать веб-сервер. Он выполняется сразу после boot.py.
Примечание: Хорошей практикой является использование файлов boot.py и main.py. Однако при желании вы можете включить весь код в файл main.py.
boot.py
Создайте новый файл в вашей IDE с именем boot.py и скопируйте следующий код.
# Complete project details at https://RandomNerdTutorials.com/micropython-bme680-esp32-esp8266/
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()
from bme680 import *
# ESP32 - Pin assignment
i2c = I2C(scl=Pin(22), sda=Pin(21))
# ESP8266 - Pin assignment
#i2c = I2C(scl=Pin(5), sda=Pin(4))
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())
Этот файл импортирует необходимые библиотеки, определяет пины I2C для подключения к датчику и подключается к вашей сети.
В коде мы используем пины I2C ESP32:
i2c = I2C(scl=Pin(22), sda=Pin(21))
Если вы используете ESP8266, закомментируйте предыдущую строку и раскомментируйте следующую:
i2c = I2C(scl=Pin(5), sda=Pin(4))
Затем вставьте учётные данные вашей сети в следующие переменные:
ssid = 'REPLACE_WITH_YOUR_SSID'
password = 'REPLACE_WITH_YOUR_PASSWORD'
main.py
В файле main.py мы создадим веб-сервер и будем обрабатывать запросы. Скопируйте следующий код в файл main.py.
# Complete project details at https://RandomNerdTutorials.com/micropython-bme680-esp32-esp8266/
def web_page():
bme = BME680_I2C(i2c=i2c)
html = """<html><head><title>ESP with BME680</title>
<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; 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 BME680</h1>
<table><tr><th>MEASUREMENT</th><th>VALUE</th></tr>
<tr><td>Temp. Celsius</td><td><span class="sensor">""" + str(round(bme.temperature, 2)) + """ C</span></td></tr>
<tr><td>Temp. Fahrenheit</td><td><span class="sensor">""" + str(round((bme.temperature) * (9/5) + 32, 2)) + """ F</span></td></tr>
<tr><td>Pressure</td><td><span class="sensor">""" + str(round(bme.pressure, 2)) + """ hPa</span></td></tr>
<tr><td>Humidity</td><td><span class="sensor">""" + str(round(bme.humidity, 2)) + """ %</span></td></tr>
<tr><td>Gas</td><td><span class="sensor">""" + str(round(bme.gas/1000, 2)) + """ KOhms</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')
Этот код создаёт сервер на сокетах, который отправляет HTML-страницу с последними показаниями датчика при получении запроса на IP-адрес ESP32 или ESP8266.
По сути, у нас есть функция web_page(), которая возвращает HTML для построения веб-страницы с последними показаниями датчика. Этот HTML-текст создаёт таблицу для отображения показаний:
def web_page():
bme = BME680_I2C(i2c=i2c)
html = """<html><head><title>ESP with BME680</title>
<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; 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 BME680</h1>
<table><tr><th>MEASUREMENT</th><th>VALUE</th></tr>
<tr><td>Temp. Celsius</td><td><span class="sensor">""" + str(round(bme.temperature, 2)) + """ C</span></td></tr>
<tr><td>Temp. Fahrenheit</td><td><span class="sensor">""" + str(round((bme.temperature) * (9/5) + 32, 2)) + """ F</span></td></tr>
<tr><td>Pressure</td><td><span class="sensor">""" + str(round(bme.pressure, 2)) + """ hPa</span></td></tr>
<tr><td>Humidity</td><td><span class="sensor">""" + str(round(bme.humidity, 2)) + """ %</span></td></tr>
<tr><td>Gas</td><td><span class="sensor">""" + str(round(bme.gas/1000, 2)) + """ KOhms</span></td></tr></body></html>"""
return html
Затем мы создаём сервер на сокетах, который отправляет HTML при получении запроса. HTML-текст сохраняется в переменной response:
response = web_page()
И отправляется клиенту:
conn.sendall(response)
Мы подробно объясняли, как работают такие веб-серверы, в предыдущих руководствах. Если вы хотите узнать, как это работает, вы можете прочитать следующие статьи:
Демонстрация веб-сервера
Загрузите все предыдущие файлы на плату ESP32 или ESP8266 в следующем порядке:
bme680.py
boot.py
main.py
Если вы не знаете, как загружать код, вы можете прочитать наши руководства по началу работы с uPyCraft IDE или Thonny IDE:
Начало работы с Thonny MicroPython (Python) IDE для ESP32 и ESP8266
Начало работы с MicroPython на ESP32 и ESP8266 (uPyCraft IDE)
После загрузки кода IP-адрес вашего ESP32 или ESP8266 должен отобразиться в Serial Monitor.
Откройте веб-браузер в вашей локальной сети и введите IP-адрес вашего ESP (в нашем примере IP — http://192.168.1.114). Вы должны получить страницу с последними показаниями датчика, как показано на следующем рисунке.
Автообновление веб-страницы
В скрипте веб-сервера, представленном в этом проекте, вам нужно обновлять веб-страницу, чтобы увидеть последние показания. Если вы добавите следующий мета-тег внутрь HTML-тегов <head></head>, ваша веб-страница будет автоматически обновляться каждые 10 секунд:
<meta http-equiv="refresh" content="10">
Заключение
Мы надеемся, что это руководство было для вас полезным. У нас есть другие проекты и руководства по MicroPython, которые могут вам понравиться:
Метеостанция с низким энергопотреблением на ESP8266 и BME280 с MicroPython
MicroPython: ESP32/ESP8266 с датчиком DHT11/DHT22 — веб-сервер
MicroPython: адресные RGB-светодиоды WS2812B с ESP32 и ESP8266
Если вы хотите узнать больше о программировании ESP32 и ESP8266 с MicroPython, получите доступ к нашей электронной книге: MicroPython Programming with ESP32 and ESP8266.
Спасибо за чтение.