import network
import time
import ujson
import utime
import ntptime
import urandom
from umqtt.simple import MQTTClient
from machine import Pin, I2C
import ssd1306
# =======================================================
# DEFINIÇÕES DE CONEXÃO
# =======================================================
WIFI_SSID = 'Wokwi-GUEST'
WIFI_PASSWORD = ''
# Parâmetros MQTT do TagoIO
MQTT_CLIENT_ID = "micropython-simulador-iot"
MQTT_BROKER = "mqtt.tago.io"
MQTT_USER = "Simulador_IoT"
MQTT_PASSWORD = "6c3a150e-2275-427f-9944-a1b1e4dc4c32"
MQTT_TOPIC = "application/WORKI/device/esp3200000000h2s/rx" # Tópico TagoIO
# Parâmetros de Tempo
GMT_OFFSET_SEC = -10800 # -3 horas (Brasil/GMT-3)
INTERVAL = 10 # Envio de dados a cada 10 segundos
# =======================================================
# DEFINIÇÕES DO DISPLAY OLED
# =======================================================
OLED_WIDTH = 128
OLED_HEIGHT = 64
I2C_SCL_PIN = 22
I2C_SDA_PIN = 21
oled = None
# =======================================================
# VARIÁVEIS DE SIMULAÇÃO
# =======================================================
# Níveis de poluição para cada Ponto (0.0 a 1.0)
pollution_levels = {
'A': 0.9, # Ponto A: Alta poluição
'B': 0.5, # Ponto B: Média poluição
'C': 0.1 # Ponto C: Baixa poluição
}
# Parâmetros de Interpolação (Valores Mínimos e Máximos)
PH_CLEAN = 7.5
PH_POLUTED = 4.5
TEMP_CLEAN = 20.0 # °C
TEMP_POLUTED = 32.0 # °C
H2S_CLEAN = 0.0 # ppm H2S
H2S_POLUTED = 11.0 # ppm H2S
# Oxigênio Dissolvido
OD_SAT_CLEAN = 90.0
OD_SAT_POLUTED = 40.0
OD_MGL_CLEAN = 7.0
OD_MGL_POLUTED = 2.0
# Saúde (Pressão Arterial - Correlacionada ao H2S)
PAS_CLEAN = 120.0
PAS_POLUTED = 170.0
PAD_CLEAN = 80.0
PAD_POLUTED = 110.0
# --- FUNÇÕES DE CONEXÃO E TEMPO ---
def connect_wifi():
print("Connecting to WiFi", end="")
sta_if = network.WLAN(network.STA_IF)
sta_if.active(True)
sta_if.connect(WIFI_SSID, WIFI_PASSWORD)
while not sta_if.isconnected():
print(".", end="")
time.sleep(0.1)
print(" Connected!")
def sync_time():
print("Sincronizando Data/Hora via NTP... ", end="")
try:
ntptime.host = "pool.ntp.org"
ntptime.settime()
print("Sincronizado!")
except Exception as e:
print(f"Falha na sincronização NTP: {e}")
def get_timestamp():
epoch_time = utime.time() + GMT_OFFSET_SEC
t = utime.localtime(epoch_time)
return "{:04d}-{:02d}-{:02d}T{:02d}:{:02d}:{:02d}Z".format(
t[0], t[1], t[2], t[3], t[4], t[5]
)
def connect_mqtt():
print("Connecting to MQTT server... ", end="")
client = MQTTClient(MQTT_CLIENT_ID, MQTT_BROKER, user=MQTT_USER, password=MQTT_PASSWORD)
client.connect()
print("Connected!")
return client
# --- FUNÇÕES DE SIMULAÇÃO E PAYLOAD ---
def generate_tago_payload(data, timestamp, stream_name):
payload = []
# Adiciona todas as variáveis de dados (pH, Temp, H2S, etc.)
for key, value in data.items():
payload.append({
"variable": f"{stream_name}_{key}", # Ex: A_ph
"value": round(value, 2),
"time": timestamp
})
# ADICIONA A VARIÁVEL DE LAST MESSAGE RECEIVED (solicitado)
payload.append({
"variable": f"{stream_name}_last_message_received", # Ex: A_last_message_received
"value": timestamp,
"time": timestamp
})
# ADICIONA A VARIÁVEL DE PONTO DE COLETA (solicitado)
payload.append({
"variable": f"{stream_name}_ponto_de_coleta", # Ex: A_last_message_received
"value": f"PONTO {stream_name}",
"time": timestamp
})
return ujson.dumps(payload)
def simulate_stream_data(stream_name):
base_pollution_level = pollution_levels[stream_name]
current_pollution_level = max(0.0, min(1.0, base_pollution_level + urandom.uniform(-0.1, 0.1)))
wind_speed = 0.5 + (urandom.randint(0, 75) / 10.0)
wind_speed = min(wind_speed, 8.0)
ph = PH_CLEAN - current_pollution_level * (PH_CLEAN - PH_POLUTED)
temp = TEMP_CLEAN + current_pollution_level * (TEMP_POLUTED - TEMP_CLEAN)
h2s = H2S_CLEAN + current_pollution_level * (H2S_POLUTED - H2S_CLEAN)
od_sat = OD_SAT_CLEAN - current_pollution_level * (OD_SAT_CLEAN - OD_SAT_POLUTED)
od_mgl = OD_MGL_CLEAN - current_pollution_level * (OD_MGL_CLEAN - OD_MGL_POLUTED)
dispersion_factor = wind_speed / 10.0
h2s = h2s * (1.0 - dispersion_factor)
h2s_ratio = h2s / H2S_POLUTED
pas = PAS_CLEAN + (PAS_POLUTED - PAS_CLEAN) * h2s_ratio
pad = PAD_CLEAN + (PAD_POLUTED - PAD_CLEAN) * h2s_ratio
pas += urandom.uniform(-5.0, 5.0)
pad += urandom.uniform(-3.0, 3.0)
ph = max(4.0, min(8.0, ph))
temp = max(18.0, min(35.0, temp))
h2s = max(0.0, min(10.0, h2s))
od_sat = max(0.0, min(100.0, od_sat))
od_mgl = max(0.0, min(10.0, od_mgl))
pas = max(100.0, min(200.0, pas))
pad = max(60.0, min(120.0, pad))
return {
"ph": ph,
"temperatura": temp,
"h2s": h2s,
"velocidade_vento": wind_speed,
"od_sat": od_sat,
"od_mgl": od_mgl,
"pas": pas,
"pad": pad
}
# --- FUNÇÕES DO DISPLAY OLED (Adaptadas para Funções) ---
def init_oled():
global oled
# 1. Inicializa I2C (agora dentro de uma função para evitar erro de sintaxe global)
try:
i2c = I2C(0, scl=Pin(I2C_SCL_PIN), sda=Pin(I2C_SDA_PIN), freq=400000)
except Exception as e:
print(f"ERRO: Falha ao inicializar I2C: {e}. Sem display.")
return False
print("Scanning I2C bus...")
devices = i2c.scan()
print(f"I2C devices found: {[hex(d) for d in devices]}")
# 2. Tenta inicializar o SSD1306
if 0x3C in devices:
try:
oled = ssd1306.SSD1306_I2C(OLED_WIDTH, OLED_HEIGHT, i2c, addr=0x3C)
oled.fill(0); oled.text("OLED OK @ 0x3C", 0, 0); oled.show()
return True
except OSError:
print("Erro ao inicializar OLED em 0x3C, mesmo após detecção.")
elif 0x3D in devices:
try:
oled = ssd1306.SSD1306_I2C(OLED_WIDTH, OLED_HEIGHT, i2c, addr=0x3D)
oled.fill(0); oled.text("OLED OK @ 0x3D", 0, 0); oled.show()
return True
except OSError:
print("Erro ao inicializar OLED em 0x3D, mesmo após detecção.")
else:
print("OLED não detectado nos endereços 0x3C ou 0x3D. Sem display.")
return False
def update_oled_display(stream_name, data):
if oled:
oled.fill(0)
oled.text(f"Ponto. {stream_name}", 0, 0)
oled.text(f"Temp: {data['temperatura']:.1f} C", 0, 10)
oled.text(f"pH: {data['ph']:.1f}", 0, 20)
oled.text(f"H2S: {data['h2s']:.1f} ppm", 0, 30)
oled.text(f"OD%: {data['od_sat']:.0f}%", 0, 40)
oled.text(f"PA: {data['pas']:.0f}/{data['pad']:.0f} mmHg", 0, 50)
oled.show()
# =======================================================
# MAIN
# =======================================================
oled_initialized = init_oled()
if oled_initialized:
oled.fill(0); oled.text("Conectando WIFI...", 0, 0); oled.show()
connect_wifi()
sync_time()
client = connect_mqtt()
if oled_initialized:
oled.fill(0); oled.text("TagoIO OK", 0, 0); oled.text("Iniciando Sim.", 0, 10); oled.show()
time.sleep(1)
stream_names = ['A', 'B', 'C']
current_stream_index = 0
while True:
stream_name = stream_names[current_stream_index]
data = simulate_stream_data(stream_name)
update_oled_display(stream_name, data)
timestamp = get_timestamp()
payload = generate_tago_payload(data, timestamp, stream_name)
client.publish(MQTT_TOPIC, payload)
print("----------------------------------")
print(f"PONTO: {stream_name}")
print(f"DATA/HORA: {timestamp}")
print(f" pH: {data['ph']:.2f}")
print(f" Temperatura: {data['temperatura']:.2f} °C")
print(f" H2S: {data['h2s']:.2f} ppm")
print(f" Vento: {data['velocidade_vento']:.2f} m/s")
print(f" OD %: {data['od_sat']:.2f}%")
print(f" OD mg/L: {data['od_mgl']:.2f} mg/L")
print(f" PAS (Pressão Sistólica): {data['pas']:.0f} mmHg")
print(f" PAD (Pressão Diastólica): {data['pad']:.0f} mmHg")
print("----------------------------------")
current_stream_index = (current_stream_index + 1) % len(stream_names)
time.sleep(INTERVAL)