#!/usr/bin/env python
from machine import Pin, I2C, PWM
import utime
import dht
from pico_i2c_lcd import I2cLcd
import os
import stepper
import network
import socket
# --- Credenciais de Wi-Fi ---
# ATENÇÃO: Substitua 'SUA_REDE' e 'SUA_SENHA' pelas suas credenciais reais.
SSID = "Wokwi-GUEST"
PASSWORD = ""
# --- Constantes de Pinos ---
DHT_PIN = 2
RELAY_HEAT_PIN = 3
FAN_PIN = 4
UMIDIFICADOR_PIN = 6
SPEAKER_PIN = 7
STATUS_LED_PIN = 13
OVOSCOPIO_LED_PIN = 5
STEPPER_PINS = [28, 27, 26, 22]
# --- Constantes de Controle da Incubadora ---
TEMP_MIN = 37.0
TEMP_MAX = 38.0
UMIDADE_MIN = 45.0
UMIDADE_MAX = 55.0
TEMPO_INCUBACAO_DIAS = 21
DIAS_ALARME_ECLOSAO = 3
# --- Constantes de Tempo em Milissegundos ---
INTERVALO_VIRADA = 60 * 1000
ALARME_DELAY = 1 * 60 * 1000
UPDATE_LCD_INTERVAL = 2000
MILISSEGUNDOS_POR_DIA = 8640
WEB_SERVER_PORT = 80
# --- Variáveis de Estado (globais) ---
ultima_virada = 0
ultimo_alarme = 0
ultimo_update_lcd = 0
alarme_ativado = False
alarme_eclosao_ativado = False
data_inicio_ms = 0
# --- Inicialização de Hardware ---
dht_sensor = dht.DHT22(Pin(DHT_PIN, Pin.PULL_UP))
i2c = I2C(0, scl=Pin(1), sda=Pin(0), freq=100000)
lcd = I2cLcd(i2c, 0x27, 2, 16)
buzzer_pwm = PWM(Pin(SPEAKER_PIN))
stepper_motor = stepper.HalfStepMotor.frompins(*STEPPER_PINS)
pin_heat = Pin(RELAY_HEAT_PIN, Pin.OUT)
pin_fan = Pin(FAN_PIN, Pin.OUT)
pin_umidificador = Pin(UMIDIFICADOR_PIN, Pin.OUT)
pin_status_led = Pin(STATUS_LED_PIN, Pin.OUT)
pin_ovoscopio_led = Pin(OVOSCOPIO_LED_PIN, Pin.OUT)
# --- Funções de Controle ---
def play_alarm():
buzzer_pwm.duty_u16(50000)
def stop_alarm():
buzzer_pwm.duty_u16(0)
def load_start_time():
global data_inicio_ms
try:
with open('start_time.txt', 'r') as f:
data_inicio_ms = int(f.read())
print(f"Data de início carregada: {data_inicio_ms}")
except (OSError, ValueError):
data_inicio_ms = utime.ticks_ms()
with open('start_time.txt', 'w') as f:
f.write(str(data_inicio_ms))
print("Nova data de início salva.")
def connect_to_wifi():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(SSID, PASSWORD)
max_wait = 20
while max_wait > 0:
if wlan.status() < 0 or wlan.status() >= 3:
break
max_wait -= 1
print('Esperando por conexao...')
utime.sleep(1)
if wlan.status() != 3:
raise RuntimeError('Conexao falhou')
else:
status = wlan.ifconfig()
print('Conectado a rede:', SSID)
print('IP Address:', status[0])
return wlan, status[0]
def start_web_server(ip):
addr = socket.getaddrinfo(ip, WEB_SERVER_PORT)[0][-1]
s = socket.socket()
s.bind(addr)
s.listen(1)
return s
def get_web_page(temperatura, umidade, dias_restantes):
html = f"""
<!DOCTYPE html>
<html>
<head>
<title>Incubadora Status</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body {{ font-family: sans-serif; text-align: center; background-color: #f0f0f0; }}
.container {{ margin: 20px; padding: 20px; border-radius: 10px; background-color: #fff; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }}
h1 {{ color: #333; }}
.status {{ font-size: 1.5em; margin: 10px 0; }}
.controls button {{ background-color: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 5px; margin: 5px; cursor: pointer; }}
.controls button:hover {{ background-color: #0056b3; }}
</style>
</head>
<body>
<div class="container">
<h1>Incubadora de Ovos</h1>
<p>Conectado via Wi-Fi</p>
<div class="status">
<p>Temperatura: {temperatura:.1f}°C</p>
<p>Umidade: {umidade:.1f}%</p>
<p>Faltam {dias_restantes} dias</p>
</div>
<hr>
<h2>Controle Manual</h2>
<div class="controls">
<p>
<a href="/turn_on_fan">
<button>Ligar Ventilador</button>
</a>
<a href="/turn_off_fan">
<button>Desligar Ventilador</button>
</a>
</p>
<p>
<a href="/turn_on_heat">
<button>Ligar Aquecedor</button>
</a>
<a href="/turn_off_heat">
<button>Desligar Aquecedor</button>
</a>
</p>
<p>
<a href="/turn_on_humidifier">
<button>Ligar Umidificador</button>
</a>
<a href="/turn_off_humidifier">
<button>Desligar Umidificador</button>
</a>
</p>
<p>
<a href="/turn_eggs">
<button>Virar Ovos Manualmente</button>
</a>
</p>
</div>
</div>
</body>
</html>
"""
return html
def handle_web_request(conn):
try:
request = conn.recv(1024).decode('utf-8')
request_line = request.split('\n')[0].strip()
print('Request:', request_line)
# Parse a URL para encontrar a ação
action = request_line.split(' ')[1]
# --- Controle manual dos atuadores ---
if action == '/turn_on_fan':
pin_fan.value(1)
elif action == '/turn_off_fan':
pin_fan.value(0)
elif action == '/turn_on_heat':
pin_heat.value(1)
elif action == '/turn_off_heat':
pin_heat.value(0)
elif action == '/turn_on_humidifier':
pin_umidificador.value(1)
elif action == '/turn_off_humidifier':
pin_umidificador.value(0)
elif action == '/turn_eggs':
stepper_motor.step(180)
temperatura = dht_sensor.temperature()
umidade = dht_sensor.humidity()
dias_passados = utime.ticks_diff(utime.ticks_ms(), data_inicio_ms) // MILISSEGUNDOS_POR_DIA
dias_restantes = TEMPO_INCUBACAO_DIAS - dias_passados
response_html = get_web_page(temperatura, umidade, dias_restantes)
conn.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
conn.send(response_html)
conn.close()
except Exception as e:
print(f"Erro ao processar requisicao: {e}")
conn.close()
def setup():
global ultima_virada, ultimo_alarme, ultimo_update_lcd
lcd.backlight_on()
lcd.clear()
lcd.move_to(0, 0)
lcd.putstr("ChacadeiraDe0v0s")
utime.sleep(2)
lcd.clear()
load_start_time()
pin_heat.value(0)
pin_fan.value(0)
pin_umidificador.value(0)
pin_status_led.value(0)
stepper_motor.reset()
ultima_virada = utime.ticks_ms()
ultimo_alarme = utime.ticks_ms()
ultimo_update_lcd = utime.ticks_ms()
buzzer_pwm.freq(1000)
buzzer_pwm.duty_u16(0)
# --- LOOP PRINCIPAL ---
def main_loop():
global ultimo_update_lcd, ultimo_alarme, alarme_ativado, alarme_eclosao_ativado, ultima_virada
# Inicia a conexao Wi-Fi e o servidor web
wlan, ip_address = connect_to_wifi()
if not ip_address:
print("Nao foi possivel conectar ao Wi-Fi. Reinicie o dispositivo.")
return
server_socket = start_web_server(ip_address)
server_socket.settimeout(0.5) # Define um tempo limite nao-bloqueante
while True:
tempo_atual = utime.ticks_ms()
# Leitura do sensor
try:
dht_sensor.measure()
temperatura = dht_sensor.temperature()
umidade = dht_sensor.humidity()
except (OSError, ValueError) as e:
print(f"Erro no sensor DHT: {e}")
lcd.clear()
lcd.putstr("Erro no sensor")
utime.sleep(2)
continue
# --- Lógica de controle de aquecimento, ventilação e umidade ---
if temperatura < TEMP_MIN:
pin_heat.value(1)
pin_fan.value(0)
else:
pin_heat.value(0)
if temperatura > TEMP_MAX:
pin_fan.value(1)
pin_heat.value(0)
else:
pin_fan.value(0)
if umidade < UMIDADE_MIN:
pin_umidificador.value(1)
else:
pin_umidificador.value(0)
# --- Atualização do LCD (não bloqueante) ---
if utime.ticks_diff(tempo_atual, ultimo_update_lcd) >= UPDATE_LCD_INTERVAL:
print(f"Temperatura: {temperatura:.2f}°C, Umidade: {umidade:.2f}%")
lcd.clear()
lcd.putstr(f"T:{temperatura:.1f}C U:{umidade:.1f}%")
dias_passados = utime.ticks_diff(tempo_atual, data_inicio_ms) // MILISSEGUNDOS_POR_DIA
dias_restantes = TEMPO_INCUBACAO_DIAS - dias_passados
lcd.move_to(0, 1)
if dias_restantes > 0:
lcd.putstr(f"Aguarde: {dias_restantes} dias")
if dias_restantes == 14:
lcd.move_to(0, 1)
lcd.putstr(f"Ovoscopio:{dias_restantes} dia")
pin_ovoscopio_led.value(1)
play_alarm()
if dias_restantes < 14:
pin_ovoscopio_led.value(0)
stop_alarm()
if dias_restantes == 11:
lcd.move_to(0, 1)
lcd.putstr(f"Ovoscopio:{dias_restantes} dia")
pin_ovoscopio_led.value(1)
play_alarm()
if dias_restantes < 11:
pin_ovoscopio_led.value(0)
stop_alarm()
if dias_restantes == 0:
lcd.putstr("Eclosao!")
utime.sleep(2)
lcd.move_to(1, 0)
lcd.clear()
lcd.putstr("Incubando:::")
utime.sleep(2)
ultimo_update_lcd = tempo_atual
# --- Lógica de Alarme de Faixa (Temperatura/Umidade) ---
fora_da_faixa = (temperatura < TEMP_MIN or temperatura > TEMP_MAX or umidade < UMIDADE_MIN or umidade > UMIDADE_MAX)
if fora_da_faixa:
if utime.ticks_diff(tempo_atual, ultimo_alarme) >= ALARME_DELAY:
if not alarme_ativado:
play_alarm()
alarme_ativado = True
pin_status_led.value(1)
lcd.clear()
lcd.putstr("ALARME: Fora da faixa")
else:
ultimo_alarme = tempo_atual
if alarme_ativado:
stop_alarm()
alarme_ativado = False
pin_status_led.value(0)
# --- Lógica de Alarme de Eclosão ---
dias_passados = utime.ticks_diff(tempo_atual, data_inicio_ms) // MILISSEGUNDOS_POR_DIA
dias_restantes = TEMPO_INCUBACAO_DIAS - dias_passados
if dias_restantes <= DIAS_ALARME_ECLOSAO and dias_restantes > 0 and not alarme_eclosao_ativado:
play_alarm()
alarme_eclosao_ativado = True
lcd.clear()
lcd.putstr("Alerta: Eclosao!")
lcd.move_to(0, 1)
lcd.putstr("Ini_Incuba_Seca")
utime.sleep(2)
# --- Viragem dos ovos (não bloqueante) ---
if utime.ticks_diff(tempo_atual, ultima_virada) >= INTERVALO_VIRADA:
stepper_motor.step(180)
ultima_virada = tempo_atual
# --- Verificacao de requisição web (não bloqueante) ---
try:
conn, addr = server_socket.accept()
print(f'Conexao de {addr}')
handle_web_request(conn)
except OSError as e:
if e.args[0] == 11: # errno.EAGAIN
pass
else:
print(f"Erro no servidor socket: {e}")
# --- Início do programa ---
if __name__ == "__main__":
setup()
main_loop()