Skip to content

Latest commit

 

History

History
executable file
·
296 lines (211 loc) · 11.4 KB

8266搭建微型服务器.md

File metadata and controls

executable file
·
296 lines (211 loc) · 11.4 KB

8266搭建微型服务器

前言

昨天我分别用arduino(昨天全篇都把这个单词拼错了)和8266点亮了OLED,感觉还是很好玩的,而且很有成就感,这个成就感最大的来源是,终于在硬件方面有了一点点突破,当然之前没突破的原因可能是时机不成熟。

今天我发现树莓派其实也是可以点亮oled的,而且树莓派新能更强,按理说可玩性应该很高,没玩起来可能还是实力不够,不过现在这些都已经成为过去了,毕竟万事开头难,昨天开了一个好头,后面应该会越来越顺的。

今天我们要分享下如何用8266搭建一个微型服务器,目前我找到两种解决方案,一种是普通的web服务器(类似于我之前写过的syske-boot),另一种是webservice,从传输数据的灵活性方面来看,后一种更灵活,也更方便,下面我们具体来看下如何实现。

微型服务器搭建

在开始之前,我们先简单介绍下Arduino IDE

安装Arduino IDE

从事开发工作的小伙伴应该对IDE都不陌生,所有的语言都有自己的IDE,它的中文意思是集成开发环境,所以Arduino IDE就是Arduino的集成开发环境,除了Arduino IDE之外,我们还可以用VS CODE开发Arduino

Arduino IDE的安装很简单,直接下载安装文件双击运行即可。当然,你也可以下载便携版,这个版本是免安装的。

目前最新版本是1.8.15,左下方的选项是下载安装版的,右上方的ZIP File选项是下载免安装版的。

下载安装之后,首次打开长这个样子:

主要区域有三块,菜单栏(工具栏)、代码区(写代码的地方)、终端。大部分IDE都包括这个三个分区。

菜单栏五个图标分别表示

  • 第一个表示编译代码,主要用于检查代码是否有编译错误
  • 第二个表示将代码上传到开发板中,在此之前要先安装好开发板的驱动,然后选择对应的串口号
  • 第三个是新建项目
  • 第四个是打开,主要用了打开新项目
  • 第五个是保存,用于保存当前项目

出了这个几个常用的菜单外,还有几个菜单我们会经常用到:

第一个是管理库,就是用来管理Arduino的第三方库的,比如ESP8266之类的,我们可以在这个菜单下下载新的库,目前第三方库特别多:

下面那个端口菜单,主要是用来切换端口的,一般我们开发板连接电脑后,安装完驱动之后,系统会给他分配串口号,具体串口号可以去设备管理器下查看:

好了,关于Arduino IED我们暂时就先说这么多,有不清楚的小伙伴可以留言或者私信。

web微型服务器搭建

下面我们就直接上代码了:

#include <ESP8266WiFi.h>;
#include <ArduinoWiFiServer.h>;
#include <SPI.h>; // 加载SPI库
#include <Wire.h>; // 加载Wire库
#include <Adafruit_GFX.h>; // 加载Adafruit_GFX库
#include <Adafruit_SSD1306.h>; // 加载Adafruit_SSD1306库

// 定义 OLED屏幕的分辨率
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire);

// WiFi parameters
const char* ssid = "wifi name";
const char* password = "wifi-password";
// 创建服务器实例,并指定服务器端口
ArduinoWiFiServer server(2323);
String infoStr = "";
String ip = "";

void setup() {

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // 设置OLED的I2C地址

  display.clearDisplay(); // 清空屏幕

  display.setTextSize(2); // 设置字体大小
  display.setTextColor(SSD1306_WHITE); // 设置字体颜色
  display.setCursor(0, 0); // 设置开始显示文字的坐标
  display.println("Hello World!"); // 输出的字符
  display.println("   by syske");
  display.display(); // 使更改的显示生效

  delay(1000);

  Serial.begin(9600); // 设置串口波特率

  Serial.println("OLED FeatherWing test"); // 串口输出

  delay(10);
  // 必须采用 AP 与 Station 兼容模式
  WiFi.mode(WIFI_AP_STA);
  delay(500);
  // 等待配网
  //  WiFi.beginSmartConfig();
  // Connect to WiFi
  WiFi.begin(ssid, password);
  // 收到配网信息后ESP8266将自动连接,WiFi.status 状态就会返回:已连接
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    // 完成连接,退出配网等待。
    Serial.println(WiFi.smartConfigDone());
  }
  ip = WiFi.localIP().toString();
  display.println("IP: " + ip); // 输出的字符
  display.display(); // 使更改的显示生效
  server.begin();
  // 串口数据打印,这里主要是为了方便调试
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

}

void loop() {
  // put your main code here, to run repeatedly:
  WiFiClient client = server.available(); // returns first client which has data to read or a 'false' client
  Serial.println(client);
  if (client) { // client is true only if it is connected and has data to read
    String s = client.readStringUntil('\n'); // read the message incoming from one of the clients
    s.trim(); // trim eventual \r
    Serial.println(s); // print the message to Serial Monitor
    if (s.length() > 0) {
      infoStr = String(infoStr + "\n" + s);
      display.clearDisplay(); // 清空屏幕
      display.setTextSize(1); // 设置字体大小
      display.setTextColor(SSD1306_WHITE); // 设置字体颜色
      display.setCursor(0, 0); // 设置开始显示文字的坐标
      display.print("IP: " + ip); // 输出的字符
      display.println(infoStr); // 输出的字符
      display.display(); // 使更改的显示生效
      client.print("HTTP/1.1 OK\nContent-Type:text/html\n\r\n<html><head><link rel=\"icon\" href=\"data:;base64,=\"></head><body>hello 8266</body></html>"); // this is only for the sending client
      server.println(s); // send the message to all connected clients
      server.flush(); // flush the buffers

      client.stop();
    }
  }
}

代码都比较基础,这里做一个简单说明。首先我们引入了ESP8266WiFi的依赖,这个依赖就是我们8266开发板的依赖,我们主要是通过这个依赖对我们的开发板进行配网;另外一个依赖是ArduinoWiFiServer,这个依赖主要是用来搭建web服务器的;剩下的依赖都是OLED的依赖,主要是为了把我们的请求数据打印出来,方便查看。

再接着就是我们基础的代码了:

  • 定义屏幕、wifi名称和密码、初始化服务器,然后在setup方法内,我们先打印了一段文字,然后进行了配网操作,最后打印服务器ip地址,并启动服务器。
  • loop方法内部,我们进行服务端监听,如果收到客户端请求,则会接收服务端请求数据,给客户端发送响应数据,然后把请求数据打印输出到屏幕上。
测试效果

我直接通过电脑访问(确保在同一个wifi下):

服务端显示效果如下:

websocket微型服务器

我们同样也是直接上代码,相比与前面的web服务器,websocket服务器的代码要少一些:

#include <ArduinoWebsockets.h>
#include <ESP8266WiFi.h>
#include <Wire.h>; // 加载Wire库
#include <Adafruit_GFX.h>; // 加载Adafruit_GFX库
#include <Adafruit_SSD1306.h>; // 加载Adafruit_SSD1306库

// 定义 OLED屏幕的分辨率
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire);

// WiFi parameters
const char* ssid = "wifi name";
const char* password = "wifi-password";
String ip = "";

using namespace websockets;

WebsocketsServer server;
void setup() {
  Serial.begin(9600);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // 设置OLED的I2C地址

  display.clearDisplay(); // 清空屏幕
  display.setTextSize(1); // 设置字体大小
  display.setTextColor(SSD1306_WHITE); // 设置字体颜色
  display.setCursor(0, 0); // 设置开始显示文字的坐标
  // Connect to wifi
  WiFi.begin(ssid, password);

  // Wait some time to connect to wifi
  for (int i = 0; i < 15 && WiFi.status() != WL_CONNECTED; i++) {
    Serial.print(".");
    delay(1000);
  }
  ip = WiFi.localIP().toString();
  display.println("IP: " + ip); // 输出的字符
  display.display(); // 使更改的显示生效

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());   //You can get IP address assigned to ESP

  server.listen(80);
  Serial.print("Is server live? ");
  Serial.println(server.available());
}

void loop() {
  auto client = server.accept();
  if (client.available()) {
    auto msg = client.readBlocking();

    // log
    Serial.print("Get Message: ");
    Serial.println(msg.data());

    // return echo
    client.send("Echo: " + msg.data());

    // close the connection
    client.close();

    display.clearDisplay(); // 清空屏幕
    display.setTextSize(1); // 设置字体大小
    display.setTextColor(SSD1306_WHITE); // 设置字体颜色
    display.setCursor(0, 0); // 设置开始显示文字的坐标
    display.println("IP: " + ip); // 输出的字符
    display.println("message: " + msg.data()); // 输出的字符
    display.display(); // 使更改的显示生效
  }

  delay(1000);
}

大部分代码都是相同的,不同点大致如下:

  • 依赖变了,websocket的依赖包变成了ArduinoWebsockets

  • 服务器初始化变了,直接实例化WebsocketsServer,然后指定监听端口

    server.listen(80);
  • 读取数据变成了websocket的方式:

     auto client = server.accept();
     if (client.available()) {
        auto msg = client.readBlocking();
      }

    其实最大的改变是,客户端发送数据的方式变了。第一种方式最大的问题是不方便数据的解析,http本质上就是socket,所以socket是会出现阻塞问题,我们之前手写web服务器的时候就遇到过,最后是通过NIO解决的,但是用webscoekt是没有这个问题的,直接发送的就是数据,基本上都不需要解析。

    websocket客户端

    以为我的设想是是通过客户端把需要展示的数据发送到服务器端(8266),所以8266作为服务端是最好的选择。这里我的客户端用的是python,写起来很快,用起来很方便:

    from websocket import create_connection
    
    ws = create_connection("ws://192.168.0.102:80")
    print("Sending 'Hello, World'...")
    ws.send("syske master")
    print("Sent")
    print("Receiving...")
    result = ws.recv()
    print("Received '%s'" % result)
    ws.close()

    短短几行代码就搞定了,上面的代码就是给服务器发送一段文字,8266收到我们的消息后,会把我们的消息展示在屏幕上。

    测试

    下面我们看下效果:

总结

8266可玩性确实比较高,特别是它的wifi功能,简直不要太强。好了,今天的内容就分享这么多吧,后面我会不定期给大家分享arduino的相关内容的。各位小伙伴,晚安哦!