当前位置: 首页 > news >正文

记大三心血之作:物联网应用开发-智能家居

物联网应用开发-智能家居项目

记大三上学期结束,以智能家居项目结束了大学前2年半愉快的生活。做完这个项目,突然觉得自己对编程好像还是有点兴趣的,遂将剩余的一年半的大学生活重心向技术倾斜,虽然仍然上课老是打瞌睡,但是还是将剩余的大部分空闲时间扔在了实验室和学生会。

源码地址:https://github.com/hellozhaoxudong/SmartHome


1.项目成员
  • 赵旭东
  • 郑普元:元哥当年精通HTML和JS,没想到去国企当主任去了。
  • 胡旸:华为美铝。
  • 甄洪磊:富二代。

2.成果

(1)全部成果

(2)数据实时展示、控制命令发送网站



(3)网关-开发板

(4)传感器节点


3.项目背景

目前通常把智能家居被定义为利用电脑、网络和综合布线技术,通过家庭信息管理平台将与家居生活有关的各种子系统有机地结合的一个系统。也就是说,首先,它们都要在一个家居中建立一个通讯网络,为家庭信息提供必要的通路,在家庭网络的操作系统的控制下,通过相应的硬件和执行机构,实现对所有家庭网络上的家电和设备的控制和监测。其次,它们都要通过一定的媒介平台,构成与外界的通讯通道,以实现与家庭以外的世界沟信息,满足远程控制/监测和交换信息的需求。最后,它们的最终目的都是为满足人们对安全、舒适、方便和符合绿色环境保护的需求。


4.总体设计思路

写一个控制各种传感器的网站,前端能适配到PC端和移动端。网站后台把用户命令发送到服务器,服务器进行判断发送到网关,网关进行判断进行相应的操作。网关接收协调器的各种信息上传到服务器,服务器把数据存入数据库。


5.模块设计思路

该系统在开发时分为PC、移动端前端模块,服务器模块,网站后台模块,数据处理模块,数据存储模块,网关模块,ZigBee网络模块。


6.关键技术

Bootstrap框架、ECharts框架、Ajax、Socket、QT


7.网站关键代码
(1) 前端与后台交互:Ajax
var xmlHttp; function lockdoor(){ // 向后台发送标识 //使用方法创建一个对象XmlHttp xmlHttp=createXMLHttp(); //要给服务器发送数据 var url="order?sign=1"; xmlHttp.open("GET",url,true); //4.绑定回调方法 xmlHttp.onreadystatechange=lockdoorcallback; xmlHttp.send(null); } function lockdoorcallback(){ }
(2) 网站后台与前端数据传输:Selvet+Ajax

用户在前端点击按钮,发送一个标识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 sign=request.getParameter("sign");//标识这是用户的那种操作 Integer Sign=Integer.valueOf(sign);//转换后的标识 if(Sign==110){ //继电器模块 System.out.println("用户想开空调"); response.getWriter().write(1); AppConnectServer appConnectServer=new AppConnectServer(Sign); appConnectServer.connect(); }else if(Sign==111){
(3) 服务器和网关交互:Socket(java)<–>Socket(QT)

服务器一直监听8899端口,网关开机后根据用户输入的服务器的IP和Port创建一个新线程SocketTh向服务器发起Socket请求,请求成功后建立Socket长连接,网关收集到的各个传感器的数据通过这个Socket长连接发送至服务器。

public void connect(){ try { Socket socket=new Socket("localhost",8889); System.out.println("网站已连接服务器"); OutputStream os=socket.getOutputStream();//字节输出流 PrintWriter pw=new 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 toGatewayTh=new ServertoGateway();。 toGatewayTh.start(); ServerSocket serverSocket=new ServerSocket(8889); Socket server_socket_th=null; while (true){ server_socket_th=serverSocket.accept(); ExecutorService exec = Executors.newCachedThreadPool(); ServerSocketCa serverSocketCa=new ServerSocketCa(server_socket_th); Future f=exec.submit(serverSocketCa); int ordertogateway=Integer.valueOf(f.get().toString()); System.out.println("线程返回了用户传递来的命令:"+ordertogateway); SendOrdertoGate sendnow=new SendOrdertoGate(); sendnow.sendtogateway(ordertogateway); } }
(2) 和网关建立Socket长连接:线程ServertoGateway

主线程初始化时创建这个线程,该线程在8899端口等待网关的Socket请求,一旦有请求则建立并保持Socket长连接。

@Override public void run() { try { serverSocket_toGateway = new ServerSocket(8899); socket_gateway=serverSocket_toGateway.accept(); System.out.println("网关已连接"); while(true){ if(socket_gateway!=null){ InputStream is=null;//输入流 try { socket_gateway.setKeepAlive(true);//检查两边是否连接 is=socket_gateway.getInputStream();//获取输入流 byte[] buff=new 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 is=null;//输入流 OutputStream os=null;//输出流 is=socket_th.getInputStream();//获取输入流 os=socket_th.getOutputStream();//获取输出流 byte[] buff=new byte[5]; is.read(buff); String signfromhtml =new String(buff); System.out.println(signfromhtml); signtogateway=Integer.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 os=new 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 URL="jdbc:mysql://127.0.0.1:3306/ihome"; private static final String NAME="root"; private static final String PASSWORD="root"; private static Connection conn=null; 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 ptmt=conn.prepareStatement(sql); ptmt.execute();

9.网关-开发板关键代码
(1) 和服务器保持Socket长连接:线程SocketTh
void SocketTh::run(){ socket=new QTcpSocket(); socket->connectToHost(QHostAddress(connectIP), connectPORT); isconnect=socket->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; msg=Gatewayclient->readAll(); if(msg.length()!=0){ int order=msg.toInt(); if(order==110){//开继电器 changeRelay(relays->getState()); }else if(order==111){//关继电器 changeRelay(relays->getState()); }else if(order==120){//电机正转 changeMotor(1); }else if(order==121){//电机到转 changeMotor(2); } } }

8.总结

通过这次实训对多线程、Socket通信、JDBC、Ajax等技术有了一个感性的认识,第一次正在在项目中应用多线程、socket等技术遇到了不少问题,不过还是一一解决了,收获很多,不足之处是许多细节没有考虑很全面,比如Socket掉线重连等等都没有解决。

闲来无事睡不着,更新下当年的心血之作。代码虽青涩,想象力丰富。

http://www.zskr.cn/news/1438209.html

相关文章:

  • 终极指南:5分钟在Android手机运行Windows应用的完整教程
  • Cobalt Strike反向连接如何绕过防火墙?一个多层内网穿透的清晰图解
  • 动态博弈与鲁棒控制在多智能体系统中的应用
  • 保姆级教程:用Altium Designer(AD)从零画一块Type-C小板(附立创商城白嫖封装技巧)
  • 别再只会用Keil了!FlyMCU串口烧录STM32保姆级教程(附ST-LINK Utility对比)
  • 别再死记硬背了!用‘找对象’的思路图解匈牙利算法(附LeetCode棋盘覆盖题解)
  • 英伟达CEO黄仁勋:AI将让人类更忙碌,未来十年将诞生750万个智能体!
  • 考研数学救命稻草:用Python的SymPy库5分钟搞定无穷小阶数比较(附代码)
  • 开发者必看:CvT-21-384-22k模型配置与参数解析完整指南
  • Kagome晶格VQE算法与量子自然梯度优化实践
  • 别再死记硬背SQL JOIN了!用这个电商订单查询案例,5分钟搞懂INNER JOIN到底怎么用
  • 告别拖影与模糊:手把手教你用Python+OpenCV实现一个简易的时空联合3D降噪器
  • 告别错误代码7!LabVIEW报表工具包发布应用程序的完整配置流程(Win10/11实测)
  • Shell脚本避坑指南:为什么你的mapfile命令在管道后面‘失灵’了?
  • 从文件误删到路径拼接:Python os模块实战避坑指南(附真实案例)
  • 在RK3588上把YOLOv8推理速度优化到17ms:我的C++部署踩坑与调优实录
  • zteOnu深度解析:中兴光猫工厂模式认证技术实现
  • Jetson Orin上YOLOv8推理慢?手把手教你安装GPU版PyTorch并导出TensorRT引擎(附版本避坑指南)
  • 如何快速搭建AI应用:46个Dify工作流实战指南
  • bert-large-uncased-finetuned-ner高级技巧:处理子词实体与提升识别精度的实用方法
  • 告别社区5级!手把手教你用PHP脚本绕过小米BL解锁限制(保姆级避坑指南)
  • Edge浏览器里用document.querySelector给视频加速报错?试试这个插件方案(GlobalSpeed实测)
  • OpCore Simplify:自动化OpenCore EFI配置工具深度解析与实战指南
  • 给嵌入式新手的保姆级指南:一文看懂ARM Cortex-M0/M3/M4/M7到底该怎么选
  • 别再只会用os.listdir了!Python os.path模块的这5个隐藏用法,让文件操作效率翻倍
  • 从Ajtai的突破到现代密码学:手把手理解SIS问题如何成为抗量子攻击的基石
  • iftop、nethogs 和 nload:Linux 服务器网络流量实时监控工具介绍
  • Rime小狼毫LaTeX方案深度调优:从能用,到好用,再到顺手(附完整配置文件)
  • 别再问我H5怎么调用摄像头了!一个Vue3组件搞定拍照上传(附完整代码)
  • 保姆级教程:在Ubuntu 22.04上为KVM配置AMD SEV机密虚拟机(附完整命令)