乐趣区

将路由器温度通过MQTT协议加入Homeassistant及Homekit

前言

最近入手了一台斐讯 K3 路由器, 可是博通的芯片发热太严重, 想要随时了解路由器的温度, 于是自己动手实现了一组程序来将路由器温度通过 MQTT 加入 Homeassistant 及 Homekit.

准备

  1. 已经获取 root 权限的 K3 路由器
  2. 部署好 HomeAssistant 的内网服务器
  3. 部署好 Node.js 的内网服务器

前置知识

  • 基本的 Shell 编程
  • 基本的 HTTP 及 web 服务器知识
  • 基本的 MQTT 原理
  • 基础 JavaScript 编程

软件结构

最早的想法是直接在路由器上通过 Python 获取数据及通过 MQTT 发送至 HASS 服务器, 但是一个是 opkg 的源太慢了, 另一个是不想给路由器增加额外负担(万一加了测温软件温度涨几度就尴尬了), 最终采用了如下的软件结构

  • 路由器 —> Node.js Server —> Homeassistant

其中路由器到 Node.js 通过简单的 HTTP, 将温度数据通过 JSON 发送过来.
Node.js 通过 Express.js 实现 web 服务器用于接受路由器数据,mqtt 包实现 mqtt 通讯, 发送给 Homeassistant.

服务器端 Shell 程序

温度获取

首先第一步是获取路由器的温度数据:

  • CPU
cat /proc/dmu/temperature #CPU 温度
wl -i eth1 phy_tempsense  #2.4GHz 无线芯片温度
wl -i eth2 phy_tempsense  #5GHz 无线芯片温度

运行结果如下:

需要注意的是这里有一个坑,CPU 温度的文件中又不符合 UTF- 8 的字符, 直接用 curl 发的话会导致错误, 这里我们直接用 cut 进行处理, 这里暂时不考虑温度为或 3 位的情况(事实上不太可能发生)
cat /proc/dmu/temperature|cut -c19-20

同理我们对另外两项数据也进行处理

wl -i eth1 phy_tempsense|cut -c0-2
wl -i eth2 phy_tempsense|cut -c0-2

发送温度数据

HTTP 数据约定

GET Method
数据位于 data 参数下, 内容封装于 JSON 中, 格式如下
{“type”:”data”,”CPU”:61,”W24G”:51,”W5G”:65}

curl 实现

这里我们通过 curl 来发送数据, 这里是用 GET 方法, 为了以后增加控制信息方便, 数据包格式如下

{"type":"data","CPU":61,"W24G":51,"W5G":65}

经过 url encode 的结果为

%7B%22type%22:%22data%22,%22CPU%22:61,%22W24G%22:51,%22W5G%22:65%7D

我的 Node.js 服务器地址是 192.168.2.103, 端口3000 所以我们的 url 是

url="http://192.168.2.103:3000/?data=%7B%22type%22:%22data%22,%22CPU%22:$cpu,%22W24G%22:$w24,%22W5G%22:$w5%7D"

增加无限循环后的完整程序

#!/bin/sh

echo "run.."
while true
do
    cpu=$(cat /proc/dmu/temperature|cut -c19-20)
    w24=$(wl -i eth1 phy_tempsense|cut -c0-2)
    w5=$(wl -i eth2 phy_tempsense|cut -c0-2)
    url="http://192.168.2.103:3000/?data=%7B%22type%22:%22data%22,%22CPU%22:$cpu,%22W24G%22:$w24,%22W5G%22:$w5%7D"
    curl $url
    sleep 60    #设置 1 分钟的查询周期
    continue
done
echo "end.."

为了让程序不断运行, 推荐用 screen 来管理

Node 端程序

HTTP 服务器

这里我们基本使用了模版提供的功能, 由于我们这里只对数据进行透明传输, 所以 JSON 不需要反序列化

router.get('/', function(req, res, next) {
  var data = req.query.data
  res.render('index', { title: 'Express'});
});

MQTT 客户端

MQTT 数据约定

我们的数据分别放在三个 Topic 下

homeassistant/sensor/K3/CPU/state
homeassistant/sensor/K3/24G/state
homeassistant/sensor/K3/5G/state

MQTT 实现

Node 端程序为了方便, 我们直接通过 webstorm 创建 Express.js 程序模版, 我们的程序之间放在 router/index.js
记得用 npm 安装 mqtt 包
npm install mqtt

首先我们需要初始化 mqtt, 填入你的 MQTT 服务器账号密码(如果未设置匿名)

var mqtt = require('mqtt');
var client = mqtt.connect('mqtt://192.168.2.103',{
    username: 'homeassistant',
    password: 'password',
    clientId: 'K3Server'
}); // 连接到服务端
client.subscribe('presence');

注意,mqtt 中客户端 id 不可重复, 后来者将踢出原先的客户端

Node 完整程序

var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
  var data = req.query.data
    client.publish('homeassistant/sensor/K3/CPU/state', data, { qos: 0, retain: true});
    client.publish('homeassistant/sensor/K3/24G/state', data, { qos: 0, retain: true});
    client.publish('homeassistant/sensor/K3/5G/state', data, { qos: 0, retain: true});
  res.render('index', { title: 'Express'});
});

var mqtt = require('mqtt');
var client = mqtt.connect('mqtt://192.168.2.103',{
    username: 'homeassistant',
    password: 'hello',
    clientId: 'K3Server'
}); // 连接到服务端
client.subscribe('presence');

module.exports = router;

HomeAssistant 配置

我们这里使用 HA 自带的 MQTT 代理, 配置如下

# Sensors
sensor:
  - platform: mqtt
    name: 'K3_CPU'
    state_topic: 'homeassistant/sensor/K3/CPU/state'
    unit_of_measurement: '°C'
    value_template: '{{value_json.CPU}}'
  
  - platform: mqtt
    name: 'K3_24'
    state_topic: 'homeassistant/sensor/K3/24G/state'
    unit_of_measurement: '°C'
    value_template: '{{value_json.W24G}}'

  - platform: mqtt
    name: 'K3_5'
    state_topic: 'homeassistant/sensor/K3/5G/state'
    unit_of_measurement: '°C'
    value_template: '{{value_json.W5G}}'

效果

退出移动版