-- PrivateRouter Easy Mesh
local m , s , o
local sys = require " luci.sys "
local uci = require " luci.model.uci " . cursor ( )
local iwinfo = require " iwinfo "
m = Map ( " easymesh " ,
translate ( " Easy Mesh WiFi Setup " ) ,
translate ( " Powered by Batman-adv (Better Approach To Mobile Adhoc Networking - Advanced). First setup your Mesh Gateway Server then setup the nodes. When configuring a Mesh Node, first activate your mesh WiFi on the radio device and establish a connection. Then enable it as a DHCP node. The default settings are typically adequate for most Mesh WiFi configurations. " )
.. " <br/> " .. translate ( " Official website: " ) .. ' <a href="https://www.open-mesh.org/projects/batman-adv/wiki" target="_blank">https://www.open-mesh.org/projects/batman-adv/wiki</a> '
)
function detect_Node ( )
local data = { }
-- Streamline the command to retrieve node information
local lps = luci.util . execi ( " batctl n 2>/dev/null | tail +2 | sed 's/^[ ]*//;s/[ ]*/ /g' " )
for line in lps do
-- Split the line into parts using pattern matching
local ifa , neighbor , lastseen = string.match ( line , " (%S+) (%S+) (%S+) " )
if ifa and neighbor and lastseen then
-- Construct the row and add it to the data table
local row = { [ " IF " ] = ifa , [ " Neighbor " ] = neighbor , [ " lastseen " ] = lastseen }
table.insert ( data , row )
end
end
return data
end
function get_verbose_hw_info ( iface )
local type = iwinfo.type ( iface )
if not type then
return " Generic "
end
local driver = iwinfo [ type ]
if not driver then
return " Driver not supported "
end
local hw_name = driver.hardware_name and driver.hardware_name ( iface )
if not hw_name or hw_name == " " then
hw_name = " Unknown hardware "
end
local hw_modes = driver.hwmodelist and driver.hwmodelist ( iface )
local supported_modes = { }
if hw_modes then
for mode , supported in pairs ( hw_modes ) do
if supported then
table.insert ( supported_modes , mode )
end
end
end
if # supported_modes == 0 then
supported_modes_str = " No mode information "
else
supported_modes_str = table.concat ( supported_modes , " / " )
end
local verbose_info = hw_name .. " ( " .. supported_modes_str .. " ) "
return verbose_info
end
local Nodes = luci.sys . exec ( " batctl n 2>/dev/null| tail +3 | wc -l " )
local Node = detect_Node ( )
v = m : section ( Table , Node , translate ( " Active Nodes " ) , " <b> " .. translate ( " Number of Active Nodes: " ) .. Nodes .. " </b> " )
v : option ( DummyValue , " IF " , translate ( " Interface " ) )
v : option ( DummyValue , " Neighbor " , translate ( " Neighbor Nodes " ) )
v : option ( DummyValue , " lastseen " , translate ( " Last Seen Timestamp " ) )
-- Basic
s = m : section ( TypedSection , " easymesh " , translate ( " Mesh Gateway & Node WiFi Settings " ) , translate ( " Choose Mesh Gateway or Mesh Node WiFi Settings: Begin by completing this section on your mesh server and nodes. Ensure each radio's WiFi network name is consistent. For example: easymesh_AC, easymesh_N. " ) )
s.anonymous = true
-- Connection Type Dropdown
--o = s:option(ListValue, "backbone", translate("Connection Type"), translate("Choose if Node or Gateway is connected to internet by LAN or WiFi"))
--o:value("lan", translate("LAN"))
--o:value("wifi", translate("WiFi"))
--o.default = "lan"
--o.rmempty = false
-- AP Name
--apn = s:option(Value, "apname", translate("AP Name"), translate("Enter the client WiFi AP name"))
--apn:depends("backbone", "wifi")
--apn.placeholder = "easymesh_AC"
--apn.rmempty = true
-- AP Password
--app = s:option(Value, "appass", translate("AP Password"), translate("Enter the client WiFi AP password"))
--app:depends("backbone", "wifi")
--app.password = true
--app.placeholder = "easymesh"
--app.rmempty = true
s : tab ( " setup " , translate ( " Basic Setup " ) )
s : tab ( " apmode " , translate ( " AP Mode " ) )
s : tab ( " advanced " , translate ( " Advanced Settings " ) )
---- Eanble
o = s : taboption ( " setup " , Flag , " enabled " , translate ( " Enable " ) )
o.default = 0
-- Move basic settings under the "Setup" tab
o = s : taboption ( " setup " , ListValue , " role " , translate ( " Mesh Mode " ) )
o : value ( " server " , translate ( " Server " ) )
o : value ( " off " , translate ( " Node " ) )
o.default = " server "
--o:value("client", translate("Client (advanced)"))
apRadio = s : taboption ( " setup " , MultiValue , " apRadio " , translate ( " Mesh Radio(s) " ) )
uci : foreach ( " wireless " , " wifi-device " ,
function ( s )
local iface = s [ ' .name ' ]
local hw_modes = get_verbose_hw_info ( iface )
local desc = string.format ( " %s (%s) " , iface , hw_modes )
apRadio : value ( iface , desc ) -- Display radio interface with its hardware modes
end )
apRadio.default = " radio0 "
apRadio.widget = " select "
o = s : taboption ( " setup " , Value , " mesh_id " , translate ( " Mesh SSID " ) )
o.default = " easymesh_AC "
encryption = s : taboption ( " setup " , Flag , " encryption " , translate ( " Enable Password " ) , translate ( " " ) )
encryption.default = 0
o = s : taboption ( " setup " , Value , " key " , translate ( " Mesh Password " ) )
o.default = " easymesh "
o : depends ( " encryption " , 1 )
o.password = true
enable_kvr = s : taboption ( " advanced " , Flag , " kvr " , translate ( " K/V/R " ) , translate ( " Enable Key Value Roaming " ) )
enable_kvr.default = 1
mobility_domain = s : taboption ( " advanced " , Value , " mobility_domain " , translate ( " Mobility Domain " ) , translate ( " 4-character hexadecimal ID " ) )
mobility_domain.default = " 4f57 "
--mobility_domain.datatype = "and(hexstring,rangelength(4,4))"
rssi_val = s : taboption ( " advanced " , Value , " rssi_val " , translate ( " Threshold for a good RSSI " ) )
rssi_val.default = " -60 "
--rssi_val.datatype = "range(-1,-120)"
low_rssi_val = s : taboption ( " advanced " , Value , " low_rssi_val " , translate ( " Threshold for a bad RSSI " ) )
low_rssi_val.default = " -88 "
--low_rssi_val.datatype = "range(-1,-120)"
---- Apply MESH settings
--ctrl = m:section(TypedSection, "easymesh", "Apply Mesh WiFi Settings to Server or Node")
--ctrl.anonymous = true
--ctrl.addremove = false
----btnStop = ctrl:option(Button, "_btn_start", translate("Apply Mesh WiFi Settings"))
--function btnStop.write()
-- io.popen("/etc/init.d/easymesh start")
--end
---- 802.11F
--enable = s:option(Flag, "iapp", translate("inter-access point protocol"), translate("Wireless Access Points (APs) running on different vendors can communicate with each other"))
--enable.default = 0
--enable.rmempty = false
-- NodeMode
-- s = m:section(TypedSection, "easymesh", translate("Enable Router as DHCP Mesh Node"), translate("Set up Easy Mesh WiFi on your server and nodes first. All mesh nodes will utilize your mesh server for DHCP. "))
-- s.anonymous = true
---- ap_mode
o = s : taboption ( " apmode " , Value , " hostname " , translate ( " Node Hostname " ) )
o.default = " node2 "
o : value ( " node2 " , " node2 " )
o : value ( " node3 " , " node3 " )
o : value ( " node4 " , " node4 " )
o : value ( " node5 " , " node5 " )
o : value ( " node6 " , " node6 " )
o : value ( " node7 " , " node7 " )
o : value ( " node8 " , " node8 " )
o : value ( " node9 " , " node9 " )
o.datatype = " string "
o : depends ( " role " , " off " )
-- IP Mode (DHCP or Static)
ipmode = s : taboption ( " apmode " , ListValue , " ipmode " , translate ( " IP Mode " ) , translate ( " Choose if the node uses DHCP or a Static IP " ) )
ipmode : value ( " dhcp " , translate ( " DHCP " ) )
ipmode : value ( " static " , translate ( " Static " ) )
ipmode.default = " dhcp "
ipmode : depends ( " role " , " off " )
-- Static IP address
o = s : taboption ( " apmode " , Value , " ipaddr " , translate ( " Static IP Address " ) )
o.default = " 192.168.70.254 "
o.datatype = " ip4addr "
o : depends ( { ipmode = " static " , role = " off " } )
-- DNS (Mesh Gateway IP Address)
o = s : taboption ( " apmode " , Value , " gatewayIP " , translate ( " Mesh Gateway IP Address " ) )
o.default = " 192.168.70.1 "
o.datatype = " ip4addr "
o : depends ( { ipmode = " static " , role = " off " } )
-- IPv4 netmask
o = s : taboption ( " apmode " , Value , " netmask " , translate ( " IPv4 netmask " ) )
o.default = " 255.255.255.0 "
o.datatype = " ip4addr "
o : depends ( { ipmode = " static " , role = " off " } )
btnAPMode = s : taboption ( " apmode " , Button , " _btn_apmode " , translate ( " Enable Dumb AP Mode " ) , translate ( " WARNING: THIS WILL CHANGE THIS NODE'S IP ADDRESS, YOU WILL LOOSE ACCESS TO THIS UI " ) )
function btnAPMode . write ( )
luci.sys . call ( " /easymesh/dumbap.sh " )
end
btnAPMode : depends ( " role " , " off " )
m.on_before_apply = function ( self )
local enabled = m : formvalue ( " cbid.easymesh.config.enabled " )
if enabled and enabled == " 1 " then
luci.sys . call ( " /easymesh/easymesh.sh enable & " )
else
luci.sys . call ( " /easymesh/easymesh.sh disable & " )
end
end
return m