W5500-EVB - Smart home controller made by Pico
Control by docking with smart home master control platform using various sensor modules and other hardware devices
summary
The project aims to maximize the convenience and efficiency of modern life. The main goal is to make users' living spaces more comfortable and safe through intelligent home systems. The system also focuses on optimizing energy consumption to reduce environmental impact and minimize inconveniences that may arise in users' daily lives.
1 Hardware preparation
The devices used in this project are:
- Bedroom environment and air quality data collection consisting of ESP32-C3-Mini-1U module and development board + DHT11 temperature and humidity sensor module + ENS160 air quality sensor module.
- The control center consisting of W5500-EVB-Pico + rocker potentiometer is used to control the opening and closing of curtains and the opening and closing of ventilation fans.
- It is a smart home control device composed of ESP32-S3 module and development board + reduction motor + relay. It is used to control the opening and closing of curtains and the opening and closing of ventilation fans.
The three modules used in this project are independent of each other and can be docked with a smart home master control platform to achieve connected control..
2 Smart home platform connection
The MQTT protocol is used to connect to the smart home platform, and the ESP32C3 reports sensor data to the smart home platform via MQTT after connecting to WIFI.
To realize the function of the operation introduction, you must first set up the corresponding device on the smart home platform and set the corresponding MQTT topic for receiving environmental data and the corresponding JSON data format for reporting environmental data to achieve docking. The data structure defined here is:
{
"temperature": "16.75", // 温度
"humidity": "69.82", // 湿度
"aqi": 2, // 空气质量等级(Air Quality Index)
"tvoc": 343, // 有机挥发物浓度(Total Volatile Organic Compounds)
"eCO2": 842, // 二氧化碳浓度
"wifi_rssi": "-41.00" // WIFI信号强度
}
3 Code
3.1 Environmental data collection
The environmental data collection process is relatively simple, just initialize I2C and then read air quality data through I2C. It uses MQTT to report data to the smart home platform in a predefined format. If you need to automatically control the connection of other smart home devices based on air quality conditions, simply configure the corresponding execution logic in the smart home platform. For example, if the concentration of carbon dioxide in indoor air is too high, a ventilation fan or outside air blower will automatically turn on. Operation will not stop until the indoor carbon dioxide concentration falls to a predetermined value.
The implementation code is as follows:
import dht
import time
import ujson
import asyncio
import machine
import network
import ubinascii
from button import Button
from ENS160 import myENS160
from umqtt.simple import MQTTClient
report_interval = 10 # 上报传感器数据间隔时间(单位:秒)
# 网络配置
wifi_ssid = "@PHICOMM_34"
wifi_password = "12345678"
station = network.WLAN(network.STA_IF)
station.active(True)
# 连接至wifi
def connect_wifi():
# 不断尝试连接到配置的WIFI
while not station.isconnected():
print("Connecting...")
station.connect(wifi_ssid, wifi_password) # 连接至配置的WIFI AP
time.sleep(10)
# 连接成功,输出IP地址
print("WIFI连接成功,IP地址:", station.ifconfig()[0])
dht11_sensor=dht.DHT11(machine.Pin(9))
ens160_sersor=myENS160()
# 获取传感器数据,用于将传感器数据上报至智能家居平台
def get_sensor_data():
temperature = 0 # 温度数据
humidity = 0 # 湿度数据
aqi = 0 # 光照强度
tvoc = 0 # 光照强度
eCO2 = 0 # 光照采样
wifi_rssi = 0 # 信号强度
# 获取环境温湿度数据
dht11_sensor.measure() # 测量
temperature=dht11_sensor.temperature() # 读取温度
humidity=dht11_sensor.humidity() # 读取湿度
# 获取空气质量数据
tvoc=ens160_sersor.getTVOC()
aqi=ens160_sersor.getAQI()
eCO2=ens160_sersor.getECO2()
# 获取WIFI信号质量
wifi_rssi = station.status('rssi')
json_data = {
'temperature': f'{temperature:.2f}', # 温度数据
'humidity': f'{humidity:.2f}', # 湿度数据
'aqi': aqi, # 光照强度
'tvoc': tvoc, # 光照采样
'eCO2': eCO2, # 光照采样
'wifi_rssi': f'{wifi_rssi:.2f}' # 信号强度
}
# print(ujson.dumps(json_data))
return ujson.dumps(json_data)
'''
MQTT 连接
'''
client = None
CLIENT_ID = ubinascii.hexlify(machine.unique_id())
MQTT_SERVER = '192.168.2.120'
async def mqtt_client():
# 连接wifi
connect_wifi()
print("connected wifi")
global client
client = MQTTClient(client_id=CLIENT_ID, server=MQTT_SERVER,user="esp32c3",password="123456")
client.connect()
print("mqtt client connected")
while True:
# client.wait_msg()
await asyncio.sleep_ms(100)
# 上报传感器数据至智能家居平台
async def report_sensor_data():
print("report_sensor_data()")
while True:
await asyncio.sleep(report_interval) # 间隔段时间才开始上报
# 上报传感器数据
data = get_sensor_data()
print("publish: ", data)
client.publish(b"sensor/esp32c3/bedroom/state", data)
async def main():
tasks = []
# MQTT任务
mqtt_task = asyncio.create_task(
mqtt_client()
)
tasks.append(mqtt_task)
# 传感器数据上报任务
report_task = asyncio.create_task(
report_sensor_data()
)
tasks.append(report_task)
# 提交任务执行
await asyncio.gather(i for i in tasks)
if __name__ == "__main__":
print("run in main")
# 异步执行任务
asyncio.run(main())
3.2 커튼 및 환기팬 제어장치
Curtain and ventilation fan equipment control uses a self-produced control board based on the ESP32-S3 module, which has two relay modules and one reduction motor drive module. The software implementation principle is based on MQTT communication and subscribes to topics from two control units. If other devices in the smart home platform need to control curtains and ventilation fans, they can send instructions to them to achieve connected control.
- Curtain Control: Curtain control has three states: open, closed, and stopped. Since a reduction motor is used to control the opening and closing of the curtain, it is designed to use -100 to 100 to express the duty cycle of forward and reverse rotation. If the value is 0, it means that the curtain's reduction motor stops. operate. Positive values indicate the curtains are closed, negative values indicate the curtains are open. The larger the positive and negative values, the higher the duty cycle and the faster the rotation speed of the reduction motor.
- Based on the above logic, when the curtain needs to be opened, you can control the curtain behavior by sending a value between -100 and 100 to the MQTT topic [device/esp32s3/curtain/control].
Ventilation fan control: The ventilation fan control design is relatively simple with only two states for easy understanding, and the specified values are 0 and 1. 0 means turn off the ventilation fan, 1 means turn on the ventilation fan. So, if you need to control the ventilation fan to turn on, just send 1 to the MQTT topic [ device/esp32s3/ventilator/control ] to turn the ventilation fan on.
The implementation code is as follows:
import dht
import time
import ujson
import asyncio
import machine
import network
import ubinascii
from umqtt.simple import MQTTClient
report_interval = 10 # 上报传感器数据间隔时间(单位:秒)
# 网络配置
wifi_ssid = "@PHICOMM_34"
wifi_password = "12345678"
ventilator_pin = machine.Pin(46, machine.Pin.OUT, value=0) # 换气扇控制
curtain_forward_pwm = machine.PWM(machine.Pin(21)) # 窗帘正向控制(打开)
curtain_forward_pwm.freq(10000) # 设定 PWM 频率为 10KHz
curtain_reverse_pwm = machine.PWM(machine.Pin(47)) # 窗帘逆向控制(关闭)
curtain_reverse_pwm.freq(10000) # 设定 PWM 频率为 10KHz
station = network.WLAN(network.STA_IF)
station.active(True)
# 连接至wifi
def connect_wifi():
# 不断尝试连接到配置的WIFI
while not station.isconnected():
print("Connecting...")
station.connect(wifi_ssid, wifi_password) # 连接至配置的WIFI AP
time.sleep(10)
# 连接成功,输出IP地址
print("WIFI连接成功,IP地址:", station.ifconfig()[0])
'''
MQTT 连接
'''
# MQTT订阅消息回调
def message_callback(topic, msg):
print(topic, msg)
if topic == MQTT_TOPIC_CURTAIN_CONTROL:
curtain_state = int(msg.decode())
print("窗帘控制: %s" %(curtain_state))
if -100 <= curtain_state <= 100:
# 窗帘控制使用百分比数值,需要转换为占空比数值,相差10.23倍。因此简单相乘即可
curtain_state *= 10
else: # 非百分比范围,重置值
curtain_state = 0
# 窗帘有三种状态:打开,静止,关闭。其中打开和关闭状态可以通过PWM进行控制。
if 0 == curtain_state: # 窗帘停止移动
print("停止 %d" %curtain_state)
curtain_forward_pwm.duty_u16(curtain_state)
curtain_reverse_pwm.duty_u16(curtain_state)
elif 0 < curtain_state: # 窗帘正向移动(关闭)
print("关闭 %d" %(abs(curtain_state)))
curtain_forward_pwm.duty_u16(0)
curtain_reverse_pwm.duty_u16(abs(curtain_state))
elif 0 > curtain_state: # 窗帘正向移动(关闭)
print("打开 %d" %(abs(curtain_state)))
curtain_forward_pwm.duty_u16(abs(curtain_state))
curtain_reverse_pwm.duty_u16(0)
else:
print("未知")
elif topic == MQTT_TOPIC_VENTILATOR_CONTROL:
ventilator_state = int(msg.decode())
print("换气扇控制: %s" %(ventilator_state))
# 换气扇只有两个状态:开和关
if 0 == ventilator_state: # 消息为0即为关闭状态
print("关闭换气扇")
ventilator_pin.off()
else: # 非0即为打开状态
print("打开换气扇")
ventilator_pin.on()
else:
print("未知指令: %s ---> %s" %(topic.decode(), msg.decode()))
client = None
CLIENT_ID = ubinascii.hexlify(machine.unique_id())
MQTT_SERVER = '192.168.2.120'
MQTT_TOPIC_CURTAIN_CONTROL = b"device/esp32s3/curtain/control" # 窗帘控制消息主题
MQTT_TOPIC_VENTILATOR_CONTROL = b"device/esp32s3/ventilator/control" # 换气扇控制消息主题
async def mqtt_client():
# 连接wifi
connect_wifi()
print("connected wifi")
global client
client = MQTTClient(client_id=CLIENT_ID, server=MQTT_SERVER,user="esp32c3",password="123456")
client.connect()
print("mqtt client connected")
client.set_callback(message_callback) # 注册订阅消息回调函数
client.subscribe(MQTT_TOPIC_CURTAIN_CONTROL) # 订阅主题(窗帘控制)
client.subscribe(MQTT_TOPIC_VENTILATOR_CONTROL) # 订阅主题(换气扇控制)
while True:
# client.wait_msg()
await asyncio.sleep_ms(10)
client.check_msg()
# 上报传感器数据至智能家居平台
async def report_sensor_data():
print("report_sensor_data()")
while True:
await asyncio.sleep(report_interval) # 间隔段时间才开始上报
# 获取WIFI信号质量
wifi_rssi = station.status('rssi')
# 上报传感器数据
data = {
'wifi_rssi': f'{wifi_rssi:.2f}' # 信号强度
}
print("publish: ", data)
client.publish(b"sensor/esp32s3/bedroom/state", ujson.dumps(data))
async def main():
tasks = []
# MQTT任务
mqtt_task = asyncio.create_task(
mqtt_client()
)
tasks.append(mqtt_task)
# 传感器数据上报任务
report_task = asyncio.create_task(
report_sensor_data()
)
tasks.append(report_task)
# 提交任务执行
await asyncio.gather(i for i in tasks)
if __name__ == "__main__":
print("run in main")
# 异步执行任务
asyncio.run(main())
3.3 controller
The controller is implemented using the W5500-EVB-Pico + rocker potentiometer, and when successfully connected to the network, it reads the status of the rocker potentiometer and rocker button and sends command values to the corresponding MQTT topic. After curtains and ventilation fans, when the equipment receives a command, it can control the curtains or ventilation fans to perform the corresponding actions.
Since the curtains only have one direction, you only need to use one axis of the rocker. Here the X-axis of the rocker is used to control the left and right movement of the curtain. The rocker button is used to control the switch on the ventilation fan; pressing it once turns the ventilation fan on, pressing it again turns the ventilation fan off, and so on.
The implementation code is as follows:
import os
import time
import board
import busio
import asyncio
import analogio
import digitalio
import displayio
import terminalio
import adafruit_displayio_ssd1306
from adafruit_display_text import label
import adafruit_minimqtt.adafruit_minimqtt as MQTT
import adafruit_wiznet5k.adafruit_wiznet5k_socket as socket
import task2
''' 摇杆引脚初始化 '''
x = analogio.AnalogIn(board.GP27)
y = analogio.AnalogIn(board.GP26)
led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT
button = digitalio.DigitalInOut(board.GP6)
# button.switch_to_input(pull=digitalio.Pull.UP)
""" 递推平均滤波法(又称滑动平均滤波法)"""
FILTER_N = 12
x_buf = []
def filter_x(value):
global x_buf
x_buf.append(value)
if FILTER_N < len(x_buf):
x_buf = x_buf[1:]
x_sum = sum(x_buf)
return int(x_sum / FILTER_N)
y_buf = []
def filter_y(value):
global y_buf
y_buf.append(value)
if FILTER_N < len(y_buf):
y_buf = y_buf[1:]
y_sum = sum(y_buf)
return int(y_sum / FILTER_N)
ADC_VALUE_MIN = 0
ADC_VALUE_MAX = 65535
RANGE_MIN = -100
RANGE_MAX = 100
def map(value, source_min = ADC_VALUE_MIN, source_max = ADC_VALUE_MAX, dest_min = RANGE_MIN, dest_max = RANGE_MAX):
return (value - source_min) * (dest_max - dest_min) / (source_max - source_min) + dest_min
### MQTT主题 ###
mqtt_host = os.getenv("MQTT_HOST")
mqtt_port = os.getenv("MQTT_PORT")
mqtt_user = os.getenv("MQTT_USER")
mqtt_pass = os.getenv("MQTT_PASS")
# 窗帘控制
curtain_topic = "device/esp32s3/curtain/control"
# 换气扇控制
ventilator_topic = "device/esp32s3/ventilator/control"
### MQTT事件 ###
'''
MQTT 连接成功
'''
def connected(client, userdata, flags, rc):
# This function will be called when the client is connected
# successfully to the broker.
print(f"Connected to MQTT broker [{mqtt_host}:{mqtt_port}]! Listening for topic changes on {curtain_topic}, {ventilator_topic}")
# Subscribe to all changes on the onoff_feed.
# client.subscribe(curtain_topic)
'''
MQTT 连接断开
'''
def disconnected(client, userdata, rc):
# This method is called when the client is disconnected
print(f"Disconnected from MQTT broker [{mqtt_host}:{mqtt_port}]!")
'''
接收到订阅主题消息
'''
def message(client, topic, message):
# This method is called when a topic the client is subscribed to
# has a new message.
print(f"New message on topic {topic}: {message}")
if topic == curtain_topic:
print(f"synchronizing curtain: {message}")
elif topic == ventilator_topic:
print(f"synchronizing ventilator: {message}")
mqtt_client = None
async def init():
### MQTT 连接配置 ###
socket.set_interface(task2.eth)
MQTT.set_socket(socket, task2.eth)
# 设置客户端参数
global mqtt_client
mqtt_client = MQTT.MQTT(
broker=mqtt_host,
port=mqtt_port,
username=mqtt_user,
password=mqtt_pass
)
# 订阅事件
mqtt_client.on_connect = connected
mqtt_client.on_disconnect = disconnected
mqtt_client.on_message = message
print("MQTT init done.")
mqtt_client.connect()
mqtt_client.subscribe(ventilator_topic)
async def monitor_control():
ventilator_state = False # 换气扇开关状态
while True:
print("X value is: %d, Y value is: %d" %(map(filter_x(x.value)), map(filter_y(y.value))))
mqtt_client.publish(curtain_topic, int(map(filter_x(x.value))))
if not button.value: # 摇杆按键按下
if not ventilator_state: # 当前状态
led.value = True
mqtt_client.publish(ventilator_topic, 1)
else:
led.value = False
mqtt_client.publish(ventilator_topic, 0)
ventilator_state = not ventilator_state # 重置开关状态
await asyncio.sleep_ms(10)
4. result
ventilation fan control
curtain control
5. Why? W5500-evb-pico
The main reason to use the W5500-EVB-Pico is its powerful networking capabilities. This board provides a stable Internet connection and has a built-in hardware TCP/IP stack for TCP/IP communications, greatly reducing the complexity that can arise from network communications. This allows developers to focus less on network-related code and more time developing the functionality of the actual application. Additionally, this board's fast processing speed and stability are critical for real-time data processing and response, increasing the reliability of smart home systems.
6. Conclusion
In conclusion, this project uses W5500-EVB-Pico as the core controller, transforming the user's home into a smarter and more comfortable space. Multiple sensors and devices work together efficiently to make our daily lives easier, safer, and more energy efficient. This is a great example of how technology can improve our lives.