思路回顾

【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. Python从文件中读取数据(2)

    一.读取文件中各行的内容并存储到一个列表中 继续用resource.txt 举例 resource.txt my name is joker, I am 18 years old, How about ...

  2. 剑指Offer(书):链表中环的入口节点

    题目:给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null. public ListNode EntryNodeOfLoop(ListNode pHead) { //第一步,查找是 ...

  3. cocos2d-x游戏开发(一)之环境搭建篇

    前言 进入研究生生涯已经有一段时间,感觉却没做些什么,实验室虽有一个很大的国家项目,但考虑到它这么的单一,总想利用业余时间做些什么,拓宽一下自己的知识面. 偶然机会,了解到cocos这个东东,恰好,实 ...

  4. JavaScript正则表达式-断言

    (?=reg_pattern):正前向断言 只有当字符串右侧出现匹配reg_pattern的字符时才匹配正则表达式. str = "img1.jpg,img2.jpg,img3.bmp&qu ...

  5. poj--2139

    Description The cows have been making movies lately, so they are ready to play a variant of the famo ...

  6. Android自动化测试Uiautomator--UiCollection接口简介

    这个对象可以理解为一个对象的集合,因为UiSelector描述后得到的有可能是多个满足条件的控件集合,因此可以用来生成UiCollection,继承自UiObject. 用于枚举一个容器的用户界面(U ...

  7. python基础学习笔记——迭代器

    我们之前一直在用可迭代对象进行操作,那么到底什么是可迭代对象.我们现在就来讨论讨论可迭代对象.首先我们先回顾下我们 熟知的可迭代对象有哪些: str  list   tuple  dic  set  ...

  8. Myeclipse 添加Android开发工具

    1.JDK是必须的,同时配置相应环境变量. 2.Android SDK 下载后解压缩需要把SDK目录下的tools和platform-tools加入环境变量. 3.MyEclipse中安装ADT插件 ...

  9. 【04】图解JSON

    [04]图解JSON   附件列表

  10. Django深入----django.db.transaction

    django 的事务: transaction.py atomic---原子性 def atomic(using=None, savepoint=True): # Bare decorator: @a ...