找回密码
 立即注册

微信扫码登录

搜索
查看: 35|回复: 2

[求助] 求救sos:mqtt识别不了nodered实体

[复制链接]

1

主题

0

回帖

16

积分

新手上路

积分
16
金钱
15
HASS币
0
发表于 5 小时前 | 显示全部楼层 |阅读模式
悬赏10金钱未解决
求救sos

我的HAOS是部署在飞牛虚拟机上的,现在Node-Red通过Glances 服务获取到了飞牛主机的CPU,内存等信息,然后通过MQTT out传给了HA的MQTT也能监听到消息,但无论如何都识别不了实体,deepseek和豆包都用了,请大佬帮忙看一下哪里错了吗。



NodeRED流程截图
1755964344080.png
{"name":"飞牛NAS CPU使用率","state_topic":"fnos/monitor","value_template":"{{ value_json.cpu_usage }}","unit_of_measurement":"%","device_class":"percentage","state_class":"measurement","unique_id":"fnos_cpu_usage","device":{"identifiers":["fnos_monitor"],"name":"飞牛NAS监控","model":"自定义监控","manufacturer":"Node-RED"}}

MQTT监听
1755964534894.png
{"name":"飞牛NAS CPU使用率","state_topic":"fnos/monitor","value_template":"{{ value_json.cpu_usage }}","unit_of_measurement":"%","device_class":"percentage","state_class":"measurement","unique_id":"fnos_cpu_usage","device":{"identifiers":["fnos_monitor"],"name":"飞牛NAS监控","model":"自定义监控","manufacturer":"Node-RED"}}

mqtt out截图
1755964596038.png
function函数代码

// 获取输入数据
const data = msg.payload;

// 精确匹配物理网卡(排除虚拟接口)
const getPhysicalNic = (baseName) => {
    return data.network?.find(nic =>
        nic.interface_name === baseName &&
        nic.is_up === true &&
        nic.speed > 0  // 确保是物理网卡
    );
};

const nic1 = getPhysicalNic("enp1s0"); // 爱快软路由网卡
const nic2 = getPhysicalNic("enp4s0"); // 飞牛NAS网卡

// 字节转MB换算函数
const bytesToMB = (bytes) => bytes ? (bytes / 1048576).toFixed(2) : 0;

// 原始数据处理
const payloadData = {
    // 基础监控指标
    cpu_usage: data.cpu?.total || 0,
    mem_usage: data.mem ? (data.mem.used / data.mem.total * 100).toFixed(1) : 0,
    disk_usage: data.fs?.[0] ? (data.fs[0].used / data.fs[0].size * 100).toFixed(1) : 0,

    // 爱快软路由网卡数据(使用累计值)
    network_up_ik: bytesToMB(nic1?.cumulative_tx),
    network_down_ik: bytesToMB(nic1?.cumulative_rx),
    nic_name_ik: nic1?.interface_name || "未连接",
    nic_speed_ik: nic1?.speed ? `${(nic1.speed / 1000000).toFixed(0)} Mbps` : "未知",

    // 飞牛NAS网卡数据(使用累计值)
    network_up_fn: bytesToMB(nic2?.cumulative_tx),
    network_down_fn: bytesToMB(nic2?.cumulative_rx),
    nic_name_fn: nic2?.interface_name || "未连接",
    nic_speed_fn: nic2?.speed ? `${(nic2.speed / 1000000).toFixed(0)} Mbps` : "未知",

    timestamp: new Date().toISOString()
};

// MQTT自动发现配置(核心部分)
const discoveryPrefix = "homeassistant"; // HA默认发现前缀
const baseTopic = "fnos/monitor"; // 你的数据发送主题(可根据实际修改)

// 所有需要生成的实体配置
const sensors = [
    // CPU使用率
    {
        object_id: "cpu_usage",
        name: "飞牛NAS CPU使用率",
        value_key: "cpu_usage",
        unit: "%",
        device_class: "percentage"
    },
    // 内存使用率
    {
        object_id: "mem_usage",
        name: "飞牛NAS 内存使用率",
        value_key: "mem_usage",
        unit: "%",
        device_class: "percentage"
    },
    // 磁盘使用率
    {
        object_id: "disk_usage",
        name: "飞牛NAS 磁盘使用率",
        value_key: "disk_usage",
        unit: "%",
        device_class: "percentage"
    },
    // 爱快上行流量
    {
        object_id: "network_up_ik",
        name: "爱快软路由 上行流量",
        value_key: "network_up_ik",
        unit: "MB",
        device_class: "data_size"
    },
    // 爱快下行流量
    {
        object_id: "network_down_ik",
        name: "爱快软路由 下行流量",
        value_key: "network_down_ik",
        unit: "MB",
        device_class: "data_size"
    },
    // 爱快网卡速度
    {
        object_id: "nic_speed_ik",
        name: "爱快软路由 网卡速度",
        value_key: "nic_speed_ik",
        unit: ""
    },
    // 飞牛上行流量
    {
        object_id: "network_up_fn",
        name: "飞牛NAS 上行流量",
        value_key: "network_up_fn",
        unit: "MB",
        device_class: "data_size"
    },
    // 飞牛下行流量
    {
        object_id: "network_down_fn",
        name: "飞牛NAS 下行流量",
        value_key: "network_down_fn",
        unit: "MB",
        device_class: "data_size"
    },
    // 飞牛网卡速度
    {
        object_id: "nic_speed_fn",
        name: "飞牛NAS 网卡速度",
        value_key: "nic_speed_fn",
        unit: ""
    }
];

// 生成自动发现消息
const discoveryMessages = sensors.map(sensor => {
    return {
        topic: `${discoveryPrefix}/sensor/fnos_${sensor.object_id}/config`,
        payload: {
            name: sensor.name,
            state_topic: baseTopic,
            value_template: `{{ value_json.${sensor.value_key} }}`,
            unit_of_measurement: sensor.unit,
            device_class: sensor.device_class || null,
            state_class: "measurement",
            unique_id: `fnos_${sensor.object_id}`,
            device: {
                "identifiers": ["fnos_monitor"],
                "name": "飞牛NAS监控",
                "model": "自定义监控",
                "manufacturer": "Node-RED"
            }
        },
        retain: true // 保留配置,HA重启后仍有效
    };
});

// 数据消息(发送实际监控值)
const dataMessage = {
    topic: baseTopic,
    payload: payloadData,
    retain: false
};

// 输出所有消息(配置消息 + 数据消息)
return [...discoveryMessages, dataMessage];





回复

使用道具 举报

28

主题

202

回帖

1702

积分

论坛UI达人

积分
1702
金钱
1467
HASS币
50
发表于 4 小时前 | 显示全部楼层
mqtt是非用不可吗,nodered安装node-red-contrib-home-assistant-websocket插件,ha安装Node-RED Companion集成,两者就能直接通讯,使用这些节点就能直接给ha创建自己定义的实体
image.png
回复

使用道具 举报

11

主题

255

回帖

2541

积分

金牌会员

积分
2541
金钱
2270
HASS币
20
发表于 3 小时前 | 显示全部楼层
本帖最后由 hungheo 于 2025-8-24 01:50 编辑

function输出的不是json格式字符串,homeassistant要解析只能是son格式字符串
我的给你参考一下

const countMaps = {
    'keting': { name:'客厅开灯数量', count: 0 },
    'zhuwo': { name:'主卧开灯数量', count: 0 },
    'daciwo': { name:'大次卧开灯数量', count: 0 },
    'xiaociwo': { name:'小次卧开灯数量', count: 0 },
    'zhuwei': { name:'主卫开灯数量', count: 0 },
    'kewei': { name:'客卫开灯数量', count: 0 },
    'chufang': { name:'厨房开灯数量', count: 0 },
    'all': { name:'所有开灯数量', count: 0 }
};

// 配置基础设备信息
const device = {
    identifiers: "devices_count",
    name: "设备数量统计",
    manufacturer: "counts",
    model: "devices",
    sw_version: "v1.0"
};
//const countsMap = msg.payload;

const baseTopic = "homeassistant/sensor";
const stateBaseTopic = "counts/lights";

if(msg.topic == "state"){
    const data = msg.payload;
    // 更新 state 值
    for (const key in data) {
        if (countMaps.hasOwnProperty(key)) {
            countMaps[key].count = data[key]; 
        }
    }
    msg = {
        topic: stateBaseTopic,
        payload: countMaps,
        retain: true,
        qos: 1
    }
    return msg
}else{
    const messages = [];
    //遍历 生成初始化配置
    Object.keys(countMaps).forEach((key) => {
        const ids = countMaps[key];
        messages.push({
            topic: `${baseTopic}/${device.identifiers}/${key}/config`,
            payload: JSON.stringify({
                name: ids.name,
                state_topic: `${stateBaseTopic}`, 
                value_template: `{{ value_json.${key}.count }}`,
                unique_id: `${device.identifiers}_light_${key}`,
                object_id: `${device.identifiers}_light_${key}`,
                unit_of_measurement: "盏",
                device: device,
                qos: 1,
                retain: true
            })
        });
    });
    return [messages];
}

自动发现部分payload里面所有的内容通过JSON.stringify转换成son格式字符串就应该可以了
我的function节点输出的格式
屏幕截图 2025-08-24 013745.png




回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Hassbian ( 晋ICP备17001384号-1 )

GMT+8, 2025-8-24 05:20 , Processed in 0.050707 second(s), 8 queries , MemCached On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表