记大三心血之作:物联网应用开发-智能家居
物联网应用开发-智能家居项目记大三上学期结束以智能家居项目结束了大学前2年半愉快的生活。做完这个项目突然觉得自己对编程好像还是有点兴趣的遂将剩余的一年半的大学生活重心向技术倾斜虽然仍然上课老是打瞌睡但是还是将剩余的大部分空闲时间扔在了实验室和学生会。源码地址https://github.com/hellozhaoxudong/SmartHome1.项目成员赵旭东郑普元元哥当年精通HTML和JS没想到去国企当主任去了。胡旸华为美铝。甄洪磊富二代。2.成果1全部成果2数据实时展示、控制命令发送网站3网关-开发板4传感器节点3.项目背景目前通常把智能家居被定义为利用电脑、网络和综合布线技术通过家庭信息管理平台将与家居生活有关的各种子系统有机地结合的一个系统。也就是说首先它们都要在一个家居中建立一个通讯网络为家庭信息提供必要的通路在家庭网络的操作系统的控制下通过相应的硬件和执行机构实现对所有家庭网络上的家电和设备的控制和监测。其次它们都要通过一定的媒介平台构成与外界的通讯通道以实现与家庭以外的世界沟信息满足远程控制/监测和交换信息的需求。最后它们的最终目的都是为满足人们对安全、舒适、方便和符合绿色环境保护的需求。4.总体设计思路写一个控制各种传感器的网站前端能适配到PC端和移动端。网站后台把用户命令发送到服务器服务器进行判断发送到网关网关进行判断进行相应的操作。网关接收协调器的各种信息上传到服务器服务器把数据存入数据库。5.模块设计思路该系统在开发时分为PC、移动端前端模块服务器模块网站后台模块数据处理模块数据存储模块网关模块ZigBee网络模块。6.关键技术Bootstrap框架、ECharts框架、Ajax、Socket、QT7.网站关键代码(1) 前端与后台交互Ajaxvar xmlHttp; function lockdoor(){ // 向后台发送标识 //使用方法创建一个对象XmlHttp xmlHttpcreateXMLHttp(); //要给服务器发送数据 var urlorder?sign1; xmlHttp.open(GET,url,true); //4.绑定回调方法 xmlHttp.onreadystatechangelockdoorcallback; xmlHttp.send(null); } function lockdoorcallback(){ }(2) 网站后台与前端数据传输SelvetAjax用户在前端点击按钮发送一个标识Sign到网站后台后台对这个Sign进行判断判断如果是一个命令那么直接调用AppConnectServer类的connect(发送至服务器。前端每5s向后台发送“10110”请求各个传感器节点的信息后台接收到后立刻返回一个封装了各个传感器信息的字符串给前端。public class Background extends HttpServlet{ Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(UTF-8); response.setCharacterEncoding(UTF-8); String signrequest.getParameter(sign);//标识这是用户的那种操作 Integer SignInteger.valueOf(sign);//转换后的标识 if(Sign110){ //继电器模块 System.out.println(用户想开空调); response.getWriter().write(1); AppConnectServer appConnectServernew AppConnectServer(Sign); appConnectServer.connect(); }else if(Sign111){(3) 服务器和网关交互Socket(java)–Socket(QT)服务器一直监听8899端口网关开机后根据用户输入的服务器的IP和Port创建一个新线程SocketTh向服务器发起Socket请求请求成功后建立Socket长连接网关收集到的各个传感器的数据通过这个Socket长连接发送至服务器。public void connect(){ try { Socket socketnew Socket(localhost,8889); System.out.println(网站已连接服务器); OutputStream ossocket.getOutputStream();//字节输出流 PrintWriter pwnew PrintWriter(os);//将输出流包装为打印流 pw.write(String.valueOf(sign)); pw.flush(); socket.shutdownOutput();//关闭输出流 pw.close(); os.close(); socket.close(); }8.服务器关键代码服务器初始化时会开一个线程ServertoGateway这个线程负责连接数据库和监听8899端口等待网关请求建立Socket长连接收到网关的数据后存入数据库。主线程监听8889端口等待网站后台Socket请求一旦有请求会开一个线程ServerSocketCa进行和网站后台的数据交换并把数据返回。主线程拿到返回的数据发送至网关。(1)等待socket请求主线程主线程在8889端口等待请求一旦有socket请求开一个线程去处理这个请求。public static void main(String[] args){ try { ServertoGateway toGatewayThnew ServertoGateway();。 toGatewayTh.start(); ServerSocket serverSocketnew ServerSocket(8889); Socket server_socket_thnull; while (true){ server_socket_thserverSocket.accept(); ExecutorService exec Executors.newCachedThreadPool(); ServerSocketCa serverSocketCanew ServerSocketCa(server_socket_th); Future fexec.submit(serverSocketCa); int ordertogatewayInteger.valueOf(f.get().toString()); System.out.println(线程返回了用户传递来的命令ordertogateway); SendOrdertoGate sendnownew SendOrdertoGate(); sendnow.sendtogateway(ordertogateway); } }(2) 和网关建立Socket长连接线程ServertoGateway主线程初始化时创建这个线程该线程在8899端口等待网关的Socket请求一旦有请求则建立并保持Socket长连接。Override public void run() { try { serverSocket_toGateway new ServerSocket(8899); socket_gatewayserverSocket_toGateway.accept(); System.out.println(网关已连接); while(true){ if(socket_gateway!null){ InputStream isnull;//输入流 try { socket_gateway.setKeepAlive(true);//检查两边是否连接 issocket_gateway.getInputStream();//获取输入流 byte[] buffnew byte[20]; is.read(buff); String tempdata new String(buff); System.out.println(正在接收数据:tempdata);(3) 接收网站后台数据线程ServerSocketCa服务器一直监听8889端口一旦后台发来了新的连接请求则开一个新的线程ServerSocketCa去处理这个请求数据收发完毕后会返回主线程程一个Sign标识服务器再把这个标识发送到网关。Override public Object call() throws Exception { try { InputStream isnull;//输入流 OutputStream osnull;//输出流 issocket_th.getInputStream();//获取输入流 ossocket_th.getOutputStream();//获取输出流 byte[] buffnew byte[5]; is.read(buff); String signfromhtml new String(buff); System.out.println(signfromhtml); signtogatewayInteger.valueOf(signfromhtml.trim()); socket_th.shutdownInput();//关闭输入流 is.close(); os.close(); }(4) 发送用户命令到网关线程SendOrderToGateWay向网关发起一次Socke请求并传送用户命令。Override public void run() { try { System.out.println(向网关发起Socket请求的线程初始化完毕); System.out.println(向网关发起请求); OutputStream osnew Socket(192.168.134.110,9999).getOutputStream(); os.write(temp.getBytes(UTF-8)); os.close(); }(5) 数据存储: JDBC服务器接收到网关上传的各个传感器的实时数据后上传到MySql数据库进行存储。try { Class.forName(com.mysql.jdbc.Driver); conn DriverManager.getConnection(URL,NAME,PASSWORD); } private static final String URLjdbc:mysql://127.0.0.1:3306/ihome; private static final String NAMEroot; private static final String PASSWORDroot; private static Connection connnull; String sql insert into ihome (temp,hump,light,smoke,infray,shake) values(Integer.valueOf(temp),Integer.valueOf(hump),Double.valueOf(light), Integer.valueOf(smoke),Integer.valueOf(infray),Double.valueOf(shake)); java.sql.PreparedStatement ptmtconn.prepareStatement(sql); ptmt.execute();9.网关-开发板关键代码(1) 和服务器保持Socket长连接线程SocketThvoid SocketTh::run(){ socketnew QTcpSocket(); socket-connectToHost(QHostAddress(connectIP), connectPORT); isconnectsocket-waitForConnected(); qDebug()connect sucessful; }(2) 接收服务器发送的用户命令主线程Gatewayserver new QTcpServer(); qDebug()lisening 9999; Gatewayserver-listen(QHostAddress::Any, 9999); connect(Gatewayserver, SIGNAL(newConnection()), this, SLOT(acceptConnection())); void MainWindow::acceptConnection(){ qDebug()server ask connect; Gatewayclient Gatewayserver-nextPendingConnection(); connect(Gatewayclient, SIGNAL(readyRead()), this, SLOT(readMsg())); } void MainWindow::readMsg(){ QString msg; msgGatewayclient-readAll(); if(msg.length()!0){ int ordermsg.toInt(); if(order110){//开继电器 changeRelay(relays-getState()); }else if(order111){//关继电器 changeRelay(relays-getState()); }else if(order120){//电机正转 changeMotor(1); }else if(order121){//电机到转 changeMotor(2); } } }8.总结通过这次实训对多线程、Socket通信、JDBC、Ajax等技术有了一个感性的认识第一次正在在项目中应用多线程、socket等技术遇到了不少问题不过还是一一解决了收获很多不足之处是许多细节没有考虑很全面比如Socket掉线重连等等都没有解决。闲来无事睡不着更新下当年的心血之作。代码虽青涩想象力丰富。