实现MQTT协议 - 实现MQTTnet Clinet并接入Home Assistant - MqttAutoDiscovery
在发布自动发现消息(PublishSwitchDiscovery)后,需要订阅命令主题(command_topic)
在命令主题的消息处理事件程序中,根据接收到的命令("ON"或"OFF")更新设备状态,并将更新后的状态发布到状态主题(state_topic)。
实时发布设备的当前可用性消息(例如,在连接时发布"online",在断开连接时发布"offline")
在Home Assistant 打开开关
在Home Assistant 打开开关后,会向命令主题(command_topic)发送一个消息("ON" 或 "OFF")。
我们要在 MQTT 客户端中订阅这个命令主题,以便接收开关状态变化的指令。
当收到指令时,我们需要更新开关的状态,并将状态发布到状态主题(state_topic)),这样Home Assistant就会知道开关的当前状态
构建完整主题-topic
var uniqueId = "my_csharp_switch";
var discoveryTopic = $"homeassistant/switch/{uniqueId}/config";
state_topic = $"homeassistant/switch/{uniqueId}/state",
command_topic = $"homeassistant/switch/{uniqueId}/command",
availability
new { topic = $"homeassistant/switch/{uniqueId}/availability" }使用 MQTT 客户端工具(如 MQTT Explorer)订阅:
使用以下主题:
配置主题:homeassistant/switch/my_csharp_switch/config 设备配置信息,也是自动发现主题
状态主题:homeassistant/switch/my_csharp_switch/state 状态数据:
命令主题:homeassistant/switch/my_csharp_switch/command 可写控制命令,如开关:开、关
有效主题:homeassistant/switch/my_csharp_switch/availability 设备在线状态。如开关:离线,在线
构建发现消息-Home Assistant automatically discovers MQTT devices
Create virtual devices
Adding devices to Home Assistant
#region example Mqtt Switch Discovery
/// <summary>
/// run ok
/// Home Assistant automatically discovers MQTT devices if you send a discovery payload:
/// </summary>
/// <param name="mqttClient"></param>
/// <returns></returns>
public async Task PublishSwitchDiscovery(IMqttClient mqttClient)
{
var uniqueId = "my_csharp_switch";
var discoveryTopic = $"homeassistant/switch/{uniqueId}/config";
var payload = new
{
name = "My C# MQTT Switch",
unique_id = uniqueId,
state_topic = $"homeassistant/switch/{uniqueId}/state",
command_topic = $"homeassistant/switch/{uniqueId}/command",
payload_on = "ON",
payload_off = "OFF",
availability = new[]
{
new { topic = $"homeassistant/switch/{uniqueId}/availability" } // for PublishAvailabilityAsync,online or offline
},
retain = true, // Crucial for discovery persistence
device = new // Optional: Group with other entities come from:https://www.home-assistant.io/integrations/switch.mqtt/
{
identifiers = new[] { "my_csharp_device" },
name = "My C# Device",
manufacturer = "MyCompany",
model_id = "dx29",
sw_version = "1.0.0",
}
};
var jsonPayload = JsonSerializer.Serialize(payload);
var message = new MqttApplicationMessageBuilder()
.WithTopic(discoveryTopic)
.WithPayload(jsonPayload)
.WithQualityOfServiceLevel(MQTTnet.Protocol.MqttQualityOfServiceLevel.AtLeastOnce)
.WithRetainFlag(true)
.Build();
await mqttClient.PublishAsync(message);
}
#endregion
订阅消息
当连上mqtt server后,会收到这几个主题
[ 收到消息: 主题=homeassistant/switch/my_csharp_switch/command, 内容=ON
Received on homeassistant/switch/my_csharp_switch/command: ON
[ 收到消息: 主题=homeassistant/switch/my_csharp_switch/state, 内容=OFF
Received on homeassistant/switch/my_csharp_switch/state: OFF
[ 收到消息: 主题=homeassistant/switch/my_csharp_switch/availability, 内容=online
状态同步
当收到命令后,必须更新状态主题(state_topic)
使用保留消息(retain=true)确保状态持久化
mqttClient.ApplicationMessageReceivedAsync += async e =>
{
var topic = e.ApplicationMessage.Topic;
var payload = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
// 根据 QoS 级别可定制 ACK 行为
if (e.ApplicationMessage.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
{
// 手动确认
await e.AcknowledgeAsync(CancellationToken.None);
}
Console.WriteLine($"[处理事件(内嵌)]test function:Received Message on {topic}: {payload}");
var uniqueId = "my_csharp_switch";
string command = e.ApplicationMessage.ConvertPayloadToString();
Console.WriteLine($"Received command from HA: {command}");
var stateTopic = $"homeassistant/switch/{uniqueId}/state";
if (e.ApplicationMessage.Topic == $"homeassistant/switch/{uniqueId}/command")
{
if (command == "ON")
{
// Your device logic to turn on goes here
var state = "ON";
//根据收到的命令发布状态主题,保持同步
var msg = new MqttApplicationMessageBuilder()
.WithTopic(stateTopic)
.WithPayload(state)
.WithQualityOfServiceLevel(MQTTnet.Protocol.MqttQualityOfServiceLevel.AtLeastOnce)
.WithRetainFlag(false) // 保持状态 false // 不保留消息
.Build();
var result= await mqttClient.PublishAsync(msg);
if (result.ReasonCode==MqttClientPublishReasonCode.Success)
{
Console.WriteLine($"from pc to HA:状态发布成功 {result.IsSuccess}");
}
else
{
Console.WriteLine($"from pc to HA:状态发布成功: {result.ReasonCode} {result.ReasonString}");
}
}
else if (command == "OFF")
{
var state = "OFF";
// Your device logic to turn off goes here
var msg = new MqttApplicationMessageBuilder()
.WithTopic(stateTopic)
.WithPayload(state)
.WithQualityOfServiceLevel(MQTTnet.Protocol.MqttQualityOfServiceLevel.AtLeastOnce)
.WithRetainFlag(true) // 保持状态
.Build();
await mqttClient.PublishAsync(msg);
}
}
};