小优机器人WIFI+SSDP入网具体实现
来源:互联网 发布:网络投资小项目 编辑:程序博客网 时间:2024/05/21 10:16
小优入网实现
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;//广播IP private static final int BROADCAST_INT_PORT = SSDPUtils.PORT; // 不同的port对应不同的socket发送端和接收端 MulticastSocket broadSocket ;//用于接收广播信息 public static boolean work=false;//循环监听因子 InetAddress broadAddress ;//广播地址 //DatagramSocket数据报Socket DatagramSocket 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 exception System.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 exception System.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 exception System.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 exception System.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 exception System.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 exception System.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.1 ST: urn: schemas-upnp-org:device: 设备名称:1 HOST: 239.255.255.250:1900 EXT: CACHE-CONTROL: max-age=1800 LOCATION: http://127.0.0.1:8008/ssdp/device-desc.xml CONFIGID.UPNP.ORG: 7339 BOOTID.UPNP.ORG: 7339 USN: 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.1 ST: urn: schemas-upnp-org:device: 设备名称:1 HOST: 239.255.255.250:1900 EXT: CACHE-CONTROL: max-age=1800 LOCATION: http://127.0.0.1:8008/ssdp/device-desc.xml CONFIGID.UPNP.ORG: 7339 BOOTID.UPNP.ORG: 7339 USN: 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 IP ip = 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() { @Override public void onInit(int status) { // TODO Auto-generated method stub } }); mTextToSpeech.setOnUtteranceCompletedListener(new OnUtteranceCompletedListener() { @Override public 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 block e.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() { @Override public void onCompletion(MediaPlayer mp2) { // TODO Auto-generated method stub if(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() { @Override public void onCompletion(MediaPlayer mp2) { // TODO Auto-generated method stub if(mphw!=null){ mphw.release(); mphw=null; } cancelDialog();// startvoice();// handler.sendEmptyMessage(rtcode); } }); } } class MyReceiver extends BroadcastReceiver { @Override public 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;/** * <div class="English"> * 设备监听器,当机器人上线时与机器人进行连接 * </div> * * <div class="Chinese"> * * </div> * <br> * @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; } @Override public void deviceAdded(JSONObject device) { } @Override public void deviceRemoved(JSONObject device) { } @Override public void deviceOnlined(JSONObject device) { LOGGER.d("deviceOnlined,device:{0}", device); //得到机器人sn和ip String 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 block e.printStackTrace(); break; } } } }).start(); } } @Override public void deviceOfflined(JSONObject device) { // TODO Auto-generated method stub towork=false; towork2=false; } @Override public void deviceAlarmed(JSONObject device, String alarmName, JSONObject parameter) { } @Override public 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; } } /** * <div class="English"> </div> * <div class="Chinese">上报血压仪数据,上报数据之前先上报上线 </div> * @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); } /** * <div class="English"> </div> * <div class="Chinese">上报体重秤数据,上报数据之前先上报上线 </div> * @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<br> * Description: ssdp发现模式设备驱动<br> * Copyright: Copyright (c) 1988-2015<br> * Company: Huawei Tech. Co., Ltd<br> * @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; @Override public JSONObject doAction(String sn, String commmand, JSONObject params, String deviceClass) throws ActionException { LOGGER.i("sn:" + sn + ",commmand:" + commmand + ",params:" + params + ",deviceClass:" + deviceClass); //ssdp设备是IP设备,先校验IP String 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; }/** * 初始化服务端口,并读取端口信息 */ @Override public 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() "); }}
- 小优机器人WIFI+SSDP入网具体实现
- 浅谈智慧家庭小优机器人通过WIFI+SSDP方式接入华为智能网关
- 聊天机器人的具体实现
- 小慕机器人实现学习
- SSDP
- SSDP
- SSDP
- SSDP
- SSDP
- SSDP
- SSDP
- C SSDP 发现设备实现
- ACE实现SSDP设备发现
- WAP2 wifi密码破解具体流程(BT5实现)
- java实现小九机器人接口
- Android智能机器人“小慕”的实现
- SSDP协议的Android实现以及使用
- SSDP协议的Android实现以及使用
- 多线程执行时为什么调用的是start()方法而不是run()方法
- XML知识索引
- ThreadLocal与synchronized
- 切割圆形头像
- CDISC SDTM AE domain学习笔记 - 2
- 小优机器人WIFI+SSDP入网具体实现
- PDF格式的文档如何编辑修改
- scala sbt 代理设置
- Ajax提交文件
- 隐藏系统信息旗标检测
- kafka学习四:开发producer
- 使用spring sts工具创建springmvc项目
- ios学习路线—Objective-C(autoreleasepool)
- linux 替换系统自带jdk方法