Servidor Web Raspberry Pi Pico BME680 com MicroPython
Neste guia do usuário, aprenderemos a criar um servidor web Raspberry Pi Pico com sensor ambiental BME680, que é usado para medir temperatura ambiente, pressão barométrica, umidade relativa e gás (VOC) ou qualidade do ar interno (IAQ). Aprenderemos como exibir valores de sensores em uma página da Web usando o firmware Raspberry Pi Pico e MicroPython. Este servidor da web funcionará como uma estação meteorológica, pois mostrará as leituras de temperatura, umidade, pressão e IAQ na página da web.
Raspberry Pi Pico não suporta recursos Wi-Fi, portanto, temos que usar um módulo Wi-Fi separado para habilitar a conectividade Wi-Fi. Portanto, vamos fazer a interface e programar o módulo Wi-Fi ESP-01 com o Raspberry Pi Pico para habilitar os recursos Wi-Fi. Usaremos o Thonny IDE para programar o Raspberry Pi Pico com ESP-01 e BME680 em MircoPython. Usaremos comandos AT através da porta serial que é UART para configurar o módulo Wi-Fi ESP-01.
Conteudo
Pré-requisitos
Antes de começarmos esta lição, certifique-se de que você esteja familiarizado e tenha a versão mais recente do Python 3 em seu sistema, tenha configurado o MicoPython no Raspberry Pi Pico e tenha um Ambiente de Desenvolvimento Integrado (IDE) em execução no qual faremos a programação.
Introdução ao BME680
O BME680 é um sensor quatro em um de baixa potência, que possui sensores integrados de temperatura, pressão, umidade e detecção de gás. Ele funciona em uma tensão de operação de 1,8-3,8V e se comunica com outros microcontroladores através do protocolo I2C e SPI. Este sensor é usado em áreas como rastreamento da qualidade do ar, indicadores de umidade, tendências climáticas, automação residencial e controle e aprimoramentos de GPS.
Faixa de operação e precisão
Alguns dos principais recursos do BME680 incluem:
- Medição de temperatura: mede a temperatura ambiente com precisão de ±1,0°C e faixa de operação de -40 a 85°C.
- Medição de Umidade Relativa: mede a umidade relativa com uma taxa de resposta rápida e uma precisão de ±3% e uma faixa de operação de 0-100%.
- Medição de pressão: mede a pressão barométrica com precisão absoluta de ±1 hPa e a altitude com precisão de ±1 metro. A faixa de operação de pressão varia de 300-1100 hPa.
Precisão | Faixa de operação | |
Temperatura | ±1.0°C | -40 a 85 ºC |
Humidade | ±3% | 0-100% |
Pressão | ±1 hPa | 300-1100 hPa |
- Medição de gás: detecta uma ampla gama de gases, incluindo compostos orgânicos voláteis (VOCs), determinando assim a qualidade do ar interno.
- Devido ao seu tamanho compacto e operação de baixo consumo de energia, é adequado para aplicações móveis, smartwatches e sistemas de navegação.
Em comparação com o BME280, o BME680 é um sensor exclusivo e atualizado no sentido de que contém um sensor MOX (óxido metálico) de tamanho pequeno.
Sensor de gás
O sensor BME680 pode determinar o número de poluentes/COVs no ambiente, como monóxido de carbono, etano, isopreno/2-metil-1,3 butadieno, acetona e etanol. Os COVs são detectados pela adsorção de moléculas de oxigênio na camada de óxido metálico. Sua detecção real é feita pelo princípio de alterar a resistência do sensor MOX. Sempre que o MOX entra em contato com um poluente no ar, a resistência do sensor muda com a concentração dos poluentes presentes. Isso significa que o maior número de poluentes no ar leva a uma resistência significativamente menor do sensor. Da mesma forma, com a menor concentração de VOCs no ar, a resistência do sensor é significativamente maior.
Observação: O sensor de gás BME680 não é um sensor de medição de CO2 ou etanol. Ele obtém a ideia relativa do CO2 do VOC no ar, mas não podemos usá-lo para medição direta do CO2.
Como todos os outros sensores de gás, o BME680 também fornece resultados variáveis a cada vez. Para garantir maior precisão, temos que calibrá-lo em relação a uma fonte conhecida e, em seguida, traçar sua curva. Como os níveis de sensibilidade não são constantes durante o uso inicial do sensor, recomenda-se inicialmente executá-lo por quarenta e oito horas, que depois pode ser ajustado para trinta minutos antes de cada uso.
Módulos BME680
Vários tipos de sensores BME680 com diferentes tamanhos e números de terminais estão disponíveis no mercado. Mas todos os módulos fornecem dados através de interfaces SPI e I2C e podemos usar o mesmo script MicroPython para obter as leituras dos sensores. Alguns deles são mostrados abaixo:
Você pode escolher o módulo de acordo com sua conveniência e o tipo de microcontrolador ao qual deseja conectá-lo. Neste artigo, usaremos o sensor BME680 com 6 terminais, mostrado abaixo. Possui 4 terminais SPI e 2 I2C.
Diagrama de pinagem
A figura abaixo mostra o sensor BME680 e sua pinagem.
Nome Pino | Descrição |
VCC | Este pino energiza o sensor. |
GND | Este é o pino de aterramento comum para alimentação e lógica. |
SCL | Ao usar o protocolo I2C este pino atua como SCL ou pino de clock serial e ao usar o protocolo SPI este pino atua como SCK ou o pino serial para SPI. É a entrada para o chip. |
SDA | Ao usar o protocolo I2C este pino atua como pino SDA ou Serial Data e ao usar o protocolo SPI este pino atua como SDI ou Serial Data In também conhecido como MOSI (‘Master out Slave in’). Isso é usado como a entrada I2C/SPI para o sensor. |
SDO | Este é o pino SDO (Slave data out) /MISO (Master in slave out) para comunicação SPI. Este pino é usado como saída SPI do sensor. |
CS | Este é o pino Chip Select usado na comunicação SPI. Atua como uma entrada para o sensor. |
Interface Raspberry Pi Pico com BME680 e ESP-01
Esta seção mostra como conectar o Raspberry Pi Pico com o sensor BME680 e o ESP-01.
Vamos precisar dos seguintes componentes:
- Raspberry PI Pico
- Sensor BME680
- Módulo ESP-01
- Fios de conexão
- Protoboard
Raspberry Pi Pico com BME680
Conforme discutido anteriormente, o BME680 oferece duas interfaces, como I2C e SPI. Podemos usar a interface SPI ou I2C para conectar um sensor ao Raspberry Pi Pico. SPI requer quatro pinos para se comunicar. Pelo contrário, o I2C requer dois pinos. Portanto, usaremos a interface I2C para este artigo.
A conexão do BME680 com o Raspberry Pi Pico é muito simples. Temos que conectar o terminal VCC com 3,3V, terra com o terra (terra comum), SCL do sensor com SCL da placa e SDA do sensor com o pino SDA da placa.
Pinos I2C Raspberry Pi Pico
Raspberry Pi Pico tem dois controladores I2C. Ambos os controladores I2C são acessíveis através dos pinos GPIO do Raspberry Pi Pico. A tabela a seguir mostra a conexão dos pinos GPIO com os dois controladores I2C. Cada conexão do controlador pode ser configurada através de vários pinos GPIO conforme mostrado na figura. Mas antes de usar um controlador I2C, você deve configurar no software quais pinos GPIO você deseja usar com um controlador I2C específico.
Controlador I2C | Pinos GPIO |
I2C0 – SDA | GP0/GP4/GP8/GP12/GP16/GP20 |
I2C0 – SCL | GP1/GP5/GP9/GP13/GP17/GP21 |
I2C1 – SDA | GP2/GP6/GP10/GP14/GP18/GP26 |
I2C1 – SCL | GP3/GP7/GP11/GP15/GP19/GP27 |
As conexões entre os dois dispositivos que estamos usando podem ser vistas abaixo.
BME680 | Raspberry Pi Pico |
VCC | 3.3V |
SDA | GP2 (I2C1 SDA) |
SCL | GP3 (I2C1 SCL) |
GND | GND |
Usamos as mesmas conexões especificadas na tabela acima. No entanto, você também pode usar outras combinações de pinos SDA/SCL, mas lembre-se de alterá-las no script MicroPython.
Raspberry Pi Pico com ESP-01
O módulo ESP-01 é composto por 8 pinos. No entanto, usaremos 5 pinos para conectar com a placa Pi Pico. Estes incluem os pinos VCC, EN, GND, RX e TX. Os pinos RX e TX do módulo serão conectados aos pinos UART da placa Pi Pico. Vamos primeiro dar uma olhada nos pinos UART do Raspberry Pi Pi.
Pinos UART Raspberry Pi Pico
Raspberry Pi Pico contém dois periféricos UART idênticos com FIFOs 32×8 Tx e 32×12 Rx separados.
A tabela a seguir lista os pinos GPIO para ambos os periféricos UART que são expostos nas pinagens da placa de desenvolvimento Raspberry Pi Pico.
Pinos UART | Pinos GPIO |
UART0-TX | GP0/GP12/GP16 |
UART0-RX | GP1/GP13/GP17 |
UART1-TX | GP4/GP8 |
UART1-RX | GP5/GP9 |
Para este guia, usaremos os pinos UART0-TX e RX.
Siga o diagrama de conexão abaixo para conectar os dois dispositivos.
Raspberry Pi Pico | ESP-01 |
3.3V | VCC |
3.3V | EN |
GND | GND |
GP1 (UART0 RX) | TX |
GP0 (UART0 TX) | RX |
Diagrama de conexão Raspberry Pi Pico com BME680 e ESP-01
Usamos as mesmas conexões fornecidas nas duas tabelas acima. Todos os três dispositivos serão comumente aterrados e alimentados com o mesmo pino de 3,3 V do Raspberry Pi Pico.
O diagrama abaixo mostra o diagrama de conexão do Raspberry Pi Pico com BME680 e ESP-01.
Biblioteca MicroPython BME680
Para este projeto, precisaremos da biblioteca MicroPython BME680.
Usaremos o Thonny IDE para programar nosso Raspberry Pi Pico. Certifique-se de ter a versão mais recente do IDE instalada em seu sistema. Abra um novo arquivo no Thonny. Copie a biblioteca abaixo. Salve-o no Raspberry Pi Pico com o nome bme680.py na pasta lib.
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
Servidor Web MicroPython Script Raspberry Pi Pico BME680 com ESP-01 (Exibir temperatura, umidade, gás e pressão)
import uos import machine import utime from machine import Pin, I2C from bme680 import * recv_buf="" # receive buffer global variable print() print("Machine: \t" + uos.uname()[4]) print("MicroPython: \t" + uos.uname()[3]) i2c=I2C(1,sda=Pin(2), scl=Pin(3), freq=400000) #initializing the I2C method bme = BME680_I2C(i2c=i2c) uart0 = machine.UART(0, baudrate=115200) print(uart0) def Rx_ESP_Data(): recv=bytes() while uart0.any()>0: recv+=uart0.read(1) res=recv.decode('utf-8') return res def Connect_WiFi(cmd, uart=uart0, timeout=3000): print("CMD: " + cmd) uart.write(cmd) utime.sleep(7.0) Wait_ESP_Rsp(uart, timeout) print() def Send_AT_Cmd(cmd, uart=uart0, timeout=3000): print("CMD: " + cmd) uart.write(cmd) Wait_ESP_Rsp(uart, timeout) print() def Wait_ESP_Rsp(uart=uart0, timeout=3000): prvMills = utime.ticks_ms() resp = b"" while (utime.ticks_ms()-prvMills)<timeout: if uart.any(): resp = b"".join([resp, uart.read(1)]) print("resp:") try: print(resp.decode()) except UnicodeError: print(resp) Send_AT_Cmd('AT\r\n') #Test AT startup Send_AT_Cmd('AT+GMR\r\n') #Check version information Send_AT_Cmd('AT+CIPSERVER=0\r\n') #Check version information Send_AT_Cmd('AT+RST\r\n') #Check version information Send_AT_Cmd('AT+RESTORE\r\n') #Restore Factory Default Settings Send_AT_Cmd('AT+CWMODE?\r\n') #Query the Wi-Fi mode Send_AT_Cmd('AT+CWMODE=1\r\n') #Set the Wi-Fi mode = Station mode Send_AT_Cmd('AT+CWMODE?\r\n') #Query the Wi-Fi mode again #Send_AT_Cmd('AT+CWLAP\r\n', timeout=10000) #List available APs Connect_WiFi('AT+CWJAP="A32-xX23F","2eXX3A1n"\r\n', timeout=5000) #Connect to AP Send_AT_Cmd('AT+CIFSR\r\n',timeout=5000) #Obtain the Local IP Address Send_AT_Cmd('AT+CIPMUX=1\r\n') #Obtain the Local IP Address utime.sleep(1.0) Send_AT_Cmd('AT+CIPSERVER=1,80\r\n') #Obtain the Local IP Address utime.sleep(1.0) print ('Starting connection to ESP8266...') while True: res ="" res=Rx_ESP_Data() utime.sleep(2.0) if '+IPD' in res: # if the buffer contains IPD(a connection), then respond with HTML handshake temperature = str(round(bme.temperature, 2)) + ' C' humidity = str(round(bme.humidity, 2)) + ' %' pressure = str(round(bme.pressure, 2)) + ' hPa' gas = str(round(bme.gas/1000, 2)) + ' KOhms' print('Temperature:', temperature) print('Humidity:', humidity) print('Pressure:', pressure) print('Gas:', gas) print('-------') id_index = res.find('+IPD') print("resp:") print(res) connection_id = res[id_index+5] print("connectionId:" + connection_id) print ('! Incoming connection - sending webpage') uart0.write('AT+CIPSEND='+connection_id+',1440'+'\r\n') #Send a HTTP response then a webpage as bytes the 108 is the amount of bytes you are sending, change this if you change the data sent below utime.sleep(1.0) uart0.write('HTTP/1.1 200 OK'+'\r\n') uart0.write('Content-Type: text/html'+'\r\n') uart0.write('Connection: close'+'\r\n') uart0.write(''+'\r\n') uart0.write('<!DOCTYPE HTML>'+'\r\n') uart0.write('<html><head>'+'\r\n') uart0.write('<title>BME680 Web Server</title>'+'\r\n') uart0.write('<meta http-equiv=\"refresh\" content=\"10\">'+'\r\n') uart0.write('<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\'\r\n') uart0.write('<link rel=\"icon\" href=\"data:,\">'+'\r\n') uart0.write('<style>'+'\r\n') uart0.write('html {font-family: Arial; display: inline-block; text-align: center;}'+'\r\n') uart0.write('p { font-size: 1.2rem;}'+'\r\n') uart0.write('body { margin: 0;}'+'\r\n') uart0.write('.topnav { overflow: hidden; background-color: #5c055c; color: white; font-size: 1.7rem; }'+'\r\n') uart0.write('.content { padding: 20px; }'+'\r\n') uart0.write('.card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); }'+'\r\n') uart0.write('.cards { max-width: 700px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }'+'\r\n') uart0.write('.reading { font-size: 2.8rem; }'+'\r\n') uart0.write('.card.temperature { color: #0e7c7b; }'+'\r\n') uart0.write('.card.humidity { color: #17bebb; }'+'\r\n') uart0.write('.card.pressure { color: hsl(113, 61%, 29%); }'+'\r\n') uart0.write('.card.gas { color: #5c055c; }'+'\r\n') uart0.write('</style>'+'\r\n') uart0.write('</head>'+'\r\n') uart0.write('<body>'+'\r\n') uart0.write('<div class=\"topnav\">'+'\r\n') uart0.write('<h3>Raspberry Pi Pico BME680 WEB SERVER</h3>'+'\r\n') uart0.write('</div>'+'\r\n') uart0.write('<div class=\"content\">'+'\r\n') uart0.write('<div class=\"cards\">'+'\r\n') uart0.write('<div class=\"card temperature\">'+'\r\n') uart0.write('<h4>Temp. Celsius</h4><p><span class=\"reading\">' + temperature + '</p>'+'\r\n') uart0.write('</div>'+'\r\n') uart0.write('<div class=\"card humidity\">'+'\r\n') uart0.write('<h4>Humidity</h4><p><span class=\"reading\">' + humidity + '</p>'+'\r\n') uart0.write('</div>'+'\r\n') uart0.write('<div class=\"card pressure\">'+'\r\n') uart0.write('<h4>PRESSURE</h4><p><span class=\"reading\">' + pressure +'</p>'+'\r\n') uart0.write('</div>'+'\r\n') uart0.write('<div class=\"card gas\">' +'\r\n') uart0.write('<h4>Gas</h4><p><span class=\"reading\">' + gas + '</p>'+'\r\n') uart0.write('</div></div></div>'+'\r\n') uart0.write('</body></html>'+'\r\n') utime.sleep(4.0) Send_AT_Cmd('AT+CIPCLOSE='+ connection_id+'\r\n') # once file sent, close connection utime.sleep(4.0) recv_buf="" #reset buffer print ('Waiting For connection...')
Como o Código Funciona?
Começaremos importando o módulo máquina e o módulo uos. Também importaremos a classe I2C e Pin do módulo da máquina. Isso ocorre porque temos que especificar o pino para comunicação I2C. Também importamos o módulo utime para que possamos adicionar um atraso de 10 segundos entre nossas leituras. Além disso, importe a biblioteca bme280 que instalamos anteriormente.
import uos import machine import utime from machine import Pin, I2C from bme680 import *
Em seguida, imprimiremos as informações sobre nosso sistema operacional atual no terminal Thonny shell. Vamos uos.uname() e imprimir a versão e lançamento do sistema operacional.
print() print("Machine: \t" + uos.uname()[4]) print("MicroPython: \t" + uos.uname()[3])
Inicializar a comunicação I2C
Em seguida, inicializaremos os pinos I2C GPIO para SCL e SDA, respectivamente. Usamos os pinos I2C1 SCL e I2C0 SDA.
Criamos um método I2C() que recebe quatro parâmetros. O primeiro parâmetro é o canal I2C que estamos usando. O segundo parâmetro especifica o pino I2C GPIO da placa que está conectada à linha SDA. O terceiro parâmetro especifica o pino I2C GPIO da placa que está conectada à linha SCL. O último parâmetro é a conexão de frequência.
Estamos configurando o SCL no pino 3 e o SDA no pino 2.
i2c=I2C(1,sda=Pin(2), scl=Pin(3), freq=400000)
Em seguida, criamos um objeto do BME680 chamado bme e especificamos o protocolo de comunicação I2C para ler os dados do sensor. Isso será usado para acessar as leituras do sensor.
bme = BME680_I2C(i2c=i2c)
Inicializar a comunicação UART
Em seguida, criaremos um objeto uart usando UART() e especificaremos o canal UART como o primeiro parâmetro e a taxa de transmissão como o segundo parâmetro. Estamos usando UART0 neste caso com baud rate 115200 para a comunicação uart. O ESP8266 tem uma taxa de transmissão padrão de 115200, portanto, usaremos a mesma taxa de transmissão aqui para a comunicação UART do Raspberry Pi Pico para criar a sincronização. Além disso, também imprimiremos os detalhes do UART no terminal do shell.
uart0 = machine.UART(0, baudrate=115200) print(uart0)
Esta função Connect_WiFi() é usada para conectar o ESP8266 com WiFi.
def Connect_WiFi(cmd, uart=uart0, timeout=3000): print("CMD: " + cmd) uart.write(cmd) utime.sleep(7.0) Wait_ESP_Rsp(uart, timeout) print()
A seguir, definiremos três funções. O primeiro é Rx_ESP_Data(). Isso lê os dados seriais que estão sendo recebidos. Esses dados são decodificados do formato UTF-8 e retornados.
def Rx_ESP_Data(): recv=bytes() while uart0.any()>0: recv+=uart0.read(1) res=recv.decode('utf-8') return res
A segunda função é Send_AT_Cmd(cmd, uart=uart0, timeout=3000). Leva em três parâmetros, o comando AT, o canal UART e o tempo de resposta. Esta função será utilizada para enviar um comando AT para o ESP8266 via uart0. O tempo de resposta é definido para 3 segundos.
def Send_AT_Cmd(cmd, uart=uart0, timeout=3000): print("CMD: " + cmd) uart.write(cmd) Wait_ESP_Rsp(uart, timeout) print()
A função Wait_ESP_Rsp(uart=uart0, timeout=3000) aguarda 3 segundos para obter a resposta do ESP8266. Após receber os dados do ESP8266 ele concatena os bytes recebidos e os imprime no terminal shell.
def Wait_ESP_Rsp(uart=uart0, timeout=3000): prvMills = utime.ticks_ms() resp = b"" while (utime.ticks_ms()-prvMills)<timeout: if uart.any(): resp = b"".join([resp, uart.read(1)]) print("resp:") try: print(resp.decode()) except UnicodeError: print(resp)
Comandos AT
Agora vamos ver a série de comandos AT que enviaremos através do UART0 para o ESP8266.
Send_AT_Cmd('AT\r\n') #Test AT startup Send_AT_Cmd('AT+GMR\r\n') #Check version information Send_AT_Cmd('AT+CIPSERVER=0\r\n') #Check version information Send_AT_Cmd('AT+RST\r\n') #Check version information Send_AT_Cmd('AT+RESTORE\r\n') #Restore Factory Default Settings Send_AT_Cmd('AT+CWMODE?\r\n') #Query the Wi-Fi mode Send_AT_Cmd('AT+CWMODE=1\r\n') #Set the Wi-Fi mode = Station mode Send_AT_Cmd('AT+CWMODE?\r\n') #Query the Wi-Fi mode again Connect_WiFi('AT+CWJAP="A32-X23F","3X421X1a"\r\n', timeout=5000) #Connect to AP Send_AT_Cmd('AT+CIFSR\r\n',timeout=5000) #Obtain the Local IP Address Send_AT_Cmd('AT+CIPMUX=1\r\n') #Obtain the Local IP Address utime.sleep(1.0) Send_AT_Cmd('AT+CIPSERVER=1,80\r\n') #Obtain the Local IP Address utime.sleep(1.0)
AT: Este tipo de comando é usado para testar a função de inicialização do módulo WiFi. A resposta seria ok, contra este comando se tudo estiver ok.
Send_AT_Cmd('AT\r\n') #Test AT startup
AT+GMR: Este tipo de comando AT é usado para verificar a versão do comando AT e usamos a versão SDK do comando AT neste tipo de módulo WIFI.
Send_AT_Cmd('AT+GMR\r\n') #Check version information
AT+CIPSERVER=0: Isso configura o ESP8266 como servidor e define o modo como 0, o que significa excluir servidor (precisa seguir por reinicialização)
Send_AT_Cmd('AT+CIPSERVER=0\r\n')
AT+RST: Este tipo de comando é usado para redefinir o módulo WiFi quando estiver em condições de funcionamento. A resposta seria ok, quando resetar o módulo.
Send_AT_Cmd('AT+RST\r\n')
AT+RESTORE: Este tipo de comando é usado para restaurar as configurações de fábrica significa, quando este comando é inserido, todos os parâmetros são redefinidos automaticamente para os padrões.
Send_AT_Cmd('AT+RESTORE\r\n') #Restore Factory Default Settings
AT+CWMODE?: Este tipo de comando é usado para consultar o modo WiFi do ESP8266.
Send_AT_Cmd('AT+CWMODE?\r\n') #Query the WiFi mode
AT+CWMODE=1: Isso define o modo WiFi do ESP8266 neste caso no modo estação.
Send_AT_Cmd('AT+CWMODE=1\r\n') #Set the WiFi mode = Station mode
AT+CWJAP=”SSID”,”PASSWORD”\r\n’, timeout=TIME_ms: Isso conecta o ESP8266 com um AP cujo SSID e senha são fornecidos, O tempo limite aqui é o tempo de reconexão.
Connect_WiFi('AT+CWJAP="A31-x221","1uX73A1n"\r\n', timeout=5000) #Connect to AP
AT+CIFSR: Este comando obtém o endereço IP local.
Send_AT_Cmd('AT+CIFSR\r\n')
AT+CIPMUX=1: Este comando é usado para habilitar múltiplas conexões (máximo 4)
Send_AT_Cmd('AT+CIPMUX=1\r\n')
AT+CIPSERVER=1:Este comando configura o ESP8266 como servidor.
Send_AT_Cmd('AT+CIPSERVER=1,80\r\n')
loop while
Dentro do loop while, vamos primeiro chamar Rx_ESP_Data() que retorna os dados que o ESP8266 recebe. Isso é salvo na variável ‘res.’
Adicione um atraso de 2 segundos antes de prosseguir.
res ="" res=Rx_ESP_Data() utime.sleep(2.0)
A seguir, verificaremos se o buffer contém ou não uma conexão IPD. Se isso acontecer, responda com um handshake HTML.
Para obter as leituras do sensor, usaremos o objeto “bme” nos métodos de temperatura, umidade, pressão e gás. Essas leituras são salvas em suas variáveis correspondentes.
Imprima as leituras do sensor BME680 junto com a resposta no terminal shell. Obtenha o ID de conexão e imprima-o também.
if '+IPD' in res: # if the buffer contains IPD(a connection), then respond with HTML handshake temperature = str(round(bme.temperature, 2)) + ' C' humidity = str(round(bme.humidity, 2)) + ' %' pressure = str(round(bme.pressure, 2)) + ' hPa' gas = str(round(bme.gas/1000, 2)) + ' KOhms' print('Temperature:', temperature) print('Humidity:', humidity) print('Pressure:', pressure) print('Gas:', gas) print('-------') id_index = res.find('+IPD') print("resp:") print(res) connection_id = res[id_index+5] print("connectionId:" + connection_id)
Então, usando o objeto uart no método write(), enviaremos os bytes para o UART. Primeiro, estamos escrevendo o comando AT: AT+CIPSEND=’ID’, ‘LENGTH’ Isso definirá o comprimento dos dados que serão enviados. Em seguida, após um atraso de 1 segundo, escreveremos o corpo HTML que construirá a página da web na porta serial. Depois disso, fecharemos as múltiplas conexões enquanto estamos enviando o comando AT: AT+CIPCLOSE=’ID’. Em seguida, vamos redefinir o buffer e aguardar a conexão.
print ('! Incoming connection - sending webpage') uart0.write('AT+CIPSEND='+connection_id+',1440'+'\r\n') #Send a HTTP response then a webpage as bytes the 108 is the amount of bytes you are sending, change this if you change the data sent below utime.sleep(1.0) uart0.write('HTTP/1.1 200 OK'+'\r\n') uart0.write('Content-Type: text/html'+'\r\n') uart0.write('Connection: close'+'\r\n') uart0.write(''+'\r\n') uart0.write('<!DOCTYPE HTML>'+'\r\n') uart0.write('<html><head>'+'\r\n') uart0.write('<title>BME680 Web Server</title>'+'\r\n') uart0.write('<meta http-equiv=\"refresh\" content=\"10\">'+'\r\n') uart0.write('<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\'\r\n') uart0.write('<link rel=\"icon\" href=\"data:,\">'+'\r\n') uart0.write('<style>'+'\r\n') uart0.write('html {font-family: Arial; display: inline-block; text-align: center;}'+'\r\n') uart0.write('p { font-size: 1.2rem;}'+'\r\n') uart0.write('body { margin: 0;}'+'\r\n') uart0.write('.topnav { overflow: hidden; background-color: #5c055c; color: white; font-size: 1.7rem; }'+'\r\n') uart0.write('.content { padding: 20px; }'+'\r\n') uart0.write('.card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); }'+'\r\n') uart0.write('.cards { max-width: 700px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }'+'\r\n') uart0.write('.reading { font-size: 2.8rem; }'+'\r\n') uart0.write('.card.temperature { color: #0e7c7b; }'+'\r\n') uart0.write('.card.humidity { color: #17bebb; }'+'\r\n') uart0.write('.card.pressure { color: hsl(113, 61%, 29%); }'+'\r\n') uart0.write('.card.gas { color: #5c055c; }'+'\r\n') uart0.write('</style>'+'\r\n') uart0.write('</head>'+'\r\n') uart0.write('<body>'+'\r\n') uart0.write('<div class=\"topnav\">'+'\r\n') uart0.write('<h3>Raspberry Pi Pico BME680 WEB SERVER</h3>'+'\r\n') uart0.write('</div>'+'\r\n') uart0.write('<div class=\"content\">'+'\r\n') uart0.write('<div class=\"cards\">'+'\r\n') uart0.write('<div class=\"card temperature\">'+'\r\n') uart0.write('<h4>Temp. Celsius</h4><p><span class=\"reading\">' + temperature + '</p>'+'\r\n') uart0.write('</div>'+'\r\n') uart0.write('<div class=\"card humidity\">'+'\r\n') uart0.write('<h4>Humidity</h4><p><span class=\"reading\">' + humidity + '</p>'+'\r\n') uart0.write('</div>'+'\r\n') uart0.write('<div class=\"card pressure\">'+'\r\n') uart0.write('<h4>PRESSURE</h4><p><span class=\"reading\">' + pressure +'</p>'+'\r\n') uart0.write('</div>'+'\r\n') uart0.write('<div class=\"card gas\">' +'\r\n') uart0.write('<h4>Gas</h4><p><span class=\"reading\">' + gas + '</p>'+'\r\n') uart0.write('</div></div></div>'+'\r\n') uart0.write('</body></html>'+'\r\n') utime.sleep(4.0) Send_AT_Cmd('AT+CIPCLOSE='+ connection_id+'\r\n') # once file sent, close connection utime.sleep(4.0) recv_buf="" #reset buffer print ('Waiting For connection...')
Criar página da Web (HTML+CSS)
Para construir a página da web, adicionaremos código HTML e, para estilizar, adicionaremos script CSS.
Agora vamos passar por cada linha de código HTML para entender como ele constrói a página da web.
Neste documento HTML, usamos cartões, parágrafos, títulos e tags de título para criar uma página da web. Esta página da web exibe as leituras de temperatura, umidade, pressão e gás do sensor BME680.
HTML é uma linguagem de marcação de hipertexto que é usada para construir páginas da web. Todos os navegadores da Web entendem essa linguagem e podem ler páginas da Web baseadas na linguagem HTML.
Em HTML, colocamos todo o conteúdo de uma página web entre as tags <html> e </html>. A tag <html> mostra o início de uma página da web e a </html> indica o final de uma página da web.
O código HTML inclui principalmente duas partes, como cabeça e corpo. A parte principal contém CSS, scripts, meta tags, links de recursos externos e códigos de estilo. Ele é colocado entre as tags <head> e </head>.
uart0.write('<!DOCTYPE HTML>'+'\r\n') uart0.write('<html><head>'+'\r\n') uart0.write('<title>BME680 Web Server</title>'+'\r\n') uart0.write('<meta http-equiv=\"refresh\" content=\"10\">'+'\r\n') uart0.write('<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\'\r\n') uart0.write('<link rel=\"icon\" href=\"data:,\">'+'\r\n') uart0.write('<style>'+'\r\n') uart0.write('html {font-family: Arial; display: inline-block; text-align: center;}'+'\r\n') uart0.write('p { font-size: 1.2rem;}'+'\r\n') uart0.write('body { margin: 0;}'+'\r\n') uart0.write('.topnav { overflow: hidden; background-color: #5c055c; color: white; font-size: 1.7rem; }'+'\r\n') uart0.write('.content { padding: 20px; }'+'\r\n') uart0.write('.card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); }'+'\r\n') uart0.write('.cards { max-width: 700px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }'+'\r\n') uart0.write('.reading { font-size: 2.8rem; }'+'\r\n') uart0.write('.card.temperature { color: #0e7c7b; }'+'\r\n') uart0.write('.card.humidity { color: #17bebb; }'+'\r\n') uart0.write('.card.pressure { color: hsl(113, 61%, 29%); }'+'\r\n') uart0.write('.card.gas { color: #5c055c; }'+'\r\n') uart0.write('</style>'+'\r\n') uart0.write('</head>'+'\r\n')
Vamos começar com o título da página web. A tag <title> indicará o início do título e a tag </title> indicará o final. Entre essas tags, especificaremos “BME680 Web Server” que será exibido na barra de título do navegador.
Neste documento HTML, usamos cartões, parágrafos, títulos e tags de título para criar uma página da web. Esta página da web exibe as leituras de temperatura, umidade e pressão do sensor BME280.
HTML é uma linguagem de marcação de hipertexto que é usada para construir páginas da web. Todos os navegadores da Web entendem essa linguagem e podem ler páginas da Web baseadas na linguagem HTML.
Em HTML, colocamos todo o conteúdo de uma página web entre as tags <html> e </html>. A tag <html> mostra o início de uma página da web e a </html> indica o final de uma página da web.
O código HTML inclui principalmente duas partes, como cabeça e corpo. A parte principal contém CSS, scripts, meta tags, links de recursos externos e códigos de estilo. Ele é colocado entre as tags <head> e </head>.
uart0.write('<!DOCTYPE HTML>'+'\r\n') uart0.write('<html><head>'+'\r\n') uart0.write('<title>BME280 Web Server</title>'+'\r\n') uart0.write('<meta http-equiv=\"refresh\" content=\"10\">'+'\r\n') uart0.write('<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\'\r\n') uart0.write('<link rel=\"icon\" href=\"data:,\">'+'\r\n') uart0.write('<style>'+'\r\n') uart0.write('html {font-family: Arial; display: inline-block; text-align: center;}'+'\r\n') uart0.write('p { font-size: 1.2rem;}'+'\r\n') uart0.write('body { margin: 0;}'+'\r\n') uart0.write('.topnav { overflow: hidden; background-color: #5c055c; color: white; font-size: 1.7rem; }'+'\r\n') uart0.write('.content { padding: 20px; }'+'\r\n') uart0.write('.card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); }'+'\r\n') uart0.write('.cards { max-width: 700px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }'+'\r\n') uart0.write('.reading { font-size: 2.8rem; }'+'\r\n') uart0.write('.card.temperature { color: #0e7c7b; }'+'\r\n') uart0.write('.card.humidity { color: #17bebb; }'+'\r\n') uart0.write('.card.pressure { color: hsl(113, 61%, 29%); }'+'\r\n') uart0.write('.card.gas { color: #5c055c; }'+'\r\n') uart0.write('</style>'+'\r\n') uart0.write('</head>'+'\r\n')
Vamos começar com o título da página web. A tag <title> indicará o início do título e a tag </title> indicará o final. Entre essas tags, especificaremos “BME280 Web Server” que será exibido na barra de título do navegador.
uart0.write('<title>BME680 Web Server</title>'+'\r\n')
Esta meta-tag http-equiv fornece atributos para o cabeçalho HTTP. O atributo http-equiv recebe muitos valores ou informações para simular a resposta do cabeçalho. Neste exemplo, usamos o atributo http-equiv para atualizar o conteúdo da página da Web após cada intervalo de tempo especificado. Os usuários não precisam atualizar a página da Web para obter os valores atualizados do sensor. Essa linha força a página HTML a se atualizar a cada 10 segundos. Além disso, essa metatag garantirá que nosso servidor da Web esteja disponível para todos os navegadores, por exemplo, smartphones, laptops, computadores etc.
uart0.write('<meta http-equiv=\"refresh\" content=\"10\">'+'\r\n') uart0.write('<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\'\r\n')
Estilizando a página da Web com CSS
CSS é usado para dar estilos a uma página da web. Para adicionar arquivos CSS em tags head, usamos tags <style></style>. Este código CSS estiliza os cartões e a página da web, especificando as cores, fonte, tamanho da fonte, etc.
Este código CSS define o alinhamento do texto, o preenchimento, a margem e a largura das tags do corpo do documento HTML, juntamente com o tamanho da fonte, cor dos cartões, etc. Queremos exibir temperatura, pressão e umidade nos cartões e queremos que eles sejam exibidos no centro da página web.
uart0.write('<style>'+'\r\n') uart0.write('html {font-family: Arial; display: inline-block; text-align: center;}'+'\r\n') uart0.write('p { font-size: 1.2rem;}'+'\r\n') uart0.write('body { margin: 0;}'+'\r\n') uart0.write('.topnav { overflow: hidden; background-color: #5c055c; color: white; font-size: 1.7rem; }'+'\r\n') uart0.write('.content { padding: 20px; }'+'\r\n') uart0.write('.card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); }'+'\r\n') uart0.write('.cards { max-width: 700px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }'+'\r\n') uart0.write('.reading { font-size: 2.8rem; }'+'\r\n') uart0.write('.card.temperature { color: #0e7c7b; }'+'\r\n') uart0.write('.card.humidity { color: #17bebb; }'+'\r\n') uart0.write('.card.pressure { color: hsl(113, 61%, 29%); }'+'\r\n') uart0.write('.card.gas { color: #5c055c; }'+'\r\n') uart0.write('</style>'+'\r\n')
Corpo da página da Web HTML
A segunda parte mais importante de um documento HTML é o corpo que vai dentro das tags <body> e </body>. A parte do corpo inclui o conteúdo principal da página da Web, como títulos, imagens, botões, ícones, tabelas, gráficos, etc. Por exemplo, neste servidor da Web baseado em Raspberry Pi Pico BME680 MicroPython, a parte do corpo inclui cabeçalho e quatro cartões exibir as leituras do sensor BME680.
uart0.write('<body>'+'\r\n') uart0.write('<div class=\"topnav\">'+'\r\n') uart0.write('<h3>Raspberry Pi Pico BME680 WEB SERVER</h3>'+'\r\n') uart0.write('</div>'+'\r\n') uart0.write('<div class=\"content\">'+'\r\n') uart0.write('<div class=\"cards\">'+'\r\n') uart0.write('<div class=\"card temperature\">'+'\r\n') uart0.write('<h4>Temp. Celsius</h4><p><span class=\"reading\">' + temperature + '</p>'+'\r\n') uart0.write('</div>'+'\r\n') uart0.write('<div class=\"card humidity\">'+'\r\n') uart0.write('<h4>Humidity</h4><p><span class=\"reading\">' + humidity + '</p>'+'\r\n') uart0.write('</div>'+'\r\n') uart0.write('<div class=\"card pressure\">'+'\r\n') uart0.write('<h4>PRESSURE</h4><p><span class=\"reading\">' + pressure +'</p>'+'\r\n') uart0.write('</div>'+'\r\n') uart0.write('<div class=\"card gas\">' +'\r\n') uart0.write('<h4>Gas</h4><p><span class=\"reading\">' + gas + '</p>'+'\r\n') uart0.write('</div></div></div>'+'\r\n') uart0.write('</body></html>'+'\r\n')
Incluiremos o cabeçalho da nossa página dentro das tags <h3></h3> e será “Raspberry Pi Pico BME680 WEB SERVER”.
uart0.write('<h3>Raspberry Pi Pico BME680 WEB SERVER</h3>'+'\r\n')
Em seguida, incluiremos as seguintes linhas de código para exibir textos e cartões para leituras de temperatura, pressão, umidade e gás.
uart0.write('</div>'+'\r\n') uart0.write('<div class=\"content\">'+'\r\n') uart0.write('<div class=\"cards\">'+'\r\n') uart0.write('<div class=\"card temperature\">'+'\r\n') uart0.write('<h4>Temp. Celsius</h4><p><span class=\"reading\">' + temperature + '</p>'+'\r\n') uart0.write('</div>'+'\r\n') uart0.write('<div class=\"card humidity\">'+'\r\n') uart0.write('<h4>Humidity</h4><p><span class=\"reading\">' + humidity + '</p>'+'\r\n') uart0.write('</div>'+'\r\n') uart0.write('<div class=\"card pressure\">'+'\r\n') uart0.write('<h4>PRESSURE</h4><p><span class=\"reading\">' + pressure +'</p>'+'\r\n') uart0.write('</div>'+'\r\n') uart0.write('<div class=\"card gas\">' +'\r\n') uart0.write('<h4>Gas</h4><p><span class=\"reading\">' + gas + '</p>'+'\r\n') uart0.write('</div></div></div>'+'\r\n')
Demonstração
Depois de copiar o código a seguir em um novo arquivo, clique no ícone ‘Salvar’ para salvar o código do programa em seu PC.
Depois de salvar o código, pressione o botão Executar para fazer o upload do código para sua placa. Antes de fazer o upload do código, certifique-se de que a placa correta esteja selecionada.
No terminal shell do seu IDE, você poderá visualizar o endereço IP depois que uma conexão bem-sucedida for estabelecida:
Agora, abra seu navegador da Web em seu laptop ou celular e digite o endereço IP que encontramos na última etapa. Assim que você digitar o endereço IP no seu navegador da Web e pressionar enter, o servidor da Web Raspberry Pi Pico receberá uma solicitação HTTP.
Você verá a página da web com os valores de temperatura mais recentes em seu navegador da web:
A página da Web visualizada de um telefone celular terá a seguinte aparência: