-- 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.") .. "
" .. translate("Official website:") .. ' https://www.open-mesh.org/projects/batman-adv/wiki' ) function detect_Node() local data = {} local lps = luci.util.execi(" batctl n 2>/dev/null | tail +2 | sed 's/^[ ][ ]*//g' | sed 's/[ ][ ]*/ /g' | sed 's/$/ /g' ") for value in lps do local row = {} local pos = string.find(value, " ") local IFA = string.sub(value, 1, pos - 1) local value = string.sub(value, pos + 1, string.len(value)) pos = string.find(value, " ") local pos = string.find(value, " ") local Neighbora = string.sub(value, 1, pos - 1) local value = string.sub(value, pos + 1, string.len(value)) pos = string.find(value, " ") local pos = string.find(value, " ") local lastseena = string.sub(value, 1, pos - 1) local value = string.sub(value, pos + 1, string.len(value)) pos = string.find(value, " ") row["IF"] = IFA row["Neighbor"] = Neighbora row["lastseen"] = lastseena table.insert(data, row) end return data end function get_verbose_hw_info(iface) local type = iwinfo.type(iface) if not type then return "Unknown interface" 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 node") .. "" .. Nodes .. "") v:option(DummyValue, "IF", translate("IF")) v:option(DummyValue, "Neighbor", translate("Neighbor")) v:option(DummyValue, "lastseen", translate("lastseen")) -- 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 o.rmempty = false -- Move basic settings under the "Setup" tab o = s:taboption("setup", ListValue, "role", translate("Mesh Mode")) o:value("off", translate("Node")) o:value("server", translate("Server")) --o:value("client", translate("Client (advanced)")) o:depends("enabled", 1) o.rmempty = false 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:depends("enabled", 1) apRadio.rmempty = false apRadio.widget = "select" o = s:taboption("setup", Value, "mesh_id", translate("Mesh SSID")) o.default = "easymesh_AC" o:depends("enabled", 1) encryption = s:taboption("setup", Flag, "encryption", translate("Encryption WIP DROPDOWN"), translate("")) encryption.default = 0 encryption.rmempty = false encryption:depends("enabled", 1) o = s:taboption("setup", Value, "key", translate("Mesh Password")) o.default = "easymesh" o:depends({enabled = "1", encryption = "1"}) o.password = true -- Move K/V/R settings to the "Advanced" tab enable_kvr = s:taboption("advanced", Flag, "kvr", translate("K/V/R"), translate("Enable Key Value Roaming")) enable_kvr.default = 1 enable_kvr.rmempty = false 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))" mobility_domain:depends("kvr", 1) rssi_val = s:taboption("advanced", Value, "rssi_val", translate("Threshold for a good RSSI")) rssi_val.default = "-60" --rssi_val.datatype = "range(-1,-120)" rssi_val:depends("kvr", 1) 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)" low_rssi_val:depends("kvr", 1) ---- 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, "gateway", 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") btnAPMode = s:taboption("apmode", Button, "_btn_apmode", translate("Join Mesh Network"), translate("WARNING: THIS WILL CHANGE THIS NODE'S IP ADDRESS, YOU WILL LOOSE ACCESS TO THIS UI")) function btnAPMode.write() luci.sys.call("/easymesh/easymesh.sh apmode") end btnAPMode:depends("role", "off") ---- ip address --o = s:option(Value, "ipaddr", translate("Static IP Address")) --o.default = "192.168.8.2" --o.datatype = "ip4addr" --o:depends("ap_mode", 1) -- o = s:option(Value, "dns", translate("Mesh Gateway IP Address")) -- o.default = "192.168.8.1" -- o.datatype = "ip4addr" -- o:depends("ap_mode", 1) -- o = s:option(Value, "netmask", translate("IPv4 netmask")) -- o.default = "255.255.255.0" -- o.datatype = "ip4addr" -- o:depends("ap_mode", 1) -- MESH Node Control: apply mesh settings ctrl = m:section(TypedSection, "easymesh", "Click Save Then Enable or Disable Your Mesh WiFi settings") ctrl.anonymous = true ctrl.addremove = false function m.on_after_commit(self) local enabled = m:formvalue("cbid.easymesh.easymesh.enabled") if enabled and enabled == "1" then luci.sys.call("/easymesh/easymesh.sh start &") else luci.sys.call("/easymesh/easymesh.sh stop &") end end function o.write(self, section, value) Flag.write(self, section, value) -- Run init start -- luci.sys.call("uci commit") -- luci.sys.call("/etc/init.d/easymesh start &") end return m