一、 通过Docker搭建MQTT服务器(emqx)
- 获取 Docker 镜像
docker pull emqx/emqx:5.4.1
- 启动 Docker 容器
docker run -d --name emqx -p 1883:1883 -p 8083:8083 -p 8084:8084 -p 8883:8883 -p 18083:18083 emqx/emqx:5.4.1
- 通过浏览器访问 http://localhost:18083/(localhost 可替换为您的实际 IP 地址)以访问 EMQX Dashboard 管理控制台,进行设备连接与相关指标监控管理。
- 默认用户名及密码:
账户:admin 密码: public
至此,MQTT服务器便搭建完毕。如果想添加用户、密码就在系统里添加,然并卵,没屌用。
二、 Homeassistant设置
Homeassistant设置比较简单,直接添加MQTT集成即可,地址就填刚才搭建的MQTT服务器地址。当然,你也可以跳过搭建MQTT服务器,直接使用公用MQTT服务器也可。
点击下一步
完成后。。。。
三、通过MQTTX客户端添加实体
通过MQTTX客户端连接MQTT服务器
可以参考官网MQTT介绍
我的设置如下:
TOPIC:xuhome/EP/ddsu666-power/config
格式:discovery prefix(前缀)+模块ID(随意起)+实体ID(随意起)+config
弄完可以参考下面的 这个是功率:
{
"unique_id": "ddsu666-power",
"name": "power",
"icon": "mdi:thermometer",
"state_topic": "ddsu666/power/state",
"json_attributes_topic": "ddsu666/power/attributes",
"unit_of_measurement": "Kw",
"device": {
"identifiers": "ddsu666",
"manufacturer": "制造商",
"model": "EP",
"name": "ddsu666",
"sw_version": "1.0"
}
}
后面就添加电压、电流、功率。记得 TOPIC的实体ID必须更换。
**添加电量,**这个与前面的不同,因为要添加到“能源”里面,由特定的要求。但是“device”里面不用变,只添加一些东西。
topic:xuhome/sensor/EP/ddsu666-electricity/config
(注意xuhome是我的前缀,更改成你的)
{
"unique_id": "ddsu666",
"name": "electricity",
"icon": "mdi:gauge",
"state_topic": "ddsu666/electricity/state",
"json_attributes_topic": "ddsu666/electricity/attributes",
"unit_of_measurement": "kWh",
"last_reset_value_template": "{{ value_json['electricity'].TotalStartTime }}",
"device_class":"energy",
"state_class":"total_increasing",
"device": {
"identifiers": "ddsu666",
"manufacturer": "XuHome",
"model": "EP",
"name": "ddsu666",
"sw_version": "1.0"
}
}
完成后你会发现hass的MQTT里面多了一个设备 n个实体
点击设备 会弹出你添加的东西,当然 你不会由数据 因为你还差一步。
(1)"device_class"对应的设备类型如下:
None: 通用传感器。这是默认值,不需要设置。
apparent_power: 视在功率,单位为VA。
aqi: 空气质量指数,无单位。
atmospheric_pressure: 大气压力,单位为cbar、bar、hPa、mmHg、inHg、kPa、mbar、Pa或psi。
battery: 剩余电池百分比,单位为%。
carbon_dioxide: 二氧化碳浓度,单位为ppm。
carbon_monoxide: 一氧化碳浓度,单位为ppm。
current: 电流,单位为A、mA。
data_rate: 数据传输速率,单位为bit/s、kbit/s、Mbit/s、Gbit/s、B/s、kB/s、MB/s、GB/s、KiB/s、MiB/s或GiB/s。
data_size: 数据大小,单位为bit、kbit、Mbit、Gbit、B、kB、MB、GB、TB、PB、EB、ZB、YB、KiB、MiB、GiB、TiB、PiB、EiB、ZiB或YiB。
date: 日期字符串(ISO 8601)。
distance: 距离,单位为km、m、cm、mm、mi、yd或in。
duration: 持续时间,单位为d、h、min或s。
energy: 能量,单位为Wh、kWh、MWh、MJ或GJ。
energy_storage: 储存能量,单位为Wh、kWh、MWh、MJ或GJ。
enum: 具有有限状态集合(非数值型)。
frequency: 频率,单位为Hz、kHz、MHz或GHz。
gas: 气体体积,单位为m³、ft³或CCF。
humidity: 空气湿度百分比,单位为%。
illuminance: 当前光照强度,单位为lx。
irradiance: 辐照度,单位为W/m²或BTU/(h⋅ft²)。
moisture: 物质中水分的百分比,单位为%。
monetary: 货币价值(ISO 4217)。
nitrogen_dioxide: 二氧化氮浓度,单位为µg/m³。
nitrogen_monoxide: 一氧化氮浓度,单位为µg/m³。
nitrous_oxide: 一氧化二氮浓度,单位为µg/m³。
ozone: 臭氧浓度,单位为µg/m³。
ph: 水溶液的酸碱度(pH)值。
pm1: 小于1微米的颗粒物浓度,单位为µg/m³。
pm25: 小于2.5微米的颗粒物浓度,单位为µg/m³。
pm10: 小于10微米的颗粒物浓度,单位为µg/m³。
power_factor: 功率因数,无单位或%。
power: 功率,单位为W或kW。
precipitation: 累积降水量,单位为cm、in或mm。
precipitation_intensity: 降水强度,单位为in/d、in/h、mm/d或mm/h。
pressure: 压力,单位为Pa、kPa、hPa、bar、cbar、mbar、mmHg、inHg或psi。
reactive_power: 无功功率,单位为var。
signal_strength: 信号强度,单位为dB或dBm。
sound_pressure: 声压级,单位为dB或dBA。
speed: 速度,单位为ft/s、in/d、in/h、km/h、kn、m/s、mph或mm/d。
sulphur_dioxide: 二氧化硫浓度,单位为µg/m³。
temperature: 温度,单位为°C、°F或K。
timestamp: 日期时间对象或时间戳字符串(ISO 8601)。
volatile_organic_compounds: 挥发性有机化合物浓度,单位为µg/m³。
volatile_organic_compounds_parts: 挥发性有机化合物的比例,单位为ppm或ppb。
voltage: 电压,单位为V、mV。
volume: 体积,单位为L、mL、gal、fl. oz.、m³、ft³或CCF。
volume_storage: 储存体积,单位为L、mL、gal、fl. oz.、m³、ft³或CCF。
water: 水消耗量,单位为L、gal、m³、ft³或CCF。
weight: 质量,单位为kg、g、mg、µg、oz、lb或st。
wind_speed: 风速,单位为ft/s、km/h、kn、m/s或mph。
(2)"state_class"对应的设置:
1. 传感器的值永远不会重置,例如,终生总能耗或生产:state_class,未设置为或设置为total、last_reset、None;
2. 传感器的值可能会重置为 0,其值只能增加:state class 。示例:与计费周期一致的能源消耗,例如每月,每次断开连接时,电表都会重置为 0 则,total_increasing;
3. 传感器的值可以重置为 0,其值可以增加和减少: 状态类 ,当值重置时更新。例如:与计费周期一致的净能耗,例如每月。totallast_reset;
4. 传感器的状态会随着每次状态更新而重置,例如,传感器每分钟更新一次过去一分钟的能耗:状态类,每次状态更改都会更新。total或last_reset。
四、完成数据发布
先做个实验:用MQTTX客户端连接MQTT服务器,发布一条数据
topic: ddsu666/voltage/state (这个可以看上一节添加实体的topic)
"state_topic": "ddsu666/power/state",
内容就直接填个数据:33
发布完看看HASS里面的MQTT数据是否变了。
五、ESP32发布数据
后面的就更简单了。。搭建电路就不说了,我用的Arduino。用的是PubSubClient库。
程序参考库的例子。
说一下读正泰的电量表吧。
//电能表 SUDD6666
float U, //电压8192
I, //电流8194
P, //瞬时功率8196
Q, //瞬时无功功率8198
S, //瞬时视在功率8200
PF, //功率因数8202
Fr, //电网频率8204
EP; //总功率16384
这个是电量表的modbus地址,ESP32添加ModbusRTU库。
//两个uint16t 转化位Float
float intof(uint16_t a,uint16_t b){
bigSwit.u[0]=b;
bigSwit.u[1]=a;
return bigSwit.f;
}
// 任务:RTU
void Task_RTU( void *pvParameters ){
Serial2.begin(9600,SERIAL_8N2,34,32); //定义串口通讯,波特率 校验方式
mb.begin(&Serial2);
mb.master();
vTaskDelay(1000);
for(;;){
vTaskDelay(10);
if (!mb.slave()) { // 检查是否没有正在进行的事务
mb.readHreg(1,8192,res,14,cb); // 从Modbus服务器发送读取Hreg
while(mb.slave()) { // 检查交易是否处于活动状态
mb.task();
vTaskDelay(10);
}
U=intof(res[0],res[1]);
I=intof(res[2],res[3]);
P=intof(res[4],res[5]);
Q=intof(res[6],res[7]);
S=intof(res[8],res[9]);
PF=intof(res[10],res[11]);
Fr=intof(res[12],res[13]);
}
if (!mb.slave()) {
mb.readHreg(1,16384,res1,2,cb);
while(mb.slave()) {
mb.task();
vTaskDelay(10);
}
EP=intof(res1[0],res1[1]);
}
}
}
发布MQTT就更简单了,也用不到订阅。建个定时器。
void time02(){
digitalWrite(LED,!digitalRead(LED));
if (mqtt_client.connect("ddsu666")){ //为什么要加这个,因为每次都需要连接一下,不然值不变。。。不知道啥原因。
mqtt_client.publish("ddsu666/voltage/state",String(U).c_str());
vTaskDelay(100);
mqtt_client.publish("ddsu666/current/state",String(I).c_str());
vTaskDelay(100);
mqtt_client.publish("ddsu666/power/state",String(P).c_str());
vTaskDelay(100);
mqtt_client.publish("ddsu666/electricity/state",String(EP).c_str());
vTaskDelay(100);}
}
setup()函数里添加
mqtt_client.setServer(mqtt_broker, mqtt_port);
mqtt_client.setCallback(mqttCallback);
connectToMQTTBroker();
connectToMQTTBroker()函数内容是:
void connectToMQTTBroker() {
while (!mqtt_client.connected()) {
Serial.printf("Connecting to MQTT Broker as %s.....\n", client_id.c_str());
if (mqtt_client.connect("ddsu666", mqtt_username, mqtt_password)) {
Serial.println("Connected to MQTT broker");
mqtt_client.subscribe("ddsu666/electricity/state");
// Publish message upon successful connection
// mqtt_client.publish("ddsu666/electricity/state", "98.65");
} else {
Serial.print("Failed to connect to MQTT broker, rc=");
Serial.print(mqtt_client.state());
Serial.println(" try again in 1 seconds");
delay(1000);
}
}
}
其实connectToMQTTBroker()可以简化mqtt_client.connect(“ddsu666”)。
至此 就ok了 剩下的继续探索吧,少年!