diff options
Diffstat (limited to 'applications/luci-app-dawn')
10 files changed, 276 insertions, 196 deletions
diff --git a/applications/luci-app-dawn/Makefile b/applications/luci-app-dawn/Makefile index a216f28187..10877fad15 100644 --- a/applications/luci-app-dawn/Makefile +++ b/applications/luci-app-dawn/Makefile @@ -1,7 +1,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI support for DAWN -LUCI_DEPENDS:=+luci-base +dawn +luci-compat +luci-lib-json +LUCI_DEPENDS:=+luci-base +dawn include ../../luci.mk diff --git a/applications/luci-app-dawn/htdocs/luci-static/resources/dawn/dawn-common.js b/applications/luci-app-dawn/htdocs/luci-static/resources/dawn/dawn-common.js new file mode 100644 index 0000000000..5d002d9b7f --- /dev/null +++ b/applications/luci-app-dawn/htdocs/luci-static/resources/dawn/dawn-common.js @@ -0,0 +1,69 @@ +'use strict'; +'require baseclass'; +'require rpc'; + +let callDawnGetNetwork, callDawnGetHearingMap, callHostHints; + +callDawnGetNetwork = rpc.declare({ + object: 'dawn', + method: 'get_network', + expect: { } +}); + +callDawnGetHearingMap = rpc.declare({ + object: 'dawn', + method: 'get_hearing_map', + expect: { } +}); + +callHostHints = rpc.declare({ + object: 'luci-rpc', + method: 'getHostHints', + expect: { } +}); + +function getAvailableText(available) { + return ( available ? _('Available') : _('Not available') ); +} + +function getChannelFromFrequency(freq) { + if (freq <= 2400) { + return 0; + } + else if (freq == 2484) { + return 14; + } + else if (freq < 2484) { + return (freq - 2407) / 5; + } + else if (freq >= 4910 && freq <= 4980) { + return (freq - 4000) / 5; + } + else if (freq <= 45000) { + return (freq - 5000) / 5; + } + else if (freq >= 58320 && freq <= 64800) { + return (freq - 56160) / 2160; + } + else { + return 0; + } +} + +function getFormattedNumber(num, decimals, divider = 1) { + return (num/divider).toFixed(decimals); +} + +function getHostnameFromMAC(hosthints, mac) { + return ( hosthints[mac] && hosthints[mac].name ? hosthints[mac].name : mac); +} + +return L.Class.extend({ + callDawnGetNetwork: callDawnGetNetwork, + callDawnGetHearingMap: callDawnGetHearingMap, + callHostHints: callHostHints, + getAvailableText: getAvailableText, + getChannelFromFrequency: getChannelFromFrequency, + getFormattedNumber: getFormattedNumber, + getHostnameFromMAC: getHostnameFromMAC +}); diff --git a/applications/luci-app-dawn/htdocs/luci-static/resources/view/dawn/hearing_map.js b/applications/luci-app-dawn/htdocs/luci-static/resources/view/dawn/hearing_map.js new file mode 100644 index 0000000000..ea2aa67998 --- /dev/null +++ b/applications/luci-app-dawn/htdocs/luci-static/resources/view/dawn/hearing_map.js @@ -0,0 +1,78 @@ +'use strict'; +'require uci'; +'require view'; +'require dawn.dawn-common as dawn'; + +return view.extend({ + handleSaveApply: null, + handleSave: null, + handleReset: null, + + load: function() { + return Promise.all([ + dawn.callDawnGetHearingMap(), + dawn.callHostHints() + ]); + }, + + render: function(data) { + + const dawnHearingMapData = data[0]; + const hostHintsData = data[1]; + + const body = E([ + E('h2', _('Hearing Map')) + ]); + + for (let network in dawnHearingMapData) { + + body.appendChild( + E('h3', 'SSID: ' + network) + ); + + let hearing_map_table = E('table', { 'class': 'table cbi-section-table' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', { 'class': 'th' }, _('Client')), + E('th', { 'class': 'th' }, _('Access Point')), + E('th', { 'class': 'th' }, _('Frequency')), + E('th', { 'class': 'th' }, E('span', { 'data-tooltip': _('High Throughput') }, [ _('HT') ])), + E('th', { 'class': 'th' }, E('span', { 'data-tooltip': _('Very High Throughput') }, [ _('VHT') ])), + E('th', { 'class': 'th' }, _('Signal')), + E('th', { 'class': 'th' }, E('span', { 'data-tooltip': _('Received Channel Power Indication') }, [ _('RCPI') ])), + E('th', { 'class': 'th' }, E('span', { 'data-tooltip': _('Received Signal to Noise Indicator') }, [ _('RSNI') ])), + E('th', { 'class': 'th' }, _('Channel Utilization')), + E('th', { 'class': 'th' }, _('Stations Connected')), + E('th', { 'class': 'th' }, _('Score')) + ]) + ]); + + let clients = Object.entries(dawnHearingMapData[network]).map(function(client) { + + return Object.entries(client[1]).map(function(ap) { + + if (ap[1].freq != 0) { + return [ + dawn.getHostnameFromMAC(hostHintsData, client[0]), + dawn.getHostnameFromMAC(hostHintsData, ap[0]), + dawn.getFormattedNumber(ap[1].freq, 3, 1000) + ' GHz (' + _('Channel') + ': ' + dawn.getChannelFromFrequency(ap[1].freq) + ')', + dawn.getAvailableText(ap[1].ht_capabilities && ap[1].ht_support), + dawn.getAvailableText(ap[1].vht_capabilities && ap[1].vht_support), + ap[1].signal, + ap[1].rcpi, + ap[1].rsni, + dawn.getFormattedNumber(ap[1].channel_utilization, 2, 2.55) + '%', + ap[1].num_sta, + ap[1].score + ] + } + }).flat() + + }); + + cbi_update_table(hearing_map_table, clients, E('em', _('No clients connected.'))); + + body.appendChild(hearing_map_table); + } + return body; + } +}); diff --git a/applications/luci-app-dawn/htdocs/luci-static/resources/view/dawn/network_overview.js b/applications/luci-app-dawn/htdocs/luci-static/resources/view/dawn/network_overview.js new file mode 100644 index 0000000000..71133991ab --- /dev/null +++ b/applications/luci-app-dawn/htdocs/luci-static/resources/view/dawn/network_overview.js @@ -0,0 +1,93 @@ +'use strict'; +'require uci'; +'require view'; +'require dawn.dawn-common as dawn'; + +return view.extend({ + handleSaveApply: null, + handleSave: null, + handleReset: null, + + load: function() { + return Promise.all([ + dawn.callDawnGetNetwork(), + dawn.callHostHints() + ]); + }, + + render: function(data) { + + const dawnNetworkData = data[0]; + const hostHintsData = data[1]; + + const body = E([ + E('h2', _('Network Overview')) + ]); + + let client_table = {}; + + for (let network in dawnNetworkData) { + + body.appendChild( + E('h3', 'SSID: ' + network) + ); + + let ap_table = E('table', { 'class': 'table cbi-section-table' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', { 'class': 'th left cbi-section-actions' }, _('Access Point')), + E('th', { 'class': 'th left cbi-section-actions' }, _('Interface')), + E('th', { 'class': 'th left cbi-section-actions' }, _('MAC')), + E('th', { 'class': 'th left cbi-section-actions' }, _('Utilization')), + E('th', { 'class': 'th left cbi-section-actions' }, _('Frequency')), + E('th', { 'class': 'th left cbi-section-actions' }, _('Stations Connected')), + E('th', { 'class': 'th left cbi-section-actions' }, E('span', { 'data-tooltip': _('High Throughput') }, [ _('HT') ])), + E('th', { 'class': 'th left cbi-section-actions' }, E('span', { 'data-tooltip': _('Very High Throughput') }, [ _('VHT') ])), + E('th', { 'class': 'th center cbi-section-actions' }, _('Clients')), + ]) + ]); + + let aps = Object.entries(dawnNetworkData[network]).map(function(ap) { + client_table[ap[0]] = E('table', { 'class': 'table cbi-section-table', 'style': 'display: table' }, [ + E('tr', { 'class': 'tr table-titles' }, [ + E('th', { 'class': 'th' }, _('Client')), + E('th', { 'class': 'th' }, E('span', { 'data-tooltip': _('High Throughput') }, [ _('HT') ])), + E('th', { 'class': 'th' }, E('span', { 'data-tooltip': _('Very High Throughput') }, [ _('VHT') ])), + E('th', { 'class': 'th' }, _('Signal')) + ]) + ]); + + let clients = []; + let clientData = Object.entries(ap[1]); + for (let i = 0; i < clientData.length; i++) { + if (typeof clientData[i][1] === 'object') { + clients.push([ + dawn.getHostnameFromMAC(hostHintsData ,clientData[i][0]), + dawn.getAvailableText(clientData[i][1].ht), + dawn.getAvailableText(clientData[i][1].vht), + clientData[i][1].signal + ]); + } + } + + cbi_update_table(client_table[ap[0]], clients, E('em', _('No clients connected.'))); + + return [ + ap[1].hostname, + ap[1].iface, + ap[0], + dawn.getFormattedNumber(ap[1].channel_utilization, 2, 2.55) + '%', + dawn.getFormattedNumber(ap[1].freq, 3, 1000) + ' GHz (' + _('Channel') + ': ' + dawn.getChannelFromFrequency(ap[1].freq) + ')', + ap[1].num_sta, + dawn.getAvailableText(ap[1].ht_support), + dawn.getAvailableText(ap[1].vht_support), + ap[1].num_sta > 0 ? client_table[ap[0]] : E('em', { 'style': 'display: inline' }, _('No clients connected.')) + ] + }); + + cbi_update_table(ap_table, aps, E('em', _('No access points available.'))); + + body.appendChild(ap_table); + } + return body; + } +}); diff --git a/applications/luci-app-dawn/luasrc/controller/dawn.lua b/applications/luci-app-dawn/luasrc/controller/dawn.lua deleted file mode 100644 index 1ae903f3a4..0000000000 --- a/applications/luci-app-dawn/luasrc/controller/dawn.lua +++ /dev/null @@ -1,10 +0,0 @@ -module("luci.controller.dawn", package.seeall) - -function index() - local e = entry({ "admin", "dawn" }, firstchild(), "DAWN", 60) - e.dependent = false - e.acl_depends = { "luci-app-dawn" } - - entry({ "admin", "dawn", "view_network" }, cbi("dawn/dawn_network"), "View Network Overview", 1) - entry({ "admin", "dawn", "view_hearing_map" }, cbi("dawn/dawn_hearing_map"), "View Hearing Map", 2) -end diff --git a/applications/luci-app-dawn/luasrc/model/cbi/dawn/dawn_hearing_map.lua b/applications/luci-app-dawn/luasrc/model/cbi/dawn/dawn_hearing_map.lua deleted file mode 100644 index 3ba5329855..0000000000 --- a/applications/luci-app-dawn/luasrc/model/cbi/dawn/dawn_hearing_map.lua +++ /dev/null @@ -1,70 +0,0 @@ -m = Map("dawn", "Hearing Map", translate("Hearing Map")) -m.pageaction = false - -s = m:section(NamedSection, "__hearingmap__") - -function s.render(self, sid) - local tpl = require "luci.template" - tpl.render_string([[ - <% - local utl = require "luci.util" - local xml = require "luci.xml" - local status = require "luci.tools.ieee80211" - local stat = utl.ubus("dawn", "get_hearing_map", { }) - local name, macs - - for name, macs in pairs(stat) do - %> - <div class="cbi-section-node"> - <h3>SSID: <%= xml.pcdata(name) %></h3> - <table class="table" id="dawn_hearing_map"> - <tr class="tr table-titles"> - <th class="th">Client MAC</th> - <th class="th">AP MAC</th> - <th class="th">Frequency</th> - <th class="th">HT Sup</th> - <th class="th">VHT Sup</th> - <th class="th">Signal</th> - <th class="th">RCPI</th> - <th class="th">RSNI</th> - <th class="th">Channel Utilization</th> - <th class="th">Station connect to AP</th> - <th class="th">Score</th> - </tr> - <% - local mac, data - for mac, data in pairs(macs) do - - local mac2, data2 - local count_loop = 0 - for mac2, data2 in pairs(data) do - if data2.freq ~= 0 then --prevent empty entry crashes - %> - <tr class="tr"> - <td class="td"><%= (count_loop == 0) and mac or "" %></td> - <td class="td"><%= mac2 %></td> - <td class="td"><%= "%.3f" %( data2.freq / 1000 ) %> GHz Channel: <%= "%d" %( status.frequency_to_channel(data2.freq) ) %></td> - <td class="td"><%= (data2.ht_capabilities == true and data2.ht_support == true) and "True" or "False" %></td> - <td class="td"><%= (data2.vht_capabilities == true and data2.vht_support == true) and "True" or "False" %></td> - <td class="td"><%= "%d" % data2.signal %></td> - <td class="td"><%= "%d" % data2.rcpi %></td> - <td class="td"><%= "%d" % data2.rsni %></td> - <td class="td"><%= "%.2f" % (data2.channel_utilization / 2.55) %> %</td> - <td class="td"><%= "%d" % data2.num_sta %></td> - <td class="td"><%= "%d" % data2.score %></td> - </tr> - <% - count_loop = count_loop + 1 - end - end - end - %> - </table> - </div> - <% - end - %> - ]]) -end - -return m diff --git a/applications/luci-app-dawn/luasrc/model/cbi/dawn/dawn_network.lua b/applications/luci-app-dawn/luasrc/model/cbi/dawn/dawn_network.lua deleted file mode 100644 index f9e04b90cb..0000000000 --- a/applications/luci-app-dawn/luasrc/model/cbi/dawn/dawn_network.lua +++ /dev/null @@ -1,94 +0,0 @@ -m = Map("dawn", "Network Overview", translate("Network Overview")) -m.pageaction = false - -s = m:section(NamedSection, "__networkoverview__") - -function s.render(self, sid) - local tpl = require "luci.template" - local json = require "luci.json" - local utl = require "luci.util" - tpl.render_string([[ - <% - local status = require "luci.tools.ieee80211" - local utl = require "luci.util" - local sys = require "luci.sys" - local xml = require "luci.xml" - local hosts = sys.net.host_hints() - local stat = utl.ubus("dawn", "get_network", { }) - local name, macs - for name, macs in pairs(stat) do - %> - <div class="cbi-section-node"> - <h3>SSID: <%= xml.pcdata(name) %></h3> - <table class="table" id="network_overview_main"> - <tr class="tr table-titles"> - <th class="th">AP</th> - <th class="th">Clients</th> - </tr> - <% - local mac, data - for mac, data in pairs(macs) do - %> - <tr class="tr"> - <td class="td" style="vertical-align: top;"> - <table class="table" id="ap-<%= mac %>"> - <tr class="tr table-titles"> - <th class="th">Hostname</th> - <th class="th">Interface</th> - <th class="th">MAC</th> - <th class="th">Utilization</th> - <th class="th">Frequency</th> - <th class="th">Stations</th> - <th class="th">HT Sup</th> - <th class="th">VHT Sup</th> - </tr> - <tr class="tr"> - <td class="td"><%= xml.pcdata(data.hostname) %></td> - <td class="td"><%= xml.pcdata(data.iface) %></td> - <td class="td"><%= mac %></td> - <td class="td"><%= "%.2f" %(data.channel_utilization / 2.55) %> %</td> - <td class="td"><%= "%.3f" %( data.freq / 1000 ) %> GHz (Channel: <%= "%d" %( status.frequency_to_channel(data.freq) ) %>)</td> - <td class="td"><%= "%d" % data.num_sta %></td> - <td class="td"><%= (data.ht_support == true) and "available" or "not available" %></td> - <td class="td"><%= (data.vht_support == true) and "available" or "not available" %></td> - </tr> - </table> - </td> - <td class="td" style="vertical-align: top;"> - <table class="table" id="clients-<%= mac %>"> - <tr class="tr table-titles"> - <th class="th">MAC</th> - <th class="th">HT</th> - <th class="th">VHT</th> - <th class="th">Signal</th> - </tr> - <% - local mac2, data2 - for clientmac, clientvals in pairs(data) do - if (type(clientvals) == "table") then - %> - <tr class="tr"> - <td class="td"><%= clientmac %></td> - <td class="td"><%= (clientvals.ht == true) and "available" or "not available" %></td> - <td class="td"><%= (clientvals.vht == true) and "available" or "not available" %></td> - <td class="td"><%= "%d" % clientvals.signal %></td> - </tr> - <% - end - end - %> - </table> - </td> - </tr> - <% - end - %> - </table> - </div> - <% - end - %> - ]]) -end - -return m diff --git a/applications/luci-app-dawn/luasrc/tools/ieee80211.lua b/applications/luci-app-dawn/luasrc/tools/ieee80211.lua deleted file mode 100644 index 44b0464427..0000000000 --- a/applications/luci-app-dawn/luasrc/tools/ieee80211.lua +++ /dev/null @@ -1,20 +0,0 @@ -module("luci.tools.ieee80211", package.seeall) - -function frequency_to_channel(freq) - if (freq <= 2400) then - return 0; - elseif (freq == 2484) then - return 14; - elseif (freq < 2484) then - return (freq - 2407) / 5; - elseif (freq >= 4910 and freq <= 4980) then - return (freq - 4000) / 5; - elseif (freq <= 45000) then - return (freq - 5000) / 5; - elseif (freq >= 58320 and freq <= 64800) then - return (freq - 56160) / 2160; - else - return 0; - end -end - diff --git a/applications/luci-app-dawn/root/usr/share/luci/menu.d/luci-app-dawn.json b/applications/luci-app-dawn/root/usr/share/luci/menu.d/luci-app-dawn.json new file mode 100644 index 0000000000..96e88db39e --- /dev/null +++ b/applications/luci-app-dawn/root/usr/share/luci/menu.d/luci-app-dawn.json @@ -0,0 +1,30 @@ +{ + "admin/dawn/": { + "title": "DAWN", + "order": 60, + "action": { + "type": "firstchild" + }, + "depends": { + "acl": [ "luci-app-dawn" ] + } + }, + + "admin/dawn/network_overview": { + "title": "Network Overview", + "order": 1, + "action": { + "type": "view", + "path": "dawn/network_overview" + } + }, + + "admin/dawn/hearing_map": { + "title": "Hearing Map", + "order": 2, + "action": { + "type": "view", + "path": "dawn/hearing_map" + } + } +} diff --git a/applications/luci-app-dawn/root/usr/share/rpcd/acl.d/luci-app-dawn.json b/applications/luci-app-dawn/root/usr/share/rpcd/acl.d/luci-app-dawn.json index 4fece64a86..5968c406a0 100644 --- a/applications/luci-app-dawn/root/usr/share/rpcd/acl.d/luci-app-dawn.json +++ b/applications/luci-app-dawn/root/usr/share/rpcd/acl.d/luci-app-dawn.json @@ -2,7 +2,11 @@ "luci-app-dawn": { "description": "Grant UCI access for luci-app-dawn", "read": { - "uci": [ "dawn" ] + "uci": [ "dawn" ], + "ubus": { + "dawn": [ "get_network", "get_hearing_map" ], + "luci-rpc": [ "getHostHints" ] + } }, "write": { "uci": [ "dawn" ] |