资讯详情

【室内农业】温湿度测控,继电器控制加热器、加湿器、电风扇

main.lua

cf_iot=require("cf_iot") common=require("common") json=require("json") mqtt=require("mqtt") hardware=require("hardware") media=require("media")  PackagePath=this().PackagePath--当前虚拟机加载用户自定义模块的根目录 LuaLibPath=this().LuaLibPath--当前虚拟机加载用户自定义模块的根目录 package.path = PackagePath .. [[/?/init.lua;]] .. PackagePath .. [[/?/init.lua;]] .. PackagePath .. [[/?.lua;]] .. package.path package.path = LuaLibPath .. [[/?/init.lua;]] .. LuaLibPath .. [[/?.lua;]] .. package.path  require "General_Function"  require "Parser.Parser_Relay_AiErSai"--继电器分析器 require "OBJ.OBJ_EA"--用于表示加湿器、加热器等电器的一般类别,有开关、更新状态等方法   require "Parser.Parser_Sensor_Temp_Humidity_jdrk"--温湿度传感器分析器 require "OBJ.OBJ_Sensor_Temp_Humidity"--温湿度传感器,有读取、更新等方法   local FirmwareInfo=json.decode(cf_iot.GetFirmwareInfo())  --[[ Config存储各通道的485节点配置新闻 ]] local Config={  mqtt={   Subscribe_Topic="cfiot/cmd_channel",--订阅主题名,接受后台的命令   Publish_Topic="cfiot/data_channel"--发布主题名,报告数据  },  HardwareChannel={   Serial1={    Node_Parser={},    MyDevice={}   },   Serial2={    Node_Parser=节点分析器列表     {      Node_Address=1,      Parser_Relay=Parser_Relay_AiErSai     },     {      Node_Address=2,      Parser_Relay=Parser_Relay_AiErSai     },     {      Node_Address=3,      Parser_Relay=Parser_Sensor_Temp_Humidity_jdrk     }    },    MyDevice={-我的设备列表     Heater=OBJ_EA:new({-加热器相关属性,通道-节点地址-开关编号-      Cmd_Channel="Serial2",      Node_Address=1,      Switch_Number=1,      State="Off",      Parser_Relay=Parser_Relay_AiErSai     }),     Humidifier=OBJ_EA:new({-加湿器相关属性,通道-节点地址-开关编号-继电器分析器      Cmd_Channel="Serial2",      Node_Address=1,      Switch_Number=2,      State="Off",      Parser_Relay=Parser_Relay_AiErSai     }),     ElectricFan=OBJ_EA:new({-电风扇相关属性,通道-节点地址-开关编号-      Cmd_Channel="Serial2",      Node_Address=2,      Switch_Number=1,      State="Off",      Parser_Relay=Parser_Relay_AiErSai     }),     Sensor_Temp_Humidity=OBJ_Sensor_Temp_Humidity:new({-温湿度传感器      Cmd_Channel="Serial2",      Node_Address=3,      Data={       Temp=nil,       Humidity=nil      },      Parser_Relay=Parser_Sensor_Temp_Humidity_jdrk     })    }    },   Serial3={    Node_Parser={},    MyDevice={}   },   Serial4={    Node_Parser={},    MyDevice={}   }  } } --[[  ServerConfig存储服务器配置信息 ]] local ServerConfig={   Enable={   AutomaticControl=true  } }  function HardwareChannel_DataParsing(Channel,data)   local Node_Address=data.byteArray[1]-获取数据的节点地址  for key,node in pairs(Config.HardwareChannel[Channel].Node_Parser) do     if node.Node_Address==Node_Address then     node.Parser_Relay.ParserRouting(data)--开始数据分析路由     break     end  end   for key,Device in pairs(Config.HardwareChannel[Channel].MyDevice) do   if Device.Node_Address==Node_Address then    Device:UpdateStatus()-更新设备状态   end  end  end  function mqtt_init()   --[[    服务器端json数据格式    {    "msgId":"Enable",    "data":{     "AutomaticControl":true    }   }   ]]   if mqtt.WaitMQTTClientReady()--等待mqtt准备好主通道  then    mqtt.AddSubscribeTopic(Config.mqtt.Subscribe_Topic)--订阅mqtt主题    local mqtt_OnMessage = function(msg)--信息处理函数     if (msg.Toppic==Config.mqtt.Subscribe_Topic) then      local tb=json.decode(msg.Payload)      if tb.msgId=="Enable" then      ServerConfig.Enable.AutomaticControl=tb.data.AutomaticControl     end     end    end   mqtt.SetOnMessageHandler(LuaVMName,mqtt_OnMessage)--设置消息处理回调函数  end  end function hardware_init()   hardware.SetSerialDataRoute(1)-设置串口数据路由,0:服务器,1:lua虚拟机   local Hardware_OnEvent= function(data)--硬件事件回调函数   local portName=data.portName   local EventName=data.EventName   local Message=data.Message   local info=portName ..":".. EventName .. ":" .. Message   mqtt.Publish(Config.mqtt.Publish_Topic,0,false,info)  end  hardware.SetHardwareOnEvent(LuaVMName,Hardware_OnEvent)   local Serial2_OnData= function(data)--串口2数据处理函数   --16进程字符数组 data.hexArray   --byte数组data.byteArray   --print(data.hexArray,data.byteArray)   HardwareChannel_DataParsing("Serial2",data)   end  hardware.SetSerialWriteDataSleep("Serial2",50)-设置串口发送数据包后的延迟时间,单位毫秒,延时是在CFIOT在固件中执行,防止粘包  hardware.SetSerialOnDataHandler(LuaVMName,"Serial2",Serial2_OnData)  hardware.SerialOpen("Serial2",9600,8,"None",1)--打开串口2  end  function main()   Debug=true  LuaVMName=this().LuaVMName--目前虚拟机的名称   cf_iot.SetDebug(LuaVMName,Debug)  cf_iot.SetWatchdogTimeout(LuaVMName,300)    mqtt_init()  hardware_init()   --看门狗定时器  cf_iot.AddTimer(LuaVMName,"MainTimer",5000,function()    cf_iot.Watchdog(LuaVMName,1)-发送看门狗信号   end)   --信号采集定时器  cf_iot.AddTimer(LuaVMName,"SignalAcquisitionTimer",25000,function()   --采集温湿度   local Channel=Config.HardwareChannel["Serial2"]   Channel.MyDevice.Sensor_Temp_Humidity:ReadData()   Channel.MyDevice.Heater:ReadData()   Channel.MyDevice.ElectricFan:ReadData()   end)   --定时器的自动控制  cf_iot.AddTimer(LuaVMName,"AutomaticControlTimer",20000,function()    if not(ServerConfig.Enable.AutomaicControl) then
			return
		end

		local Channel=Config.HardwareChannel["Serial2"]

		local Temp=Channel.MyDevice.Sensor_Temp_Humidity.Data.Temp
		local Humidity=Channel.MyDevice.Sensor_Temp_Humidity.Data.Humidity

		if Temp==nil or Humidity==nil then
			return
		end

		if Temp<20.5 then
			Channel.MyDevice.Heater:Power("On")--打开加热器
			Channel.MyDevice.ElectricFan:Power("On")--打开电风扇吹热风
		elseif Temp>=20.5 then
			Channel.MyDevice.Heater:Power("Off")--关闭加热器
			Channel.MyDevice.ElectricFan:Power("Off")--关闭电风扇
		end


		if Humidity<=50 then
			Channel.MyDevice.Humidifier:Power("On")--打开加湿器
		elseif Humidity>=55 then
			Channel.MyDevice.Humidifier:Power("Off")--关闭加湿器
		end

	end)

	--数据上传定时器

	cf_iot.AddTimer(LuaVMName,"UploadDataTimer",30000,function()

		local Channel=Config.HardwareChannel["Serial2"]

		local data={
			IMEI=FirmwareInfo.ModuleState.IMEI,
			CCID=FirmwareInfo.ModuleState.CCID,
			State={
				Heater=Channel.MyDevice.Heater.State,
				ElectricFan=Channel.MyDevice.ElectricFan.State,
				Humidifier=Channel.MyDevice.Humidifier.State
			},
			Sensor={
				Temp=Channel.MyDevice.Sensor_Temp_Humidity.Data.Temp,
				Humidity=Channel.MyDevice.Sensor_Temp_Humidity.Data.Humidity
			}
		}

		mqtt.Publish(Config.mqtt.Publish_Topic,0,false,json.encode(data))

	end)
end









OBJ_EA.lua

--[[
定义一个电器类
Node_Address:节点地址,即485控制器上的总线地址
Switch_Number:开关编号,即继电器控制板上的第几路开关
Cmd_Channel:命令通道,即发送开关命令所用的通道,对应控制网关上的串口TTL电平
]]
OBJ_EA={--相关属性
			Cmd_Channel="Serial2",
			Node_Address=1,
			Switch_Number=1,
			State="Off",
			Parser_Relay=nil
	}

function OBJ_EA:Power(v)
	--为加热器Heater增加一个控制开关
	--v:电源选项,On:开机,Off:关机
	--local info=self.Node_Address .. ":" .. self.Switch_Number .. "" .. v
	--print(info)
	local cmd=self.Parser_Relay.get_Switch_Cmd(v,self.Node_Address,self.Switch_Number)
	if cmd~=nil then
		hardware.SerialWriteDataByte(self.Cmd_Channel,cmd)
		--General_Function.printTable(cmd)
	end

end

function OBJ_EA:ReadData()
	--下发读取继电器状态数据
	local cmd=self.Parser_Relay.get_ReadData_Cmd(self.Node_Address)
	if cmd~=nil then
		hardware.SerialWriteDataByte(self.Cmd_Channel,cmd)
		--General_Function.printTable(cmd)
	end
end

function OBJ_EA:UpdateStatus()
	--更新状态
	if self.Parser_Relay.data["g"..self.Switch_Number]==1 then
		self.State="On"
	else
		self.State="Off"
	end
end

-- 派生类的方法 new
function OBJ_EA:new (obj)

  setmetatable(obj, self)
  self.__index = self
  return obj

end

return OBJ_EA

OBJ_Sensor_Temp_Humidity.lua

--[[
定义一个温湿度传感器
Node_Address:节点地址,即485控制器上的总线地址
Switch_Number:开关编号,即继电器控制板上的第几路开关
Cmd_Channel:命令通道,即发送开关命令所用的通道,对应控制网关上的串口TTL电平
]]

OBJ_Sensor_Temp_Humidity={--相关属性
		Cmd_Channel="Serial2",
		Node_Address=1,
		Parser_Relay=nil,
		Data={
			Temp=nil,
			Humidity=nil
		}
	}

function OBJ_Sensor_Temp_Humidity:ReadData()
	--下发读取温湿度数据
	local cmd=self.Parser_Relay.get_ReadData_Cmd(self.Node_Address)
	if cmd~=nil
	then
		hardware.SerialWriteDataByte(self.Cmd_Channel,cmd)
		--General_Function.printTable(cmd)
	end
end

function OBJ_Sensor_Temp_Humidity:UpdateStatus()
	--更新温湿度数据
	if self.Parser_Relay ~= nil
	then
		self.Data.Temp=self.Parser_Relay.data.Temp
		self.Data.Humidity=self.Parser_Relay.data.Humidity
	end
end

-- 派生类的方法 new
function OBJ_Sensor_Temp_Humidity:new (obj)

  setmetatable(obj, self)
  self.__index = self
  return obj

end

return OBJ_Sensor_Temp_Humidity

Parser_Relay_AiErSai.lua



Parser_Relay_AiErSai={}

--[[
	data:每路继电器状,一个板卡最多支持8路继电器
]]
Parser_Relay_AiErSai.data={
	g1=0,
	g2=0,
	g3=0,
	g4=0,
	g5=0,
	g7=0,
	g8=0
}

--[[
	get_Switch_Cmd(data)
	功能:打开继电器
	参数:data={hexArray={},byteArray={}}
	]]
function Parser_Relay_AiErSai.get_Switch_Cmd(v,Node_Address,Switch_Number)

	if not(Switch_Number>=1 and Switch_Number<=8)
	then
		return nil
	end

	local s=0x00

	if v=="On"
	then
		s=0xff
	elseif v=="Off"
	then
		s=0x00
	end

	local cmd={Node_Address,5,0,(Switch_Number-1),s,0}
	local r=common.CRC16(cmd)
	table.insert(cmd, r[1])
	table.insert(cmd, r[2])
	return cmd
end

--[[
	get_ReadData_Cmd(data)
	功能:获取继电器状态
	参数:data={hexArray={},byteArray={}}
	]]
function Parser_Relay_AiErSai.get_ReadData_Cmd(Node_Address)
	local cmd={Node_Address,0x01,0x00,0x00,0x00,0x08}
	local r=common.CRC16(cmd)
	table.insert(cmd, r[1])
	table.insert(cmd, r[2])
	return cmd
end

--[[
	ParserRouting(data)
	功能:解析器路由,根据功能码选择数据解析函数
	参数:data={hexArray={},byteArray={}}
	]]
function Parser_Relay_AiErSai.ParserRouting(data)

	--数据CRC16验证
	if not(General_Function.DataChecking(data))
	then
		return
	end

	--解析器路由
	local cmdID=data.hexArray[2]
	if(cmdID=="01") then
		Parser_Relay_AiErSai.ParserState(data)
	end
	if(cmdID=="05") then
		Parser_Relay_AiErSai.ParserState1(data)
	end
end
--[[
	ParserState(data)
	作用:解析继电器状态
]]
function Parser_Relay_AiErSai.ParserState(data)
	local t,s=common.byte2bin(data.byteArray[4])
	Parser_Relay_AiErSai.data.g1=t[8]
	Parser_Relay_AiErSai.data.g2=t[7]
	Parser_Relay_AiErSai.data.g3=t[6]
	Parser_Relay_AiErSai.data.g4=t[5]
	Parser_Relay_AiErSai.data.g5=t[4]
	Parser_Relay_AiErSai.data.g6=t[3]
	Parser_Relay_AiErSai.data.g7=t[2]
	Parser_Relay_AiErSai.data.g8=t[1]
	--General_Function.printTable(Parser_Relay_AiErSai.data)
end

function Parser_Relay_AiErSai.ParserState1(data)

	local state=data.hexArray[5]..data.hexArray[6]
	if (state=="ff00") then
		Parser_Relay_AiErSai.data["g"..(data.byteArray[4]+1)]=1
	else
		Parser_Relay_AiErSai.data["g"..(data.byteArray[4]+1)]=0
	end

end

function Parser_Relay_AiErSai.test()

	local data={
		hexArray={"ff","01","01","01","a1","a0"},
		byteArray={255,1,1,1,161,160}
	}

	Parser_Relay_AiErSai.ParserRouting(data)

end

return Parser_Relay_AiErSai

Parser_Sensor_Temp_Humidity_jdrk.lua

--[[
	建大仁科温湿度传感器解析器
]]
Parser_Sensor_Temp_Humidity_jdrk={}

--[[
	data:温度和湿度
]]
Parser_Sensor_Temp_Humidity_jdrk.data={
	Temp=nil,
	Humidity=nil
}

--[[
	get_ReadData_Cmd(data)
	功能:获取读温湿度的数据包
	参数:data={hexArray={},byteArray={}}
	]]
function Parser_Sensor_Temp_Humidity_jdrk.get_ReadData_Cmd(Node_Address)
	local cmd={Node_Address,0x03,0x00,0x00,0x00,0x02}
	local r=common.CRC16(cmd)
	table.insert(cmd, r[1])
	table.insert(cmd, r[2])
	return cmd
end




--[[
	ParserRouting(data)
	功能:解析器路由,根据功能码选择数据解析函数
	参数:data={hexArray={},byteArray={}}
	]]
function Parser_Sensor_Temp_Humidity_jdrk.ParserRouting(data)

	--数据CRC16验证
	if not(General_Function.DataChecking(data))
	then
		return
	end

	--解析器路由
	local cmdID=data.hexArray[2]
	if(cmdID=="03") then
		Parser_Sensor_Temp_Humidity_jdrk.ParserTempAndHumidity(data)
	end

end
--[[
	ParserTempAndHumidity(data)
	作用:解析温湿度
	03 03 04 01 BC 00 7F 58 0B
]]
function Parser_Sensor_Temp_Humidity_jdrk.ParserTempAndHumidity(data)

	Parser_Sensor_Temp_Humidity_jdrk.data.Humidity=common.H_To_O(data.hexArray[4]..data.hexArray[5]) / 10

	local t,s=common.byte2bin(data.byteArray[6])
	if t[1]==0
	then
		Parser_Sensor_Temp_Humidity_jdrk.data.Temp=common.H_To_O(data.hexArray[6]..data.hexArray[7]) /10
	else
		Parser_Sensor_Temp_Humidity_jdrk.data.Temp=common.H_To_NgO(data.hexArray[6]..data.hexArray[7]) /10 * -1
	end

end

return Parser_Sensor_Temp_Humidity_jdrk

General_Function.lua

General_Function={}



function General_Function.printTable(tb)

	for k, v in pairs(tb) do
		print(k,v)
    end

end

--[[
LUA 5.1 CRC16/Modbus 校验 纯LUA实现
https://blog.csdn.net/u013625451/article/details/103241737

性能不行,不建议使用,可以使用cf_iot提供的

]]

function General_Function.And(num1,num2)
	local tmp1 = num1
	local tmp2 = num2
	local ret = 0
	local count = 0
	repeat
		local s1 = tmp1 % 2
		local s2 = tmp2 % 2
		if s1 == s2 and s1 == 1 then
			ret = ret + 2^count
		end
		tmp1 = math.modf(tmp1/2)
		tmp2 = math.modf(tmp2/2)
		count = count + 1
	until(tmp1 == 0 and tmp2 == 0)
	return ret
end

function General_Function.Xor(num1,num2)
	local tmp1 = num1
	local tmp2 = num2
	local ret = 0
	local count = 0
	repeat
		local s1 = tmp1 % 2
		local s2 = tmp2 % 2
		if s1 ~= s2 then
			ret = ret + 2^count
		end
		tmp1 = math.modf(tmp1/2)
		tmp2 = math.modf(tmp2/2)
		count = count + 1
	until(tmp1 == 0 and tmp2 == 0)
	return ret
end

function General_Function.bit_rshift(value,n)
	value = math.modf(value / (2^n))
	return value
end

function General_Function.CRC16(arr)
	local tmp = 0xffff
	for i=1,#arr do
		tmp = General_Function.Xor(arr[i],tmp)
		for j=1,8 do
			local tmp1 = General_Function.And(tmp,0x01)
			if tmp1 == 1 then
				tmp = General_Function.bit_rshift(tmp,1)
				tmp = General_Function.Xor(tmp,0xa001)
			else
				tmp = General_Function.bit_rshift(tmp,1)
			end
		end
	end
	local ret1 = (tmp % 256)
	local ret2 = math.modf( tmp / 256)
	return {ret1,ret2}
end

--[[
https://stackoverflow.com/questions/24821045/does-lua-have-something-like-pythons-slice
]]

function General_Function.slice(tbl, first, last, step)
  local sliced = {}

  for i = first or 1, last or #tbl, step or 1 do
    sliced[#sliced+1] = tbl[i]
  end

  return sliced
end


--[[
http://love2d.org/forums/viewtopic.php?f=4&t=84988&start=10&__cf_chl_captcha_tk__=6d04f55cf83896b2cb788fe655b479ab248a7f14-1610387423-0-AWqM-FI75XLbX1zsV8rb6xSnmZ0Ko7qZweX5EBFhNkG2oLcBX9SlHAA-W-R-CnqDhbC9Ju8bQ0nhEfDk0ixd24bynxLM4rEGwo8zedXQA6izYB445Wo374uui9pYxPcWQRijBZqoQkhuuHoC5DQU4hsf5H9r_ABQiaTlXVh6bSC83Zy9SuOkfOrQyiBwoIVK4DyZsgvLd80lKnisBbJ-Swdg4n8XybtXayXNJDxHr7PBDBzVggprEhBI2phDYF5X6bEEfeLd8ZBOalNT0E-tMxTOL-kc6X-JGkuhC0SkVz6KnX2GR104z42ZEjpwcx0QclscEXBppazk8sFlEAQTRdjwINJ6HyMCxI0LzNu1efaPJ8AdduM_aGBq5owK6gx9NstnS58Y7nWNEyb_aSZw-CzlbgkV7IyyokkckLBhYTTwFUr2p-Jvz4Izm6dvPub8JRJr-xqYQ63Xq8xjweeAeEV0kdoiNTmEVoVHIJbwotDeVf0CM63SqIrfr3yvLRVOvxupr3SAs0BRoJAc50_qkCHd_7l3hy1TIxEURZPBkswzuEb5lftCOGiPkGXnCRkrzNAyZg5Jp80Z9WMRxDiLizZkt8snWxjQ8Dth8mZGRGb5N-SmSsoXrzFzxb5PQjLT1KxyWB1iIwkxqK_wq9uJJHA
https://www.cnblogs.com/v5captain/p/11739414.html
]]
--10进制转换2进制
function General_Function.byte2bin(n)
  local t = {}
  for i=7,0,-1 do
    t[#t+1] = math.floor(n / 2^i)
    n = n % 2^i
  end
  return t,table.concat(t)
end

--10进制转换2进制,可以表示大数
function General_Function.byte2bin1(n)
local t, d = {}, 0
  d = math.log(n)/math.log(2) -- binary logarithm
  for i=math.floor(d+1),0,-1 do
    t[#t+1] = math.floor(n / 2^i)
    n = n % 2^i
  end
  return t,table.concat(t)
end


--[[
	DataChecking(data)
	作用:检测数据有效性
]]
function General_Function.DataChecking(data)

	if #data.byteArray<3
	then
		return false
	end

	local len=#data.byteArray
	local array=General_Function.slice(data.byteArray,1,len-2)
	local r=common.CRC16(array)

	if (r[1]==data.byteArray[len-1] and r[2]==data.byteArray[len])
	then
		return true
	else
		return false
	end
end

return General_Function

 

标签: 继电器能用来加热吗4路继电器模块a1热继电器hg6d继电器热继电器631000v热继电器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台