import network
import time
import dht
import umail
import ubinascii
from machine import Pin
# 👉 credenciales desde secrets.py
from secrets import SENDER_EMAIL, APP_PASSWORD, RECEIVER_EMAIL
# -------- WIFI --------
SSID = "Wokwi-GUEST"
PASSWORD = ""
# -------- SMTP --------
SMTP_HOST = "smtp.gmail.com"
SMTP_PORT = 465
# -------- SENSOR --------
sensor = dht.DHT22(Pin(15))
# -------- CREAR IMAGENES SI NO EXISTEN --------
def ensure_images_exist():
try:
open("logo.png", "rb").close()
except:
with open("logo.png", "wb") as f:
f.write(
b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x02\x00\x00\x00\x90wS\xde'
b'\x00\x00\x00\x19IDATx\x9ccddbf\xa0\x040Q\xa4\x86Q\x0c\x00\x1c\x8a\x03\x11\x9c\xd3\x9a\x1b\x00\x00\x00\x00IEND\xaeB`\x82'
)
try:
open("badge.png", "rb").close()
except:
with open("badge.png", "wb") as f:
f.write(
b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x02\x00\x00\x00\x90wS\xde'
b'\x00\x00\x00\x19IDATx\x9ccdf\x60\xa0\x040Q\xa4\x86Q\x0c\x00\x1c\x8a\x03\x11\x9c\xd3\x9a\x1b\x00\x00\x00\x00IEND\xaeB`\x82'
)
# -------- WIFI CONNECT --------
def connect_wifi():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(SSID, PASSWORD)
print("Conectando WiFi...", end="")
while not wlan.isconnected():
print(".", end="")
time.sleep(0.4)
print("\nWiFi OK")
# -------- HELPERS --------
def b64_wrap(data_bytes, line_len=76):
b64 = ubinascii.b2a_base64(data_bytes).decode().strip()
out = []
for i in range(0, len(b64), line_len):
out.append(b64[i:i+line_len])
return "\r\n".join(out) + "\r\n"
def read_file_bytes(path):
with open(path, "rb") as f:
return f.read()
# -------- HTML NEWSLETTER --------
HTML_TEMPLATE = """\
<!doctype html>
<html>
<body style="background:#f3f5f7; margin:0; padding:0;">
<table width="100%" cellpadding="0" cellspacing="0">
<tr><td align="center">
<table width="600" cellpadding="0" cellspacing="0" style="background:#ffffff; border:1px solid #e6e8eb;">
<tr>
<td style="padding:16px; border-bottom:1px solid #eef0f2;">
<img src="cid:logo" width="120">
<span style="float:right;">Timestamp: <b>{{TS}}</b></span>
</td>
</tr>
<tr>
<td style="padding:10px; background:#0b5fff;">
<a href="#resumen" style="color:white; margin-right:10px;">Resumen</a>
<a href="#metricas" style="color:white; margin-right:10px;">Metricas</a>
<a href="#detalle" style="color:white;">Detalle</a>
</td>
</tr>
<tr>
<td style="padding:18px;">
<h1 id="resumen">Reporte IoT ESP32</h1>
<p>Lectura automatica del sensor DHT22</p>
<table cellpadding="0" cellspacing="0">
<tr>
<td bgcolor="#0b5fff" style="border-radius:10px;">
<a href="{{CTA_URL}}" style="color:white; padding:12px 16px; display:inline-block; text-decoration:none;">
Ver Dashboard
</a>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td style="padding:18px;">
<h2 id="metricas">Metricas</h2>
<p>Temperatura: <b>{{TEMP}} C</b></p>
<p>Humedad: <b>{{HUM}} %</b></p>
<img src="cid:badge" width="40">
</td>
</tr>
<tr>
<td style="padding:18px;">
<h2 id="detalle">Detalle</h2>
<table border="1" cellpadding="6">
<tr><td>Timestamp</td><td>{{TS}}</td></tr>
<tr><td>Temp</td><td>{{TEMP}}</td></tr>
<tr><td>Hum</td><td>{{HUM}}</td></tr>
</table>
</td>
</tr>
<tr>
<td style="padding:14px; background:#111827; color:white;">
Enviado por ESP32 - Newsletter MIME completo
</td>
</tr>
</table>
</td></tr>
</table>
</body>
</html>
"""
# -------- EMAIL SEND --------
def send_newsletter_email(temp, hum):
ts = int(time.time())
cta_url = "https://example.com/panel"
logo_b64 = b64_wrap(read_file_bytes("logo.png"))
badge_b64 = b64_wrap(read_file_bytes("badge.png"))
html_body = (HTML_TEMPLATE
.replace("{{TS}}", str(ts))
.replace("{{TEMP}}", "%.2f" % temp)
.replace("{{HUM}}", "%.2f" % hum)
.replace("{{CTA_URL}}", cta_url)
)
csv_text = "timestamp,temp_c,hum_pct\n%d,%.2f,%.2f\n" % (ts, temp, hum)
csv_b64 = b64_wrap(csv_text.encode())
boundary_mixed = "====ESP32_MIXED_%d====" % ts
boundary_related = "====ESP32_REL_%d====" % ts
msg = ""
msg += "From: ESP32 <%s>\r\n" % SENDER_EMAIL
msg += "To: <%s>\r\n" % RECEIVER_EMAIL
msg += "Subject: Reporte DHT22 Newsletter\r\n"
msg += "MIME-Version: 1.0\r\n"
msg += 'Content-Type: multipart/mixed; boundary="%s"\r\n\r\n' % boundary_mixed
# RELATED
msg += "--%s\r\n" % boundary_mixed
msg += 'Content-Type: multipart/related; boundary="%s"\r\n\r\n' % boundary_related
# HTML
msg += "--%s\r\n" % boundary_related
msg += 'Content-Type: text/html; charset="UTF-8"\r\n\r\n'
msg += html_body + "\r\n"
# LOGO CID
msg += "--%s\r\n" % boundary_related
msg += 'Content-Type: image/png\r\n'
msg += "Content-Transfer-Encoding: base64\r\n"
msg += "Content-ID: <logo>\r\n\r\n"
msg += logo_b64
# BADGE CID
msg += "--%s\r\n" % boundary_related
msg += 'Content-Type: image/png\r\n'
msg += "Content-Transfer-Encoding: base64\r\n"
msg += "Content-ID: <badge>\r\n\r\n"
msg += badge_b64
msg += "--%s--\r\n" % boundary_related
# CSV ADJUNTO
msg += "--%s\r\n" % boundary_mixed
msg += 'Content-Type: text/csv\r\n'
msg += "Content-Transfer-Encoding: base64\r\n"
msg += 'Content-Disposition: attachment; filename="lectura.csv"\r\n\r\n'
msg += csv_b64
msg += "--%s--\r\n" % boundary_mixed
print("Enviando correo...")
smtp = umail.SMTP(SMTP_HOST, SMTP_PORT, ssl=True)
smtp.login(SENDER_EMAIL, APP_PASSWORD)
smtp.to(RECEIVER_EMAIL)
smtp.write(msg)
smtp.send()
smtp.quit()
print("Correo enviado OK")
# -------- MAIN --------
connect_wifi()
ensure_images_exist()
while True:
try:
sensor.measure()
t = sensor.temperature()
h = sensor.humidity()
print("Lectura:", t, "C,", h, "%")
send_newsletter_email(t, h)
except Exception as e:
print("Error:", e)
time.sleep(60)