小优机器人WIFI+SSDP入网具体实现
小优入网实现
1. 小优响应设备查询服务
当小优连接网络时,开启一个SSDP后台服务后,除了向局域网广播通知自己存在,还创建了一个广播监听线程,当收到智能网关发来的设备查询服务广播时,如下:
SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900
MAN: “ssdp:discover”
MX: 120
ST: ssdp:all
广播监听线程会立刻响应查询服务,发送小优存在广告通知,信息内容跟入网时发的一样,如下:
NOTIFY * HTTP/1.1
Host: 239.255.255.250:1900
NT: urn:schemas-upnp-org:device:CanbotRobot:1
NTS: ssdp:alive
USN:uuid:Upnp-KL-U03S-1_0-04e67647e222::urn:schemas-upnp-org:device:CanbotRobot
Cache-Control: max-age = 1800
通过收到的设备查询服务广播,小优可以获取智能网关的ip地址,为接下来的通信提供目标地址,最后当网络断开时,会停止SSDP后台服务,再次连接网络时再启动。
2. 小优端声控指令转字符串
小优端获取到声音指令后,转化为字符串,对字符串做判断比较,是否符合本地指令,符合的就本地处理,不符合的字符串,就把它发送到智能网关处理。
小优端核心代码如下:
LanSend类主要实现ssdp加入多播组、监听发现服务并单播响应信息
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.MulticastSocket;import android.content.Context;
import android.util.Log;public class LanSend {/*** @param args* @throws Exception *///广播地址private static final String BROADCAST_IP = SSDPUtils.ADDRESS;//广播IPprivate static final int BROADCAST_INT_PORT = SSDPUtils.PORT; // 不同的port对应不同的socket发送端和接收端MulticastSocket broadSocket ;//用于接收广播信息public static boolean work=false;//循环监听因子InetAddress broadAddress ;//广播地址//DatagramSocket数据报SocketDatagramSocket sender ;//数据流套接字 相当于码头,用于发送信息private Context context;
// private InetSocketAddress mMulticastGroup;public LanSend(Context contex) {try {this.context=contex;//初始化broadSocket=new MulticastSocket(BROADCAST_INT_PORT); //多播Socket
// mMulticastGroup = new InetSocketAddress(SSDPUtils.ADDRESS, SSDPUtils.PORT);broadAddress = InetAddress.getByName(BROADCAST_IP);//获取网络多播地址sender = new DatagramSocket();} catch (Exception e) {// TODO: handle exceptionSystem.out.println("*****lanSend初始化失败*****"+e.toString());}}public void join() { try{Log.e("LanSend", "join");broadSocket.joinGroup(broadAddress); //把套接字socket加入到组播地址,这样就能接收到组播信息new Thread(new GetPacket()).start(); //新建一个线程,用于循环侦听端口信息}catch (Exception e) {// TODO: handle exceptionSystem.out.println("*****加入组播失败*****");}}//广播发送查找在线用户void sendGetUserMsg() {byte[] b=new byte[1024];DatagramPacket packet; //数据包,相当于集装箱,封装信息try{b = SSDPUtils.buildSSDPSearchString().getBytes(); packet = new DatagramPacket(b, b.length, broadAddress, BROADCAST_INT_PORT); //广播信息到指定端口sender.send(packet);//单播信息会给目标主机System.out.println("*****已发送请求*****"); }catch (Exception e) {System.out.println("*****查找出错*****");}}//当局域网内的在线机子收到广播信息时响应并向发送广播的ip地址(此处广播自己的存在来响应)主机发送返还信息,达到交换信息的目的void returnUserMsg(String mac){byte[] b=new byte[1024];DatagramPacket packet;try {b=SSDPUtils.buildSSDPAliveString(mac).getBytes();packet = new DatagramPacket(b,b.length,broadAddress, BROADCAST_INT_PORT);sender.send(packet);System.out.print("发送信息成功!");} catch (Exception e) {// TODO: handle exceptionSystem.out.println("*****发送返还信息失败*****"+e);}}//当局域网内的在线机子收到广播信息时响应并向发送广播的ip地址主机发送返还信息,达到交换信息的目的void returnUserMsg(String mac,InetAddress inetaddress,int port){byte[] b=new byte[1024];DatagramPacket packet;try {b=SSDPUtils.buildSSDPAliveString(mac).getBytes();packet = new DatagramPacket(b,b.length,inetaddress, port);sender.send(packet);System.out.print("发送信息成功!");} catch (Exception e) {// TODO: handle exceptionSystem.out.println("*****发送返还信息失败*****"+e);}}//当局域网某机子下线是需要广播发送下线通知void offLine(){byte[] b=new byte[1024];DatagramPacket packet;try {b=SSDPUtils.buildSSDPByebyeString().getBytes();packet = new DatagramPacket(b,b.length,broadAddress, BROADCAST_INT_PORT);sender.send(packet);System.out.println("*****已离线*****");} catch (Exception e) {// TODO: handle exceptionSystem.out.println("*****离线异常*****");}}class GetPacket implements Runnable { //新建的线程,用于侦听,packet数据包public void run() {DatagramPacket inPacket;work=true;String[] message;while(work){try {Log.e("LanSend", "GetPacket while");inPacket=new DatagramPacket(new byte[1024], 1024);broadSocket.receive(inPacket); //接收广播信息并将信息封装到inPacket中
// inPacket.getData()
// message=new String(inPacket.getData(),0,inPacket.getLength()).split("@"); //获取信息,并切割头部,判断是何种信息(find--上线,retn--回答,offl--下线)String data=new String(inPacket.getData()).trim();if (data!=null) {String socketAddress=inPacket.getSocketAddress().toString();String[] datas=data.split(SSDPUtils.NEWLINE);for (int i = 0; i < datas.length; i++) {Log.e("LanSend", "datas["+i+"] = "+datas[i]);if (datas[i].trim().equalsIgnoreCase("ST: ssdp:all")) {Log.e("ALIVE", "response");String mac=SSDPUtils.getUserId(context);InetAddress sourceip=inPacket.getAddress();int port=inPacket.getPort();returnUserMsg(mac,sourceip,port);break;}}Log.e("LanSend", "收到的数据包的 data :"+data+" 数据包的socketAddress:"+socketAddress);System.out.println("收到的数据包的 data :"+data+" 数据包的socketAddress:"+socketAddress);}} catch (Exception e) {// TODO: handle exceptionSystem.out.println("线程出错 "+e);}}}}}
SSDPUtils 为SSDP工具类,主要实现小优ssdp信息的生成
import android.content.Context;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.util.Log;/*** Created by florent.noel on 6/14/13.*/
public class SSDPUtils {private static String TAG = SSDPUtils.class.getName();public static final String ADDRESS = "239.255.255.250";public static final int PORT = 1900;public static final int MAX_REPLY_TIME = 5;public static final int MSG_TIMEOUT = MAX_REPLY_TIME * 1000 + 1000;public static final String STRING_MSEARCH = "M-SEARCH * HTTP/1.1";public static final String NOTIFY_MSEARCH = "NOTIFY * HTTP/1.1";// public static final String STRING_RootDevice = "ST: upnp:rootdevice";public static final String STRING_AllDevice = "ST: ssdp:all";public static final String NEWLINE = "\r\n";public static final String MAN = "Man:\"ssdp:discover\"";public static String LOCATION_TEXT = "LOCATION: http://";public static String buildSSDPSearchString(){StringBuilder content = new StringBuilder();content.append(STRING_MSEARCH).append(NEWLINE);content.append("Host: " + ADDRESS + ":" + PORT).append(NEWLINE);content.append(MAN).append(NEWLINE);content.append("MX: " + MAX_REPLY_TIME).append(NEWLINE);content.append(STRING_AllDevice).append(NEWLINE);content.append(NEWLINE);Log.e(TAG, content.toString());return content.toString();}/** * 方法描述:获取本地userId方法* @param String app_name* @return * @see RobotUtil*/public static String getUserId(Context context) {WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);if (!wifi.isWifiEnabled()) {wifi.setWifiEnabled(true);}WifiInfo info = wifi.getConnectionInfo();String mac = info.getMacAddress();if(mac==null){if (!wifi.isWifiEnabled()) {wifi.setWifiEnabled(true);}long starttime = System.currentTimeMillis();while(true&&System.currentTimeMillis()-starttime<5000){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}info = wifi.getConnectionInfo();mac = info.getMacAddress();if(mac!=null){break;}}if (mac==null) {Log.e("getUserId","getUserId失败 ");return null;}}Log.e("getUserId","getUserId "+mac);String str=mac.replace(":", "");
// StringBuffer a = new StringBuffer(mac);
// a.deleteCharAt(2).deleteCharAt(4).deleteCharAt(6).deleteCharAt(8)
// .deleteCharAt(10);
// mac = a.toString();return str;}/*** NOTIFY * HTTP/1.1ST: urn: schemas-upnp-org:device: 设备名称:1HOST: 239.255.255.250:1900EXT:CACHE-CONTROL: max-age=1800LOCATION: http://127.0.0.1:8008/ssdp/device-desc.xmlCONFIGID.UPNP.ORG: 7339BOOTID.UPNP.ORG: 7339USN: uuid: Upnp-设备系列号-设备识别号::urn:schemas-upnp-org:device:设备名称*/public static String buildSSDPAliveString(String mac){StringBuilder content = new StringBuilder();// content.append("HTTP/1.1 200 OK").append(NEWLINE);content.append(NOTIFY_MSEARCH).append(NEWLINE);content.append("ST: urn:schemas-upnp-org:device:设备名称:1").append(NEWLINE);content.append("Host: " + ADDRESS + ":" + PORT).append(NEWLINE);content.append("Cache-Control: max-age=1800").append(NEWLINE);content.append("CONFIGID.UPNP.ORG: 7339").append(NEWLINE);content.append("BOOTID.UPNP.ORG: 7339").append(NEWLINE);content.append("USN: uuid:Upnp-设备系列号-"+mac+"::urn:schemas-upnp-org:device:设备名称").append(NEWLINE);content.append(NEWLINE);/*** NOTIFY * HTTP/1.1ST: urn: schemas-upnp-org:device: 设备名称:1HOST: 239.255.255.250:1900EXT:CACHE-CONTROL: max-age=1800LOCATION: http://127.0.0.1:8008/ssdp/device-desc.xmlCONFIGID.UPNP.ORG: 7339BOOTID.UPNP.ORG: 7339USN: uuid: Upnp-设备系列号-设备识别号::urn:schemas-upnp-org:device:设备名称*/Log.e(TAG, content.toString());return content.toString();}public static String buildSSDPByebyeString(){StringBuilder content = new StringBuilder();content.append(NOTIFY_MSEARCH).append(NEWLINE);content.append("Host: " + ADDRESS + ":" + PORT).append(NEWLINE);content.append("NT: someunique:idscheme3").append(NEWLINE);content.append("NTS: ssdp:byebye").append(NEWLINE);content.append("USN: someunique:idscheme3").append(NEWLINE);content.append(NEWLINE);Log.e(TAG, content.toString());return content.toString();}public static String parseIP(String msearchAnswer){String ip = "0.0.0.0";//find the index of "LOCATION: http://"int loactionLinePos = msearchAnswer.indexOf(LOCATION_TEXT);if(loactionLinePos != -1){//position the index right after "LOCATION: http://"loactionLinePos += LOCATION_TEXT.length();//find the next semi-colon (would be the one that separate IP from PORT nr)int locColon = msearchAnswer.indexOf(":", loactionLinePos);//grab IPip = msearchAnswer.substring(loactionLinePos, locColon);}return ip;}
}
HuaweiSmartGateway 类主要实现ServerSocket,并对声控结果指令、智能网关指令信息的处理
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;import org.json.JSONException;
import org.json.JSONObject;import android.R.integer;
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;
import android.speech.tts.TextToSpeech.OnUtteranceCompletedListener;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;
import android.widget.Toast;import com.unisrobot.rsk.MainApplication;
import com.unisrobot.rsk.R;
import com.unisrobot.rsk.preference.ConstUtils;
import com.unisrobot.rsk.util.Logger;public class HuaweiSmartGateway {//广播地址private static final String TAG = "HuaweiSmartGateway";public static final String ACTION_HEALTH_MANAGEMENT_DATA="识别string";public static final String ACTION_SMARTHOME_CMD="识别string2";private static final int BROADCAST_INT_PORT = SSDPUtils.PORT; // 不同的port对应不同的socket发送端和接收端public static String responseMsg;//成功返回智能家居的执行成功结果,小优播放的文本语音(测试用)public static String speakresponseMsg=null;//成功返回智能家居的执行成功结果,保存用,小优播放的文本语音(测试用)private Context mContext;private LanSend lSend;private TextToSpeech mTextToSpeech;private MyReceiver mReceiverResult;private Dialog dialog;Handler mHander = new Handler() {public void handleMessage(Message msg) {switch (msg.what) {case 4:Toast.makeText(mContext, (String)msg.obj, Toast.LENGTH_SHORT).show();break;case 5:
// Toast.makeText(mContext, (String)msg.obj, Toast.LENGTH_SHORT).show();String str=(String)msg.obj;if (str!=null&&!str.isEmpty()) {createDialog((String)msg.obj);}break;case 6:
// Toast.makeText(mContext, (String)msg.obj, Toast.LENGTH_SHORT).show();String str2=(String)msg.obj;if (str2!=null&&!str2.isEmpty()) {createDialog((String)msg.obj);}int rs=msg.arg1;if (rs!=0) {playhuaweiVoice2(mContext, rs);}break;}}};public HuaweiSmartGateway(Context contex) {this.mContext=contex;}public void init() {if (mTextToSpeech==null) {mTextToSpeech = new TextToSpeech(mContext, new OnInitListener() {@Overridepublic void onInit(int status) {// TODO Auto-generated method stub}});mTextToSpeech.setOnUtteranceCompletedListener(new OnUtteranceCompletedListener() {@Overridepublic void onUtteranceCompleted(String utteranceId) {cancelDialog();// TODO Auto-generated method stub
// startvoice();}});}//针对华为智能网关SSDPNotify();initServerSocket();registerResult();}public void destroy(){
// mHander.removeMessages(6);unRegisterBroadcastResult();}private void registerResult() {if (mReceiverResult == null) {mReceiverResult = new MyReceiver();}Logger.d(TAG, "注册---识别结果广播");IntentFilter filter = new IntentFilter();filter.addAction(ACTION_HEALTH_MANAGEMENT_DATA);filter.addAction(ACTION_SMARTHOME_CMD);mContext.registerReceiver(mReceiverResult, filter);}private void unRegisterBroadcastResult() {if (mReceiverResult != null) {Logger.d(TAG, "反注册---识别结果广播");mContext.unregisterReceiver(mReceiverResult);}}/*** 创建内容提示框* @param tip*/public void createDialog(String tip){if (dialog==null) {dialog = new Dialog(mContext,R.style.dialog);LayoutInflater layoutInflater = LayoutInflater.from(mContext);View viewDialog = layoutInflater.inflate(R.layout.dialog_center3, null);TextView tv = (TextView)viewDialog.findViewById(R.id.tv_dialogcenter);tv.setText(tip);dialog.setContentView(viewDialog);dialog.setCanceledOnTouchOutside(false);
// dialog.setCancelable(false);dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);dialog.show();}}/*** 取消提示框*/public void cancelDialog(){if (dialog!=null) {if (dialog.isShowing()) {dialog.cancel();}dialog=null;}}/*** 监听ssdp查询服务*/public void SSDPNotify(){if (lSend==null) {try {lSend=new LanSend(mContext);lSend.join(); //加入组播,并创建线程侦听} catch (Exception e) {System.out.println("*****加入组播失败*****");}}}/*** 初始化小优端ServerSocket*/private ServerSocket mServerSocket;private Socket socket;public void initServerSocket(){if (mServerSocket==null) {new Thread() {public void run() {try {mServerSocket = new ServerSocket(socket通信端口号);while (true) {Log.e(TAG, "111111111");socket=mServerSocket.accept();handle(socket);}} catch (IOException e) {e.printStackTrace();}};}.start();}}DataOutputStream out ;private DataInputStream mDataInputStream;private MediaPlayer mphw;void handle(Socket socket) throws IOException {Log.e("myrobotSocket", "new socket");try {out = new DataOutputStream(socket.getOutputStream());mDataInputStream = new DataInputStream(socket.getInputStream());while (true) {Log.e("myrobotSocket", "true");final String cmd = mDataInputStream.readUTF();JSONObject jsonO2 = new JSONObject(cmd) ;String type=jsonO2.getString("type");String action_cmd=jsonO2.getString("action_cmd");Log.e("myrobotSocket", "type : "+type+" ::: cmd : "+action_cmd);if (type!=null&&!type.isEmpty()&&action_cmd!=null&&!action_cmd.isEmpty()) {Message msg=new Message();msg.what=4;msg.obj="type : "+type+" ::: cmd : "+action_cmd;mHander.sendMessage(msg);}if("001".equals(type)){if (action_cmd.contains("0X")) {int action = Integer.valueOf(action_cmd.replace("0X", ""), 16);MainApplication.getInstance().sendActionCmd((byte) action);}else if(action_cmd.contains("0x")){int action = Integer.valueOf(action_cmd.replace("0x", ""), 16);MainApplication.getInstance().sendActionCmd((byte) action);}}else if("002".equals(type)) {//播放插件响应,返回结果JSONObject jsonCMD = new JSONObject(action_cmd) ;String rsp=jsonCMD.getString("rsp");String content=jsonCMD.getString("content");if (content!=null&&!content.equals("")&&!content.isEmpty()) {boolean blplay=false;int resid = 0;
// Turn on the living room lights.
// Turn off the living room lights.if (content.equals("success")&&speakresponseMsg!=null&&!speakresponseMsg.equals("")) {if (speakresponseMsg.contains("turn on")&&speakresponseMsg.contains("living room")&&speakresponseMsg.contains("light")) {blplay=true;resid=R.raw.livingroom_on;content="The living room lights have been turned on.";}else if (speakresponseMsg.contains("turn off")&&speakresponseMsg.contains("living room")&&speakresponseMsg.contains("light")) {blplay=true;resid=R.raw.livingroom_off;content="The living room lights have been turned off.";}else {content=speakresponseMsg;}}else if (content.equals("ALARM_DOOR_OPEN")) {blplay=true;resid=R.raw.door_open2;
// content="欢迎光临智慧沃家体验馆!";
// createDialog(content);
// playhuaweiVoice2(mContext, resid);
// continue;
// content="Warning! The door is open.";}else if (content.equals("ALARM_DOOR_CLOSE")) {blplay=false;content="";
// blplay=true;
// resid=R.raw.door_close;
// content="The door is closed.";}else if (content.equals("ALARM_FALL")) {//老人看护,有人跌倒blplay=true;resid=R.raw.someone_felldown;content="Warning! Someone fell down.";}if (content!=null&&!content.isEmpty()) {Message msg=new Message();msg.what=4;msg.obj=content;mHander.sendMessage(msg);}if (blplay) {if (content!=null&&!content.isEmpty()) {if (content.equals("ALARM_DOOR_OPEN")) {content="欢迎光临智慧沃家体验馆!";Message msg=new Message();msg.what=6;msg.obj=content;msg.arg1=resid;mHander.sendMessage(msg);
// mHander.sendMessageDelayed(msg, 6*1000);}else {Message msg=new Message();msg.what=5;msg.obj=content;mHander.sendMessage(msg);
// createDialog(content);if (resid!=0) {playhuaweiVoice(mContext, resid);}}}}else {if (mTextToSpeech!=null) {if (content!=null&&!content.isEmpty()) {Log.e("myrobotSocket", "type : "+type+" :mTextToSpeech : "+content);mTextToSpeech.speak(content, TextToSpeech.QUEUE_FLUSH, null);}}}}}}
// }} catch (IOException e) {e.printStackTrace();Log.e(TAG, "" + e.toString());out.close();mDataInputStream.close();socket.close();} catch (JSONException e) {// TODO Auto-generated catch blocke.printStackTrace();out.close();mDataInputStream.close();socket.close();}}/*** 播放华为定制的语音2* @param mContext* @param resid*/public void playhuaweiVoice2(final Context mContext,int resid){if (mphw != null) {mphw.release();mphw = null;}if (mphw == null) {mphw = MediaPlayer.create(mContext, resid);mphw.start();mphw.setOnCompletionListener(new OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp2) {// TODO Auto-generated method stubif(mphw!=null){mphw.release();mphw=null;}cancelDialog();
// String path=Environment.getExternalStorageDirectory()+"/ai/qnqn/myrobot/uushow/action/roundDance.mp3";
// File file=new File(path);
// if (file.exists()) {
// Uri uri=Uri.parse(path);
// mphw = MediaPlayer.create(mContext, uri);
// if (mphw!=null) {
// mphw.start();
// mphw.setOnCompletionListener(new OnCompletionListener() {
// @Override
// public void onCompletion(MediaPlayer mp) {
// // TODO Auto-generated method stub
// if(mphw!=null){
// mphw.release();
// mphw=null;
// }
// cancelDialog();
// }
// });
// int action = Integer.valueOf("2B", 16);
// MainApplication.getInstance().sendActionCmd((byte) action);
// MainApplication.getInstance().sendActionCmd((byte) action);
//
// }else {
// cancelDialog();
// }
// }else {
// cancelDialog();
// }// startvoice();
// handler.sendEmptyMessage(rtcode);}});}}/*** 播放华为定制的语音* @param mContext* @param resid*/public void playhuaweiVoice(Context mContext,int resid){if (mphw != null) {mphw.release();mphw = null;}if (mphw == null) {mphw = MediaPlayer.create(mContext, resid);mphw.start();mphw.setOnCompletionListener(new OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp2) {// TODO Auto-generated method stubif(mphw!=null){mphw.release();mphw=null;}cancelDialog();
// startvoice();
// handler.sendEmptyMessage(rtcode);}});}}class MyReceiver extends BroadcastReceiver{@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();Log.e(TAG, "onReceive " + action);if (ACTION_HEALTH_MANAGEMENT_DATA.equals(action)) {//上报健康管理数据if (out!=null&&socket!=null) {try{socket.sendUrgentData(0xFF);//发送一个字节判断是否为空,此字节服务端会自动舍弃String healthData=intent.getStringExtra("health_data");Log.e(TAG, "healthData = " + healthData);JSONObject datajs=new JSONObject();JSONObject healthjs=new JSONObject(healthData.trim());datajs.put("datatype", "health_data");datajs.put("datacontent", healthjs);String device=healthjs.getString("device").trim();Log.e(TAG, "device = " + device);if (device.equals("BloodPressure")) {out.writeUTF(datajs.toString());out.flush();
// Toast.makeText(mContext, "上传血压数据成功", Toast.LENGTH_SHORT).show();}else if(device.equals("Temperature")){out.writeUTF(datajs.toString());out.flush();Log.e("myrobotSocket", "healthData = " + healthData);Log.e("myrobotSocket", "datajs = " + datajs.toString());
// Toast.makeText(mContext, "上传体温数据成功", Toast.LENGTH_SHORT).show();}else if(device.equals("Weighting")){out.writeUTF(datajs.toString());out.flush();}return;}catch(Exception ex){Toast.makeText(mContext, "网关不通,上传数据失败", Toast.LENGTH_SHORT).show();return;}}else {Toast.makeText(mContext, "socket=null,上传数据失败", Toast.LENGTH_SHORT).show();return;}}else if(ACTION_SMARTHOME_CMD.equals(action)) {//智能家居命令上报if (out!=null&&socket!=null) {try{socket.sendUrgentData(0xFF);//发送一个字节判断是否为空,此字节服务端会自动舍弃String smarthomeCMD=intent.getStringExtra("smarthome_cmd");Log.e(TAG, "smarthomeCMD = " + smarthomeCMD);JSONObject smarthomejs=new JSONObject();smarthomejs.put("datatype", "smarthome_data");smarthomejs.put("datacontent", smarthomeCMD.trim());out.writeUTF(smarthomejs.toString());out.flush();
// Toast.makeText(mContext, "上报智能家居指令成功", Toast.LENGTH_SHORT).show();Intent i= new Intent(ConstUtils.ACTION_SMARTHOME_CMD_HANDLE_EXCEPTION) ;mContext.sendBroadcast(i);
// startvoice();return;}catch(Exception ex){ex.printStackTrace();Toast.makeText(mContext, "网关不通,上报智能家居指令失败", Toast.LENGTH_SHORT).show();Intent i= new Intent(ConstUtils.ACTION_SMARTHOME_CMD_HANDLE_EXCEPTION) ;mContext.sendBroadcast(i);
// startvoice();return;}}else {Toast.makeText(mContext, "socket=null,上报智能家居指令失败", Toast.LENGTH_SHORT).show();Intent i= new Intent(ConstUtils.ACTION_SMARTHOME_CMD_HANDLE_EXCEPTION) ;mContext.sendBroadcast(i);
// startvoice();return;}}}} ;}
智能网关小优驱动插件实现
3. 智能网关插件上报指令信息
智能网关插件收到小优端、手机端、其他智能设备发过来字符串信息,就对其进行语义分析,如果能跟智能网关上的事件信息匹配上,把此事件上报给智能网关处理,否则不上报。
核心代码如下(其中部分代码为华为Openlife平台提供):
CanbotDeviceListener 类为小优的设备监听类,起一个循环测试线程,每隔6秒测试一次socket是否通,不通重连,监听到设备端发来的事件信息并作出处理
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;import org.json.JSONObject;import com.huawei.smarthome.api.event.IDeviceEventListener;
import com.huawei.smarthome.driver.IDeviceService;
import com.huawei.smarthome.driver.ip.AbstractSsdpDeviceDriverAdapter;
import com.huawei.smarthome.log.LogService;
import com.huawei.smarthome.log.LogServiceFactory;/*** * 设备监听器,当机器人上线时与机器人进行连接* * * * * *
* @author Lixin* @since NetOpen 1.0* 2015年12月30日*/
public class CanbotDeviceListener implements IDeviceEventListener
{//日志服务,用于调试时打印日志final private static LogService LOGGER = LogServiceFactory.getLogService(CanbotDeviceListener.class);public boolean towork=false;public boolean towork2=false;//ssdp设备驱动private AbstractSsdpDeviceDriverAdapter adapter;private IDeviceService deviceService;private Socket client;private DataOutputStream out;private DataInputStream in;public CanbotDeviceListener(AbstractSsdpDeviceDriverAdapter adapter,IDeviceService deviceService){this.adapter = adapter;this.deviceService=deviceService;}@Overridepublic void deviceAdded(JSONObject device){}@Overridepublic void deviceRemoved(JSONObject device){}@Overridepublic void deviceOnlined(JSONObject device){LOGGER.d("deviceOnlined,device:{0}", device);//得到机器人sn和ipString sn = device.optJSONObject("basic").optString("sn");String ip = adapter.getDeviceIp(sn);LOGGER.d("device sn={0};ip={1}", sn,ip);towork2=true;//建立和机器人的连接start(ip,sn);if (!towork) {towork=true;new Thread(new Runnable() {public void run() {while (towork) {try {Thread.sleep(6*1000);//每隔6秒检测一次testSocket(ip,sn);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();break;}}}}).start();}}@Overridepublic void deviceOfflined(JSONObject device){// TODO Auto-generated method stubtowork=false;towork2=false;}@Overridepublic void deviceAlarmed(JSONObject device, String alarmName, JSONObject parameter){}@Overridepublic void deviceProerptyChanged(JSONObject device, String dataClass, String propertyName, Object value){LOGGER.d("deviceProerptyChanged,device:{0},dataClass:{1},propertyName:{2},value:{3}", device,dataClass,propertyName,value);}public void start(String ip ,String sn) {if(!towork2){return;}try {client = new Socket(ip, socket通信端口);out = new DataOutputStream(client.getOutputStream());in=new DataInputStream(client.getInputStream());//??先测试用此句LOGGER.d("send cmd 0x01");sendActionCmd(sn,ip,"0x01","001");new Thread(new Runnable() {public void run() {while (towork2) {LOGGER.d("receive : read data");String data;try {data = in.readUTF();LOGGER.d("receive : " + data);JSONObject datajs=new JSONObject(data.trim());String datatype=datajs.getString("datatype");if (datatype.equals("health_data")) {JSONObject contentjs=datajs.getJSONObject("datacontent");String device=contentjs.getString("device");JSONObject deviceDatajs=contentjs.getJSONObject("deviceData");//收到的上报数据为血压计数据if (device.equals("BloodPressure")) {//得到血压计上报的数据String mac=deviceDatajs.getString("MAC");String type=deviceDatajs.getString("type");//舒张压String dbp =deviceDatajs.getString("DBP");//收缩压String sbp =deviceDatajs.getString("SBP");LOGGER.d("sn:{0},type:{1},dbp:{2},sbp:{3}",mac,type,dbp,sbp);reportBloodDeviceData(mac, type, Integer.parseInt(dbp), Integer.parseInt(sbp));JSONObject rspmsg=new JSONObject();rspmsg.put("rsp", "健康响应");rspmsg.put("content", "已成功上传血压数据");sendActionCmd(sn,ip, rspmsg.toString(), "002");}//收到的上报数据为体重秤数据else if(device.equals("Weighting")){String weight=deviceDatajs.getString("weight");String mac=deviceDatajs.getString("MAC");reportWeighingDeviceData(mac, Float.parseFloat(weight));JSONObject rspmsg=new JSONObject();rspmsg.put("rsp", "健康响应");rspmsg.put("content", "已成功上传体重数据");sendActionCmd(sn,ip, rspmsg.toString(), "002");}} else if(datatype.equals("smarthome_data")){String smarthome_cmd=datajs.getString("datacontent").trim();if (smarthome_cmd!=null&&!smarthome_cmd.equals("")&&!smarthome_cmd.isEmpty()) {JSONObject robotClassData = new JSONObject(smarthome_cmd);deviceService.reportDeviceAlarm(sn, "VOICE_CMD_EVENT", robotClassData);/*JSONObject rspmsg=new JSONObject();rspmsg.put("rsp", "智能家居响应");rspmsg.put("content", "控制成功");sendActionCmd(sn,ip, rspmsg.toString(), "002");*/}else {JSONObject rspmsg=new JSONObject();rspmsg.put("rsp", "智能家居响应");rspmsg.put("content", "指令为空");sendActionCmd(sn,ip, rspmsg.toString(), "002");}}} catch (IOException e) {LOGGER.e("IOException:", e);deviceService.reportDeviceOffline(sn, "uurobot");
// towork2=false;break;}}}}).start();} catch (UnknownHostException e) {LOGGER.e("UnknownHostException:", e);} catch (IOException e) {LOGGER.e("IOException:", e);}}public void sendActionCmd(String sn,String ip,String cmd,String type) {if (out==null) {start(ip,sn);LOGGER.d("out==null xiaoyou lose ");return;}if (client!=null) {try{client.sendUrgentData(0xFF);//发送一个字节判断是否为空,此字节服务端会自动舍弃}catch(Exception ex){start(ip,sn);LOGGER.d("socket close xiaoyou lose ");return;}}else {start(ip,sn);LOGGER.d("client==null xiaoyou lose ");return;}try {JSONObject jsonO = new JSONObject();jsonO.put("type", type);jsonO.put("action_cmd", cmd);out.writeUTF(jsonO.toString());out.flush();LOGGER.d("send " + cmd);} catch (IOException e) {LOGGER.e("IOException:", e);}}public void testSocket(String ip,String sn) {//测试socket是否通,不通重连if (out==null) {start(ip,sn);LOGGER.d("out==null xiaoyou lose ");return;}if (client!=null) {try{client.sendUrgentData(0xFF);//发送一个字节判断是否为空,此字节服务端会自动舍弃}catch(Exception ex){start(ip,sn);LOGGER.d("socket close xiaoyou lose ");return;}}else {start(ip,sn);LOGGER.d("client==null xiaoyou lose ");return;}}/*** * 上报血压仪数据,上报数据之前先上报上线 * @param sn* @param type 类别* @param dbp 舒张压* @param sbp 收缩压*/private void reportBloodDeviceData(String sn,String type,int dbp,int sbp){deviceService.reportDeviceOnline(sn, "uurobot_bloodDevice");JSONObject data = new JSONObject();JSONObject bloodDevice = new JSONObject();bloodDevice.put("diastolicPressure", dbp);bloodDevice.put("systolicPressure", sbp);JSONObject uurobot_bloodDevice = new JSONObject();uurobot_bloodDevice.put("result", type);data.put("uurobot_bloodDevice", uurobot_bloodDevice);data.put("bloodDevice", bloodDevice);LOGGER.d("sn:{0},data:{1}", sn,data);deviceService.reportDeviceProperty(sn, "uurobot_bloodDevice", data);}/*** * 上报体重秤数据,上报数据之前先上报上线 * @param sn* @param weight 体重*/private void reportWeighingDeviceData(String sn,float weight){deviceService.reportDeviceOnline(sn, "uurobot_weighingDevice");deviceService.reportDeviceProperty(sn, "uurobot_weighingDevice", "weighingDevice","weight",weight);}}
CanbotRobotDriver 类为小优设备驱动类,此类会初始化小优设备监听器,并执行事件的响应doAction
import org.json.JSONObject;import com.huawei.smarthome.api.event.IDeviceEventService;
import com.huawei.smarthome.api.exception.ActionException;
import com.huawei.smarthome.driver.ip.AbstractSsdpDeviceDriverAdapter;
import com.huawei.smarthome.localapi.ServiceApi;
import com.huawei.smarthome.log.LogService;
import com.huawei.smarthome.log.LogServiceFactory;/*** Title: iManager NetOpen V100R001C00
* Description: ssdp发现模式设备驱动
* Copyright: Copyright (c) 1988-2015
* Company: Huawei Tech. Co., Ltd
* @author h00210095* @version 1.0 2015-10-19*/
public class CanbotRobotDriver extends AbstractSsdpDeviceDriverAdapter
{final private static LogService LOGGER = LogServiceFactory.getLogService(CanbotRobotDriver.class);private CanbotDeviceListener canbotDeviceListener;@Overridepublic JSONObject doAction(String sn, String commmand, JSONObject params, String deviceClass)throws ActionException{LOGGER.i("sn:" + sn + ",commmand:" + commmand + ",params:" + params + ",deviceClass:" + deviceClass);//ssdp设备是IP设备,先校验IPString ip = this.getDeviceIp(sn);if ("uurobot".equalsIgnoreCase(deviceClass) && ip != null && !"".equals(ip)){String cmd = null;String type= null;// 腿部指令if ("moveLeg".equals(commmand)) {type="001";String param=params.getString("direction");{if(param.equals("front")){cmd = "0X8a";}else if(param.equals("back")){cmd = "0x8b";}else if(param.equals("left")){cmd = "0x03";}else if(param.equals("right")){cmd = "0x04";}}}// 头部指令else if ("moveHead".equals(commmand)) {type="001";String param=params.getString("direction");{if(param.equals("up")){cmd = "0X0a";}else if(param.equals("down")){cmd = "0X0b";}else if(param.equals("left")){cmd = "0X07";}else if(param.equals("right")){cmd = "0X06";}else if(param.equals("reset")){cmd = "0X09";}}}// 关闭关命else if ("reportMsg".equals(commmand)) {type="002";String param=params.getString("msg");if(param.equals("result")){String content=params.getString("content");LOGGER.i("content:" + content);JSONObject rspmsg=new JSONObject();rspmsg.put("rsp", "result");rspmsg.put("content", content);cmd=rspmsg.toString();
// cmd="0X0a";}else if(param.equals("alarm"))//此处响应智能家居控制,以后还需要改{String alarmName=params.getJSONObject("content").getString("alarmName");LOGGER.i("alarmName:" + alarmName);JSONObject rspmsg=new JSONObject();rspmsg.put("rsp", "alarm");rspmsg.put("content", alarmName);cmd=rspmsg.toString();}else if(param.equals("message")){
// cmd="0X07";}}if (cmd!=null&&type!=null) {canbotDeviceListener.sendActionCmd(sn,ip, cmd,type);}}else{throw new ActionException(-1, "couldn't find device class " + deviceClass);}return null;}
/*** 初始化服务端口,并读取端口信息*/@Overridepublic void init(){//得到其他设备并且驱动
// IDeviceManageService deviceManageService = ServiceApi.getService(IDeviceManageService.class, null);
// deviceManageService.doAction(sn, action, parameter, deviceClass)//添加监听器,机器人上线时与机器人建立连接IDeviceEventService service = ServiceApi.getService(IDeviceEventService.class, null);canbotDeviceListener=new CanbotDeviceListener(this,deviceService);service.addDeviceListener("uurobot",canbotDeviceListener);LOGGER.d("init() ");}
}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
