Qt智能家居應用開發:硬件設備實現智能網絡配置時候,如何使用第三方smart config 庫

背景

閱讀前預備知識:css

  • 學習安曉輝老師的qt for android 核心編程(瞭解怎麼在Qt 裏邊c++ 調用java,java庫怎麼加進qt工程中)java

  • qt android wifi 開發篇android

如今作智能硬件設備,都是使用模塊化的流行wifi芯片來接入雲端,實現實時通信和數據交互的工做.之前使用wifi芯片咱們常常會遇到一個問題:在wifi設備初始化過程當中,咱們要手動從ap模式配置鏈接路由器,這個操做流程對於咱們開發人員來講看起來很簡單,當換路由器的時候,按復位鍵而後手動配置就行了.甚至如今我看到許多這樣的產品好比網絡攝像頭,一些遠程控制設備都是這個模式.甚至我在學校工做室的時候老師買了一套智能家居設備,咱們要看着一本說明書按着流程來手動配置網絡.也就是如今大部分智能設備仍是存在這個問題(其實已經有解決方案了,也許開發商尚未留意到如今流行的智能網絡配置功能,這個有沒缺點漏洞我不知道,畢竟我也是新手,只用這個技術作過簡單的智能家居系統).c++

wifi設備實現網絡配置方式之間差別

比起傳統的ap模式網頁配置wif芯片網絡或者串口配置網絡,smartconfig是一種新型的智能網絡配置功能,操做起來更智能方便,時物聯網芯片產品的一大趨向。
區別:git

ap模式下的網頁形式配置

ap (所謂ap模式就是把wifi芯片啓動成像路由器同樣,可讓其餘wifi終端鏈接到這個wifi芯片)模式下的網頁形式是經過wifi終端手動搜索wifi芯片開的ap服務,而後鏈接該wifi芯片。接着在wifi終端打開瀏覽器,訪問wifi芯片的地址(好比: http://192.168.0.1 ),因爲wifi芯片原本支持ap模式,它已是一個簡單的網站服務,經過這網頁去獲取權限設置wifi芯片提供的設置項服務,好比重啓鏈接到路由器等等。編程

串口配置

大部分wifi芯片都支持串口命令控制wifi芯片的全部功能。這時候就須要經過串口命令區控制wifi芯片了。segmentfault

smartconfig

smartconfig 是一個面向軟件開發者的智能網絡配置功能。硬件開發商無需關係本身的wifi芯片怎麼鏈接到路由器,也無需知道動態的路由怎麼被切換。由於smartconfig時經過終端軟件去讓wifi芯片鏈接到路由器的。具體實現原理參考:智能硬件接入雲平臺解決方案瀏覽器


微信硬件平臺

微信硬件平臺裏邊有一個叫作airkiss 技術,下面的兩個產品都支持這個技術,對於實現智能網絡配置功能,它是一個相對完美的平臺和方案.詳細的學習請自行進平臺官網看文檔.微信


hi-fly系列wifi芯片(筆者的項目就是用這個芯片)

esp8266 wifi 芯片

hi-fly和esp系列芯片看起來大同小異,知識esp8266芯片實現智能網絡配置比較麻煩,它裏邊只有實現源碼,並無封裝成java庫來使用,hi-fly產品就產商提供了一個java庫,後邊着重介紹怎麼在qt裏邊使用這個庫.網絡

wifi芯片學習:

若是有官方評估版能夠徹底參考HF-LPT220wifi模塊評估版使用指南學習搭建完整的調試環境,若是沒有的話請參考HF-LPT220wifi模塊用戶手冊這份文檔作一個調試板子。

clipboard.png

這個板子是本身作的,使用的時HF-LPT220芯片。電路設計按狀況,留出串口和復位鍵,就能夠看成官方評估版使用了。

前期硬件開發要了解wifi芯片的操做:

  • 監聽wifi芯片串口傳來的數據

  • 瞭解透傳模式

  • 瞭解串口數據傳輸和wifi串口控制命令。

軟件實現smartconfig

就拿個人項目來做分析:

clipboard.png

咱們在建立qt android項目的時候要把hi-flying 提供的hiflying-iots-android-smartlink7.0.2.jar 拷貝到android/libs目錄下

而後寫給c++調用的java接口類:
SmartLinkManager.java

package com.tommego;

//hifly smart link libs
import com.hiflying.smartlink.ISmartLinker;
import com.hiflying.smartlink.OnSmartLinkListener;
import com.hiflying.smartlink.SmartLinkedModule;
import com.hiflying.smartlink.v3.SnifferSmartLinker;
import com.hiflying.smartlink.v7.MulticastSmartLinker;

import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

//屏幕像素密度
import android.util.DisplayMetrics;

public class SmartLinkManager extends org.qtproject.qt5.android.bindings.QtActivity implements OnSmartLinkListener{

    private static SmartLinkManager m_instance;


    //smart link
    protected static ISmartLinker mSnifferSmartLinker;
    private static boolean  mIsConncting = false;
    protected static Handler mViewHandler = new Handler();
//    protected static ProgressDialog mWaitingDialog;
    private static BroadcastReceiver mWifiChangedReceiver;
    private static String mSSID;


    public SmartLinkManager(){
        m_instance = this;

        //smart linker initialization
        mSnifferSmartLinker = MulticastSmartLinker.getInstance();
    }

    public static void startSmartLink(String ssid,String pwd){
        // TODO Auto-generated method stub
        if(!mIsConncting){

                //設置要配置的ssid 和pswd
                try {

                        mViewHandler.post(new Runnable() {

                            @Override
                            public void run() {
                                    // TODO Auto-generated method stub

                                    Toast.makeText(m_instance.getApplicationContext(), "正在後臺配置wifi,請稍後",
                                                    Toast.LENGTH_LONG).show();
                            }
                        });

                        mSnifferSmartLinker.setOnSmartLinkListener(m_instance);

//                        showDialog();
                        //開始 smartLink
                        mSnifferSmartLinker.start(m_instance.getApplicationContext(), pwd.trim(),
                                        ssid.trim());
                        mIsConncting = true;
//                        mWaitingDialog.show();
                } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
        }
    }

    public static void stopSmartLink(){
        mSnifferSmartLinker.stop();
        mIsConncting = false;
//        closeDialog();
    }


    public static String getSSID(){
        WifiManager conMan = (WifiManager) m_instance.getSystemService(Context.WIFI_SERVICE);
        return conMan.getConnectionInfo().getSSID();
    }

    @Override
    public void onLinked(final SmartLinkedModule module) {
            // TODO Auto-generated method stub

//            Log.w(TAG, "onLinked");
            mViewHandler.post(new Runnable() {

                    @Override
                    public void run() {
                            Toast.makeText(m_instance.getApplicationContext(), "發現新wifi模塊"+
                             "\n mac:"+module.getMac()+ "\n ip:"+module.getModuleIP(),
                                            Toast.LENGTH_SHORT).show();
                    }
            });
    }

    @Override
    public void onCompleted() {

//            Log.w(TAG, "onCompleted");
            mViewHandler.post(new Runnable() {

                    @Override
                    public void run() {
                            // TODO Auto-generated method stub
                            Toast.makeText(m_instance.getApplicationContext(), "智能配置完成!",
                                            Toast.LENGTH_SHORT).show();
//                            mWaitingDialog.dismiss();
                            mIsConncting = false;
//                            closeDialog();
                    }
            });
    }

    @Override
    public void onTimeOut() {

//            Log.w(TAG, "onTimeOut");
            mViewHandler.post(new Runnable() {

                    @Override
                    public void run() {
                            // TODO Auto-generated method stub
                            Toast.makeText(m_instance.getApplicationContext(), "配置超時!",
                                            Toast.LENGTH_SHORT).show();
//                            mWaitingDialog.dismiss();
                            mIsConncting = false;
                    }
            });
    }

    //獲取屏幕像素密度
    public static double getDentisy(){
        DisplayMetrics metrics=new DisplayMetrics();
        m_instance.getWindowManager().getDefaultDisplay().getMetrics(metrics);
        return metrics.density;
    }


//    public static native void showDialog();
//    public static native void closeDialog();





}

而後c++ 就能夠調度這個庫了:
wifidevicemanager.h

#ifndef WIFIDEVICEMANAGER_H
#define WIFIDEVICEMANAGER_H

#include <QObject>
#include <QUdpSocket>
#include <QHostAddress>
#include <QList>
#include <QAndroidJniObject>
#include <jni.h>
#include <QDebug>
#include <QByteArray>
#include <QTcpSocket>

struct WifiDevice{
    QString ip,mac;
};

class WifiDeviceManager : public QObject
{
    Q_OBJECT
public:
    explicit WifiDeviceManager(QObject *parent = 0);
    //device list
    Q_PROPERTY(QString deviceList READ deviceList NOTIFY deviceListChanged)
    QString deviceList();
    Q_PROPERTY(QString revDatas READ revDatas NOTIFY revDatasChanged)
    QString revDatas();
    Q_PROPERTY(QString revTcpDatas READ revTcpDatas NOTIFY revTcpDatasChanged)
    QString revTcpDatas();

    //tcp socket properties
    Q_PROPERTY(QString tcpState READ tcpState NOTIFY tcpStateChanged)
    QString tcpState();
    //tcp con
    Q_INVOKABLE void connectTcp(QString ip);
    Q_INVOKABLE void sendDatasTcp(QString data);

    //smart config
    Q_INVOKABLE void startSmartLink(QString SSID,QString pwd);
    Q_PROPERTY(QString ssID READ ssID NOTIFY ssIDChanged)
    QString ssID(){
        return mssid;
    }

    //send udp datas
    Q_INVOKABLE void searchDevice();

    //send datas
    Q_INVOKABLE void sendDatas(QString datas);
    Q_INVOKABLE void sendDatas(QString datas,int port);
    Q_INVOKABLE void setDAddress(QString ad){
        this->dAddress=ad;
    }

signals:
    void deviceListChanged();
    void ssIDChanged();
    void revDatasChanged();
    void tcpStateChanged();
    void revTcpDatasChanged();

public slots:
    void readDatas();
    void readTcpDatas();

private:
    QString             myAddress;

    QList<WifiDevice>   mdeviceList;
    QUdpSocket          *socket;
    QTcpSocket          *tcpSocket;

    int                 port;

    QString             mssid;
    QString             mrevDatas;
    QString             mRevTcpDatas;
    QString             dAddress;
    QString             m_tcpState;

};

#endif // WIFIDEVICEMANAGER_H

wifidevicemanager.cpp

#include "wifidevicemanager.h"

WifiDeviceManager::WifiDeviceManager(QObject *parent) : QObject(parent)
{
    //init socket
    port=48899;
    socket=new QUdpSocket(this);
    socket->bind(QHostAddress::Broadcast,port);

    tcpSocket=new QTcpSocket();
    tcpSocket->bind (8899);
    connect(socket,SIGNAL(readyRead()),this,SLOT(readDatas()));
    connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readTcpDatas()));

    this->m_tcpState="unConnected";
    tcpStateChanged();

    //init ssid
    QAndroidJniObject str=QAndroidJniObject::callStaticObjectMethod("com/tommego/SmartLinkManager",
                                                                             "getSSID",
                                                                             "()Ljava/lang/String;");
    this->mssid=str.toString();
    ssIDChanged();

    //init address
    QHostAddress address;
    myAddress=address.toString();
}

QString WifiDeviceManager::deviceList(){
    return "";
}
void WifiDeviceManager::readDatas(){
    socket->waitForReadyRead(100);
//    qDebug()<<"&&&&&&&&&&&&&&&&&&&&&datas:"<<socket->readAll();
    this->mrevDatas=socket->readAll();
    while (socket->hasPendingDatagrams()) {
        QByteArray datagram;
        datagram.resize(socket->pendingDatagramSize());
        QHostAddress sender;
        quint16 senderPort;
//        currentDatas="aa";
//        mdataChanged();

        socket->readDatagram(datagram.data(), datagram.size(),
                                &sender, &senderPort);
        mrevDatas=datagram.data();
        revDatasChanged();
//        mdataChanged();
    }
    revDatasChanged();


}

void WifiDeviceManager::startSmartLink(QString SSID, QString pwd){
    QAndroidJniObject cssid=QAndroidJniObject::fromString(SSID);
    QAndroidJniObject cpwd=QAndroidJniObject::fromString(pwd);
    QAndroidJniObject::callStaticMethod<void>("com/tommego/SmartLinkManager",
                                                                                 "startSmartLink",
                                                                                 "(Ljava/lang/String;Ljava/lang/String;)V",
                                                     cssid.object<jstring>(),
                                                     cpwd.object<jstring>());

}

void WifiDeviceManager::searchDevice(){
    QByteArray cmd;
    cmd.append("HF-A11ASSISTHREAD");
    QString address="192.168.0.255";
    QHostAddress ad(address);
    socket->writeDatagram(cmd,ad,port);
//    socket->writeDatagram(cmd,"192.168.1.255",port);
}
void WifiDeviceManager::sendDatas(QString datas){
    QByteArray cmd;
    cmd.append(datas);
    QString address="192.168.0.255";
    QHostAddress ad(address);
    socket->writeDatagram(cmd,ad,port);
//    socket->writeDatagram(cmd,"192.168.1.255",port);
}
QString WifiDeviceManager::revDatas(){
    return this->mrevDatas;
}
void WifiDeviceManager::sendDatas(QString datas, int mport){
    QByteArray cmd;
    cmd.append(datas);
    QString address="192.168.0.255";
    QHostAddress ad(address);
    socket->writeDatagram(cmd,ad,mport);
}

QString WifiDeviceManager::tcpState (){
    return this->m_tcpState;
}
void WifiDeviceManager::connectTcp (QString ip){
    if(tcpSocket->state()==QTcpSocket::ConnectedState)
        return ;
    QHostAddress address(ip);
    tcpSocket->connectToHost(address,8899);
    if(tcpSocket->state()==QTcpSocket::ConnectedState)
        this->m_tcpState="connected";
    else
        this->m_tcpState="unConnected";
    tcpStateChanged();


}

void WifiDeviceManager::sendDatasTcp (QString data){
    if(tcpSocket->state()==QTcpSocket::ConnectedState){
        QByteArray mdata;
        mdata.append(data);
        this->tcpSocket->write (mdata);
    }
}

void WifiDeviceManager::readTcpDatas(){
    tcpSocket->waitForReadyRead(500);
    mRevTcpDatas=tcpSocket->readAll();
    revTcpDatasChanged();
}
QString WifiDeviceManager::revTcpDatas(){
    return this->mRevTcpDatas;
}

這裏是調用smartlink庫核心實現部分,在實現這個功能過程,遇到了不少java接口的坑.不過還好,整個源碼實現完美在qt中跑起來了.這時候咱們的app,就能夠經過smartlink實現對爲初始化的wifi設備進行一鍵配置網絡了!(就算是有幾十臺wifi設備,都能直接在app中一鍵配置而且搜到wifi設備哈哈!)
功能截圖:

clipboard.png

clipboard.png

相關文章
相關標籤/搜索