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