From 6cf849bcf6a440d57ee4a8190d56c6861963432a Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Sat, 10 Oct 2020 03:45:06 +0200 Subject: luci-mod-status: add WPS control for wifi info Add a way to trigger and get the WPS Push Button status from the webui if supported. Fixes: #1072 Signed-off-by: Ansuel Smith --- .../resources/view/status/include/60_wifi.js | 256 +++++++++++++-------- 1 file changed, 164 insertions(+), 92 deletions(-) (limited to 'modules/luci-mod-status/htdocs/luci-static/resources/view/status') diff --git a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/60_wifi.js b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/60_wifi.js index deb6f8609f..928b5959ba 100644 --- a/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/60_wifi.js +++ b/modules/luci-mod-status/htdocs/luci-static/resources/view/status/include/60_wifi.js @@ -2,90 +2,44 @@ 'require baseclass'; 'require dom'; 'require network'; +'require uci'; +'require fs'; 'require rpc'; -var callSessionAccess = rpc.declare({ - object: 'session', - method: 'access', - params: [ 'scope', 'object', 'function' ], - expect: { 'access': false } -}); - -function renderbox(radio, networks) { - var chan = null, - freq = null, - rate = null, - badges = []; - - for (var i = 0; i < networks.length; i++) { - var net = networks[i], - is_assoc = (net.getBSSID() != '00:00:00:00:00:00' && net.getChannel() && !net.isDisabled()), - quality = net.getSignalPercent(); - - var icon; - if (net.isDisabled()) - icon = L.resource('icons/signal-none.png'); - else if (quality <= 0) - icon = L.resource('icons/signal-0.png'); - else if (quality < 25) - icon = L.resource('icons/signal-0-25.png'); - else if (quality < 50) - icon = L.resource('icons/signal-25-50.png'); - else if (quality < 75) - icon = L.resource('icons/signal-50-75.png'); - else - icon = L.resource('icons/signal-75-100.png'); - - var badge = renderBadge( - icon, - '%s: %d dBm / %s: %d%%'.format(_('Signal'), net.getSignal(), _('Quality'), quality), - _('SSID'), net.getActiveSSID() || '?', - _('Mode'), net.getActiveMode(), - _('BSSID'), is_assoc ? (net.getActiveBSSID() || '-') : null, - _('Encryption'), is_assoc ? net.getActiveEncryption() : null, - _('Associations'), is_assoc ? (net.assoclist.length || '-') : null, - null, is_assoc ? null : E('em', net.isDisabled() ? _('Wireless is disabled') : _('Wireless is not associated'))); - - badges.push(badge); - - chan = (chan != null) ? chan : net.getChannel(); - freq = (freq != null) ? freq : net.getFrequency(); - rate = (rate != null) ? rate : net.getBitRate(); - } - - return E('div', { class: 'ifacebox' }, [ - E('div', { class: 'ifacebox-head center ' + (radio.isUp() ? 'active' : '') }, - E('strong', radio.getName())), - E('div', { class: 'ifacebox-body left' }, [ - L.itemlist(E('span'), [ - _('Type'), radio.getI18n().replace(/^Generic | Wireless Controller .+$/g, ''), - _('Channel'), chan ? '%d (%.3f %s)'.format(chan, freq, _('GHz')) : '-', - _('Bitrate'), rate ? '%d %s'.format(rate, _('Mbit/s')) : '-' - ]), - E('div', {}, badges) - ]) - ]); -} - -function wifirate(rt) { - var s = '%.1f\xa0%s, %d\xa0%s'.format(rt.rate / 1000, _('Mbit/s'), rt.mhz, _('MHz')), - ht = rt.ht, vht = rt.vht, - mhz = rt.mhz, nss = rt.nss, - mcs = rt.mcs, sgi = rt.short_gi; - - if (ht || vht) { - if (vht) s += ', VHT-MCS\xa0%d'.format(mcs); - if (nss) s += ', VHT-NSS\xa0%d'.format(nss); - if (ht) s += ', MCS\xa0%s'.format(mcs); - if (sgi) s += ', ' + _('Short GI').replace(/ /g, '\xa0'); - } - - return s; -} - return baseclass.extend({ title: _('Wireless'), + WPSTranslateTbl: { + Disabled: _('Disabled'), + Active: _('Active'), + 'Timed-out': _('Timed-out'), + Overlap: _('Overlap'), + Unknown: _('Unknown') + }, + + callSessionAccess: rpc.declare({ + object: 'session', + method: 'access', + params: [ 'scope', 'object', 'function' ], + expect: { 'access': false } + }), + + wifirate: function(rt) { + var s = '%.1f\xa0%s, %d\xa0%s'.format(rt.rate / 1000, _('Mbit/s'), rt.mhz, _('MHz')), + ht = rt.ht, vht = rt.vht, + mhz = rt.mhz, nss = rt.nss, + mcs = rt.mcs, sgi = rt.short_gi; + + if (ht || vht) { + if (vht) s += ', VHT-MCS\xa0%d'.format(mcs); + if (nss) s += ', VHT-NSS\xa0%d'.format(nss); + if (ht) s += ', MCS\xa0%s'.format(mcs); + if (sgi) s += ', ' + _('Short GI').replace(/ /g, '\xa0'); + } + + return s; + }, + handleDelClient: function(wifinet, mac, ev) { dom.parent(ev.currentTarget, '.tr').style.opacity = 0.5; ev.currentTarget.classList.add('spinning'); @@ -95,25 +49,143 @@ return baseclass.extend({ wifinet.disconnectClient(mac, true, 5, 60000); }, + handleGetWPSStatus: function(wifinet) { + return rpc.declare({ + object: 'hostapd.%s'.format(wifinet), + method: 'wps_status', + })() + }, + + handleCallWPS: function(wifinet, ev) { + ev.currentTarget.classList.add('spinning'); + ev.currentTarget.disabled = true; + ev.currentTarget.blur(); + + return rpc.declare({ + object: 'hostapd.%s'.format(wifinet), + method: 'wps_start', + })(); + }, + + handleCancelWPS: function(wifinet, ev) { + ev.currentTarget.classList.add('spinning'); + ev.currentTarget.disabled = true; + ev.currentTarget.blur(); + + return rpc.declare({ + object: 'hostapd.%s'.format(wifinet), + method: 'wps_cancel', + })(); + }, + + renderbox: function(radio, networks) { + var chan = null, + freq = null, + rate = null, + badges = []; + + for (var i = 0; i < networks.length; i++) { + var net = networks[i], + is_assoc = (net.getBSSID() != '00:00:00:00:00:00' && net.getChannel() && !net.isDisabled()), + quality = net.getSignalPercent(); + + var icon; + if (net.isDisabled()) + icon = L.resource('icons/signal-none.png'); + else if (quality <= 0) + icon = L.resource('icons/signal-0.png'); + else if (quality < 25) + icon = L.resource('icons/signal-0-25.png'); + else if (quality < 50) + icon = L.resource('icons/signal-25-50.png'); + else if (quality < 75) + icon = L.resource('icons/signal-50-75.png'); + else + icon = L.resource('icons/signal-75-100.png'); + + var WPS_button; + + if (this.isWPSEnabled[net.sid]) { + if (net.wps_status == 'Active') { + WPS_button = E('button', { + 'class' : 'cbi-button cbi-button-remove', + 'click': L.bind(this.handleCancelWPS, this, net.getIfname()), + }, [ _('Stop WPS') ]) + } else { + WPS_button = E('button', { + 'class' : 'cbi-button cbi-button-apply', + 'click': L.bind(this.handleCallWPS, this, net.getIfname()), + }, [ _('Start WPS') ]) + } + } + + var badge = renderBadge( + icon, + '%s: %d dBm / %s: %d%%'.format(_('Signal'), net.getSignal(), _('Quality'), quality), + _('SSID'), net.getActiveSSID() || '?', + _('Mode'), net.getActiveMode(), + _('BSSID'), is_assoc ? (net.getActiveBSSID() || '-') : null, + _('Encryption'), is_assoc ? net.getActiveEncryption() : null, + _('Associations'), is_assoc ? (net.assoclist.length || '-') : null, + null, is_assoc ? null : E('em', net.isDisabled() ? _('Wireless is disabled') : _('Wireless is not associated')), + _('WPS status'), this.WPSTranslateTbl[net.wps_status], + '', WPS_button + ); + + badges.push(badge); + + chan = (chan != null) ? chan : net.getChannel(); + freq = (freq != null) ? freq : net.getFrequency(); + rate = (rate != null) ? rate : net.getBitRate(); + } + + return E('div', { class: 'ifacebox' }, [ + E('div', { class: 'ifacebox-head center ' + (radio.isUp() ? 'active' : '') }, + E('strong', radio.getName())), + E('div', { class: 'ifacebox-body left' }, [ + L.itemlist(E('span'), [ + _('Type'), radio.getI18n().replace(/^Generic | Wireless Controller .+$/g, ''), + _('Channel'), chan ? '%d (%.3f %s)'.format(chan, freq, _('GHz')) : '-', + _('Bitrate'), rate ? '%d %s'.format(rate, _('Mbit/s')) : '-', + ]), + E('div', {}, badges) + ]) + ]); + }, + + isWPSEnabled: {}, + load: function() { return Promise.all([ network.getWifiDevices(), network.getWifiNetworks(), network.getHostHints(), - callSessionAccess('access-group', 'luci-mod-status-index-wifi', 'read'), - callSessionAccess('access-group', 'luci-mod-status-index-wifi', 'write') - ]).then(function(radios_networks_hints) { - var tasks = []; - - for (var i = 0; i < radios_networks_hints[1].length; i++) - tasks.push(L.resolveDefault(radios_networks_hints[1][i].getAssocList(), []).then(L.bind(function(net, list) { + this.callSessionAccess('access-group', 'luci-mod-status-index-wifi', 'read'), + this.callSessionAccess('access-group', 'luci-mod-status-index-wifi', 'write'), + uci.load('wireless') + ]).then(L.bind(function(data) { + var tasks = [], + radios_networks_hints = data[1], + hasWPS = L.hasSystemFeature('hostapd', 'wps'); + + for (var i = 0; i < radios_networks_hints.length; i++) { + tasks.push(L.resolveDefault(radios_networks_hints[i].getAssocList(), []).then(L.bind(function(net, list) { net.assoclist = list.sort(function(a, b) { return a.mac > b.mac }); - }, this, radios_networks_hints[1][i]))); + }, this, radios_networks_hints[i]))); + + if (hasWPS && uci.get('wireless', radios_networks_hints[i].sid, 'wps_pushbutton') == '1') { + this.isWPSEnabled[radios_networks_hints[i].sid] = true; + tasks.push(L.resolveDefault(this.handleGetWPSStatus(radios_networks_hints[i].getIfname()), null) + .then(L.bind(function(net, data) { + net.wps_status = data ? data.pbc_status : _('No Data'); + }, this, radios_networks_hints[i]))); + } + } return Promise.all(tasks).then(function() { - return radios_networks_hints; + return data; }); - }); + }, this)); }, render: function(data) { @@ -127,7 +199,7 @@ return baseclass.extend({ var table = E('div', { 'class': 'network-status-table' }); for (var i = 0; i < radios.sort(function(a, b) { a.getName() > b.getName() }).length; i++) - table.appendChild(renderbox(radios[i], + table.appendChild(this.renderbox(radios[i], networks.filter(function(net) { return net.getWifiDeviceName() == radios[i].getName() }))); if (!table.lastElementChild) @@ -215,9 +287,9 @@ return baseclass.extend({ ]) ]), E('span', {}, [ - E('span', wifirate(bss.rx)), + E('span', this.wifirate(bss.rx)), E('br'), - E('span', wifirate(bss.tx)) + E('span', this.wifirate(bss.tx)) ]) ]; -- cgit v1.2.3