添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
精彩文章免费看

物联网(五)---搭建自己的云平台[ESP8266+Django]

物联网(一)---快速上手[STM32+OneNET+ESP8266]
物联网(二)---原理分析[STM32+OneNET+ESP8266]
物联网(三)---WEB下发命令控制单片机[STM32+OneNET+ESP8266]
物联网(四)---搭建自己的TCP服务器[ESP8266]
物联网(五)---搭建自己的云平台[ESP8266+Django]

下面的这些文章写的都比我好很多,但:
希望你在点击完下面的连接后,最终能回归文章,继续搭建自己的物联网平台。

本节所用到的程序源码下载地址: https://github.com/keep1234quiet/IOT

使用到的工具:
  • Redis 数据库
  • Channels-redis
  • 将ESP8266变成Arduino的官方库
  • 这篇文章来之不易,总共花费了我整整6天的时间,其中5天摸索,1天写文章,还望好好阅读。

    其中未使用 STM32 + ESP8266 的方式是因为我不知道该如何回应服务器端 Ping ESP8266 Pong ,这里应该是要自己手动去实现 WebSocket Ping Pong 的,然后再发送给 ESP8266 的串口,后期需要的话再看下能自己实现不。

    这里本来没什么难度,但要注意的是:

  • 插入链接 https://arduino-esp8266.readthedocs.io/en/latest/installing.html#boards-manager 至Arduino IDE后,要重启Arduino IDE才行;
  • 下载包的时候网络问题,由于总所周知的原因这里不展开介绍;
  • 程序下载的时候需要选好参数,否则会下载不成功,这里每一款模块都是不一样的,我的是ESP-12S的,仅供参考。
  • ESP8266 Arduino core 程序下载参数配置

    当上面的工作完成后,应该就能够用Arduino IDE给ESP8266下载程序了,这里自己下载程序验证一下,推荐使用串口程序验证,看看是否生效。

    二、云平台开发

    2.1 为什么需要用WEB框架来进行开发

    你可能会问,为什么需要用WEB框架来进行开发,如果是小型项目,确实可以不用,但是当你要做一个大项目,比如[OneNET云平台]、[机智云]、[贝壳物联] 这样的稍大型平台,甚至要做体量更大的平台,没有一个好的WEB框架,想要完成开发是十分困难的。

    2.2 继续阅读下去需要什么基础

    如果看完了前面的 预读文章 ,这里应该对 Django 的一些概念有一定的了解了,比如路由 urls 、模型 models 、视图 views 这些概念都应该要知道了。当然,对其他类型框架了解的同学也可以使用其他类型的框架来代替 Django

    2.3 怎么搭建云平台

    本文使用的云平台是由 Django-channels 的聊天室例程改编而来的。原文在此:
    [如何搭建一个简单的网页聊天室]

    文章是原作者写的,教程也写的非常详细,每一步都有详细说明。

    整个过程可能需要安装各种 pythont 的库,这个Terminal会给出详细的说明,可以自己根据错误提示去安装需要的库,如果要我提供的程序里已经将需要用到的库写在了 requirements.txt 文件中了,直接使用 pip3 命令安装即可;这里注意一下 asgiref 这个库,需要升级到最新版本才行,否则会因使用了新版本里的模块而导致无法从旧版本导入而报错。

    唯独 Part 2 里的 Enable a channel layer 这里使用Redis数据库建立了一个通信管道,只告诉了要安装 channels_redis 库,并没有说明如何安装 Redis 数据库,这里在前面的使用到的工具里提供了安装方法【Redis 数据库安装方法:[Redis安装]】,里面有详细的安装教程,也对 Redis 数据库进行了相应的介绍与讲解。

    需要注意的是, Redis 数据库安装完成后,若要服务器中要使用到管道通信,则必须保持Redis数据库在后台运行,否则将无法完成多对多的通信。

    下面的教程只需要完成前三个就好了,第四个自动化测试可以不用。

    完成上面的Tutorial之后应该是下面这种效果的,可以完成同通信功能。
    1.先启动 redis 数据库: redis-server
    2.启动 django 自带的服务器: python3 manage.py runserver 0.0.0.0:8000
    3.查看自己的 ip ipconfig
    4.访问自己的聊天室: http://ip:8000/chat/ChatRoom/
    5.发送消息,服务器对消息进行广播,各个客户端都会收到消息

    2.5 适当修改ESP8266的WebSocketClient程序和服务端的程序

    当前面的工作做完之后,接下来的工作就简单了,只要给 ESP8266 烧入好程序即可。 ESP8266 自带的例程里面有一个 WebSocketClient.ino 的例程,只要对这个例程稍加修改即可,下面是我修改好的 ESP8266 的程序。

    注:其中主要是要注意 ESP8266 发送数据的格式,由于服务端聊天室只对 JSON 的数据进行了解析,所以 ESP8266 的发送的数据必须以 JSON 的格式发送,否则会造成服务端崩溃。即应以这种形式发送才能在网页上正常显示出来:
    webSocket.sendTXT("{\"message\":\"heartbeat\"}");

    ESP8266的程序较为简短,我就直接贴了,程序阅读没有什么难点,应该不会看不懂,如果有缺少的库就自己去装一下就好了。

    * WebSocketClient.ino * Created on: 24.05.2015 #include <Arduino.h> #include <ESP8266WiFi.h> #include <ESP8266WiFiMulti.h> #include <WebSocketsClient.h> #include <Hash.h> ESP8266WiFiMulti WiFiMulti; WebSocketsClient webSocket; #define USE_SERIAL Serial bool isConnected = false; void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) { switch(type) { case WStype_DISCONNECTED: USE_SERIAL.printf("[WSc] Disconnected!\n"); isConnected = false; break; case WStype_CONNECTED: { USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload); isConnected = true; // send message to server when Connected // webSocket.sendTXT("Connected");//发送Conneted 导致服务器抛出 Expecting value: line 1 column 1 (char 0) 异常而断开连接。//先注释掉试试 //原因是服务端只对JSON数据进行解析,"Connected"是字符串而不是JSON数据。 break; case WStype_TEXT: USE_SERIAL.printf("[WSc] get text: %s\n", payload); // send message to server //webSocket.sendTXT(rcvMsg); break; case WStype_BIN: USE_SERIAL.printf("[WSc] get binary length: %u\n", length); hexdump(payload, length); // send data to server // webSocket.sendBIN(payload, length); break; void setup() { // USE_SERIAL.begin(921600); USE_SERIAL.begin(115200); //Serial.setDebugOutput(true); USE_SERIAL.setDebugOutput(true); USE_SERIAL.println(); USE_SERIAL.println(); USE_SERIAL.println(); for(uint8_t t = 4; t > 0; t--) { USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t); USE_SERIAL.flush(); delay(1000); WiFiMulti.addAP("YOUR-WIFIF-NAME", "YOUR-PASSWORD"); //WiFi.disconnect(); while(WiFiMulti.run() != WL_CONNECTED) { delay(100); // server address, port and URL webSocket.begin("192.168.43.102", 8000, "/ws/chat/M/"); // event handler webSocket.onEvent(webSocketEvent); // use HTTP Basic Authorization this is optional remove if not needed ////webSocket.setAuthorization("user", "Password"); // try ever 5000 again if connection has failed webSocket.setReconnectInterval(5000); // start heartbeat (optional) // ping server every 15000 ms // expect pong from server within 3000 ms // consider connection disconnected if pong is not received 2 times webSocket.enableHeartbeat(15000, 3000, 2); //这个时间很准,可以从wireshark里面查看,ESP8266每15秒钟Ping一次服务器,期间会收到服务器的Ping,ESP8266也会Pong回去 int count = 0; String inputString = ""; boolean stringComplete = false; char sendStr[100]; void loop() { webSocket.loop(); serialEvent(); //发现ESP8266没有serialEvent()事件,故在此对该函数进行调用 count++; if(count == 60*100){ count = 0; if(isConnected){ //这里并不是心跳,心跳需要抓包才能看到 webSocket.sendTXT("{\"message\":\"heartbeat\"}"); if (stringComplete) { String s1 = "{\"message\":\""; String s2 = "\"}"; webSocket.sendTXT(s1+inputString+s2); // clear the string: inputString = ""; stringComplete = false; memset(sendStr,0,100); delay(10); void serialEvent() { while (Serial.available() && !stringComplete) { // get the new byte: char inChar = (char)Serial.read(); // if the incoming character is a newline, set a flag // so the main loop can do something about it: if (inChar == '\n') { stringComplete = true; return; // add it to the inputString: inputString += inChar;

    将上面的程序下载至 ESP8266 中,从烧录模式切换为正常运行模式,复位或重新上电。若服务器没有关闭,会从服务器的 Debug 窗口看到有新的客户端连接上了。

    当连接成功之后,就可以让 ESP8266 和服务器的其他客户端加入同一个聊天室进行聊天了,这里必须是同一个聊天室,不然无法收到信息,聊天室是由 /chat/ 后的字符决定的。

    这里我对 Web 端 的服务器的 consumer.py 文件中的 ChatConsumer类 里的 receive 稍加修改,以避免服务器收到非 JSON 消息而崩溃,修改如下:

        # Receive message from WebSocket
        def receive(self, text_data):
            print('====' * 10)
            print('rawMsg:'+text_data)
            print('====' * 10)
                text_data_json = json.loads(text_data)
                message = text_data_json['message']
            except:
                message = text_data
            # Send message to room group
            async_to_sync(self.channel_layer.group_send)(
                self.room_group_name,
                    'type': 'chat_message',
                    'message': message
    
    2.6 让ESP8266作为客户端,发送或接收信息

    电脑开启热点,让手机和服务器处于同一局域网内,如果没问题的话应该能看到如下现象:

  • 通过串口助手向ESP8266发送数据,以\n结尾,不要以\r\n结尾,程序里没作相应的处理;
  • ESP8266 将从串口接收到的数据进行解析,封装成JSON格式的数据,在通过调用函数webSocket.sendTXT(your JSON message)将数据发送至服务器;
  • 服务器收到ESP8266发来的JSON格式数据后,对其进行解析,并广播出去,其中也包括客户端ESP8266
  • 从网页端发送数据,服务器收到后,也同样会广播出去,ESP8266作为客户端也会收到被广播出来的数据,这样就完成了一次数据收发的过程了。
  • 到这里就完成开发了一个自己的云平台了,虽让功能比较简陋,但是整个流程已经走通了。相比于上一节所讲的,这一节似乎并没有太多的变化,但不同的是,我们这一节引入了WEB框架 Django,有了WEB框架,我们开发大型项目就方便快速多了,也非常有利于项目管理。

    2.7 整体框架梳理

    总结:本文内容篇幅不算长,但是大量引用了相关链接,对别人已经做得比较好的部分没有进行重复讲解,而是给出链接,希望读者能前去学习完毕后再来继续学习节教程,其中给出了DjangochannelsWebSocketESP8266 Arduino core等均给出原作者原文链接及官网,也都是很好的教程,非常详细。

    本文只是走通了【搭建自己的云平台并使用ESP8266成功连接云平台】这条道路,仍然有诸多问题尚未解决,比如:

  • 服务端不应该给所有的客户端进行消息广播,而应该是有选择性的;
  • 这里是用了ESP8266 Arduino core的库,利用的是其内置的WebSocket 协议实现,如果加上单片机呢,换一种连接方式又该怎么实现呢?
  • 这里的所有消息都是明文传输,未进行加解密,是十分不安全的;
  • 浏览器端这么丑,是不是应该美化一下呢,功能是不是应该继续丰富呢?
  • 虽然已经做了蛮多的,但是接下来要做的一点也比现在已经做的事要少,后续就留给读者自己去探寻吧,我此后我会间断的更新此系列的文章,以尽量使整个过程完整而详尽。

    本系列的物联网文章就暂时告一段落了吧。

    最后编辑于:2022-05-30 15:12