-- 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 = {} -- 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 local 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) or "Unknown hardware" local hw_modes = driver.hwmodelist and driver.hwmodelist(iface) or {} local supported_modes = {} for mode, supported in pairs(hw_modes) do if supported then supported_modes[#supported_modes + 1] = mode end end return hw_name .. " (" .. (#supported_modes > 0 and table.concat(supported_modes, "/") or "No mode information") .. ")" 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("Mesh Status") ,"" .. translate("Number of Active Nodes: ") .. Nodes .. "") v:option(DummyValue, "IF", translate("Interface")) v:option(DummyValue, "Neighbor", translate("Neighbor Nodes")) v:option(DummyValue, "lastseen", translate("Last Seen Timestamp")) s = m:section(TypedSection, "easymesh", translate("Mesh Settings")) s.anonymous = 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 Mesh Networking"), translate('

Toggle this switch to activate or deactivate the Mesh Network on this device according to the settings specified in this configuration. Make sure to configure all necessary settings before enabling the Mesh Network.

Changes will apply when you click Save and Apply

')) o.default = 0 -- Move basic settings under the "Setup" tab o = s:taboption("setup", ListValue, "role", translate("Mesh Mode"), translate('

Choose the role this device will play in your mesh network. There are two options available:

1. Server: If you select this option, this device will act as the Mesh Gateway Server. The server manages the routing of data in the network and handles connections to the internet. It is the central point of your mesh network.

2. Node: The device functions as a Mesh Node if this option is selected. Nodes connect to the Mesh Gateway Server and other nodes to extend the range of the network. Nodes can also route traffic between each other to increase network efficiency.

Remember to set up the Mesh Gateway Server first before setting up the nodes.

')) o:value("server", translate("Server")) o:value("off", translate("Node")) o:value("client", translate("Client")) o.default = "server" apRadio = s:taboption("setup", MultiValue, "apRadio", translate("Mesh Radio(s)"), translate('

Select one or multiple radio interfaces to be used for the mesh network. Each selected radio interface will be configured to participate in the mesh network, extending its range and improving its resilience. By using multiple radios, your mesh network can balance the network load and handle a larger number of connected devices.

Ensure the radios you select support mesh networking

')) 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 Network SSID"), translate('

Ensure that the SSID is the same across all the servers/nodes in your mesh network.

')) o.default = "easymesh_AC" encryption = s:taboption("setup", Flag, "encryption", translate("Password Protection"), translate('

Enable this switch to require a password to join your Mesh Network.

')) encryption.default = 0 o = s:taboption("setup", Value, "key", translate("Mesh Password")) o.default = "easymesh" o:depends("encryption", 1) o.password = true o.datatype = "minlength(8)" btnReapply = s:taboption("setup", Button, "_btn_reapply", translate("Reapply EasyMesh Settings"), translate('

Use this button to apply/reapply EasyMesh configuration after you Save & Apply.

')) function btnReapply.write() io.popen("/easymesh/easymesh.sh &") end enable_kvr = s:taboption("advanced", Flag, "kvr", translate("K/V/R"), translate('

Leave these settings as default unless you know what you\'re doing

')) enable_kvr.default = 1 mobility_domain = s:taboption("advanced", Value, "mobility_domain", translate("Mobility Domain")) mobility_domain.default = "4f57" mobility_domain.datatype = "and(hexstring,rangelength(4,4))" rssi_val = s:taboption("advanced", Value, "rssi_val", translate("Good RSSI Threshold")) rssi_val.default = "-60" rssi_val.datatype = "range(-120,-1)" low_rssi_val = s:taboption("advanced", Value, "low_rssi_val", translate("Bad RSSI Threshold")) low_rssi_val.default = "-88" low_rssi_val.datatype = "range(-120,-1)" ---- 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",role="client"}) -- 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",role="client"}) -- 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",role="client"}) -- DNS (Mesh Gateway IP Address) o = s:taboption("apmode", Value, "gateway", translate("Mesh Gateway IP Address")) o.default = "192.168.70.1" o.datatype = "ip4addr" o:depends({ipmode="static",role="off",role="client"}) -- 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",role="client"}) -- IPv4 netmask o = s:taboption("apmode", Value, "dns", translate("DNS Server")) o.default = "192.168.70.1" o.datatype = "ip4addr" o:depends({ipmode="static",role="off"role="client"}) 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() io.popen("/easymesh/easymesh.sh dumbap &") end btnAPMode:depends({role="off",role="client"}) return m