pic1

简介:

该设备是一款基于《ShineBlink 低代码核心模组》开发的《4G_Lora远程一氧化碳监测器》设备,可实现4G或Lora远程获取一氧化碳浓度值的功能。

功能:
  • 支持一氧化碳浓度采集
  • 支持 4G cat1 通讯
  • 支持 TCP + Json 接入云端
  • 支持 MQTT + Json 接入云端
  • 支持ShineBlink免开发云+小程序
  • 支持 Lora 通讯(可选)
  • 支持 uA 级低功耗休眠(可选)
  • 支持 GPS 定位及对时(可选)
应用领域:
  • 安防

  • 工业物联网

  • 智慧城市

开源资料地址:

FlexLua SmartSensor: 本仓库包含各种4G/Lora/WiFi/RS485 Modbus远程采集传感器数据的项目。

 

----------------------配置信息开始----------------------
--Part1: 系统配置
SysMode = 0 --0:4G_TCP, 1:4G_Mqtt, 2:4G_ShineBlinkCloud, 3:LoraModbusHex
SysGpsUse = "NO_GPS" --NO_GPS: 不带GPS功能, AUTO_AGPS:带GPS功能
SysWorkInterval = 10 --单位秒,系统采集传感器并发送数据的间隔周期。
--如果SysSleepEn=1,则SysWorkInterval周期间隔内会断电进入低功耗状态
SysSleepEn = 0 --0:不使用低功耗休眠 1:使用。该功能必须外挂BateryFriend才有用
--SysMyID可任意设定,用作设备的唯一标识,
--也可以用LIB_GetSysUniID()函数获取的芯片唯一ID,形如"761A6617E803F78402"
SysMyID = "Test01" -- SysMyID = LIB_GetSysUniID()

--Part2: Tcp参数(SysMode=0时才有用)
TcpServerIp = "122.114.122.174" --需要连接的服务器IP地址
TcpServerPort = 38556 --需要连接的服务器端口号

--Part3: MQTT参数(SysMode=1时才有用)
MqttServerAddr = "mqtt.ctwing.cn" --天翼云MQTT服务器ip地址或域名
MqttServerPort = 1883 --MQTT服务器端口号
MqttClientID = "15589964DTU01" --产品ID"15589964" + 设备编号"DTU01"
MqttUserName = "ShineBlink" --建议填写为用户自己的天翼物联网平台(AIoT)用户名
MqttPassword = "lMmugH2yURmY2uJqkNby-zQHGJ67ngjMAYR6kkGQmko" --采用的一型一密,特征串
MqttSubTopic = "device_control"--订阅用,用于接收服务器下发的数据
MqttPubTopic = "$device_send" --发布用,用于向服务器发送数据

--Part4: Lora参数(SysMode=3时才有用)
--Lora从机(slave)地址(范围:0-65535)
LoraAddr = 0x01 
--Lora对端中心点(center)地址(范围:0-65535)
LoraTargetAddr = 0x00
--Lora通信信道(范围:410-441MHz),相互通信的Lora节点必须在同一信道
LoraChannel = 433
--Lora无线速率(范围:0.3, 1.2, 4.8, 9.6, 19.2kpbs),速率越低通信质量越高
LoraBaudrate = "9.6kpbs"
--Lora发射功率(范围:11, 14, 17, 20dB),该值越大通信质量越高,但功耗会增加
LoraTxPwr = "20dB"

--Part5: Modbus RS485传感器配置
MbAddr = 0x01 --传感器出厂默认modbus地址, 1~250
MbBaudRate = "BAUDRATE_4800" --485总线的通信速率

--Part6: 传感器相关的配置(用户无需更改)
UI = "[1_CO_ppm_0_2000]" --UI必须和SensorStrFormat一致
SensorStrFormat = "\"CO\":%d"
SensorHeatTime = 30 --读取传感器前需等待传感器预热30秒
SensorStrInvalid = string.format(SensorStrFormat, 0) --默认非法值
----------------------配置信息结束----------------------

--定义通过 Modbus协议 485读取传感器数值函数
function GetSensorValue()
	local res,val,str
	
	print("Tx:"..LIB_HexTabToHexStr(LIB_MbRtuMasterSendTrans("03", MbAddr, 2, 1)))
	--下发读保持寄存器命令(设备地址=MbAddr,起始地址=2,读取的寄存器个数=1)
	--CO传感器寄存器地址0002H为:一氧化碳浓度值
	LIB_Uart1BlockSend(LIB_MbRtuMasterSendTrans("03", MbAddr, 2, 1))
	--等待0.2秒的应答时间
    LIB_DelayMs(200)
	--判断刚刚的命令是否收到应答数据
    recv_flag,recv_tab = LIB_Uart1Recv()
    if recv_flag == 1 then
		--解析从机发来的应答数据
		result,r = LIB_MbRtuMasterRecvTrans("03",recv_tab)
		print("Rx:"..LIB_HexTabToHexStr(recv_tab))
		if result > 0 then --获取传感器结果
			res = 1
			val = r[1] --单位:ppm
		else
			err_code = -128 - result 
			print(string.format("err=%d, data=%s",err_code, LIB_HexTabToHexStr(recv_tab)))
			res = 0
		end
	else
		print("Sensor unconnected!")
		res = 0
	end
	if res == 1 then
		str = string.format(SensorStrFormat, val)
	else
		str = SensorStrInvalid
	end
	return res,str
end

--定义通过Modbus协议向BatteryFriend获取电池电压的函数
function GetBatteryFriendVoltage()
	local res
	local vol
	
	print("Tx:"..LIB_HexTabToHexStr(LIB_MbRtuMasterSendTrans("03", 254, 1000, 1)))
	--下发读保持寄存器命令(设备地址=254,起始地址=1000,个数=1)
	--BatteryFriend的寄存器地址1000存放着电池电压,单位0.1v
	LIB_Uart1BlockSend(LIB_MbRtuMasterSendTrans("03", 254, 1000, 1))
	--等待0.2秒的应答时间
	LIB_DelayMs(200)
	--判断刚刚的命令是否收到应答数据
	recv_flag,recv_tab = LIB_Uart1Recv()
	if recv_flag == 1 then
	   --解析从机发来的应答数据
		result,r = LIB_MbRtuMasterRecvTrans("03",recv_tab)
		print("Rx:"..LIB_HexTabToHexStr(recv_tab))
		if result > 0 then --获取传感器结果
			res = 1
			vol = r[1]*0.1
		else--打印modbus应答错误码以及应答数据的Hex形式
			err_code = -128 - result 
			print(string.format("err=%d, data=%s",err_code, LIB_HexTabToHexStr(recv_tab)))
			res = 0
			vol = 0.0
		end
	else
		print("BatteryFriend unconnected!")
		res = 0
		vol = 0.0
	end
	return res,vol
end

--定义通过Modbus协议向BatteryFriend设置低功耗休眠时间,单位:秒
function SetBatteryFriendSleep(Ns)
	local res
	
	print("Tx:"..LIB_HexTabToHexStr(LIB_MbRtuMasterSendTrans("06", 254, 1001, Ns)))
	--下发写单个寄存器命令(设备地址=254,起始地址=1001,休眠时间=Ns秒)
	--BatteryFriend的寄存器地址1001用来设置休眠时间,单位1秒
	LIB_Uart1BlockSend(LIB_MbRtuMasterSendTrans("06", 254, 1001, Ns))
	--等待0.2秒的应答时间
	LIB_DelayMs(200)
	--判断刚刚的命令是否收到应答数据
	recv_flag,recv_tab = LIB_Uart1Recv()
	if recv_flag == 1 then
	   --解析从机发来的应答数据
		result,r = LIB_MbRtuMasterRecvTrans("06",recv_tab)
		print("Rx:"..LIB_HexTabToHexStr(recv_tab))
		if result > 0 then --获取传感器结果
			res = 1
		else--打印modbus应答错误码以及应答数据的Hex形式
			err_code = -128 - result 
			print(string.format("err=%d, data=%s",err_code, LIB_HexTabToHexStr(recv_tab)))
			res = 0
		end
	else
		print("BatteryFriend unconnected!")
		res = 0
	end
	return res
end

--定义10毫秒定时器的回调函数,函数名字必须是LIB_10msTimerCallback
function LIB_10msTimerCallback()
    timer_ms = timer_ms + 10
	timer1_ms = timer1_ms + 10
	timer_cnt = timer_cnt + 10
	LIB_GpioToggle("D11") --喂硬件看门狗
	--每隔0.5秒根据4G模状态更新LED灯颜色
	if timer_ms >= 500 then
		timer_ms = 0
		State,IMSI,ICCID,CSQ = LIB_Cat1StatusQuery()
		if State == "PowerOn" then --4G模块已上电但没发现sim卡
			RGB(0,0,0) --白
		elseif State == "SimOK" then --4G模块发现sim卡
			RGB(0,1,1) --红
		elseif State == "Attached" then --4G模块已连上附近的基站
			RGB(1,1,0) --蓝
		elseif State == "Connected" then --4G模块已和服务器连结
			RGB(1,0,1) --绿
		else --4G模块还未开始工作
			RGB(1,1,1) --全灭
		end
	end
end

--延时N秒函数
function DelayS(N)
	timer1_ms = 0
	target_ms = N*1000
	while timer1_ms <= target_ms do
		
	end
end

--RGB三色灯控制函数
function RGB(R,G,B)
	LIB_GpioWrite("D0",R)
	LIB_GpioWrite("D1",G)
	LIB_GpioWrite("D3",B)
end

---------------------系统初始化开始-----------------------
--LIB_SystemLogEnable() --需要看详细log.txt日志时才用
--配置D0,D1,D3为普通GPIO输出,控制LED_R,LED_G,LED_B
LIB_GpioOutputConfig("D0","STANDARD")
LIB_GpioOutputConfig("D1","STANDARD")
LIB_GpioOutputConfig("D3","STANDARD")
RGB(1,1,1) --一上电Led三色灯默认都不亮
--配置D11为普通输出,控制看门狗 
LIB_GpioOutputConfig("D11","STANDARD")
--配置Uart1开始工作,并且D8引脚作为自动切换485收发芯片的引脚
--当用LIB_Uart1BlockSend发送时,D8会自动变成低电平,发送完后会立刻变成高电平
LIB_Uart1Rs485Config(MbBaudRate,"D8")
if SysMode == 0 then --4G_TCP
	--配置4G模组需要连接的tcp服务器IP,端口号,心跳包间隔时间0秒(不使用心跳机制)。
	LIB_Cat1TcpUdpEC800Config("UART0","D5","HIGH","D6","HIGH",TcpServerIp,TcpServerPort,0,"TCP",SysGpsUse)
elseif SysMode == 1 then --4G Mqtt
	--设置4G模块占用TX0、RX0、D5、D6引脚,MQTT模式,KeepAlive周期180秒,不开启GPS功能
	LIB_Cat1MqttEC800Config("UART0","D5","HIGH","D6","HIGH",MqttServerAddr,MqttServerPort,MqttClientID,MqttUserName,MqttPassword,180,MqttSubTopic,"QOS0",SysGpsUse)
elseif SysMode == 2  then --4G ShineBlink Cloud
	--设置外部4G模块连接云
	LIB_CloudConfig("S0", "4G_EC800", 0, "SBK_01", UI, SysGpsUse)
elseif SysMode == 3 then -- Lora Modbus Hex transport
	--设置Lora参数
	LIB_LoraConfig("UART0","D5","D6",LoraAddr,LoraChannel,LoraBaudrate,LoraTxPwr)
else

end
--使能系统10毫秒定时器开始工作
timer_ms = 0
timer1_ms = 0
timer_cnt = 0
LIB_10msTimerConfig("ENABLE")
---------------------系统初始化结束-----------------------

--开始大循环
while(GC(1) == true)
do
	--------------步骤(一)通过RS485 Modbus RTU协议读取传感器的值-----------------
	DelayS(SensorHeatTime) --读取传感器前的预热时间(秒)
	SensorStr = nil
	result,str = GetSensorValue()
	if result == 1 then
		--获取传感器json对象字符串
		SensorStr = str
	end
		
	-------------步骤(二)获取GPS定位信息和UTC时间(EC800M 4G模组才具备此功能)-------------
	GpsAndUtcStr = nil
	if SysGpsUse == "AUTO_AGPS" then
		timer_cnt = 0
		while(timer_cnt < 60000)--最多等待60秒给GPS搜星定位时间
		do
			--如果收到GPS信息
			flag,lo,la,al,utc,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15,r16 = LIB_Cat1GpsQuery()
			if flag == 1 then
				--生成json对象字符串
				GpsAndUtcStr = string.format("\"Longtitude\":%.1f, \"Latitude\":%.1f, \"UTC\":%d", lo,la,utc)
				timer_cnt = 60000 --既然获取到GPS信息了就没必要停留了,尽早退出循环
			end
		end
	end
	
	-------------步骤(三)获取电池电压信息(如果外挂了BatteryFriend电池低功耗管理器)-------------
	--通过Modbus RTU协议从BatteryFriend读取电池电压值
	BatteryVolStr = nil
	if SysSleepEn == 1 then
		result,batvol = GetBatteryFriendVoltage()
		if result == 1 then
			--生成json对象字符串
			BatteryVolStr = string.format("\"BatVol\":%.1f", batvol)
		end
	end
	
	--------------步骤(四)构造需要发送的Json字符串---------------------------
	JsonStr = string.format("{\"Uid\":\"%s\"", SysMyID)
	if GpsAndUtcStr ~= nil then
		JsonStr = JsonStr..","..GpsAndUtcStr
	end
	if BatteryVolStr ~= nil then
		JsonStr = JsonStr..","..BatteryVolStr
	end
	if SensorStr ~= nil then
		JsonStr = JsonStr..","..SensorStr
		JsonStrForShineBlinkCloud = "{"..SensorStr.."}"
	else
		JsonStrForShineBlinkCloud = "{"..SensorStrInvalid.."}"
	end
	JsonStr = JsonStr.."}"
	--最终合成JsonStr字符串形如:
	--{"Uid":"Test01","Longtitude":119.2, "Latitude":26.1, "UTC":1679488305,"Temperature":25.2, "Humidity":76.7}
	print("JsonStr:"..JsonStr)
	print("SbcJsonStr:"..JsonStrForShineBlinkCloud)
	
	--------------步骤(五)通过4G或Lora向远端服务器发送数据-----------------
	Connect = 0
	--前三种工作模式都需要判断4G模组和服务器建立连接后才能发送
	if SysMode <= 2 then 
		timer_cnt = 0 
		while(timer_cnt < 60000)--最多等待60秒
		do
			State,IMSI,ICCID,CSQ = LIB_Cat1StatusQuery()
			if State == "Connected" then
				timer_cnt = 60000 --既然可以发送4G数据了,就赶紧退出循环
				Connect = 1
			end
		end
	else --Lora发送不需考虑connect
		Connect = 1
	end
	if Connect ==  1 then
		if SysMode == 0 then --4G TCP 发送Json传感器数据
			LIB_Cat1TcpUdpEC800Send(LIB_StrToTab(JsonStr))
		elseif SysMode == 1 then --4G Mqtt 发送Json传感器数据
			LIB_Cat1MqttEC800SendPub("QOS0", MqttPubTopic, JsonStr)
		elseif SysMode == 2 then --4G 向ShineBlink云发送Json传感器数据
			LIB_CloudSend(JsonStrForShineBlinkCloud)
		elseif SysMode == 3 then --通过Lora向中心节点发送Json字符串
			LIB_LoraSend(LoraTargetAddr, LIB_StrToTab(JsonStr))
			RGB(1,0,1) --绿灯闪0.05秒
			LIB_DelayMs(50)
			RGB(1,1,1) 
		else
			
		end
		DelayS(2) --等待2秒让消息发送出去
	end
	
	--------------步骤(六)判断是否需要进入低功耗休眠(需外挂BatteryFriend电池低功耗管理器)-----------------
	if SysSleepEn == 1 then
		--通过Modbus RTU协议向BatteryFriend下发休眠指令及时长(SysWorkInterval秒)
		result = SetBatteryFriendSleep(SysWorkInterval)
		if result == 0 then
			print("Can not enter sleep!")			
		end
	end
	--如果上面没有成功进入低功耗休眠掉电(没有外挂BatteryFriend)
	--则延时SysWorkInterval秒后重新执行本循环
	DelayS(SysWorkInterval)
	
	
end

更多推荐