Loading... ## 前言 这周汇报完了大组会,属于是可以稍微解放一段时间了,在家里天天打游戏也已经腻了,回头一瞥看到了角落里几个月前买的一套esp32设备,不如拿出来再做点东西玩,就想再简单地接一些传感器练练手。翻找资料看到一个DHT11温湿度传感器,又想着几个月前本来打算用esp32做点什么联网的功能,自然而然地想到了IOT(物联网),**本地测量温湿度在网页上显示**这个简简单单的想法就诞生了。 老规矩,先看效果:  ## 设计思路 虽然现在写文章的时候看上去做这个功能的整个设计过程很清晰,但实际上在真正做的时候都是边做边看的,最后经过各种尝试对比才决定用这样的设计。 物联网,简单地分解一下就是[**本地**],[**传输**],[**服务器**] 三个部分 * 本地端:传感器采集数据,与服务器建立连接,发送数据到服务器 * 传输:数据从本地发送到服务器的过程 * 服务器:接收数据并将数据显示在前端页面上 下面是每个部分的详细设计思路 ### 本地端 本地要完成的工作就很简单:收集数据,联网,发送数据。发送数据过程在传输部分说明。 收集数据:用esp32连接DHT11温湿度传感器,输出温湿度数据就行。 联网:使用esp32的网络模块连接WiFi ### 传输 传输的话就是把本地数据发送到服务器上,这里有三种思路 <img src="https://sanxiansing.top/usr/themes/handsome/assets/img/设计思路.jpg" width="500" alt="设计思路" style=""> * 思路1:直接向服务器前端发送数据,大概实现就是通过js的http功能接收数据,但是本人对于js还是http都不熟,而且要用http功能貌似得用node.js,感觉就相当于写个后端了,且这个思路只能用于这一个项目,换个项目还得重写js,扩展性不高。 * 思路2:直接向服务器数据库写入数据,看上去很方便但实现难度很大。相当于本地远程操作数据库,如果是完整python的话有MySQLdb库,但是microPython的话这个库应该算是很冷门了,大概搜了一下确实有,但是相关资料很少。 * 思路3:写个后端,应该算是拓展性最高的了,之所以选择这个也是因为之前在帮同学做一个项目的时候写过python的后端代码可以直接用,果然啊多学点东西指不定什么时候会有用。 三种思路也算是我设计时的思考逐步改进的过程,虽然写个后端相比于前两种工作量更大,但如果考虑到以后要加其他的功能的话是很有必要的,而且前两种的实现难度也更高。 ### 服务器 服务器分为后端、前端、数据库三个部分 后端完成两个功能: * 与esp32通信 * 操作数据库 数据库负责存储数据 前端负责显示数据,一般一个前端页面分为HTML(内容)+js(功能)+css(美化)三部分,这个一般直接找网页模板,然后根据自己需求改改,虽然我对前端知识懂得的皮毛都算不上,但照猫画虎瞎改改还是很有经验的。 ## 实施执行 下面是“快乐”的写代码时间 ### esp32连接温湿度传感器 硬件接线操作这次就不说了,很简单一个接地,一个接vcc,一个接I/O口,放一下传感器长什么样吧  在esp32做小彩灯的时候已经提到过,商家给的传感器教程都是基于Arduino的,所以用microPython的话得自己写,于是我还是想照猫画虎把Arduino的c程序仿写改成python的,一看好嘛,将近100行代码,人家直接从底层出发,又拉低又拉高的,不愧是c语言啊 <img src="https://sanxiansing.top/usr/themes/handsome/assets/img/20221226171134.jpg" width="500" alt="一会高电平一会低电平的" style=""> 代码有点看不懂,查了一下DHT11的原理,数据发送流程图是  这也太底层了吧!!接收到的数据还是二进制的比特流!! 当我尝试用python写了三分之一后,只想发出一句感叹:爷不玩辣! <img src="https://sanxiansing.top/usr/themes/handsome/assets/img/62da3c91fad4dcf5638f6e85df12b04.jpg" width="300"> 没那个耐心去学底层了,于是在百度的搜索栏里面打出“microPython”“dht11”,居 然 出 来 一堆!!!看人家都怎么写的,结果代码第一行赫然写着一串字母 ```python import dht ``` microPython居然有这个传感器的库!!!冷静一想,正是了,是我走偏了,底层都是C语言干的事儿,咱用python得直接找库啊,更新了一下microPython的版本后,顺利导入,寥寥几行代码爆杀C语言的100行 ```python import dht d = dht.DHT11(machine.Pin(dhPin)) d.measure() data = "temp(c): %s℃ humidity: %sRH" % (d.temperature(), d.humidity()) print(data) ``` 看一下输出:  对着传感器哈气,温度上升,湿度上升,行,大差不差吧,技术参数写着温度误差+-2℃,测个大概就行。现在数据采集功能已经完成。 ### esp32联网 esp32连接WiFi功能在microPython的中文手册上给了现成的代码,直接写上连接就完事了 [esp32快速参考](http://www.gdradio.com.cn/en/latet/esp32/quickref.html#networking) 示例代码: ```python import network def do_connect(): wlan = network.WLAN(network.STA_IF) wlan.active(True) if not wlan.isconnected(): print('connecting to network...') wlan.connect('WiFiname', 'password') while not wlan.isconnected(): pass print('network config:', wlan.ifconfig()) do_connect() ``` 不过网段只能支持2.4Ghz,5G的想想也不可能吧 ### esp32连接服务器后端 esp32连接后端当然还是经典的socket通信过程,http太高端至今不会用,还是socket最直接,翻出了当时做项目用的服务器和客户端python代码 本地为方便调用,我给连接服务器和发送数据封装成了两个函数 ```python def do_connect_server(): client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) sockaddr = socket.getaddrinfo('后端的ip/域名', 端口号)[0][-1] client.connect(sockaddr) return client def sendData(data,sock): now=get_time() s_data=[{'temperature':data[0],'humidity':data[1],'time':now}] print('ToSendData: ',s_data) data_send = bytes(str(s_data), 'utf-8') sock.send(data_send) data = sock.recv(1024) station_replay=str(data,'utf-8') print('Server response: ',station_replay) ``` 传输温度,湿度和时间三个数据给后端,其中时间是esp32的内置时钟获取的,这里不过多介绍了。就是代码的变量名命名有点乱,都是当初写的时候不规范,现在也懒得改了,能用就行。 服务器监听端口,接收数据部分代码: ```python ip_port = ('', 5231) sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM) sk.bind(ip_port) sk.listen(5) while 1: print('wait cnonnect....') conn, address = sk.accept() print(address) data=[] while 1: data_recv = conn.recv(1024) stop=str(data_recv,encoding='utf-8') if stop=='stop': conn.close() break data=eval(data_recv) print('data',data) reply=bytes('server:over',encoding='utf-8') conn.send(reply) ``` 一次传输完毕数据后,服务器给客户端发送一次“over”,但不断开连接,继续等待接收数据,当收到数据内容是'stop'时,才断开连接,重新监听端口 这里传输数据里面的bytes、str转化等操作是对数据封装成传输数据的格式,涉及到utf-8编码是为了让收发两端收到的内容格式一致,当时最开始做的时候在这个上面踩过不少坑,用通信的话来说就是对源信号进行调制使其更适合信道传输,接收端再解调,不愧是我! 至此esp32把数据发送给服务器后端,后端接收数据功能已经完成。 ### 服务器后端程序连接数据库 服务器后端程序的另一个功能就是操作数据库,即把接收到的数据存入数据库中,这个主要涉及到的是mysql的增删改查语句,python程序用MySQLdb库即可完成相应操作。 先看一下数据库的设计,iot库下data表,有三个属性,只存一行数据。因为也不绘制温度变化折线图,所以旧数据也没用,所以每次新存入数据都是更新操作,覆盖旧数据。  然后就是后端操作数据库代码,非常简单。 操作数据库代码: ```python #连接数据库 db = MySQLdb.connect("localhost", "数据库登录用户名", "数据库密码", "数据库名", charset='utf8',unix_socket='/var/lib/mysql/mysql.sock') #获取操作游标 cursor = db.cursor() #更新操作 try: # 执行SQL语句 cursor.execute('mysql操作语句') # 提交到数据库执行 db.commit() except: # 发生错误时回滚 db.rollback() ``` 连接数据库的时候当时报错: ```报错 ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2) ``` 是因为MySQLdb库默认找这个文件的路径下没有这个文件,我搜了一下自己的sock文件在tmp目录下,网上给出的解决办法中最简单的就是在这个路径下设置一个软链接指向自己的sock文件位置 ```设置软链接 ln -s /tmp/mysql.sock /var/lib/mysql/mysql.sock ``` 至此,已经实现本地数据发送到服务器后端,后端写入数据库功能,也就是本地数据已经能实时更新到服务器中了,其他程序要用都可以随用随取。 ### 前端设计 在网上大致找了一个好看的温度计网页部件  #### js+html代码样式修改 要用上面的这个模板,改成下图预期效果,需要去掉滑动条,并且复制一个新的温度计改成湿度,过程就不叙述了,毕竟我是删一句代码看一下效果,看看哪些代码操作了哪些东西,然后依葫芦画瓢改出来的,属实是过于痛苦,改了整整一天,哦不半天。(毕竟早上在睡觉)  这里放一下我改的时候参考的教程: [参考教程](http://www.shbelec.com/html/759210313.html) 最后在js里面留下两个接口,只需要给数据就能改变显示的温度数据。 ```javascript const tem = document.getElementById("temVal"); const hum = document.getElementById("humVal"); Tval=tem.dataset.value; Hval=hum.dataset.value; ``` 这下就只剩下将数据库中的数据取出来和js里面的接口对接就行了。万万没想到,这最后一步居然成了整个项目中让我最费时间和精力的部分! #### php连接数据库传输数据给js 如果一开始就知道这个方法的话倒也不会费时费力,关键就在于在这之前我对于前端操作数据库这个问题的解决毫无思路,从功能上看的话,html、js、css中能够操作数据库的也就只有js了,但是搜到的教程都基本上依赖于node.js项目,对我来说等于是要重新开始学习一个新东西了。当我还不死心地搜索解决办法时,发现了一个回答说用php连接数据库。虽然我也没学过php语言,但是这个博客是用typecho搭建起来的,typecho又是基于php语言开发的,博客的网页都是php文件,所以在接触这么久的typecho后,关于php我了解的仅仅是知道php文件能做主页、php文件里面可以写html语言,这两点恰好就够了! 创建index.php文件,先写操作php操作数据库部分 网上找的示例代码然后修改: ```php <?php $servername = "localhost"; $username = "数据库用户名"; $password = "数据库密码"; $dbname = "数据库名"; // 创建连接 $conn = new mysqli($servername, $username, $password, $dbname); // Check connection if ($conn->connect_error) { die("连接失败: " . $conn->connect_error); } //mysql查询语句 $sql = "SELECT temperature, humidity, time FROM data WHERE 1"; $result = $conn->query($sql); } $conn->close(); ?> ``` 接着把前端的index.html的内容复制到后面,通过id属性传给js,就能把数据库取出来的温湿度数据还有更新时间放到网页上显示了!虽然这中间又经历了不少的坑才完成,但总之结果是解决了,一切艰辛都是值得的! #### 前端代码放到服务器上运行 正好上次阿里之前用于图床的fuhero.top域名在闲着,正好用来解析这个项目,为了让数据显示地更快,把js文件的代码直接复制到index.php中。 ## 运行效果展示  可以直接访问网站: [www.fuhero.top](https://www.fuhero.top) 每30s更新一次数据 ## 后记 每做一个项目都是一种折磨和享受的双重体验,当然或多或少也能学到不少东西,所学的任何一个东西总有一天会有它的用处,或早或晚。对于真正感觉有意思的东西,真的会无限投入时间和精力,这个小小的项目从诞生想法到落地运行仅仅是三天的时间,中间解决了不知道多少问题,最后不管怎样花多少时间,都解决了。这种解决问题的能力对我来说是最宝贵的财富,是在大学的各种竞赛、项目、课余探索的过程中不断磨练出来的。当然也愈发认识到,之所以会被很多简单的问题挡路,还是因为知识储备不够,比如这次项目,如果我掌握了前端、掌握了http可能就不会有这么多麻烦,也可能会做的更好,不过这些和未来的研究方向大相径庭,也不着急去学,细水长流慢慢来吧。 ## 源码 最后附上源码链接,放在GitHub上了 [https://github.com/sanxiansing/IOT_wenshidu](https://github.com/sanxiansing/IOT_wenshidu) ## 内容改动 <div class="panel panel-default box-shadow-wrap-lg goal-panel"> <div class="panel-heading"> 内容改动时间线 </div> <div class="padder-md wrapper"> <div class="streamline b-l m-b"><div class="sl-item b- b-l"> <div class="m-l"> <div class="text-muted">2022-12-26</div> <p>由于内置时钟断电重启后会重置到2000年,所以改为直接获取网络时间 参考链接:[https://blog.csdn.net/weixin_42880082/article/details/126554457](https://blog.csdn.net/weixin_42880082/article/details/126554457)</p> </div> </div></div></div></div> 最后修改:2022 年 12 月 26 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 0 如果觉得我的文章对你有用,请随意赞赏
仅登录用户可评论,点击 登录