from machine import Pin, I2C, ADC
import ssd1306
import network
import time
import ntptime
from umqtt.simple import MQTTClient
import dht
import urequests
import umail
import gc
#EMAIL
SMTP_SERVER = "smtp.gmail.com"
SMTP_PORT = 465
EMAIL_USER = "[email protected]"
EMAIL_PASS = "blrm goba cbbn djvu"
# API
API_KEY = "f8375e04769e123097e3bb383f784b74"
CITY_QUERY = "Suzano,BR"
URL_BASE = f"http://api.openweathermap.org/data/2.5/weather?q={CITY_QUERY}&appid={API_KEY}&units=metric"
# Dicionário
traducoes_clima = {
"Clear": "Ceu Limpo",
"Clouds": "Nublado",
"Rain": "Chuva",
"Drizzle": "Garoa",
"Thunderstorm": "Tempestade",
"Mist": "Neblina",
"Fog": "Nevoeiro"
}
# MQTT
ssid = 'Wokwi-GUEST'
password = ''
MQTT_BROKER = "broker.hivemq.com"
MQTT_CLIENT_ID = "estacao_metereologica"
MQTT_TOPIC = b"estacao/clima"
# Funções
def enviar_email(media_t, media_u, leituras):
try:
fuso_horario = -3 * 3600
t = time.localtime(time.time() + fuso_horario)
data_formatada = f"{t[2]:02d}/{t[1]:02d}/{t[0]}"
smtp = umail.SMTP(SMTP_SERVER, SMTP_PORT, ssl=True)
smtp.login(EMAIL_USER, EMAIL_PASS)
smtp.to("[email protected]")
smtp.write(f"Subject: Relatorio Diario - {data_formatada}\n")
smtp.write(f"From: Estacao IoT <{EMAIL_USER}>\n\n")
smtp.write(f"RESUMO METEOROLOGICO DO DIA\n")
smtp.write(f"{'='*30}\n")
smtp.write(f"Data de Referencia: {data_formatada}\n")
smtp.write(f"Total de Leituras: {leituras}\n")
smtp.write(f"Media Temperatura: {media_t:.1f} C\n")
smtp.write(f"Media Umidade: {media_u:.1f} %\n")
smtp.write(f"{'='*30}\n")
smtp.write("Enviado automaticamente pelo ESP32 via MicroPython.")
smtp.send()
smtp.quit()
print(">>> E-mail enviado com sucesso!")
except Exception as e:
print(f"Erro ao enviar e-mail: {e}")
def connect_wifi():
station = network.WLAN(network.STA_IF)
station.active(True)
station.connect(ssid, password)
print('Conectando ao Wi-Fi', end='')
while not station.isconnected():
print('.', end='')
time.sleep(0.5)
print('\nConexão OK!')
def connect_mqtt():
client = MQTTClient(MQTT_CLIENT_ID, MQTT_BROKER)
client.connect()
print(f"Conectado ao Broker MQTT")
return client
def calcular_indice_calor(t, h):
# Indice de Conforto Termico INMET
return t + 0.55 * (1 - h / 100) * (t - 14.5)
def buscar_previsao():
try:
response = urequests.get(URL_BASE)
if response.status_code == 200:
dados = response.json()
t_api = dados['main']['temp']
p_api = dados['main']['pressure']
cid = dados['name']
termo_en = dados['weather'][0]['main']
prev = traducoes_clima.get(termo_en, termo_en)
return t_api, p_api, cid, prev
except:
return None, None, None, None
# Hardware
i2c = I2C(0, scl=Pin(22), sda=Pin(21))
oled = ssd1306.SSD1306_I2C(128, 64, i2c)
sensor = dht.DHT22(Pin(4))
ldr = ADC(Pin(34))
ldr.atten(ADC.ATTN_11DB)
mq2 = ADC(Pin(35))
mq2.atten(ADC.ATTN_11DB)
pino_botao = Pin(13, Pin.IN, Pin.PULL_UP)
modo_tela = 0
ultimo_envio_mqtt = 0
ultima_consulta_api = 0
temp = hum = sensacao = luz_porcento = gas = 0
temp_oficial = pressao_oficial = 0
cidade_real = "Sincronizando..."
previsao_texto = "Aguarde..."
qualidade_ar = "Lendo..."
# Google Sheets
URL_SHEETS = "https://script.google.com/macros/s/AKfycbxOsHhBkfAku14k_0ZyksW4Mg_-4XKGSJTvr1ym5JqHaAwT9PdhCBQv44-3F85_QbbC/exec"
soma_temp = 0
soma_umid = 0
cont_leituras = 0
ultimo_envio_sheets = 0
tempo_relatorio = 180000 # 86400000 para 24h
ultimo_relatorio = 0
# Conexao
connect_wifi()
ntptime.settime()
client = connect_mqtt()
while True:
# Botão
if pino_botao.value() == 0:
modo_tela = not modo_tela
while pino_botao.value() == 0:
time.sleep(0.01)
agora = time.ticks_ms()
# API externa
if time.ticks_diff(agora, ultima_consulta_api) >= 300000 or ultima_consulta_api == 0:
t_api, p_api, cid, prev = buscar_previsao()
if t_api is not None:
temp_oficial = t_api
pressao_oficial = p_api
cidade_real = cid
previsao_texto = prev
ultima_consulta_api = agora
print(f"API Atualizada: {cidade_real} - {previsao_texto}")
# Sensores e MQTT
if time.ticks_diff(agora, ultimo_envio_mqtt) >= 2000:
try:
sensor.measure()
temp = sensor.temperature()
hum = sensor.humidity()
luz = ldr.read()
leitura_bruta_gas = mq2.read()
if leitura_bruta_gas < 10000:
gas = leitura_bruta_gas
else:
gas = 843
sensacao = calcular_indice_calor(temp, hum)
luz_porcento = 100 - (luz / 4095) * 100
if gas < 1500: qualidade_ar = "Excelente"
elif gas < 2500: qualidade_ar = "Moderada"
else: qualidade_ar = "PERIGO!"
soma_temp += temp
soma_umid += hum
cont_leituras += 1
msg = f'{{"cidade":"{cidade_real}", "previsao":"{previsao_texto}", "temp_suzano":{temp_oficial:.1f},"temp_local":{temp}, "umid_local":{hum}, "gas":{gas},"sens_termica":{sensacao:.1f},"luz_porcento":{luz_porcento:.0f}, "ar":"{qualidade_ar}"}}'
client.publish(MQTT_TOPIC, msg.encode())
print(f"MQTT: {msg}")
ultimo_envio_mqtt = agora
except OSError:
print("Erro de leitura dos sensores")
#Google Sheets
if time.ticks_diff(agora, ultimo_envio_sheets) >= 30000:
gc.collect()
dados_sheets = {
"temp_local": temp,
"umid_local": hum
}
resposta = None
try:
resposta = urequests.post(URL_SHEETS, json=dados_sheets, timeout=15)
print(f"Planilha atualizada! Status: {resposta.status_code}")
except Exception as e:
print("Erro ao gravar na planilha:", e)
finally:
if resposta:
resposta.close()
del resposta
gc.collect()
ultimo_envio_sheets = agora
if time.ticks_diff(agora, ultimo_relatorio) >= tempo_relatorio:
if cont_leituras > 0:
media_t = soma_temp / cont_leituras
media_u = soma_umid / cont_leituras
print("\n" + "="*30)
print(" RELATÓRIO DIÁRIO")
print(f"Leituras: {cont_leituras}")
print(f"Média Temp: {media_t:.1f} °C")
print(f"Média Umid: {media_u:.1f} %")
print("="*30 + "\n")
enviar_email(media_t, media_u, cont_leituras)
ultimo_relatorio = agora
oled.fill(0)
if modo_tela == 0:
oled.text(" CLIMA LOCAL ", 0, 0)
oled.text(f"Temp: {temp}C", 0, 20)
oled.text(f"Umid: {hum}%", 0, 35)
oled.text(f"Sensa: {sensacao:.1f}C", 0, 50)
else:
oled.text(f"Cidade: {cidade_real}", 0, 0)
oled.text(f"{temp_oficial:.1f}C - {previsao_texto}", 0, 15)
oled.text(f"Luz: {luz_porcento:.0f}%", 0, 35)
oled.text(f"Ar: {qualidade_ar}", 0, 50)
oled.show()
time.sleep(0.1)