import network
import time
import ntptime
from machine import Pin, ADC, I2C
# Configurações do LCD
I2C_ADDR = 0x27
LCD_COLUMNS = 20
LCD_LINES = 4
class I2cLcd:
def __init__(self, i2c, i2c_addr, num_lines, num_columns):
self.i2c = i2c
self.i2c_addr = i2c_addr
self.num_lines = num_lines
self.num_columns = num_columns
self.backlight_val = 0x08
time.sleep_ms(50)
self._init_display()
def _write_nibble(self, data):
self.i2c.writeto(self.i2c_addr, bytearray([data | self.backlight_val]))
self.i2c.writeto(self.i2c_addr, bytearray([data | 0x04 | self.backlight_val]))
time.sleep_us(1)
self.i2c.writeto(self.i2c_addr, bytearray([data | self.backlight_val]))
time.sleep_us(50)
def _write_byte(self, data, mode=0):
self._write_nibble(mode | (data & 0xF0))
self._write_nibble(mode | ((data << 4) & 0xF0))
def _init_display(self):
self._write_nibble(0x30)
time.sleep_ms(5)
self._write_nibble(0x30)
time.sleep_ms(1)
self._write_nibble(0x30)
time.sleep_ms(1)
self._write_nibble(0x20)
self._write_byte(0x28)
self._write_byte(0x0C)
self._write_byte(0x06)
self.clear()
def clear(self):
self._write_byte(0x01)
time.sleep_ms(2)
def move_to(self, col, row):
row_offsets = [0x00, 0x40, 0x14, 0x54]
if row < len(row_offsets):
self._write_byte(0x80 | (col + row_offsets[row]))
def putstr(self, string):
for char in string:
self._write_byte(ord(char), 0x01)
# Inicialização do LCD
i2c = I2C(0, sda=Pin(21), scl=Pin(22), freq=400000)
lcd = I2cLcd(i2c, I2C_ADDR, LCD_LINES, LCD_COLUMNS)
# Potenciômetros para simulação
pino_tensao = ADC(Pin(34)) # Pino para leitura de tensão
pino_corrente = ADC(Pin(35)) # Pino para leitura de corrente
pino_led_pico = Pin(2, Pin.OUT) # Pino para o LED de alerta de pico
# Configuração da máquina
tensao_max = 220.0 # Tensão da rede 220V
potencia_nominal = 0.4 # kW (400W etiqueta do motor)
corrente_nominal = 2.9 # A (2.9 etiqueta para 220V)
# Limites de operação da máquina
potencia_nominal_min = 0.1 # kW (25% da potência nominal - ocioso)
potencia_nominal_max = 0.4 # kW (potência nominal normal)
potencia_pico_max = 0.8 # kW (pico máximo - 200% da potência nominal)
potencia_maxima = 1.0 # kW (limite de segurança)
# Wi-Fi para Wokwi
ssid = "Wokwi-GUEST"
password = ""
# Variáveis de consumo
tensao_atual = 0.0 # V
corrente_atual = 0.0 # A
fator_potencia = 0.8 # Valor típico para motores pequenos
potencia_aparente = 0.0 # VA
potencia_ativa = 0.0 # W (kW)
potencia_anterior = 0.0 # Para calcular a média entre leituras
consumo_diario = 0.0 # kWh
consumo_mensal = 0.0 # kWh
# Variáveis de tempo
tempo_anterior = 0
ultimo_update_lcd = 0
dia_anterior = -1
mes_anterior = -1
# Função para simular um fator de potência realista para a máquina de costura
def calcular_fator_potencia(potencia):
# FP mais baixo em cargas baixas, melhorando à medida que a carga aumenta
if potencia < potencia_nominal_min:
return 0.65 # FP baixo em carga muito baixa
elif potencia < potencia_nominal_max:
return 0.75 # FP médio em carga nominal
elif potencia < potencia_pico_max:
return 0.82 # FP bom em carga alta
else:
return 0.85 # FP máximo em plena carga
# Serve para mapear valores float
def map_float(x, in_min, in_max, out_min, out_max):
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
def setup():
global tempo_anterior
print("Iniciando...")
# Configuração do LED de pico
pino_led_pico.value(0)
# Conexão Wi-Fi
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)
while not wlan.isconnected():
time.sleep_ms(100)
print(".", end="")
print("\nWiFi conectado")
# Configuração do horário
try:
ntptime.settime()
except:
print("Erro ao sincronizar NTP")
# Inicialização do LCD
lcd.clear()
# Exibe informações da máquina ao iniciar
lcd.move_to(0, 0)
lcd.putstr("MCL-800-MN Monitor")
lcd.move_to(0, 1)
lcd.putstr("Pot: 400W / 220V")
lcd.move_to(0, 2)
lcd.putstr("Iniciando...")
time.sleep(2)
tempo_anterior = time.ticks_ms()
def loop():
global tensao_atual, corrente_atual, fator_potencia, potencia_aparente
global potencia_ativa, potencia_anterior, consumo_diario, consumo_mensal
global tempo_anterior, ultimo_update_lcd, dia_anterior, mes_anterior
# Pega o hrr real
agora = time.localtime()
# Leitura dos potenciômetros
leitura_tensao = pino_tensao.read()
leitura_corrente = pino_corrente.read()
# Converte a tensão para valores reais
tensao_atual = (leitura_tensao / 4095.0) * tensao_max
# Ajusta a corrente para ficar dentro dos limites realistas da máquina de costura
percentual_carga = leitura_corrente / 4095.0
# Mapeia o percentual para um valor realista de potência
if percentual_carga < 0.5:
# Faixa de operação nominal (0-50% do potenciômetro)
potencia_desejada = map_float(percentual_carga * 100, 0, 50, 0, potencia_nominal_max * 100) / 100.0
elif percentual_carga < 0.8:
# Faixa de operação em pico (50-80% do potenciômetro)
potencia_desejada = map_float((percentual_carga - 0.5) * 100, 0, 30, potencia_nominal_max * 100, potencia_pico_max * 100) / 100.0
else:
# Faixa de sobrecarga (80-100% do potenciômetro)
potencia_desejada = map_float((percentual_carga - 0.8) * 100, 0, 20, potencia_pico_max * 100, potencia_maxima * 100) / 100.0
# Calcula o fator de potência com base na carga
fator_potencia = calcular_fator_potencia(potencia_desejada)
# Calcula a corrente necessária para atingir a potência desejada
if tensao_atual > 0 and fator_potencia > 0:
corrente_atual = potencia_desejada * 1000 / (tensao_atual * fator_potencia)
else:
corrente_atual = 0.0
# Limita a corrente máxima ao dobro da nominal (para simular os picos realistas)
if corrente_atual > corrente_nominal * 2:
corrente_atual = corrente_nominal * 2
# Calcula as potências
potencia_aparente = tensao_atual * corrente_atual / 1000.0 # kVA
potencia_ativa = potencia_aparente * fator_potencia # kW
# Controla o LED de indicação de pico
if potencia_ativa >= potencia_maxima * 0.60:
pino_led_pico.value(1) # Liga o LED quando ultrapassar o limite de pico
else:
pino_led_pico.value(0) # Desliga o LED quando estiver abaixo do pico
# Calcula o tempo decorrido desde a última leitura em horas
tempo_atual = time.ticks_ms()
tempo_diff = time.ticks_diff(tempo_atual, tempo_anterior)
if tempo_diff > 0:
horas_decorridas = tempo_diff / 3600000.0 # Converte ms para horas
else:
horas_decorridas = 0.0
# Calcula o consumo desde a última leitura
potencia_media = (potencia_anterior + potencia_ativa) / 2.0
consumo_intervalo = potencia_media * horas_decorridas
# Adiciona ao consumo diário
consumo_diario += consumo_intervalo
# Atualiza as variáveis para o próximo cálculo
potencia_anterior = potencia_ativa
tempo_anterior = tempo_atual
# Verifica mudança de dia
if agora[2] != dia_anterior and dia_anterior != -1:
# Adiciona o consumo diário ao mensal e zera o diário
consumo_mensal += consumo_diario
consumo_diario = 0.0
print("Novo dia detectado - Resetando consumo diário")
# Verifica a mudança de mês
if agora[1] != mes_anterior and mes_anterior != -1:
# Zera o consumo mensal
consumo_mensal = 0.0
print("Novo mês detectado - Resetando consumo mensal")
# Atualiza os valores de referência para os dias e mês
dia_anterior = agora[2]
mes_anterior = agora[1]
# Atualiza LCD a cada 1 segundo
if time.ticks_diff(tempo_atual, ultimo_update_lcd) >= 1000:
ultimo_update_lcd = tempo_atual
lcd.clear()
lcd.move_to(0, 0)
lcd.putstr("V:{:.1f}V I:{:.2f}A".format(tensao_atual, corrente_atual))
lcd.move_to(0, 1)
lcd.putstr("FP:{:.2f} P:{:.2f}kW".format(fator_potencia, potencia_ativa))
lcd.move_to(0, 2)
lcd.putstr("Dia:{:.3f} Mes:{:.1f}".format(consumo_diario, consumo_mensal))
lcd.move_to(0, 3)
buffer = "{:02d}/{:02d} {:02d}:{:02d}:{:02d}".format(
agora[2], agora[1], agora[3], agora[4], agora[5])
lcd.putstr(buffer)
# Status da máquina (normal/pico)
if pino_led_pico.value() == 1:
lcd.move_to(14, 2)
lcd.putstr("PICO!")
# Imprime no terminal do Wokwi para acompanhar o consumo
print("Interlock: V: {:.1f}V, I: {:.3f}A, FP: {:.2f}, P: {:.3f}kW, Diário: {:.3f}kWh, Mensal: {:.3f}".format(
tensao_atual, corrente_atual, fator_potencia, potencia_ativa, consumo_diario, consumo_mensal), end="")
# Indica se está em modo de pico
if pino_led_pico.value() == 1:
print(" ⚠ PICO DE CONSUMO!")
else:
print("")
time.sleep_ms(100) # Pequeno delay para estabilidade
# Execução principal
setup()
while True:
loop()