思路回顾

【1】手机连接WIFI模块
【2】UDP通信对WIFI模块发送指令,以和WIFI模块保持连接状态
【3】UDP通信对WIFI模块发送指令,让其搜索可用的无线网,返回WIFI列表
【4】发送指令,让WIFI模块接入指定路由
【5】手机连接路由
【6】发送指令,获得WIFI模块的动态IP地址

UDP通信线程类

package com.jczb.smartlife.common;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException; import android.os.Handler;
import android.os.Message; import com.jczb.smartlife.common.Tool; public class GetInfoThread extends Thread {
private Handler handler;
private DatagramSocket socket;
private int msgType; private final String IP = "255.255.255.255";//广播地址
private int PORT = 26000; /**
* 48899端口:C32x系列的端口,用户可以用AT指令更改
* 49000端口:除C32x系列,其他WIFI模块的端口
* 1902端口:有人掌控宝系列产品的端口
*/
private int targetPort = 49000 ; private boolean receive = true; /**
*
* @param handler 传入监听此线程的Handler
* @param intMsg 传入监听的消息类型
*/
public GetInfoThread(Handler handler,int msgType) {
this.handler = handler;
this.msgType=msgType;
init();
} public void init(){
try { socket = new DatagramSocket(null);
socket.setBroadcast(true);
socket.setReuseAddress(true);
socket.bind(new InetSocketAddress(PORT));
} catch (SocketException e) {
e.printStackTrace();
sendErrorMsg("Search Thread init fail");
return;
}
} public void run() {
if (socket == null) {
return;
} try { byte[] data = new byte[1024];
//创建一个空的DatagramPacket对象
DatagramPacket revPacket = new DatagramPacket(data, data.length);
while (receive) {
//服务端接收数据
socket.receive(revPacket);
if(null!=handler){
byte[] realData = new byte[revPacket.getLength()];
System.arraycopy(data, 0, realData,0, realData.length);
Message msg =handler.obtainMessage(msgType,realData);
handler.sendMessage(msg);
}
}
} catch (Exception e) {
e.printStackTrace();
socket.close();
}
} public void close() {
if (socket == null)
return;
socket.close();
} private void sendErrorMsg(String info){ } /**
* 发送数据
* @param msg
*/
public void sendMsg(byte[] msg) {
if (socket != null) {
try {
System.out.println("targetPort------------------->"+targetPort);
DatagramPacket sendPacket = new DatagramPacket(msg, msg.length,
InetAddress.getByName(IP), targetPort);
socket.send(sendPacket);
} catch (UnknownHostException e) {
e.printStackTrace();
System.out.println("发送失败");
} catch (IOException e) {
e.printStackTrace();
System.out.println("发送失败");
} }
} public void setReceive(boolean receive) {
this.receive = receive;
} public void setTargetPort(int targetPort) {
this.targetPort = targetPort;
}
public void setMsgType(int msgType){
this.msgType=msgType;
}
}

发送消息的线程类

/**
* 发送消息的队列,每次发送数据时,只需要调用putMsg(byte[] data)方法
*
* @author usr_liujinqi
*
*/
private class SendMsgThread extends Thread {
// 发送消息的队列
private Queue<byte[]> sendMsgQuene = new LinkedList<byte[]>();
// 是否发送消息
private boolean send = true; private GetInfoThread ss; public SendMsgThread(GetInfoThread ss) {
this.ss = ss;
} public synchronized void putMsg(byte[] msg) {
// 唤醒线程
if (sendMsgQuene.size() == 0)
notify();
sendMsgQuene.offer(msg);
} public void run() {
synchronized (this) {
while (send) {
// 当队列里的消息发送完毕后,线程等待
while (sendMsgQuene.size() > 0) {
byte[] msg = sendMsgQuene.poll();
if (ss != null)
ss.sendMsg(msg);
}
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} public void setSend(boolean send) {
this.send = send;
}
}

应用

【举例】发送搜索WIFI模块的指令

//1.用户获得温控器中WIFI模块的WIFI模块的IP地址,MAC地址,模块名称的指令
private final byte[] getInfoCode=new byte[]{(byte)0x48,0x46,0x2D,0x41,0x31,0x31,0x41,0x53,0x53,0x49,0x53,0x54,0x48,0x52,0x45,0x41,0x44};
public static final int REC_Module=0x04;//搜索WIFI模块的信息(包括IP、Mac、名称)
//实例化一个线程,用户获得模块信息(IP,Mac,名称)
//参数为监听为此线程的Handler,以及接收成功后,给Handler发送的消息类型
getInfoThread = new GetInfoThread(handler,Tool.REC_Module);
getInfoThread.start();
//发送消息的线程
smt = new SendMsgThread(getInfoThread);
smt.start();
//设置发送的目的端口号
getInfoThread.setTargetPort(Integer.parseInt("48899"));
smt.putMsg(getInfoCode);

WIFI模块在接收到指令后,就会回复信息,以下的Handler就是针对回复过来的信息进行解析处理等操作。

//处理消息的Handler
private Handler handler= new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case Tool.REC_Module:// 解析接收到的数据
//设置发送的目的端口号
getInfoThread.setTargetPort(Integer.parseInt("48899"));
getInfoThread.setMsgType(Tool.REC_OK);
smt.putMsg(okCode);
SetServer();
SetDHCP();
byte[] data = (byte[]) msg.obj;
//将十进制的数据转化成十六进制数据
String strTemp= Tool.bytesToHexString(data);
//将十六进制的字符串去掉空格之后进行解析
String strdecode=Tool.DecodeHex(strTemp.replace(" ", ""));
//取出IP,Mac地址,模块名称
decodeIP(strdecode);
Toast.makeText(ConnectWifiActivity.this, "获得WIFI模块名称成功!"+ModuleName, Toast.LENGTH_SHORT).show(); break;
case Tool.REC_Server:
byte[] dataServer = (byte[])msg.obj;
//将十进制的数据转化成十六进制数据
String strServer= Tool.bytesToHexString(dataServer);
if("2b 6f 6b 0d 0a 0d 0a ".equals(strServer)){
Toast.makeText(ConnectWifiActivity.this, "设置服务器成功!", Toast.LENGTH_SHORT).show(); }
break;
case Tool.REC_SSID:
byte[] dataSSID=(byte[])msg.obj;
Tool.bytesToHexString(dataSSID);
decodeData(dataSSID);
break;
case Tool.REC_AT:
byte[] dataID = (byte[]) msg.obj;
//将十进制的数据转化成十六进制数据
String strTempID= Tool.bytesToHexString(dataID);
//将十六进制的字符串去掉空格之后进行解析
String strdecodeID=Tool.DecodeHex(strTempID.replace(" ", ""));
break;
case Tool.REC_DHCP:
byte[] dataDHCP = (byte[])msg.obj;
//将十进制的数据转化成十六进制数据
String strDHCP= Tool.bytesToHexString(dataDHCP);
if("2b 6f 6b 0d 0a 0d 0a ".equals(strDHCP)){
Toast.makeText(ConnectWifiActivity.this, "设置DHCP网络参数成功!", Toast.LENGTH_SHORT).show(); }
break;
default:
byte[] data1 = (byte[]) msg.obj;
//将十进制的数据转化成十六进制数据
String strTemp1= Tool.bytesToHexString(data1);
Toast.makeText(ConnectWifiActivity.this, strTemp1, Toast.LENGTH_SHORT).show();
break;
}
}
};

总结

  凡是需要对WIFI模块发送指令的,就需要用到上述的两个线程类,还有一个对返回信息进行处理的Handler。只是发送的指令的code不一样,如上述表示的是搜索WIFI模块的十六进制的指令。不管WIFI模块在AP模式下还是STA模式,通信的最开始步骤都是先搜索模块,然后获得它的IP和Mac之后,立即回复+ok指令,就可以保持连接状态。

Demo下载

UDP通信发送指令Demo

【Android开发—智能家居系列】(四):UDP通信发送指令的更多相关文章

  1. Android开发—智能家居系列】(二):用手机对WIFI模块进行配置

    在实际开发中,我开发的这款APP是用来连接温控器,并对温控器进行控制的.有图为证,哈哈. 上一篇文章[Android开发—智能家居系列](一):智能家居原理的文末总结中写到: 手机APP控制智能温控器 ...

  2. 【Android开发—智能家居系列】(一):智能家居原理

    来到JCZB公司的第二天,就接到了开发类似于小米智能家庭APP的任务.组长让我在手机上安装上此款APP,给了我个小米智能插座,就让我开始了解需求.这便开启了我的智能家居旅程.说实话,我也真是out的无 ...

  3. 【Android开发—智能家居系列】(三):手机连接WIFI模块

    版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 概述 实现连接WIFI的功能会用到一个工具类,源码可以点击链接下载.网上这些类似的工具类里的代码差不多是一样的.连接无线网主要有 ...

  4. 基于Laravel+Swoole开发智能家居后端

    基于Laravel+Swoole开发智能家居后端 在上一篇<Laravel如何优雅的使用Swoole>中我已经大概谈到了Laravel结合Swoole的用法. 今天,我参与的智能家居项目基 ...

  5. 高度集成智能家居物联网网关WiFi通信应用的无线路由模块:模小块成长记

    大家好,我叫模小块,代号L107模块,出生在BOJINGnet大家庭里,我在物联网网关里不可或缺,或许业内专业人士和物联网工程师知道我的存在.别看我体积小(40mm25mm3mm),贴片式邮票孔接口( ...

  6. [Android开发学iOS系列] 工具篇: Xcode使用和快捷键

    [Android开发学iOS系列] 工具篇: Xcode使用和快捷键 工欲善其事必先利其器. 编辑 Cmd + N: 新建文件 Option + Cmd + N: 新建文件夹 Cmd + / : 注释 ...

  7. [Android开发学iOS系列] iOS写UI的几种方式

    [Android开发学iOS系列] iOS写UI的几种方式 作为一个现代化的平台, iOS的发展也经历了好几个时代. 本文讲讲iOS写UI的几种主要方式和各自的特点. iOS写UI的方式 在iOS中写 ...

  8. [Android开发学iOS系列] Auto Layout

    [Android开发学iOS系列] Auto Layout 内容: 介绍什么是Auto Layout. 基本使用方法 在代码中写约束的方法 Auto Layout的原理 尺寸和优先级 Auto Lay ...

  9. android完整智能家居、备忘录、蓝牙配对、3D动画库、购物车页面、版本更新自动安装等源码

    Android精选源码 app 版本更新.下载完毕自动自动安装 android指针式分数仪表盘 ANdroid蓝牙设备搜索.配对 Android 图片水印框架,支持隐形数字水印 android3D旋转 ...

随机推荐

  1. UVa-101-木块问题

    这题用vector比较好写,我们设置对应的几个函数,然后进行相应的操作来简化代码,这样才不易出错. 对于输入和操作来说我们经分析之后,可以看到最后一个操作时最原始的操作也就是不需要还原任意一个堆任意高 ...

  2. 【tarjan 拓扑排序 dp】bzoj1093: [ZJOI2007]最大半连通子图

    思维难度不大,关键考代码实现能力.一些细节还是很妙的. Description 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于 ...

  3. [LUOGU] P2196 挖地雷

    题目背景 NOIp1996提高组第三题 题目描述 在一个地图上有N个地窖(N<=20),每个地窖中埋有一定数量的地雷.同时,给出地窖之间的连接路径.当地窖及其连接的数据给出之后,某人可以从任一处 ...

  4. docker系列之分区挂载和数据卷

    容器中的文件系统是独立的, 一旦容器被删除, 则文件系统也会被删除. 如果想容器和实体机在文件系统层面打通, 可以把指定目录挂载到容器当中: docker run -d -p 5000:22 -v / ...

  5. 牛客网暑期ACM多校训练营(第六场) I Team Rocket(线段树)

    题意: 给定n个区间, m次询问, 每次询问给一个点, 问这个点在哪些区间内, 然后删掉这些区间. 分析: 将n个区间按L大小升序排列, 然后将这些区间视为点构建一棵n个点的线段树, 树的节点记录这个 ...

  6. 打印 Python 的一切 —— pprint & beeprint

    打印,是所有程序员从小白时期就具备的神技,遇事不决打印一下,是 DEBUG 最简单且不依赖 IDE 的方式,自定义各种日志输出,也是项目成型后必备功能.但是为了优雅的打印格式,往往需要对各种对象进行特 ...

  7. luogu2634 聪聪可可

    点分治裸题 #include <iostream> #include <cstdio> using namespace std; int n, uu, vv, ww, ans, ...

  8. unittest断言方法的使用

    unittest框架的TestCase类提供以下方法用于测试结果的判断 方法 检查 版本 assertEqual(a, b) a ==b   assertNotEqual(a, b) a !=b   ...

  9. Python第三方库之openpyxl(7)

    Python第三方库之openpyxl(7) 散点图 散点或xy图表类似于一些折线图.主要的区别在于,一个系列的值被绘制在另一个值上.当值未排序时,这是有用的. from openpyxl impor ...

  10. Leetcode 322.零钱兑换

    零钱兑换 给定不同面额的硬币 coins 和一个总金额 amount.编写一个函数来计算可以凑成总金额所需的最少的硬币个数.如果没有任何一种硬币组合能组成总金额,返回 -1. 示例 1: 输入: co ...