#!/usr/bin/env python
from machine import Pin, I2C, PWM
import utime
import dht
from pico_i2c_lcd import I2cLcd
import os
import stepper
# --- Constantes de Pinos ---
# Note a ordem dos pinos do motor de passo
DHT_PIN = 2
RELAY_HEAT_PIN = 3
FAN_PIN = 4
UMIDIFICADOR_PIN = 6
SPEAKER_PIN = 7
STATUS_LED_PIN = 13
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 ---
# O intervalo para virar os ovos (4 horas)
INTERVALO_VIRADA = 4 * 60 * 60 * 1000
ALARME_DELAY = 1 * 60 * 1000
UPDATE_LCD_INTERVAL = 2000
MILISSEGUNDOS_POR_DIA = 86400000
# --- 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)
# --- 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 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
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"Faltam {dias_restantes} dias")
else:
lcd.putstr("Eclosao!")
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("Faltam poucos dias")
# --- Viragem dos ovos (não bloqueante) ---
if utime.ticks_diff(tempo_atual, ultima_virada) >= INTERVALO_VIRADA:
stepper_motor.step(180)
ultima_virada = tempo_atual
# --- Início do programa ---
if __name__ == "__main__":
setup()
main_loop()