透析中心可能安装了多个米家温度传感器,首先需要找到对应的实体ID。
可以在Home Assistant的开发者工具中查看当前所有传感器的状态。

也可以在已经设备与服务,集成,中找到米家的设备,找到那个传感器


找到需要配置为环境温度的传感器

点击温度实体

点击设置图标


如本例获取到的实体ID为sensor.miaomiaoc_cn_blt_3_11a1sbr5k5o01_t2_temperature_p_2_1。记住此ID,后面很多地方都会用到.
我们需要创建一个自动化规则,当传感器状态更新时及每隔30秒,将温度数据发送到Home Assistant内部集成的的MQTT服务器。
进入 "配置" → "自动化和场景" → "自动化",点击右下角的 "+" 创建新的自动化规则。

进入自动化规则编辑界面后,点击右下角的"创建自动化"按钮。在弹出的对话框中选择"创建新的自动化"。

在新建自动化界面,点右上角的三个点,如下图所示

在弹出的下拉菜单中,点击进入YHAML编辑,进入代码模式,如下所示


在这个大的文本框中粘入如下代码:
alias: 发布环境温度传感器状态到MQTT
description: 当米家温度传感器状态变化或每30秒定时时,自动发布到MQTT供Node-RED使用
triggers:
- entity_id: sensor.miaomiaoc_cn_blt_3_11a1sbr5k5o01_t2_temperature_p_2_1
trigger: state
- seconds: /30
trigger: time_pattern
conditions:
- condition: template
value_template: >-
{{ states('sensor.miaomiaoc_cn_blt_3_11a1sbr5k5o01_t2_temperature_p_2_1')
not in ['unavailable', 'unknown', 'None'] and
states('sensor.miaomiaoc_cn_blt_3_11a1sbr5k5o01_t2_temperature_p_2_1') |
float(-999) != -999 }}
actions:
- data:
topic: >-
homeassistant/sensor/sensor.miaomiaoc_cn_blt_3_11a1sbr5k5o01_t2_temperature_p_2_1/state
payload: >-
{{
states('sensor.miaomiaoc_cn_blt_3_11a1sbr5k5o01_t2_temperature_p_2_1')
}}
retain: false
qos: 0
action: mqtt.publish
mode: single
注意:
以上代码中的 sensor.miaomiaoc_cn_blt_3_11a1sbr5k5o01_t2_temperature_p_2_1 是示例实体ID,请替换为你**实际的温度传感器实体ID**。
放置完成后,如下图示意


观察上次触发列是否会每隔30秒执行一次

返回到传感器的设备界面也能看到设备的自动化下面有一条自动化规则,如下图

到此,自动化规则已配置完成。
打开nod-red编辑器,有的HA可能是配置在左侧航菜单中,如下图志示,点击即可进入

有的是没有配置node-red到左侧导航菜单的,这种情况下,可以点击"设置-加载项"进入加载项页面

找到Node-RED加载项,点击进入


进入界面如下:

点击右上角的"菜单"按钮,再点导入。

在此处贴入工作流代码,注意:要选择导入到新流程

工作流代码如下
[
{
"id": "1407d4531e19a951",
"type": "tab",
"label": "透析中心环境温度数据转发",
"disabled": false,
"info": "从HomeAssistant获取温度传感器数据并发布到公司MQTT服务器"
},
{
"id": "97e254f4a87ddde9",
"type": "mqtt in",
"z": "1407d4531e19a951",
"name": "订阅HA温度传感器",
"topic": "homeassistant/sensor/+/state",
"qos": "0",
"datatype": "auto",
"broker": "mqtt-ha-broker",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 150,
"y": 100,
"wires": [
[
"44d729e67618e4f2"
]
]
},
{
"id": "44d729e67618e4f2",
"type": "function",
"z": "1407d4531e19a951",
"name": "处理温度数据",
"func": "// 从全局变量获取共享配置\nconst nameSpace = global.get(\"nameSpace\") || \"Environment\";\nconst clientCode = global.get(\"clientCode\") || \"Data-It_XzOffice\";\nconst targetDeviceId = global.get(\"deviceId\") || \"sensor.miaomiaoc_cn_blt_3_11a1sbr5k5o01_t2_temperature_p_2_1\";\n\n// 从topic中提取当前设备ID\nconst topicParts = msg.topic.split('/');\nconst currentDeviceId = topicParts.length >= 3 ? topicParts[2] : \"\";\n\n// 只处理目标设备的消息\nif (currentDeviceId !== targetDeviceId) {\n node.log(\"忽略设备消息: \" + currentDeviceId + \" (目标设备: \" + targetDeviceId + \")\");\n return null;\n}\n\n// 生成唯一的消息ID\nconst messageId = \"temp_\" + Date.now() + \"_\" + Math.floor(Math.random() * 1000);\nconst timestamp = Date.now();\nconst deviceType = \"sensor\";\n\n// 解析温度值\nlet temperature = parseFloat(msg.payload);\nif (isNaN(temperature)) {\n node.warn(\"接收到无效的温度值: \" + msg.payload);\n return null;\n}\n\n// 按照胜透物联网通信协议格式化数据\nconst protocolMessage = {\n \"messageId\": messageId,\n \"timestamp\": timestamp,\n \"clientCode\": clientCode,\n \"deviceId\": targetDeviceId,\n \"deviceType\": deviceType,\n \"version\": \"1.0\",\n \"data\": {\n \"properties\": {\n \"temperature\": {\n \"value\": temperature,\n \"unit\": \"°C\",\n \"quality\": \"good\",\n \"timestamp\": timestamp\n }\n }\n }\n};\n\n// 设置输出消息\nmsg.payload = JSON.stringify(protocolMessage);\nmsg.topic = `${nameSpace}/sensor/${clientCode}/${targetDeviceId}/properties`;\nmsg.qos = 0;\n\nnode.log(\"温度数据已处理: \" + temperature + \"°C (设备: \" + targetDeviceId + \")\");\n\nreturn msg;",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 420,
"y": 100,
"wires": [
[
"573842ea77192dbb",
"4c630c164e08dc2c"
]
]
},
{
"id": "573842ea77192dbb",
"type": "mqtt out",
"z": "1407d4531e19a951",
"name": "发布到公司MQTT",
"topic": "",
"qos": "",
"retain": "",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "mqtt-company-broker",
"x": 990,
"y": 80,
"wires": []
},
{
"id": "4c630c164e08dc2c",
"type": "debug",
"z": "1407d4531e19a951",
"name": "调试输出",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 1040,
"y": 360,
"wires": []
},
{
"id": "495c392574ee1bf4",
"type": "inject",
"z": "1407d4531e19a951",
"name": "发布设备物模型",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "60",
"crontab": "",
"once": true,
"onceDelay": "5",
"topic": "shengtou/sensor/TH001_HA/model",
"payload": "",
"payloadType": "date",
"x": 170,
"y": 180,
"wires": [
[
"3aea3ce2deb4ea99"
]
]
},
{
"id": "3aea3ce2deb4ea99",
"type": "function",
"z": "1407d4531e19a951",
"name": "生成物模型数据",
"func": "const messageId = \"mdl_\" + Date.now();\nconst timestamp = Date.now();\n// 从全局变量获取共享配置\nconst nameSpace = global.get(\"nameSpace\") || \"Environment\";\nconst clientCode = global.get(\"clientCode\") || \"Data-It_XzOffice\";\nconst deviceId = global.get(\"deviceId\") || \"sensor.miaomiaoc_cn_blt_3_11a1sbr5k5o01_t2_temperature_p_2_1\";\nconst deviceType = \"sensor\";\n\n// 按照胜透物联网通信协议生成物模型定义\nconst modelMessage = {\n \"messageId\": messageId,\n \"timestamp\": timestamp,\n \"clientCode\": clientCode,\n \"deviceId\": deviceId,\n \"deviceType\": deviceType,\n \"version\": \"1.0\",\n \"data\": {\n \"model\": {\n \"deviceInfo\": {\n \"manufacturer\": \"小米\",\n \"model\": \"MIAOMIAOC_CN_BLT_3_11A1SBR5K5O01_T2\",\n \"version\": \"1.0.0\",\n \"description\": \"米家温湿度传感器(通过HomeAssistant集成)\"\n },\n \"properties\": {\n \"temperature\": {\n \"dataType\": \"float\",\n \"unit\": \"°C\",\n \"range\": {\n \"min\": -40,\n \"max\": 85\n },\n \"precision\": 1,\n \"description\": \"环境温度\"\n }\n },\n \"events\": {\n \"startup\": {\n \"eventType\": \"info\",\n \"description\": \"设备启动事件\"\n }\n },\n \"alarms\": {\n \"TEMP_HIGH\": {\n \"alarmType\": \"threshold_exceeded\",\n \"description\": \"温度过高报警\",\n \"defaultThreshold\": 35.0\n },\n \"TEMP_LOW\": {\n \"alarmType\": \"threshold_exceeded\",\n \"description\": \"温度过低报警\",\n \"defaultThreshold\": 0.0\n }\n }\n }\n }\n};\n\n// 设置MQTT发布主题\nmsg.topic = `${nameSpace}/sensor/${clientCode}/${deviceId}/model`;\nmsg.payload = JSON.stringify(modelMessage);\nmsg.qos = 1;\n\nnode.log(\"设备物模型数据已生成,发布到主题: \" + msg.topic);\n\nreturn msg;",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 400,
"y": 160,
"wires": [
[
"573842ea77192dbb",
"4c630c164e08dc2c"
]
]
},
{
"id": "70e1e283448c941e",
"type": "inject",
"z": "1407d4531e19a951",
"name": "设备状态心跳",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "120",
"crontab": "",
"once": true,
"onceDelay": "10",
"topic": "shengtou/sensor/TH001_HA/status",
"payload": "",
"payloadType": "date",
"x": 160,
"y": 240,
"wires": [
[
"ae74b6d386748045"
]
]
},
{
"id": "ae74b6d386748045",
"type": "function",
"z": "1407d4531e19a951",
"name": "生成状态数据",
"func": "const messageId = \"sts_\" + Date.now();\nconst timestamp = Date.now();\n// 从全局变量获取共享配置\nconst nameSpace = global.get(\"nameSpace\") || \"Environment\";\nconst clientCode = global.get(\"clientCode\") || \"Data-It_XzOffice\";\nconst deviceId = global.get(\"deviceId\") || \"sensor.miaomiaoc_cn_blt_3_11a1sbr5k5o01_t2_temperature_p_2_1\";\nconst deviceType = \"sensor\";\n\n// 计算设备运行时间(从第一次启动开始)\nif (!context.get(\"startTime\")) {\n context.set(\"startTime\", timestamp);\n}\nconst startTime = context.get(\"startTime\");\nconst uptime = timestamp - startTime;\n\n// 按照胜透物联网通信协议生成状态数据\nconst statusMessage = {\n \"messageId\": messageId,\n \"timestamp\": timestamp,\n \"clientCode\": clientCode,\n \"deviceId\": deviceId,\n \"deviceType\": deviceType,\n \"version\": \"1.0\",\n \"data\": {\n \"status\": {\n \"online\": true,\n \"lastHeartbeat\": timestamp,\n \"uptime\": uptime\n }\n }\n};\n\n// 设置MQTT发布主题\nmsg.topic = `${nameSpace}/sensor/${clientCode}/${deviceId}/status`;\nmsg.payload = JSON.stringify(statusMessage);\nmsg.qos = 0;\n\nnode.log(\"设备状态心跳已发送,发布到主题: \" + msg.topic);\n\nreturn msg;",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 400,
"y": 240,
"wires": [
[
"573842ea77192dbb",
"4c630c164e08dc2c"
]
]
},
{
"id": "7f9acf10d0c6085d",
"type": "inject",
"z": "1407d4531e19a951",
"name": "初始化全局配置",
"props": [
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": "1",
"topic": "",
"payload": "",
"payloadType": "date",
"x": 150,
"y": 40,
"wires": [
[
"6f6b825dfc5e9512"
]
]
},
{
"id": "6f6b825dfc5e9512",
"type": "function",
"z": "1407d4531e19a951",
"name": "设置全局配置",
"func": "// 设置全局共享常量\nglobal.set(\"nameSpace\", \"Environment\");\nglobal.set(\"clientCode\", \"Data-It_XzOffice\");\nglobal.set(\"deviceId\", \"sensor.miaomiaoc_cn_blt_3_11a1sbr5k5o01_t2_temperature_p_2_1\");\n\nnode.log(\"全局配置已设置: nameSpace=\" + global.get(\"nameSpace\") + \", clientCode=\" + global.get(\"clientCode\") + \", deviceId=\" + global.get(\"deviceId\"));\n\nreturn msg;",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 360,
"y": 40,
"wires": [
[
"794c422d39898a7f"
]
]
},
{
"id": "794c422d39898a7f",
"type": "function",
"z": "1407d4531e19a951",
"name": "更新MQTT订阅Topic",
"func": "// 从全局变量生成HomeAssistant MQTT订阅Topic\nconst deviceId = global.get(\"deviceId\") || \"sensor.miaomiaoc_cn_blt_3_11a1sbr5k5o01_t2_temperature_p_2_1\";\nconst haTopic = `homeassistant/sensor/${deviceId}/state`;\n\n// 将Topic保存到全局变量供其他地方使用\nglobal.set(\"haSubscribeTopic\", haTopic);\n\nnode.log(\"HomeAssistant订阅Topic已更新: \" + haTopic);\nnode.log(\"注意:如需更改MQTT In节点的订阅Topic,请手动修改为: \" + haTopic);\n\nreturn msg;",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 590,
"y": 40,
"wires": [
[]
]
},
{
"id": "3bf854e9bd3e6937",
"type": "inject",
"z": "1407d4531e19a951",
"name": "启动事件",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": "15",
"topic": "shengtou/sensor/TH001_HA/events",
"payload": "",
"payloadType": "date",
"x": 160,
"y": 340,
"wires": [
[
"26f6196b2d6fba29"
]
]
},
{
"id": "26f6196b2d6fba29",
"type": "function",
"z": "1407d4531e19a951",
"name": "生成启动事件",
"func": "const messageId = \"evt_startup_\" + Date.now();\nconst timestamp = Date.now();\n// 从全局变量获取共享配置\nconst nameSpace = global.get(\"nameSpace\") || \"Environment\";\nconst clientCode = global.get(\"clientCode\") || \"Data-It_XzOffice\";\nconst deviceId = global.get(\"deviceId\") || \"sensor.miaomiaoc_cn_blt_3_11a1sbr5k5o01_t2_temperature_p_2_1\";\nconst deviceType = \"sensor\";\n\n// 按照胜透物联网通信协议生成事件数据\nconst eventMessage = {\n \"messageId\": messageId,\n \"timestamp\": timestamp,\n \"clientCode\": clientCode,\n \"deviceId\": deviceId,\n \"deviceType\": deviceType,\n \"version\": \"1.0\",\n \"data\": {\n \"events\": [\n {\n \"eventType\": \"startup\",\n \"eventLevel\": \"info\",\n \"eventCode\": \"EVT_001\",\n \"description\": \"HomeAssistant温度传感器代理设备启动完成\",\n \"timestamp\": timestamp\n }\n ]\n }\n};\n\n// 设置MQTT发布主题\nmsg.topic = `${nameSpace}/sensor/${clientCode}/${deviceId}/events`;\nmsg.payload = JSON.stringify(eventMessage);\nmsg.qos = 1;\n\nnode.log(\"设备启动事件已生成,发布到主题: \" + msg.topic);\n\nreturn msg;",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 380,
"y": 320,
"wires": [
[
"573842ea77192dbb",
"4c630c164e08dc2c"
]
]
},
{
"id": "mqtt-ha-broker",
"type": "mqtt-broker",
"name": "HomeAssistant MQTT",
"broker": "192.168.50.83",
"port": "1883",
"clientid": "",
"autoConnect": true,
"usetls": false,
"protocolVersion": "4",
"keepalive": "60",
"cleansession": true,
"autoUnsubscribe": true,
"birthTopic": "",
"birthQos": "0",
"birthPayload": "",
"birthMsg": {},
"closeTopic": "",
"closeQos": "0",
"closePayload": "",
"closeMsg": {},
"willTopic": "",
"willQos": "0",
"willPayload": "",
"willMsg": {},
"sessionExpiry": ""
},
{
"id": "mqtt-company-broker",
"type": "mqtt-broker",
"name": "公司MQTT服务器",
"broker": "mqtt-test.ihemodialysis.com",
"port": "62183",
"clientid": "",
"usetls": false,
"protocolVersion": "4",
"keepalive": "60",
"cleansession": true,
"birthTopic": "",
"birthQos": "0",
"birthPayload": "",
"birthMsg": {},
"closeTopic": "",
"closeQos": "0",
"closePayload": "",
"closeMsg": {},
"willTopic": "shengtou/sensor/TH001_HA/status",
"willQos": "0",
"willPayload": "{\"messageId\":\"sts_offline\",\"timestamp\":0,\"deviceId\":\"TH001_HA\",\"deviceType\":\"sensor\",\"version\":\"1.0\",\"data\":{\"status\":{\"online\":false,\"lastHeartbeat\":0,\"uptime\":0}}}",
"willMsg": {},
"sessionExpiry": ""
}
]
当然,你也可以从工作流文件导入新新工作流。
点击上述链接后,下载文件,并解压,得到一个名为flows.json的文件。

点击导入节点文件,


部署成功后,会出现如下图所示的工作流

此时,工作流已创完成.
工作流中有两个MQTT节点,分别是Home Assistant的MQTT Broker和公司MQTT服务器的Broker。这两个节点的配置需要根据实际情况进行调整。
首先,要先配置Home Assistant的MQTT Broker节点,确保其连接信息正确无误。
在我们没有配置mqtt in 的连接信息时,我们发现这个节点一直处理连接中

双击该节点,进入配置界面

点击编辑图标

在编辑mqtt-broker节点的界面中的连接参数选项卡中,输入正确的服务端与端口号

如果MQTT有用户名和密码,请在认证选项卡中输入正确的用户名和密码后,然后点更新

然后,再点击完成

最后点击部署

部署完成后,我们可以看到,此节点会变为已联接

对于"发布到公司MQTT"节点,我们需要配置连接到公司MQTT服务器的Broker。也时同样的操作方法,双击



然后,更新,完成,部署即可。
查找HomeAssistant的Mqtt配置信息
对于HomeAssistant我们一般都是提前部署了内置的MQTT Broker,在不知端口与密码的情况下,我样可以在HomeAssistant中去查找
进入设置加载项

找到Mosquitto broker这个选项卡,点击进入

点击配置选项卡



在这里可以看到MQTT的端口号与用户名密码等信息,及下面的mqtt开放的端口信息,ip地址,就是ha主机所在的Ip地址。以上信息,用来配置工作流的mqtt in的参数。
公司mqtt服务端口信息
这个参数,请向公司管理员获取,或者在公司MQTT服务器的配置文件中查看。
双击工作流的节点"设置全局配置",打开编辑function节点

对如下三行,进行更改
// 设置全局共享常量
global.set("nameSpace", "Environment"); //命名空间,默认为:Environment,如果有需要,以联系相关工程师确认后,更改.
global.set("clientCode", "Data-It_XzOffice");// 客户端代码,默认为:Data-It_XzOffice,一定要改为中心对就的ClientCode,
global.set("deviceId", "sensor.miaomiaoc_cn_blt_3_11a1sbr5k5o01_t2_temperature_p_2_1");//一定要改为之前我们定的传感器实体ID
如果不确定,请联系相关工程师确认。

然后,点击,完成,部署

然后,下一步,非常重要,一定要执行

这一步,非常重要,必须执行,否则工作流没有把全局变量写入工作流,会导致发布数据不正确。
然后,我样就可以用在debug的日志中看到我们发布的节点数据了,

此图,可以观察到mqtt发布到公司的数据,clientCode,deviceid是否正常了。
我们可以使用第三方工具来查看公司mqtt服务收到的数据是否正常如下图

这里我推荐使用工具MQTTX
下载地址为:https://mqttx.app/downloads

至此,透析中心HA环境温度数据发送到胜透的工作流配置完成。