'''
1) Receive commands from MQTT broker for controlling LEDs and status updates
'''
from machine import SoftI2C, Pin
from machine_i2c_lcd import I2cLcd
from time import sleep
from umqtt.simple import MQTTClient
import ujson
import network
import utime as time
telemetry_data_old = ""
data = ""
# Device Setup
DEVICE_ID = "user07"
DEMAND_LIMIT = 2.0
# WiFi Setup
WIFI_SSID = "Wokwi-GUEST" # για το εργαστήριο: microlab
WIFI_PASSWORD = "" # για το εργαστήριο: microlab1!
# MQTT Setup
MQTT_BROKER = "broker.hivemq.com"
MQTT_CLIENT = DEVICE_ID
MQTT_TELEMETRY_TOPIC = "iot/telemetry/user07"
MQTT_CONTROL_TOPIC = "iot/control/user07"
MQTT_REQUEST_TOPIC = "iot/request/user07"
# Define the LCD I2C address and dimensions
I2C_ADDR = 0x27
I2C_NUM_ROWS = 2
I2C_NUM_COLS = 16
# switch Setup
SWITCH = Pin(8, Pin.IN)
# LED Setup
RED_LED = Pin(6, Pin.OUT)
BLUE_LED = Pin(4, Pin.OUT)
GREEN_LED = Pin(5, Pin.OUT)
YELLOW_LED = Pin(7, Pin.OUT)
# button Setup
BUTTON_BLUE = Pin(0, Pin.IN, Pin.PULL_UP)
BUTTON_GREEN = Pin(1, Pin.IN, Pin.PULL_UP)
BUTTON_RED = Pin(2, Pin.IN, Pin.PULL_UP)
BUTTON_YELLOW = Pin(3, Pin.IN, Pin.PULL_UP)
#initialize I2C on GPIOs 18 (SDA) and 19 (SCL).
i2c = SoftI2C(sda=Pin(10), scl=Pin(9), freq=400000)
#variabe to choose each load
pending_load = None
lcd = I2cLcd(i2c, I2C_ADDR, I2C_NUM_ROWS, I2C_NUM_COLS)
lcd.putstr("Initializing...")
RED_LED.on()
BLUE_LED.on()
GREEN_LED.on()
YELLOW_LED.on()
def did_receive_callback(topic, message):
global telemetry_data_old
global pending_load
global wattage
global data
print('\n\nData Received! \ntopic = {0}, message = {1}'.format(topic, message))
topic = topic.decode()
message = message.decode()
# If switch in position 1 (normal mode), the requests to enable the LEDs are ignored,
# Only the command "status" is allowed
if SWITCH.value() == 1 and message != "status":
print("Local Mode Active (Switch 1): Ignoring Remote Command")
return
if topic == MQTT_CONTROL_TOPIC:
#red led
if message == "led/red/on":
RED_LED.on()
send_led_status()
elif message == "led/red/off":
RED_LED.off()
send_led_status()
#blue led
elif message == "led/blue/on":
BLUE_LED.on()
send_led_status()
elif message == "led/blue/off":
BLUE_LED.off()
send_led_status()
#green led
elif message == "led/green/on":
GREEN_LED.on()
send_led_status()
elif message == "led/green/off":
GREEN_LED.off()
send_led_status()
#yellow led
elif message == "led/yellow/on":
YELLOW_LED.on()
send_led_status()
elif message == "led/yellow/off":
YELLOW_LED.off()
send_led_status()
elif message == "load_enable/on":
# If theres no request, the command is ignored
if pending_load is None:
print("Received 'on' but no load is pending.")
return
# turning on the requested load
if pending_load == "red": RED_LED.on()
elif pending_load == "green": GREEN_LED.on()
elif pending_load == "yellow": YELLOW_LED.on()
elif pending_load == "blue": BLUE_LED.on()
print(f"Request APPROVED. {pending_load} is now ON.")
# update of Wattage, LCD and MQTT
wattage = total_wattage()
update_lcd_display(wattage)
telemetry_data_new = create_json_data(wattage)
mqtt_client_publish(MQTT_TELEMETRY_TOPIC, telemetry_data_new)
#Reset
pending_load = None
elif message == "load_enable/off":
if pending_load is None:
return
print(f"Request DENIED. Demand Limit Reached! {pending_load} stays OFF.")
# update of LCD
lcd.clear()
lcd.putstr("LIMIT REACHED!")
time.sleep(2.0)
wattage = total_wattage()
update_lcd_display(wattage)
telemetry_data_new = create_json_data(wattage)
mqtt_client_publish(MQTT_TELEMETRY_TOPIC, telemetry_data_new)
# Reset
pending_load = None
elif message == "status":
if telemetry_data_old:
mqtt_client_publish(MQTT_TELEMETRY_TOPIC, telemetry_data_old)
else:
print("No telemetry yet — ignoring status request.")
send_led_status()
send_power_status()
elif topic == MQTT_REQUEST_TOPIC:
if wattage <= DEMAND_LIMIT:
create_json_data(1)
mqtt_client_publish(MQTT_CONTROL_TOPIC, data)
else:
create_json_data(0)
mqtt_client_publish(MQTT_CONTROL_TOPIC, data)
return
# -------------------------------------------------------------------
def mqtt_connect():
print("Connecting to MQTT broker ...", end="")
mqtt_client = MQTTClient(MQTT_CLIENT, MQTT_BROKER)
mqtt_client.set_callback(did_receive_callback)
mqtt_client.connect()
print("Connected.")
mqtt_client.subscribe(MQTT_CONTROL_TOPIC)
mqtt_client.subscribe(MQTT_REQUEST_TOPIC)
print("Subscribed.")
return mqtt_client
# -------------------------------------------------------------------
def create_json_data(power):
data = ujson.dumps({
"device_id": DEVICE_ID,
"power": float(power),
"type": "sensor"
})
return data
# -------------------------------------------------------------------
def mqtt_client_publish(topic, data):
print("\nUpdating MQTT Broker...")
mqtt_client.publish(topic, data)
print(data)
# -------------------------------------------------------------------
def send_led_status():
data = ujson.dumps({
"device_id": DEVICE_ID,
"red_led": "ON" if RED_LED.value() else "OFF",
"blue_led": "ON" if BLUE_LED.value() else "OFF",
"green_led": "ON" if GREEN_LED.value() else "OFF",
"yellow_led": "ON" if YELLOW_LED.value() else "OFF",
})
mqtt_client_publish(MQTT_TELEMETRY_TOPIC, data)
#--------------------------------------------------------------------
def send_power_status():
data = ujson.dumps({
"request_power": 1.0,
"type": "sensor",
"device_id": DEVICE_ID,
})
mqtt_client_publish(MQTT_TELEMETRY_TOPIC, data)
#--------------------------------------------------------------------
def total_wattage():
w = 0.0
if RED_LED.value(): w += 1.0
if GREEN_LED.value(): w += 1.0
if YELLOW_LED.value(): w += 1.0
if BLUE_LED.value(): w += 1.0
return w
#--------------------------------------------------------------------
def update_lcd_display(watts):
lcd.clear()
lcd.putstr("Total wattage: ")
lcd.move_to(0, 1)
lcd.putstr(str(watts) + " kW")
#--------------------------------------------------------------------
def send_power_request():
data = ujson.dumps({
"request_power": 1.0,
"type": "sensor",
"device_id": DEVICE_ID,
})
mqtt_client_publish(MQTT_REQUEST_TOPIC, data)
# Connect to WiFi
wifi_client = network.WLAN(network.STA_IF)
wifi_client.active(True)
print("Connecting device to WiFi")
wifi_client.connect(WIFI_SSID, WIFI_PASSWORD)
while not wifi_client.isconnected():
print("Connecting...")
time.sleep(0.5)
print("WiFi Connected!")
print(wifi_client.ifconfig())
# Connect to MQTT
mqtt_client = mqtt_connect()
RED_LED.off()
BLUE_LED.off()
GREEN_LED.off()
YELLOW_LED.off()
telemetry_data_old = ""
# Initialization of the states of the switches (1 = Unpressed)
curr_red = 1
curr_green = 1
curr_yellow = 1
curr_blue = 1
prev_red = 1
prev_green = 1
prev_yellow = 1
prev_blue = 1
wattage = 0
while True:
mqtt_client.check_msg()
print(". ", end="")
# current value update
curr_red = BUTTON_RED.value()
curr_green = BUTTON_GREEN.value()
curr_yellow = BUTTON_YELLOW.value()
curr_blue = BUTTON_BLUE.value()
#normal mode
if SWITCH.value() == 1:
# --- RED BUTTON TOGGLE ---
# If the button is now pressed (0) while it was unpressed before (1) -> Falling Edge
if curr_red == 0 and prev_red == 1:
if RED_LED.value() == 1:
RED_LED.off()
else:
RED_LED.on()
# --- GREEN BUTTON TOGGLE ---
if curr_green == 0 and prev_green == 1:
if GREEN_LED.value() == 1:
GREEN_LED.off()
else:
GREEN_LED.on()
# --- YELLOW BUTTON TOGGLE ---
if curr_yellow == 0 and prev_yellow == 1:
if YELLOW_LED.value() == 1:
YELLOW_LED.off()
else:
YELLOW_LED.on()
# --- BLUE BUTTON TOGGLE ---
if curr_blue == 0 and prev_blue == 1:
if BLUE_LED.value() == 1:
BLUE_LED.off()
else:
BLUE_LED.on()
wattage = total_wattage()
update_lcd_display(wattage)
print(wattage)
#demand response mode
else:
# RED Request
if curr_red == 0 and prev_red == 1:
if RED_LED.value() == 0:
pending_load = "red"
print("Sending Request for RED LED...")
send_power_request()
else:
print("RED LED already ON")
# GREEN Request
if curr_green == 0 and prev_green == 1:
if GREEN_LED.value() == 0:
pending_load = "green"
print("Sending Request for GREEN LED...")
send_power_request()
else:
print("GREEN LED already ON")
# YELLOW Request
if curr_yellow == 0 and prev_yellow == 1:
if YELLOW_LED.value() == 0:
pending_load = "yellow"
print("Sending Request for YELLOW LED...")
send_power_request()
else:
print("YELLOW LED already ON")
# BLUE Request
if curr_blue == 0 and prev_blue == 1:
if BLUE_LED.value() == 0:
pending_load = "blue"
print("Sending Request for BLUE LED...")
send_power_request()
else:
print("BLUE LED already ON")
wattage = total_wattage()
telemetry_data_new = create_json_data(wattage)
if telemetry_data_new != telemetry_data_old:
mqtt_client_publish(MQTT_TELEMETRY_TOPIC, telemetry_data_new)
telemetry_data_old = telemetry_data_new
update_lcd_display(wattage)
# Update Last States
prev_blue = curr_blue
prev_green = curr_green
prev_red = curr_red
prev_yellow = curr_yellow
# Publish only when changed
telemetry_data_new = create_json_data(wattage)
if telemetry_data_new != telemetry_data_old:
mqtt_client_publish(MQTT_TELEMETRY_TOPIC, telemetry_data_new)
telemetry_data_old = telemetry_data_new
time.sleep(0.2)