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