ESP32调试板连接MQTT自动注册小蓝灯到Homeassistant

文章目录

  • 简介
  • 代码
  • 其他

简介

使用MicroPython编写ESP32控制代码,将ESP32调试板上的小蓝灯(2号引脚)自动注册到Homeassistant

代码

# coding: utf-8
# 2023.03.12 by Yone

import time
import network
import json
from umqtt.simple import MQTTClient
from machine import Pin


class WiFi:
    def __init__(self, ssid, password) -> None:
        self._ssid = ssid
        self._password = password
        self._wlan = network.WLAN(network.STA_IF)
    
    def connect(self):
        self._wlan.active(True)
        if not self._wlan.isconnected():
            print("[+] 连接网络...")
            self._wlan.connect(self._ssid, self._password)
            i = 1
            while not self._wlan.isconnected():
                print("[-] 正在链接...{}".format(i))
                i += 1
                time.sleep(1)
        print("[!] 网络配置: ", self._wlan.ifconfig())


class Device:
    def __init__(self, name: str, sensors: list) -> None:
        self.name = name
        # 绑定 { 传感器名称: 传感器对象 }
        self.sensors = { sensor.name: sensor for sensor in sensors }        


class Sensor:
    def __init__(self, pin_id, name, type) -> None:
        self.name = name
        self.type = type
        self.pin_id = pin_id
        self._sensor = Pin(self.pin_id, Pin.OUT)
        # 绑定 { 传感器状态: 传感器控制函数 }
        self.controller = {
            "ON": self.open,
            "OFF": self.close
        }
        # self.close()
        self.controller["OFF"]()

    def open(self): 
        self.status = "ON"
        self._sensor.value(1)
        print("[*] {sensor_name}状态:ON".format(sensor_name=self.name))

    def close(self): 
        self.status = "OFF"
        self._sensor.value(0)
        print("[*] {sensor_name}状态:OFF".format(sensor_name=self.name))


class HARegistrar:
    def __init__(self, mqtt_client, device_name, sensor) -> None:
        self._mqtt_client = mqtt_client
        self._device_name = device_name
        self._sensor = sensor

    def get_register_topic(self): 
        return "homeassistant/switch/HA/{uid}/config".format(uid=self.get_uid())

    def get_register_content(self):
        return {
            # 设备和传感器名字,ID
            "unique_id": self.get_uid(),
            # 传感器类型
            "name": self._sensor.type,
            # 传感器图标
            "icon": "mdi:lightbulb",
            # 设备和传感器名字,状态主题
            "state_topic": self.get_status_topic(),
            # 设备和传感器名字,设备信息主题
            "json_attributes_topic": "{mqtt_topic_prefix}/attributes".format(mqtt_topic_prefix=self.get_iot_mqtt_topic_prefix()),
            # 设备和传感器名字,HA控制命令主题
            "command_topic": self.get_command_topic(),
            # 设备信息
            "device": {
                "identifiers": self._device_name,
                "manufacturer": "Yone",
                "model": "HA",
                "name": self._device_name,
                "sw_version": "1.0"
            }
        }
    
    def get_status_topic(self): 
        return "{mqtt_topic_prefix}/state".format(mqtt_topic_prefix=self.get_iot_mqtt_topic_prefix())

    def get_command_topic(self):
        return "{mqtt_topic_prefix}/set".format(mqtt_topic_prefix=self.get_iot_mqtt_topic_prefix())

    def get_uid(self): 
        return "HA-{device_name}-{sensor_name}".format(device_name=self._device_name, sensor_name=self._sensor.name)

    def get_iot_mqtt_topic_prefix(self): 
        return "HA-{device_name}/{sensor_name}".format(device_name=self._device_name, sensor_name=self._sensor.name)

    def register(self):
        print("[-] 注册{sensor_name}".format(sensor_name=self._sensor.name))
        # 注册传感器
        self._mqtt_client.publish(
            self.get_register_topic(),
            json.dumps(self.get_register_content())
        )
        # 发送传感器状态
        self._mqtt_client.publish(
            self.get_status_topic(),
            self._sensor.status
        )
        # 订阅传感器控制主题
        self._mqtt_client.subscribe(
            self.get_command_topic()
        )


class Manager:
    def __init__(self, wifi, mqtt_client, device) -> None:
        self._wifi = wifi
        self._mqtt_client = mqtt_client
        self._device = device
        self._controller = dict()

    def register_device(self):
        for sensor_name in self._device.sensors:
            # 创建新注册器
            registrar = HARegistrar(self._mqtt_client, self._device.name, self._device.sensors[sensor_name])
            # 注册设备
            registrar.register()
            # 绑定 { 命令主题: 传感器 }
            self._controller[registrar.get_command_topic()] = self._device.sensors[sensor_name]

    def _msg_callback(self, command_topic, msg):
        # 通过命令主题获取传感器
        sensor = self._controller[command_topic.decode()]
        # 通过状态获取控制函数,并运行
        sensor.controller[msg.decode()]()
        # 创建新注册器
        registrar = HARegistrar(self._mqtt_client, self._device.name, sensor)
        # 通过注册器获取状态主题,并更新设备状态
        self._mqtt_client.publish(registrar.get_status_topic(), msg.decode())

    def run(self):
        # 连接Wi-Fi
        self._wifi.connect()
        # 设置MQTT服务器消息回调
        self._mqtt_client.set_callback(self._msg_callback)
        # 连接MQTT服务器
        self._mqtt_client.connect()
        time.sleep(0.5)
        # 循环注册设备
        self.register_device()

        # 每秒检测一下MQTT服务器发来的消息
        while True:
            self._mqtt_client.check_msg()
            time.sleep(1)


def main():
    device_name = "ESP32_01"
    
    manager = Manager(
        WiFi("ssid", "password"),
        MQTTClient(device_name, "mqtt_server_ip", 1883, "admin", "password"),
        # 设备对象
        Device(
            # 设备名称
            device_name,
            # 传感器列表 
            [ 
                Sensor(2, "blue_led", "LED")
            ]
        )
    )

    manager.run()


if __name__ == "__main__":
    main()

其他

有空再改进一下传感器类Sensor,让不同类型(灯,温度测量,电机,编码器)的传感器成为独立的类,都继承Sensor类

你可能感兴趣的:(esp32,ESP32,MicroPython)