『瀚思彼岸』» 智能家居技术论坛

 找回密码
 立即注册
查看: 38756|回复: 64

[修仙教程] 我是来填坑的@网络电表制作攻略(MQTT)

  [复制链接]

15

主题

192

帖子

2057

积分

论坛技术达人

积分
2057
金钱
1845
HASS币
0

卓越贡献

发表于 2017-11-8 15:40:03 | 显示全部楼层 |阅读模式
本帖最后由 syjjx 于 2017-11-9 12:45 编辑

最开始之前要说明下,这不是一个比较简单的教程,需要一定的动手能力,制作过程中涉及到强电,也有一定的危险性,帖子所表述的内容有限,如果有人感兴趣,可以在论坛的QQ群中找我,我们可以一起探讨下。


之前发过一个帖子,是关于一个实时的网络电表系统,好像有些人还是蛮有兴趣的,我就整理下怎么制作和接入HA,由于原先这套系统是采集数据到我自己编写的web服务器上,采用的是websockets的协议,考虑到HA上MQTT使用起来比较方便,所有我就在esp8266上用lua重写了采集部分的代码,完全是业余水平,代码写的不好请嘴下留情。
下面开始上干货

1、先说下几个关键部件的连接顺序  esp8266-01>>>485转ttl模块>>>JSY-109电量测量系统

图片中左上角的为485转ttl模块,左下角为esp8266-01,中间的为jsy-109,右边的为220V装3V的供电系统
0049ef5c103853438156305b9a13b07ecb808896.jpg


2、HA上MQTT的准备工作,我们需要在configuration.yaml中添加配置,用户名和密码根据自己的实际情况修改


mqtt:
  broker: 127.0.0.1
  port: 1883
  client_id: home-assistant-1
  keepalive: 60
  username: 你的用户
  password: 你的密码
  discovery: true


3、物理硬件的制作 nodemcu-1.5.4.1-final-11-modules-2017-11-08-04-13-32-float.bin (465.24 KB, 下载次数: 198)


esp8266需要刷入nodemcu固件,附件中我提供一下我所使用的

我们从强电部分开始入手,首先我们火线与 jsy-109和220V转3.3v供电模块的输入脚火线相连,零线同理。之后我们就可以在供电模块的输出脚上,得到3.3V的输出,分别连接ttl转485模块和 esp8266-01的正负极,为这两个设备供电
最后我们需要把ttl装485模块上的 485信号一点与 jsy-109的485输出相连,ttl上的tx、rx 与esp8266-01上的 rx、tx互联
硬件部分的连接就完成了

4、esp8266-01上采集代码,贴上esp8266-01上的全部代码,添加了大部分注释

first_str=""  --定义一个空str,用于后面拼接和提取完整的数据
sendtime=tmr.time() --获取esp8266的运行时间,用于设置数据发送频率
watts=0 --定义一个默认的watts值,以便在功率大范围变化时可以灵敏反应
m = mqtt.Client("clientid", 120, "sammy", "19861018")  --创建一个MQTT客户端。
print("set up wifi mode")
wifi.setmode(wifi.STATION)  --wifi连接部分
wifi.sta.config("Tigermed-JX","Tg987123") --wifi连接部分
wifi.sta.connect() --wifi连接部分
wifi.sta.autoconnect(1) --wifi连接部分
wifi_connetion=0 --wifi连接部分



m:on("offline", function(client)  --注册 mqtt的 离线事件
print("offine")
tmr.stop(2) --当MQTT丢失连接之后,两个获取数据的循环都停止
tmr.stop(4) --当MQTT丢失连接之后,两个获取数据的循环都停止
handle_mqtt_error() --开始重新连接
uart.on("data") --调试 用
uart.setup(0,115200,8,0,1) --调试 用
end)


tmr.alarm(1, 1000, 1, function()   --创建一个循环,每秒执行一次,用于判断wifi连接是否成功
    if (wifi.sta.getip() == nil) and (wifi_connetion < 200000000) then 
        print("Trying Connect to Router, Waiting...")
        wifi_connetion = wifi_connetion + 1 
    else
        if (wifi_connetion < 200000000) then --当wifi.sta.getip()不为空的时候,并且尝试连接的次数小于设定值
            tmr.stop(1)  --停止尝试连接wifi的循环
            do_mqtt_connect()  --开始尝试连接mqtt

        else 
            print("Conected to Router Timeout")  --调试用,这里我应该写也,实际使用应该写 restart esp8266        
        end
    end
end)

function aready_mqtt()  --当mqtt成功连接后,回调的函数
  uart.setup(0,4800,8,0,1)  --设置窗口的速率
  tmr.alarm(4,2000,1,function() --定义一个循环,防止发送数据的循环停止
  if tmr.state(2) ~=true then
    tmr.start(2)
   end
  end)
  tmr.alarm(2,1000,1,function() uart.write(0,uart.write(0, 0x01, 0x03, 0x00, 0x48, 0x00, 0x06, 0x45, 0xDE)) tmr.stop(2) end) --通过串口发送查询数据给jsy-mk-109,并在收到回复数据前停止发送下一条
  uart.on("data",17,  --收到数据长度为17后,回调下面的函数
    function(data)
      tmr.stop(4)
      crc16a(hex2str(data))  --这里主要是进行数据的格式化,数据校验,数据发送
      tmr.start(4)
      tmr.start(2)        
  end, 0)
end

function handle_mqtt_error(client, reason)  --当mqtt尝试连接失败后,回调的函数,用于开始尝试连接MQTT
  tmr.alarm(6,5000,tmr.ALARM_SINGLE,do_mqtt_connect)
end

function do_mqtt_connect()  --尝试连接mqtt的函数,连接成功则执行aready_mqtt(),否则执行handle_mqtt_error()
  m:connect("192.168.199.151", 1883, 0,function(client) print("connected") aready_mqtt() tmr.stop(6) end,handle_mqtt_error())
end

function hex2str(hex) --数据的格式化,把16进制数据转化为字符串,这里还处理了数据的拼接与提取,保证数据的完整
 local str = ""
 for i = 1, string.len(hex) do
         local charcode = tonumber(string.byte(hex, i, i));
         str = str..string.format("%02X", charcode);
 end
 local send_str = first_str..str
 if string.len(send_str)>34 then
    local q,_=string.find(send_str, '01030C')
    send_str=string.sub(send_str, q,q+33)
    first_str=str
 else
    first_str=str
 end
 return send_str
end

function crc16a(str)  --在获取到经过拼接和截取的数据之后,进行CRC校验
 local hex = "";
 for i = 1, string.len(str) - 1, 2 do
     local doublebytestr = string.sub(str, i, i+1);
     local n = tonumber(doublebytestr, 16);
     if 0 == n then
       hex = hex .. '\00';
     else
       hex = hex .. string.format("%c", n);
     end
 end
crc=65535
 for i = 1, string.len(hex)-2 do
    
    
    crc=bit.bxor(crc,string.byte(hex, i, i))
    print(crc)
    for i=8,1,-1 do
    if bit.band(crc, 1)==1 then
    crc =bit.rshift(crc, 1)
    crc =bit.bxor(crc,40961)
    else
    crc=bit.rshift(crc, 1)
    end
    end
    
 end

crcstr=string.format("%#x",crc)
local ww=string.sub(str,31,34) --这是jsy-mk-109发回给我的crc校验码
local ee=string.sub(crcstr,3,4)..string.sub(crcstr,1,2) -- 这是通过前面数据计算出的crc校验码
if ww==string.upper(ee) then  --两个字符串进行比较,如果一致那么就可以将字符串提取转化为我们需要的数据了

   v =  tonumber(string.sub(str,7,10),16)/100
   a =  tonumber(string.sub(str,11,14),16)/1000
   w =  tonumber(string.sub(str,15,18),16)
   kwh = tonumber(string.sub(str,19,26),16)/3200
   ru='{"V":'..v..',"A":'..a..',"W":'..w..',"Kwh":'..kwh..'}'  --整理下格式为json,方便ha使用
       if tmr.time()-sendtime >10 or w-watts >1 or w-watts <-1 then --这里有2个判断,如果10秒内未发送任何数据,则强制发送条、如果功率变化值大于1W则发送
        m:publish("/power",ru,0,0, function(client) sendtime=tmr.time() watts=w end) -- 发送数据并将发送和时间和最后的功率保存起来方便下次判断
    else
        watts=w --如果10秒内功率无变化,则不通过mqtt发送数据,减少服务器开销
    end
end

end



5、HA上configuration.yaml 中sensor:的配置
sensor:
  - platform: mqtt
    state_topic: "/power"
    name: "Kwh"
    unit_of_measurement: "Kwh"
    value_template: '{{ value_json.Kwh }}'
  - platform: mqtt
    state_topic: "/power"
    name: "V"
    unit_of_measurement: "V"
    value_template: '{{ value_json.V }}'
  - platform: mqtt
    state_topic: "/power"
    name: "A"
    unit_of_measurement: "A"
    value_template: '{{ value_json.A }}'            
  - platform: mqtt
    state_topic: "/power"
    name: "W"
    unit_of_measurement: "W"
    value_template: '{{ value_json.W }}'  


最后上一张完成图
ff.png






评分

参与人数 4金钱 +65 收起 理由
wgqtx + 7 膜拜大神!
Roger + 20 666!明天就弄一个连到hass上!谢谢!.
lidicn + 20 谢谢分享!
+ 18 牛了,感谢楼主分享!

查看全部评分

回复

使用道具 举报

25

主题

687

帖子

3630

积分

论坛元老

Rank: 8Rank: 8

积分
3630
金钱
2937
HASS币
219

活跃会员

发表于 2017-11-8 15:53:47 | 显示全部楼层
看起来好nb
回复

使用道具 举报

123

主题

4664

帖子

1万

积分

管理员

囧死

Rank: 9Rank: 9Rank: 9

积分
16442
金钱
11693
HASS币
45
发表于 2017-11-8 16:29:13 | 显示全部楼层
厉害了,lua完全看不懂,不过这模块可以研究一下
回复

使用道具 举报

123

主题

4664

帖子

1万

积分

管理员

囧死

Rank: 9Rank: 9Rank: 9

积分
16442
金钱
11693
HASS币
45
发表于 2017-11-8 16:38:28 | 显示全部楼层
楼主,这模块貌似某宝上买不到啊?哪里能买
回复

使用道具 举报

15

主题

192

帖子

2057

积分

论坛技术达人

积分
2057
金钱
1845
HASS币
0

卓越贡献

 楼主| 发表于 2017-11-8 17:57:52 | 显示全部楼层
Jones 发表于 2017-11-8 16:38
楼主,这模块貌似某宝上买不到啊?哪里能买

淘宝搜索 JSY-MK 就可以找到了
回复

使用道具 举报

123

主题

4664

帖子

1万

积分

管理员

囧死

Rank: 9Rank: 9Rank: 9

积分
16442
金钱
11693
HASS币
45
发表于 2017-11-8 18:03:29 | 显示全部楼层
syjjx 发表于 2017-11-8 17:57
淘宝搜索 JSY-MK 就可以找到了

果然,但这个是485还要转一下ttl,不过好处是有软清零功能。
回复

使用道具 举报

0

主题

86

帖子

1060

积分

金牌会员

Rank: 6Rank: 6

积分
1060
金钱
974
HASS币
0
发表于 2017-11-8 18:15:04 | 显示全部楼层
牛,太帅了
回复

使用道具 举报

15

主题

192

帖子

2057

积分

论坛技术达人

积分
2057
金钱
1845
HASS币
0

卓越贡献

 楼主| 发表于 2017-11-8 18:15:04 | 显示全部楼层
本帖最后由 syjjx 于 2017-11-8 18:16 编辑
Jones 发表于 2017-11-8 18:03
果然,但这个是485还要转一下ttl,不过好处是有软清零功能。

统计的数据也还算准确,不过我使用的485转ttl模块应该质量有问题,误码率在1%左右,还好我在esp8266上用lua实现了crc的校验,错误的数据直接丢弃了,否则HA中偶尔谁出现几万伏的电压
回复

使用道具 举报

123

主题

4664

帖子

1万

积分

管理员

囧死

Rank: 9Rank: 9Rank: 9

积分
16442
金钱
11693
HASS币
45
发表于 2017-11-8 18:26:31 | 显示全部楼层
syjjx 发表于 2017-11-8 18:15
统计的数据也还算准确,不过我使用的485转ttl模块应该质量有问题,误码率在1%左右,还好我在esp8266上用lu ...

这个很有必要,厉害了大神!
回复

使用道具 举报

5

主题

356

帖子

1411

积分

金牌会员

Rank: 6Rank: 6

积分
1411
金钱
1055
HASS币
0
发表于 2017-11-8 19:09:58 | 显示全部楼层
看起来好牛B啊!!
回复

使用道具 举报

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

本版积分规则

Archiver|手机版|小黑屋|Hassbian

GMT+8, 2024-12-23 03:45 , Processed in 0.057591 second(s), 36 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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