5. 20 晴 今天的太阳挺大的,晒得我进园区直接37. 3警告,于是我百度搜索微信朋友圈怎么关闭,才把温度稳定下来。算了算了,上班说事
由于公司部门调动,逐渐接触到新的知识,新的模块;还听说这玩意比较冷门,没办法,该搞还是得搞,又不是搞不了,下面就最近一个多月的研究写点东西,废话不多说,实操起来。
一、LUCI的MVC
要实现一个简单的自定义web界面,完成基本的配置需求,其实只需要用到控制层+model层的业务代码,view层的htm暂时可放一边。
- 知识背景,预备工作
先看看新安装的openwrt软路由界面,
下图所示版本的软路由下载地址是:http://firmware.koolshare.cn/LEDE_X64_fw867/
具体的安装配置可以参考:
https://blog.csdn.net/qq_41953807/article/details/106118556
搭建好后,访问web界面得到如下图
这款固件的web主题有三种,上述是默认的,菜单栏在左侧,修改主题可按上图1->2->3->4进行设置,保存并应用。 - 需求说明
现在需要在原有的菜单上新增一块栏目,并设置菜单项,每个菜单项具有自己的配置,并实现web与固件的读写操作。下面开始代码部分 - 进入openwrt的命令行
openwrt其实就是小型的Linux,具备Linux常用的操作命令,luci安装的目录在 /usr/lib/lua/luci
- controller控制层
cd 进入controller/admin目录,在此处新建一个terminal.lua文件(vi命令和touch命令均可)
文件内容如下:
--terminal.lua
module("luci.controller.admin.terminal",package.seeall)
function index()
local page=node('admin','terminal')
page.target=firstchild()
page.title=_('终端采集系统')
page.order=70
page.index=true
entry({"admin","terminal"},alias("admin","terminal","site-manager"),_("终端采集系统"),50).index=true
entry({"admin","terminal","site-manager"},cbi("admin_terminal/site-manager"),_("站点管理"),1)
entry({"admin","terminal","args-modify"},cbi("admin_terminal/args-modify"),_("参数修改"),2)
entry({"admin","terminal","set"},cbi("admin_terminal/addtest"),_("Set"),3)
entry({"admin","terminal","addtest"},call("action_info"),_("Info"),4)
entry({"admin","terminal","testnixio"},template("test_nixio"),_("test nixio"),5)
end
function action_info()
if not nixio.fs.access("/tmp/addtest") then
return
end
local info = nixio.fs.readfile("/tmp/addtest")
luci.template.render("addtest_info",{info=info})
end
简略说明:page节点是挂在菜单栏上,新建一个自定义菜单用的。
entry是菜单项,其他的资料比较齐全,可自行查阅。
- model模型层的cbi
正如控制层entry指出的目录,进入model/cbi目录下,有样学样,新建admin_terminal目录,进入并新建args-modify.lua 和 site-manager.lua等文件
site-manager.lua 内容如下
--site-manager.lua
require("luci.sys")
m=Map("site-manager",translate("站点管理"),translate("终端采集系统的站点管理部分配置"))
m:chain("luci")
s=m:section(TypedSection,"site","配置SectionType为site,在/etc/config/site-manager中的test")
s.addremove=false
s.anonymous=true
s:option(Value,"site_id",translate("站点编号:"))
s:option(Value,"site_name",translate("站点名称:"))
s:option(Value,"site_addr",translate("地址:"))
s:option(Value,"site_longitude",translate("经度:"))
s:option(Value,"site_latitude",translate("纬度:"))
s:option(Value,"create_time",translate("创建日期:"))
s:option(Value,"device_addr",translate("设备地址:"))
s:option(Value,"subnet_mask",translate("子网掩码:"))
s:option(Value,"gateway",translate("网关:"))
s:option(Value,"server_addr",translate("服务器地址:"))
s:option(Value,"server_bak_addr",translate("备用服务器地址:"))
s:option(TextValue,"note",translate("备注:"))
return m
args-modify.lua 内容如下
--args-modify.lua
require("luci.sys")
m=Map("site-manager",translate("参数修改"),translate("终端采集系统的参数修改部分配置"))
--m:chain("luci")
local input_device_id="RWL1501023A140F10088"
b=m:section(TypedSection,"args","设备编号:"..input_device_id)
b.addremove=false
b.anonymous=true
--tag1=b:option(DummyValue,"pci","PCI1")
--b:option(Value,"work_freq_point",translate("hh"))
local str1=string.sub(input_device_id,8,9)
local str2=string.sub(input_device_id,10,10)
local str3=string.sub(input_device_id,11,11)
local num1=tonumber(str1,16)
local num2=tonumber(str2,16)
local num3=tonumber(str3,16)
local function band1()
b:tab("tab1","Band1(FDD)")
f1=b:taboption("tab1",Flag,"radio_freq_enable","射频开关")
v1=b:taboption("tab1",Value,"work_freq_point","工作频点")
v2=b:taboption("tab1",Value,"cell_band_width","小区带宽")
v3=b:taboption("tab1",Value,"pci","PCI")
v4=b:taboption("tab1",Value,"tac","TAC")
v5=b:taboption("tab1",Value,"cell_id","Cell ID")
v6=b:taboption("tab1",Value,"transmitting_power","发射功率")
v7=b:taboption("tab1",Value,"is_recapture","是否重新捕获")
v8=b:taboption("tab1",Value,"capture_time","重捕获时间(秒)")
v9=b:taboption("tab1",Value,"plmn","PLMN")
v10=b:taboption("tab1",Value,"is_redirect","是否重定向")
v11=b:taboption("tab1",Value,"redirect_type","重定向制式")
v12=b:taboption("tab1",Value,"tdd_sync_way","TDD同步方式")
v13=b:taboption("tab1",Value,"frame_head_offset","帧头偏移值")
f2=b:taboption("tab1",Flag,"auto_open_cell","开机自动开小区")
b1=b:taboption("tab1",Button,"btn_reboot","设备重启")
b1.inputtitle=translate("别点")
b1.inputstyle="apply"
end
local function band3()
b:tab("tab3","Band3(FDD)")
b:taboption("tab3",Flag,"enable","开关")
end
local function band5()
b:tab("tab5","Band5(FDD)")
b:taboption("tab5",Flag,"enable","开关")
end
local function band8()
b:tab("tab8","Band8(FDD)")
b:taboption("tab8",Flag,"enable","开关")
end
local function band34()
b:tab("tab34","Band34(TDD)")
b:taboption("tab34",Flag,"enable","开关")
end
local function band38()
b:tab("tab38","Band38(TDD)")
b:taboption("tab38",Flag,"enable","开关")
end
local function band39()
b:tab("tab39","Band39(TDD)")
b:taboption("tab39",Flag,"enable","开关")
end
local function band40()
b:tab("tab40","Band40(TDD)")
b:taboption("tab40",Flag,"enable","开关")
end
local function two2g()
b:tab("tab2g","2G")
b:taboption("tab2g",Flag,"enable","开关")
end
local function wifi()
b:tab("tabwifi","WI-FI")
b:taboption("tabwifi",Flag,"enable","开关")
end
if(num2==1) then
band1()
elseif(num2==2) then
band3()
elseif(num2==3) then
band1()
band3()
elseif(num2==4) then
band5()
elseif(num2==5) then
band1()
band5()
elseif(num2==6) then
band3()
band5()
elseif(num2==7) then
band1()
band3()
band5()
elseif(num2==8) then
band8()
elseif(num2==9) then
band1()
band8()
elseif(num2==10) then
band3()
band8()
elseif(num2==11) then
band1()
band3()
band8()
elseif(num2==12) then
band5()
band8()
elseif(num2==13) then
band1()
band5()
band8()
elseif(num2==14) then
band3()
band5()
band8()
elseif(num2==15) then
band1()
band3()
band5()
band8()
end
if(num3==1) then
band34()
elseif(num3==2) then
band38()
elseif(num3==3) then
band34()
band38()
elseif(num3==4) then
band39()
elseif(num3==5) then
band34()
band39()
elseif(num3==6) then
band38()
band39()
elseif(num3==7) then
band34()
band38()
band39()
elseif(num3==8) then
band40()
elseif(num3==9) then
band34()
band40()
elseif(num3==10) then
band38()
band40()
elseif(num3==11) then
band34()
band38()
band40()
elseif(num3==12) then
band39()
band40()
elseif(num3==13) then
band34()
band39()
band40()
elseif(num3==14) then
band38()
band39()
band40()
elseif(num3==15) then
band34()
band38()
band39()
band40()
end
if(num1==1) then
two2g()
elseif(num1==2) then
wifi()
elseif(num1==3) then
two2g()
wifi()
end
--设备重启按钮
if b1 then
local reboot = luci.http.formvalue("cbid.site-manager.test2.btn_reboot")
if reboot=="别点" then
b:option(DummyValue,"tuichu","重启中")
luci.sys.exec("/etc/init.d/uhttpd restart")
end
end
--保存并应用按钮
local apply = luci.http.formvalue("cbi.apply")
if apply then
luci.sys.exec("uci commit terminal")
end
--页面跳转示例
--local myurl=luci.dispatcher.build_url("admin/terminal/site-manager")
--luci.http.write("<script>location.href='"..myurl.."';</script>")
return m
addtest.lua内容
--addtest.lua
m=Map("addtest",translate("Luci practice"),translate("fager's test"))
s=m:section(TypedSection,"arguments","")
s.addremove=true
s.anonymous=false
s:option(Flag,"enable",translate("Enable"))
s:option(Value,"interval",translate("Interval"))
s:option(Value,"content",translate("Content"))
local apply=luci.http.formvalue("cbi.apply")
if apply then
--luci.sys.exec("/etc/init.d/addtestd start")
end
return m
- 该去写配置文件了
根据model层的代码,在创建Map的时候,第一个参数指定了配置文件的名称,而该配置文件的目录在/etc/config/下面
site-manager文件内容,这里可以用UCI命令进行操作,也可以vi,UCI命令资料挺多,自行查阅。
config site 'test'
option site_id '001'
option site_name '站点1'
option site_addr 'beijing'
option site_longitude '24.5'
option site_latitude '34.8'
option create_time '2020-04-24 15:41:20'
option device_addr '192.168.12.25'
option subnet_mask '255.255.0.0'
option gateway '192.168.12.1'
option server_addr '192.168.12.125'
option server_bak_addr '192.168.13.125'
option note '哈哈哈, 我改了'
config args 'test2'
option work_freq_point '375'
option radio_freq_enable '1'
option cell_band_width '5M'
option pci '123'
option tac '11'
option cell_id '002'
option transmitting_power '10W'
option is_recapture '是'
option plmn '46000'
option capture_time '1800'
option is_redirect '否'
option redirect_type 'oo'
option tdd_sync_way 'GPS/空口'
option frame_head_offset '0'
option auto_open_cell '1'
option aa '设备重启'
option btn_reboot '别点'
addtest 内容
config arguments
option enable '1'
option interval '2'
option content '555566'
- 看看页面效果
这下或许有的朋友来疑问了,最后一张图咋肥事,没有啊。回头看一下控制层的代码,其中一行是
entry({"admin","terminal","testnixio"},template("test_nixio"),_("test nixio"),5)
template,访问view层下面的.htm文件,所以最后还是走向了页面,下面来说说socket通讯与view。
- openwrt的socket通讯
在/usr/lib/lua目录下,我们还能看到nixio目录,查看我的另一篇博客
https://blog.csdn.net/qq_41953807/article/details/106146353大致知道是通过nixio.socket通讯,关于nixio的api可以参考
https://blog.csdn.net/qq_41953807/article/details/106131591
通过上述entry指定文件test_nixio.htm ,内容如下
<%+header%>
<%
local h=require "luci.http"
local c=require "luci.resttemplate"
-- h.write("Hello World</br>")
-- h.write("测试socket通信失败!<Br>")
-- h.write(c.send("luci web's page Client!"))
h.write(c.send(""))
%>
<%+footer%>
说明:lua是脚本语言,可在htm文件内直接使用<%%>进行引用。
阅读代码,其中luci.http是在/usr/lib/lua/luci目录下安装自带的http.lua文件;luci.resttemplate是我自定义的根据nixio编写的socket通讯简单工具类,能访问远程的服务,调用远程的接口!
同理,在/usr/lib/lua/luci目录下创建resttemplate.lua文件,内容如下:
--resttemplate.lua
core={}
local h=require "luci.http"
local n=require "nixio"
core.ip="192.168.80.192"
core.port=8080
core.uri="/users"
core.method="GET"
core.charset="UTF-8"
core.rcvTimeout=20
function core.get(name)
end
function core.httpData(data)
-- core.uri=string.upper(core.uri)
core.uri="/users"
return core.method.." "..core.uri.." HTTP/1.1\r\n"..
"Host: "..core.ip..":"..core.port.."\r\n"..
"Content-type: text/html;charset="..core.charset.."\r\n"..
"Accept-Language: zh-cn\r\n"..
"User-Agent: Mozilla/4.0(Compatible win32; MSIE)\r\n"..
"Content-Length: "..string.len(data).."\r\n"..
"Connection: close\r\n\r\n"..
data
end
function core.restData(method,uri,data,ip,port)
data=data or ""
method=method or "GET"
uri=uri or "/"
return method.." "..uri.." HTTP/1.1\r\n"..
"Accept: */*\r\n"..
"Accept-Encoding: gzip, deflate, br\r\n"..
"Accept-Language: zh-CN,zh;q=0.9\r\n"..
"Connection: keep-alive\r\n"..
"Host: "..ip..":"..port.."\r\n"..
"Content-Length: "..string.len(data).."\r\n"..
data
end
function core.testget(data)
socket:setopt("socket","rcvtimeo",timeout)
socket:send(core.httpData(data))
local tt={}
repeat
local tmp=socket:recv(100)
if tmp==false then
socket:close()
return false,"response timeout"
end
tmp=tostring(tmp)
local i= #tt
tt[i+1]=tmp
until #tmp < 1
socket:close()
return true,"success 200"
end
function core.send(data)
local position
local t={}
local http
local socket=nixio.socket("inet","stream")
local tmp
if not socket then
return false, "创建socket失败"
end
if not socket:connect(core.ip,core.port) then
socket:close()
return false, "服务无响应,连接服务器"..core.ip..":"..core.port.."失败"
end
socket:setopt("socket","rcvtimeo",core.rcvTimeout)
socket:send(core.httpData(data))
repeat
tmp=socket:recv(100)
if tmp==false then
socket:close()
return false,"响应超时"
end
tmp=tostring(tmp)
t[#t + 1] = tmp
until #tmp < 1
socket:close()
local result=table.concat(t)
position=string.find(result,"\r\n\r\n")
if position==nil then
return false,"返回的数据格式不合法。数据:"..result
end
result=string.sub(result,string.find(result,"\r\n\r\n")+4)
return result
end
--create a socket with ip,port,timeout
function core.socket(ip,port,timeout)
local socket=nixio.socket("inet","stream")
if not socket then
return false,"create socket('inet','stream') failed!"
end
if not socket:connect(ip,port) then
socket:close()
return false,"connect "..ip..":"..port.." failed!"
end
socket:setopt("socket","rcvtimeo",timeout)
return socket
end
function core.post()
end
return core
说明:此处参考了大佬的代码,
https://www.cnblogs.com/AUOONG/archive/2012/04/16/2451485.html
并根据自己对nixio和luci的相关api的理解,稍加改进,进行了一些验证。
- 验证
在本地IDEA上用tomcat启动了一个java编写的程序
就拿其中的最后一个GET请求作示例吧;
通过swagger点击测试,我们看到有返回数据的。
那现在不通过swagger页面点击,而是通过自己刚刚编写的test_nixio.htm页面进行访问,调用该接口试试:
点击test nixio,页面响应如下
可以看到页面也显示了响应的结果,完成了通讯。
但是多了69和0这两个数字。咋肥事呢?
下回分解: