本文介绍如何使用.NET为Home Assistant添加自定义设备,而无需进行额外的配置。通过使用Home Assistant的自动发现功能,我们可以让Home Assistant自动识别和添加新设备,从而简化设备管理流程。通过本文,你将学习如何编写一个简单的.NET程序,将其接入Home Assistant,并实现自定义设备的自动发现和远程关机。
1. 背景
通过前面的文章《搭建EMQX MQTT服务器并接入Home Assistant和.NET程序》,我们已经了解了如何部署EMQX MQTT服务器并接入Home Assistant。在这个基础上,我们可以通过MQTT协议实现设备之间的通信,包括设备的发现、状态更新等功能。Home Assistant提供了自动发现功能,可以自动识别和添加新设备,无需手动配置。这为我们添加自定义设备提供了便利。
在本文中,我们将介绍如何使用.NET为Home Assistant添加自定义设备,实现电脑远程关机的功能。我们将编写一个简单的.NET程序,将其接入Home Assistant,并实现自定义设备的自动发现和远程关机功能。通过这个例子,你将学习如何使用.NET和Home Assistant实现设备集成,为智能家居系统增加新的功能。
2. MQTT 发现消息格式
MQTT 发现消息需要遵循特定的格式:
<discovery_prefix>/<component>/[<node_id>/]<object_id>/config
<discovery_prefix>
:发现前缀,默认为homeassistant
,可以在 Home Assistant 配置中更改。<component>
:支持的 MQTT 集成组件之一,例如binary_sensor
。<node_id>
(可选):提供主题的节点 ID,不被 Home Assistant 使用,但可以用于结构化 MQTT 主题。<object_id>
:设备的 ID,用于区分不同的设备。
对于一个开关设备,我们可以使用以下格式:
homeassistant/button/pc/<pc_mac>/config
这里的 <pc_mac>
是电脑的 MAC 地址,这里通过这种简单的方式区分不同的设备。通过这个格式,我们可以实现设备的自动发现和配置。对于 button 组件,我们需要提供一些配置信息,例如设备的名称、唯一标识、状态主题、命令主题等。这些信息将帮助 Home Assistant 识别和管理设备,我们可以通过官网的设备介绍文档查看更多信息。
对于 MAC 地址的获取,我们可以通过下面的代码,例如:
/// <summary>
/// 获取第一个可用的网卡的MAC地址
/// </summary>
/// <returns></returns>
static string? GetMacAddress()
{
return NetworkInterface.GetAllNetworkInterfaces()
.Where(nic => nic.OperationalStatus == OperationalStatus.Up)
.Select(nic => nic.GetPhysicalAddress().ToString())
.FirstOrDefault();
}
3. 发布设备配置信息
在.NET程序中,我们在程序启动时需要发布该设备的配置信息,让Home Assistant能够识别和添加该设备。在前面的一篇文章中,我们已经了解了如何使用MQTTnet库来实现MQTT客户端,这里我们可以使用MQTTnet库来发布设备配置信息。
var topic = $"{iot_discovery_prefix}/{mac}";
// 发布发现消息
var discoveryMessage = new
{
name = "我的电脑",
command_topic = $"{topic}/commands",
unique_id = $"pc_{mac}",
availability = new
{
topic = $"{topic}/availability",
}
};
var payload = Encoding.UTF8.GetBytes(System.Text.Json.JsonSerializer.Serialize(discoveryMessage));
Console.WriteLine($"Discovery message: {Encoding.UTF8.GetString(payload)}");
var message = new MqttApplicationMessageBuilder()
.WithTopic($"{topic}/config")
.WithPayload(payload)
.Build();
这里我们使用了一个简单的JSON格式来表示设备的配置信息,包括设备的名称、命令主题、唯一标识、可用性主题等。这些信息将帮助Home Assistant识别和管理设备。我们将这个JSON消息发布到<discovery_prefix>/<component>/[<node_id>/]<object_id>/config
主题,让Home Assistant能够识别和添加该设备。
4. 调整设备可用性
上一节的配置消息发布后,我们的设备将被Home Assistant自动识别和添加,无需手动配置。这为我们添加自定义设备提供了便利,同时也提高了设备的可管理性和易用性。但是需要注意的一点是,设备添加成功后是不可用的状态,需要我们调整设备的可用性,让Home Assistant能够正常使用该设备。
关于设备的可用性,我们需要在设备启动时发布可用性消息,表示设备已经启动并可用。这样Home Assistant才能正常使用该设备。我们可以在设备启动时发布一个可用性消息,例如:
// 发布在线消息
await mqttClient.PublishAsync(new MqttApplicationMessageBuilder()
.WithTopic($"{topic}/availability")
.WithPayload("online")
.WithQualityOfServiceLevel(MQTTnet.Protocol.MqttQualityOfServiceLevel.AtMostOnce)
.WithRetainFlag()
.Build());
这里我们发布了一个online
的消息,表示设备已经启动并可用。这样Home Assistant就能够正常使用该设备了。
当然,可用性的调整也需要考虑到设备的异常情况,例如设备的断线、关机等情况。在这种情况下,我们需要发布一个offline
的消息,表示设备不可用。在设备开始连接配置时,我们可以配置一个遗嘱消息,当设备异常断线时,MQTT服务器会自动发布这个遗嘱消息,表示设备不可用。这样Home Assistant就能够及时发现设备的异常情况,提高设备的可靠性和稳定性。
var options = new MqttClientOptionsBuilder()
.WithClientId(mac)
.WithTcpServer("MQTT服务地址", 1883)
.WithCredentials("你的客户端登录用户名", "你的密码")
// 遗嘱消息
.WithWillTopic($"{topic}/availability")
.WithWillPayload("offline")
.WithWillQualityOfServiceLevel(MQTTnet.Protocol.MqttQualityOfServiceLevel.AtMostOnce)
.WithCleanSession()
.Build();
5. 实现远程关机功能
在设备添加和可用性调整后,我们的设备已经可以被Home Assistant正常使用了。接下来我们可以实现设备的功能,当监听到Home Assistant的命令时执行相应的操作,例如远程关机。这实现这一功能之前我们还需要再启动的时候订阅命令主题,例如:
// 订阅命令主题
await mqttClient.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic($"{topic}/commands").Build());
这里我们订阅了命令主题,当Home Assistant发送命令时我们就能够接收到。接收到命令后我们可以执行相应的操作,例如远程关机:
private static Task MqttClient_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg)
{
var topic = arg.ApplicationMessage.Topic;
var payload = Encoding.UTF8.GetString(arg.ApplicationMessage.PayloadSegment);
Console.WriteLine($"Message received on topic: {topic}.");
Console.WriteLine($"Payload: {payload}");
if (topic.EndsWith("commands"))
{
// 按钮按下
if (payload == "PRESS")
{
Console.WriteLine("Shutting down...");
// System.Diagnostics.Process.Start("shutdown", "/s /t 0");
System.Diagnostics.Process.Start("shutdown", "/s");
Environment.Exit(0);
// 可以取消关机 shutdown /a
}
}
return Task.CompletedTask;
}
当然这里的指令我没有使用立马关机,而是使用了弹窗的方式提醒即将关机,这样可以避免误操作。如果正在使用而出现了误操作,在调试时,我们可以使用命令行 shutdown -a
来取消关机。
6. 最后
通过这个例子,我们学习了如何使用.NET为Home Assistant添加自定义设备,实现电脑远程关机的功能。以上只是一个简单的使用案例,如果你需要具体的实现并使用这个工具,则还需要考虑更多的细节,例如信息的配置,开机启动等。通过这个例子,你可以学习如何使用.NET和Home Assistant实现设备集成,为智能家居系统增加新的功能。