wpa_cli
.wpa_cli
utility or the undocumented TechnologyModel
element from the MeeGo.Connman
module.wpa_cli
utility in Sailfish OS is no different from another Linux distribution:# wpa_cli scan
Selected interface 'wlan0'
OK
# wpa_cli scan_results
Selected interface 'wlan0'
bssid / frequency / signal level / flags / ssid
10:bf:48:4b:2b:f4 2412 -46 [WPA-PSK-CCMP][WPA2-PSK-CCMP][ESS] Asd_496283
d4:21:22:33:ec:46 2417 -57 [WPA2-PSK-CCMP][WPS][ESS] MGTS_243
78:94:b4:99:1c:41 2462 -59 [WPA2-PSK-CCMP][WPS][ESS] MGTS_GPON_8959
78:96:82:64:ea:fd 2427 -62 [WPA2-PSK-CCMP][WPS][ESS] Onlime248
90:f6:52:66:20:92 2412 -41 [WPA2-PSK-CCMP][ESS] Hearthstone
14:cc:20:32:e7:04 2437 -65 [WPA2-PSK-CCMP][WPS][ESS] ViVa239
00:0e:8f:2f:ff:3c 2412 -67 [WPA-PSK-TKIP][WPA2-PSK-CCMP][WPS][ESS] Smart_box - 297
d4:6e:0e:b0:17:16 2462 -73 [WPA2-PSK-CCMP+TKIP][WPS][ESS] MGTS_GPON_8959
94:4a:0c:ce:93:05 2462 -71 [WPA2-PSK-CCMP][WPS][ESS] MGTS_GPON_7870
e8:94:f6:fa:43:86 2417 -77 [WPA2-PSK-CCMP][ESS] Home236
be:85:56:e2:9a:fc 2427 -74 [WPA2-PSK-CCMP][WPS][ESS] DIRECT-HR-BRAVIA
c0:a0:bb:1d:4c:58 2412 -74 [WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][WPS][ESS] dlink-4C58
40:3d:ec:31:ca:fb 2432 -86 [WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][ESS] TV kinescope
fc:2d:5e:45:db:35 2437 -82 [WPA2-PSK-CCMP+TKIP][WPS][ESS] Matthew
00:0e:8f:6e:47:ba 2412 -65 [WPA-PSK-TKIP][WPA2-PSK-CCMP][WPS][ESS] Genya
c0:a0:bb:81:c7:4a 2447 -83 [WPA2-PSK-CCMP][ESS] mrnext-245
d8:fe:e3:f9:26:45 2437 -66 [WPA-PSK-CCMP][WPA2-PSK-CCMP][ESS] NBN
/** * wpa_cli. * @param password - root. */ void WpaCliHelper::callWpaCli(QString password) { // QProcess process; // Wi-Fi root process.start(QString("/bin/bash -c \"echo %1 | devel-su wpa_cli scan\"").arg((password))); // if (!process.waitForFinished()) { // , emit gotScanError(); return; } // mWifiInfo = process.readAll(); // , if (mWifiInfo.contains("Auth failed")) { emit gotAuthError(); return; } // root process.start(QString("/bin/bash -c \"echo %1 | devel-su wpa_cli scan_results\"").arg((password))); // if (!process.waitForFinished()) { // , emit gotResultError(); return; } // mWifiInfo = process.readAll(); // emit calledWpaCli(); }
/** * wpa_cli. * @param info - wpa_cli. */ void WifiInfoParser::parseInfo(QString info) { // wifiInfo.clear(); // QStringList networks = info.split('\n'); // if (networks.length() == 3) { networkCount = 0; emit parsed(PARSE_COMPLETED_WITH_NO_NETWORKS); } // Wi-Fi networkCount = networks.length() - 3; for (int i = 0; i < networkCount; i++) { // QStringList data = networks.at(i+2).split('\t'); // wifiInfo << QVariant::fromValue( (QStringList() << QString::number(calculateChannel(data[1].toInt())) // << data[2] // << data[4] // << data[0])); // BSSID } // emit parsed(PARSE_COMPLETED_CORRECTLY); }
MeeGo.Connman
module, unfortunately not presented in the standard documentation. import MeeGo.Connman 0.2
TechnologyModel
, allowing just a few lines in the QML file to get structured information about the surrounding Wi-Fi networks: TechnologyModel { id: networksList // name: "wifi" // }
Timer
component: Timer { id: updateTimer // interval: 2000 // running: true // repeat: true // triggeredOnStart: true // onTriggered: networksList.requestScan() // Wi-Fi }
NetworkService
type, which provides all the necessary information about the surrounding networks. Of all the variety of the greatest interest for the scanner are the fields described in table 1.Field name | Data type | Description |
---|---|---|
name | QString | Network name |
frequency | quint16 | Signal frequency |
strength | uint | Signal strength |
bssid | QString | Bssid |
security | QStringList | Encryption type |
SilicaListView { // id: wifiInfoList // anchors.fill: parent // model: networksList // delegate: Item { // width: parent.width // height: Theme.itemSizeHuge // Column { // anchors { fill: parent // leftMargin: Theme.horizontalPageMargin // rightMargin: Theme.horizontalPageMargin // topMargin: Theme.paddingLarge // } Row { // // anchors.right: parent.right anchors.left: parent.left height: childrenRect.height // Label { // width: parent.width / 2 // horizontalAlignment: Text.AlignLeft // font.bold: true // text: modelData.name // truncationMode: TruncationMode.Fade // } Label { // , width: parent.width / 4 // horizontalAlignment: Text.AlignRight // text: (calculateChannel(modelData.frequency) + 1) + " ch." // } Label { // width: parent.width / 4 // horizontalAlignment: Text.AlignRight // text: (modelData.strength - 120) + " dBm" // } } Item { // // anchors.right: parent.right anchors.left: parent.left height: childrenRect.height // Label { // BSSID anchors.left: parent.left // text: "bssid: " + modelData.bssid // BSSID } Label { // anchors.right: parent.right // text: modelData.security.join("/") // } } ProgressBar { // width: parent.width // minimumValue: 0 // maximumValue: 100 // value: modelData.strength // } } } VerticalScrollDecorator {} // }
/** * . * @param frequency - Wi-Fi * @return Wi-Fi */ function calculateChannel(frequency) { var channel = (frequency - 2412) / 5; return channel > 12 ? 13 : channel; }
powered
and count
, respectively. If the network interface is turned off or there are no networks around, the user needs to display a corresponding message (Figure 2). To do this, use the ViewPlaceholder
element: ViewPlaceholder { enabled: !networksList.powered // text: qsTr("Please, turn WiFi on") // } ViewPlaceholder { enabled: networksList.powered && networksList.count === 0 // text: qsTr("There are no WiFi networks") // }
Canvas
element, on which the graphics are onPaint
when the onPaint
signal onPaint
. Also, with the help of the Connections
element, the graph is redrawn when changing information about the surrounding Wi-Fi networks. As in the case with the list, the possibility is set to display a message to the user if it is impossible to obtain the necessary data. Page { ViewPlaceholder { // Wi-Fi enabled: !networksList.powered text: qsTr("Please, turn WiFi on") } ViewPlaceholder { // Wi-Fi enabled: networksList.powered && networksList.count === 0 text: qsTr("There are no WiFi networks") } SilicaFlickable { // anchors.fill: parent Canvas { // id: graph // anchors { // fill: parent leftMargin: Theme.horizontalPageMargin rightMargin: Theme.horizontalPageMargin topMargin: Theme.paddingLarge bottomMargin: Theme.paddingLarge } onPaint: drawGraph() // } } Connections { // target: networksList // - onScanRequestFinished: graph.requestPaint() // } onOrientationChanged: graph.requestPaint() // }
function drawGraph() { var context = graph.getContext("2d"); // context.clearRect(0, 0, graph.width, graph.height); // context.lineWidth = 3; // context.strokeStyle = "gray"; // context.fillStyle = "gray"; // context.font = "12pt sans-serif"; // // var channels = calculateChannelsPositions(graph.width); var levels = calculateSignalLevelsPositions(graph.height) drawAxes(context, channels, levels); // Wi-Fi if (networksList.count === 0) return; drawWifiFigures(context, graph.width, graph.height, channels); }
// Wi-Fi property variant channelsInfo: [11, 16, 21, 26, 31, 36, 41, 46, 51, 56, 61, 66, 71, 83] /** * . * @:param: width - * @:return: channels - */ function calculateChannelsPositions(width) { var channels = []; var step = (width - Theme.horizontalPageMargin) / 94; for (var index in channelsInfo) { channels[index] = channelsInfo[index] * step + Theme.horizontalPageMargin; } return channels; } /** * . * @:param: height - * @:return: levels - */ function calculateSignalLevelsPositions(height) { var levels = []; var step = (height - Theme.paddingLarge) / 10; for (var index = 0; index < 10; ++index) { levels[index] = index * step + Theme.paddingLarge; } return levels; }
moveTo
and lineTo
to move the brush and draw a straight line, respectively. /** * . * @:param: context - */ function drawGraphBounds(context) { context.beginPath(); context.moveTo(2 * Theme.horizontalPageMargin, Theme.paddingLarge); context.lineTo(graph.width - Theme.horizontalPageMargin, Theme.paddingLarge); context.lineTo(graph.width - Theme.horizontalPageMargin, graph.height - Theme.paddingLarge); context.lineTo(2 * Theme.horizontalPageMargin, graph.height - Theme.paddingLarge); context.closePath(); context.stroke(); } /** * . * @:param: context - * @:param: channelX - */ function drawChannelAxe(context, channelX) { context.beginPath(); context.moveTo(channelX, Theme.paddingLarge); context.lineTo(channelX, graph.height - Theme.paddingLarge); context.closePath(); context.stroke(); } /** * . * @:param: context - * @:param: channelIndex - * @:param: channelX - */ function drawChannelNumber(context, channelIndex, channelX) { var text = parseInt(channelIndex) + 1; var textWidth = context.measureText(text).width; context.fillText(text, channelX - (textWidth / 2), graph.height); } /** * . * @:param: context - * @:param: channels - */ function drawChannelsAxes(context, channels) { context.lineWidth = 1; for (var channelIndex in channels) { drawChannelAxe(context, channels[channelIndex]); drawChannelNumber(context, channelIndex, channels[channelIndex]); } } /** * . * @:param: context - * @:param: signalLevelY - */ function drawSignalLevelAxe(context, signalLevelY) { context.beginPath(); context.moveTo(2 * Theme.horizontalPageMargin, signalLevelY); context.lineTo(graph.width - Theme.horizontalPageMargin, signalLevelY); context.closePath(); context.stroke(); } /** * . * @:param: context - * @:param: signalLevel - * @:param: signalLevelY - */ function drawSignalLevel(context, signalLevel, signalLevelY) { if (signalLevel === '0') return; var text = '-' + signalLevel + '0'; var textWidth = context.measureText(text).width; context.fillText(text, Theme.horizontalPageMargin - (textWidth / 2), signalLevelY); } /** * . * @:param: context - * @:param: levels - */ function drawSignalLevelsAxes(context, levels) { for (var levelIndex in levels) { drawSignalLevelAxe(context, levels[levelIndex]); drawSignalLevel(context, levelIndex, levels[levelIndex]); } } /** * . * @:param: context - * @:param: channels - * @:param: levels - */ function drawAxes(context, channels, levels) { drawGraphBounds(context); drawChannelsAxes(context, channels); drawSignalLevelsAxes(context, levels); }
// property var strokeColors: ["rgb(255, 0, 0)", "rgb(128, 128, 0)", "rgb(255, 255, 0)", "rgb( 0, 128, 0)", "rgb( 0, 255, 0)", "rgb( 0, 128, 128)", "rgb( 0, 255, 255)", "rgb( 0, 0, 128)", "rgb( 0, 0, 255)", "rgb(128, 0, 128)", "rgb(255, 0, 255)", "rgb(128, 0, 0)"] // ( ) property var fillColors: ["rgba(255, 0, 0, 0.33)", "rgba(128, 128, 0, 0.33)", "rgba(255, 255, 0, 0.33)", "rgba( 0, 128, 0, 0.33)", "rgba( 0, 255, 0, 0.33)", "rgba( 0, 128, 128, 0.33)", "rgba( 0, 255, 255, 0.33)", "rgba( 0, 0, 128, 0.33)", "rgba( 0, 0, 255, 0.33)", "rgba(128, 0, 128, 0.33)", "rgba(255, 0, 255, 0.33)", "rgba(128, 0, 0, 0.33)"] /** * y- . * @:param: height - * @:param: level - * @:return: y- */ function calculateCurrentSignalLevelPosition(height, level) { return (height - Theme.paddingLarge) / 100 * Math.abs(level) + Theme.paddingLarge; } /** * x- . * @:param: width - * @:param: channel - * @:return: x- */ function calculateBoundsPositionForChannel(width, channel) { var step = (width - Theme.horizontalPageMargin) / 94; var left = (channelsInfo[channel] - 11) * step + Theme.horizontalPageMargin; var right = (channelsInfo[channel] + 11) * step + Theme.horizontalPageMargin; return [left, right]; } /** * . * http://codetheory.in/calculate-control-point-to-make-your-canvas-curve-hit-a-specific-point/ * @:param: channelCoord - * @:param: levelPosition - * @:param: bounds - * @:return: */ function calculateCurrentPoint(channelCoord, levelPosition, bounds) { var cpx = 2 * channelCoord - (bounds[0] + bounds[1]) / 2; var cpy = 2 * levelPosition - (graph.height + graph.height - (2 * Theme.paddingLarge)) / 2; return { x: cpx, y: cpy }; } /** * Wi-Fi . * @:param: context - () * @:param: channelCoord - * @:param: levelPosition - * @:param: bounds - */ function drawWifiFigure(context, channelCoord, levelPosition, bounds) { var cp = calculateCurrentPoint(channelCoord, levelPosition, bounds); context.beginPath(); context.moveTo(bounds[0], graph.height - Theme.paddingLarge); context.quadraticCurveTo(cp.x, cp.y, bounds[1], graph.height - Theme.paddingLarge); context.closePath(); context.stroke(); context.fill(); } /** * . * @:param: context - () * @:param: wifiInfo - Wi-Fi * @:param: channels - * @:param: levelPosition - */ function drawWifiName(context, wifiInfo, channels, levelPosition) { var textWidth = context.measureText(wifiInfo.name).width; context.fillText(wifiInfo.name, channels[calculateChannel(wifiInfo.frequency)] - (textWidth / 2), levelPosition - Theme.paddingSmall); } /** * . * @:param: context - () * @:param: width - * @:param: height - * @:param: channels - */ function drawWifiFigures(context, width, height, channels) { context.lineWidth = 2; for (var networkIndex = 0; networkIndex < networksList.count; ++networkIndex) { var levelPosition = calculateCurrentSignalLevelPosition(height, (networksList.get(networkIndex).strength - 120)) var bounds = calculateBoundsPositionForChannel(width, calculateChannel(networksList.get(networkIndex).frequency)) context.strokeStyle = strokeColors[networkIndex % strokeColors.length]; context.fillStyle = fillColors[networkIndex % fillColors.length]; drawWifiFigure(context, channels[calculateChannel(networksList.get(networkIndex).frequency)], levelPosition, bounds); context.fillStyle = context.strokeStyle; drawWifiName(context, networksList.get(networkIndex), channels, levelPosition); } }
Source: https://habr.com/ru/post/345750/
All Articles