CF-IOT之LUA语言开发

概述

CFIOT内置了丰富的API接口,以模块的形式类聚这些API接口,并导入到内置的LUA虚拟机,供用户的LUA脚本调用,用户可使用CFIOT云端通讯协议远程更新LUA脚本和管理虚拟机,如关闭、启动虚拟机,以及清除脚本等操作。

CFIOT支持多个LUA虚拟机并行运行,充分发挥多核CPU并行计算优势,虚拟机个数由用户的LUA脚本目录数决定,虚拟机之间可以相互通信。

CFIOT目前提供了json、basic、mqtt、hardware、websocket、media等LUA模块,基本满足用户业务逻辑开发要求,可根据用户需求定制特定LUA模块。

LUA语言

Lua 是一种轻量小巧的脚本语言, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。

  • 轻量级: 它用标准C语言编写并以源代码形式开放,编译后仅仅一百余K,可以很方便的嵌入别的程序里。
  • 可扩展: Lua提供了非常易于使用的扩展接口和机制:由宿主语言(通常是C或C++)提供这些功能,Lua可以使用它们,就像是本来就内置的功能一样。
  • 其它特性:
    • 支持面向过程(procedure-oriented)编程和函数式编程(functional programming);
    • 自动内存管理;只提供了一种通用类型的表(table),用它可以实现数组,哈希表,集合,对象;
    • 语言内置模式匹配;闭包(closure);函数也可以看做一个值;提供多线程(协同进程,并非操作系统所支持的线程)支持;
    • 通过闭包和table可以很方便地支持面向对象编程所需要的一些关键机制,比如数据抽象,虚函数,继承和重载等。

Lua 教程:https://www.runoob.com/lua/lua-tutorial.html

LUA脚本目录

对于复杂的业务逻辑,我们建议用户的LUA脚本文件组织到不同的目录下,可以解耦和充分利用CPU计算资源,一个目录下可以存放多个后缀为.lua的脚本,有且仅有一个main.lua文件,main.lua是启动脚本,CFIOT内置的LUA虚拟机管理器,会为每一个目录创建LUA虚拟机,并首先启动main.lua这个脚本。

DEMO程序

我们提供了一个DEMO程序,包含两个目录app1和app2,分别存放一个main.lua文件。

app1下main.go

json = require("json")
basic=require("basic")
mqtt=require("mqtt")
hardware=require("hardware")
websocket=require("websocket")
media=require("media")
local Debug=true
local Timer1_data={count=0,name="Timer1"}
local Timer2_data={count=0,name="Timer2"}
local Gps_data={Longitude=0,Latitude=0,N_S="",E_W="",Speed=0,Direction=0,Mode="",DateTime=""}
local Parameters={}
local LuaVMName=this().LuaVMName--当前虚拟机的名称
function testWebsocket()
	--Websocket测试
	local websocket_OnMessage = function(msg)--消息处理函数
		local msgObj=json.decode(msg)
		local channel=msgObj.channel
		if channel~=nil
		then
			local DeviceNo=msgObj.DeviceNo
			local Data=msgObj.Data
			local info=channel..DeviceNo..json.encode(Data)
			websocket.SendMessage(info)	
		end
	end
	websocket.SetOnMessageHandler(LuaVMName,websocket_OnMessage)--设置消息处理回调函数
	websocket.SendMessage("testWebsocket")	
end
function testMQTT()
	--MQTT测试
	if mqtt.WaitMQTTClientReady()--等待mqtt主通道准备好
	then
		local MQTTSettings=mqtt.GetMQTTSettings()--获取MQTT参数设置
		mqtt.Publish(MQTTSettings.PublishTopic,0,false,json.encode(MQTTSettings))--采用默认发布主题推送mqtt参数
		mqtt.AddSubscribeTopic("CloudEmbedded/testlua")--订阅mqtt主题
		mqtt.AddSubscribeTopic("CloudEmbedded/testlua1")
		local mqtt_OnMessage = function(msg)--消息处理函数
			info=msg.Toppic .. ":" .. msg.Payload
			mqtt.Publish("CloudEmbedded/lua/print",0,false,info)
			if (msg.Toppic=="CloudEmbedded/testlua1")
			then
				mqtt.DeleteSubscribeTopic("CloudEmbedded/testlua1")--删除订阅主题
			end 
		end
		mqtt.SetOnMessageHandler(LuaVMName,mqtt_OnMessage)--设置消息处理回调函数
		mqtt.Publish("CloudEmbedded/test123",0,false,"test")
	end	
end

function testJson()
	--json测试
	--[====[  
	json相关函数
	》json字符串转table
	json.decode(str)
	》table转json字符串
	json.encode(obj)
	  ]====]
	local FirmwareInfoStr=basic.GetFirmwareInfo()
	mqtt.Publish("CloudEmbedded/lua/print",0,false, FirmwareInfoStr)
	basic.print(FirmwareInfoStr,Debug)--打印固件信息
	FirmwareInfo=json.decode(FirmwareInfoStr)
	local Revisionstr=FirmwareInfo.Revision--固件版本号
	local ModuleState=FirmwareInfo.ModuleState--模块状态
	local IMEIstr=ModuleState.IMEI--模块序列号
	local CCIDstr=ModuleState.CCID--sim卡标识
	local CSQstr=ModuleState.CSQ--信号强度
	local CSQtimestr=ModuleState.CSQtime--信号时间
	local data={IMEI=IMEIstr,CCID=CCIDstr,CSQ=CSQstr,CSQtime=CSQtimestr,Revision=Revisionstr}
	mqtt.Publish("CloudEmbedded/lua/print",0,false, json.encode(data))
end
function testTimer()
	--定时器测试
	--[====[  
	 
	定时器相关函数
	》增加定时器器
	AddTimer(name,Interval,Handler)
	name:定时器名字
	Interval:定时器间隔
	Handler:定时器执行函数
	》删除定时器
	DeleteTimer(name)
	》检测定时器是否存在
	TimerExist(name)
	》启动全部定时器
	StartTimer()
	》停止所有定时器
	StopTimer()
	注意:增加定时器器会自动执行StartTimer(),删除最后一个定时器后自动执行StopTimer()
	  ]====]
	--增加一个2秒间隔的定时器Timer1
	basic.AddTimer(LuaVMName,"Timer1",2000,function()
		Timer1_data.count=Timer1_data.count+1
		mqtt.Publish("CloudEmbedded/lua/print",0,false, json.encode(Timer1_data))
	end)
	
	--增加一个5秒间隔的定时器Timer2
	local Timer2=function()
		Timer2_data.count=Timer2_data.count+1
		mqtt.Publish("CloudEmbedded/lua/print",0,false,json.encode(Timer2_data))
	end
	basic.AddTimer(LuaVMName,"Timer2",5000,Timer2)
	
	--增加一个1秒间隔的定时器deleteTimer
	basic.AddTimer(LuaVMName,"deleteTimer",1000,function()
	
		if (Timer1_data.count>=10)
		then
			Timer1_data.count=0
			basic.DeleteTimer(LuaVMName,"Timer1")
			mqtt.Publish("CloudEmbedded/lua/print",0,false, "Delete Timer1")
		end
		
		if (Timer2_data.count>=10)
		then
			Timer2_data.count=0
			basic.DeleteTimer(LuaVMName,"Timer2")
			mqtt.Publish("CloudEmbedded/lua/print",0,false, "Delete Timer2")
		end
		
		if (not basic.TimerExist(LuaVMName,"Timer1") and not basic.TimerExist(LuaVMName,"Timer2"))
		then
			basic.DeleteTimer(LuaVMName,"deleteTimer")
			mqtt.Publish("CloudEmbedded/lua/print",0,false, "The timers are all deleted")
		end
		
	end)
end
function testHardware()
	--测试硬件
	--[====[  
	》发送AT指令
	SendAt(cmd,Formatter,Timeout)
	cmd:AT指令内容
	Formatter:格式化标签,将AT响应内容格式化,如果为空,则返回原始数据,需要手动编写格式化函数
	Timeout:AT响应内容超时时间,单位毫秒,连续响应数据超时返回
	》发送字符短信
	SendSMS(No,Content)
	No:短信号码
	Content:短信内容
	》设置短信处理回调函数
	SetOnSMSHandler(fn)
	》设置gps处理回调函数
	SetOnGPSHandler(fn)
	  ]====]
	mqtt.Publish("CloudEmbedded/lua/print",0,false, "testHardware")
	local atResponseStr=hardware.SendAt("at+cgsn\r","",100)
	local Revisionstr=hardware.SendAt("ati\r","Revision",100)
	local IMEIstr=hardware.SendAt("at+cgsn\r","imei",100)
	local CCIDstr=hardware.SendAt("at+qccid\r","ccid",100)
	local CSQstr=hardware.SendAt("at+csq\r","CSQ",100)
	local data={IMEI=IMEIstr,CCID=CCIDstr,CSQ=CSQstr,cgsnResponse=atResponseStr,Revision=Revisionstr}
	mqtt.Publish("CloudEmbedded/lua/print",0,false, json.encode(data))
	hardware.SendSMS("15395016712","send sms")
	local LteModule_OnSMS = function(msg)--短信处理函数
			local info="sms:" .. msg.No .. ":" .. msg.Content
			mqtt.Publish("CloudEmbedded/lua/print",0,false,info)
	end
	hardware.SetOnSMSHandler(LuaVMName,LteModule_OnSMS)--设置短信处理回调函数
	
	local GPSModular_OnGPS = function(data)--gps处理函数
			Gps_data.Longitude=data.Longitude
			Gps_data.Latitude=data.Latitude
			Gps_data.N_S=data.N_S
			Gps_data.E_W=data.E_W
			Gps_data.Speed=data.Speed
			Gps_data.Direction=data.Direction
			Gps_data.Mode=data.Mode
			Gps_data.DateTime=data.DateTime
			mqtt.Publish("CloudEmbedded/lua/print",0,false,json.encode(Gps_data))
	end
	hardware.SetOnGPSHandler(LuaVMName,GPSModular_OnGPS)--设置gps处理回调函数
	
	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("CloudEmbedded/lua/print",0,false,info)
	end
	hardware.SetHardwareOnEvent(LuaVMName,Hardware_OnEvent)
	
	local Serial1_OnData= function(data)--串口1数据处理函数
		--16进程字符数组 data.hexArray
		--byte数组data.byteArray
		--local info="Serial1_OnData:" .. data.hex
		print(data.hexArray,data.byteArray)
		--mqtt.Publish("CloudEmbedded/lua/print",0,false,info)
	end
	hardware.SetSerialWriteDataSleep("Serial1",30)--设置串口发送数据包后延迟时间,单位毫秒,延时是在CFIOT固件中执行,防止粘包
	hardware.SetSerialOnDataHandler(LuaVMName,"Serial1",Serial1_OnData)
	hardware.SerialOpen("Serial1",9600,8,"None",1)--打开串口1
	hardware.SerialWriteData("Serial1","01 05 00 00 FF 00 8C 3A")
	hardware.SerialWriteData("Serial1","01 05 00 00 00 00 CD CA")
	hardware.SerialWriteDataByte("Serial1",{0x01,0x05,0x00,0x00,0xFF,0x00,0x8C,0X3A})
	hardware.SerialWriteDataByte("Serial1",{0x01,0x05,0x00,0x00,0x00,0x00,0xCD,0XCA})
end
function testVMMessage()
	--测试虚拟机收发消息
	local VM_OnMessage= function(data)--接收其他虚拟机消息函数
		mqtt.Publish("CloudEmbedded/lua/print",0,false,json.encode(data))
	end
	basic.SetOnMessageHandler(LuaVMName,VM_OnMessage)
	
	local msg={Source=LuaVMName,Dst="app2"}
	basic.SendMessage(LuaVMName,"app2",msg)--给app2虚拟机发消息
end
function testMedia()
	--测试摄像机,拍照、推流等
	media.SearchAllIPCamera()--onvif搜索摄像机
	media.GetIPCameraParameters("")--获取摄像机信息,json字符串
	media.GetIPCameraState("")--获取摄像机状态信息,json字符串
	media.Screenshot("007D50117625","SecondStreamProfileToken_640_352","testScreenshot","/Media")--摄像机拍照
	media.VideoRecording("007D50117625","SecondStreamProfileToken_640_352","testVideoRecording","/Media",10,"flv")
	media.StartPushStream("007D50117625","SecondStreamProfileToken_640_352","rtmp://tx.direct.huya.com/huyalive/1199558764847-1199558764847-6888343667394952147-2399117653150-10057-A-1603817515-1?seq=1605155499051&type=simple","","","")
end
function Start()
	 --[[
		basic.Sleep()延时函数请慎用,不应该出现在定时器、回调函数里,只能用于初始化阶段
		
	
	 ]]
	
	basic.SetDebug(LuaVMName,Debug)--当开启Debug模式,虚拟机运行异常信息会上行到主要上传通道
	basic.SetWatchdogTimeout(LuaVMName,300)--设置看门狗超时,单位秒,>=20,喂狗信号超时会导致虚拟机重启
	
	--增加一个2秒间隔的定时器MainTimer,可以作为主控制线程
	basic.AddTimer(LuaVMName,"MainTimer",2000,function()
		basic.Watchdog(LuaVMName,1)--发送看门狗信号
	end)
	
	Parameters=json.decode(basic.GetParameters())--固件参数
	if(Parameters.ServerSettingsData.ProtocolType==3)--判断上传通道的协议类型,后续上传数据要根据这个协议类型选择相应的通道
	then
		testWebsocket()
	elseif(Parameters.ServerSettingsData.ProtocolType==4)
	then
		testMQTT()
	else
	end
	
	basic.Sleep(30000)--延时60秒
	testJson()
	testTimer()
	basic.Sleep(60000)--延时60秒
	testHardware()
	testVMMessage()
	testMedia()
end

Start()




app2下main.lua

json = require("json")
basic=require("basic")
mqtt=require("mqtt")
hardware=require("hardware")
local Debug=true
local LuaVMName=this().LuaVMName--当前虚拟机的名称

function Start()
	basic.SetDebug(LuaVMName,Debug)--当开启Debug模式,虚拟机运行异常信息会上行到主要上传通道
	basic.SetWatchdogTimeout(LuaVMName,300)--设置看门狗超时,单位秒,>=20,喂狗信号超时会导致虚拟机重启
	
	--增加一个2秒间隔的定时器MainTimer,可以作为主控制线程
	basic.AddTimer(LuaVMName,"MainTimer",2000,function()
		basic.Watchdog(LuaVMName,1)--发送看门狗信号
	end)
	
	mqtt.WaitMQTTClientReady()--等待mqtt主通道准备好
	
	--测试虚拟机收消息
	local VM_OnMessage= function(data)--接收其他虚拟机消息函数
		mqtt.Publish("CloudEmbedded/lua/print",0,false,json.encode(data))
		
		local msg={Source=LuaVMName,Dst="app1"}
		basic.SendMessage(LuaVMName,"app1",msg)--给app1虚拟机发消息
	end
	basic.SetOnMessageHandler(LuaVMName,VM_OnMessage)
end

Start()




开发步骤

首先我们要使用云端通讯协议来控制CF-IOT设备下载您的LUA脚本固件,并启动LUA虚拟机运行脚本,LUA脚本固件应使用ZIP压缩包格式。

为了方便调试,我们将设备协议类型设置为MQTT,采用一台免费并可网页调试的MQTT服务器来完成相关功能测试。

MQTT调试网址:http://mqtt.p2hp.com/websocket/

CF-IOT云端通讯协议调试:https://blog.csdn.net/c1991786907/article/details/109570972

在MQTT调试页面,设置好订阅主题和发布主题,首先下发开发者密钥,鉴权成功后,我们就可以使用LUA虚拟机相关协议来调试和运行LUA脚本。

将以上demo程序压缩为zip格式文件,文件名可以随意,压缩包内目录结构如下:

下载LUA脚本

{
	"channel": "LuaVM_Upgrading",
	"DeviceNo": "864977047765106",
	"Data": {
		"URL": "http://www.***/lua.zip"
	}
}

下载结果会以事件上行

{
	"channel": "LuaVM_onEvent",
	"DeviceNo": "862607059076223",
	"Data": {
		"EventName": "LuaVM_Upgrading_Success",
		"Message": ""
	}
}

启动虚拟机

{
	"channel": "LuaVM_Load",
	"DeviceNo": "862607059076223",
	"Data": null
}

停止虚拟机

{
	"channel": "LuaVM_Stop",
	"DeviceNo": "862607059076223",
	"Data": null
}

脚本清除

{
	"channel": "LuaVM_Clear",
	"DeviceNo": "862607059076223",
	"Data": null
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值