由于工程代码中还有一些额外的 WebSocket 连接类,显示的 .ino 文件中一部分是必不可少的。对于整个项目,请参阅以下GitHub地址:https://github.com/bcatalin/esp8266-book/tree/master/Chapter7

必要的包含文件是:

#include "Wire.h"
#include <Adafruit_Sensor.h>
#include <Adafruit_ADXL345_U.h>
#include <FS.h>
#include <ESP8266WiFi.h>
#include "SocketIOClient.h"
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>
#include <ArduinoJson.h>
#include <Wire.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>
#include <SPI.h>

实例化一个 accel 对象并创建一个唯一标识作为类构造函数的参数:

Adafruit ADXL345_Unified accel = Adafruit_ADXL345_Unified(121212);

 

为服务器名称或IP地址分配空间,并将默认端口设置为 1234 稍后,用户可以在Wi-Fi设置过程中选择一个:

char acc_server[40];
characcport[6]="1234";

声明将使用的全局变量:

#define ACC_CLIENT_ID  "RAM%06X"
#define INFO Serial.printf 
char dev_name[50];

如果要格式化 SPIFFS 并将工程代码再次闪存到 ESP8266,请将 clean_g 设置为1:

int clean_ g = 0;
//用于保存数据的标志
bool ShouldSaveConfig = false ;

客户端对象将用于通过 websocket 协议发送和接收数据。类实现在此文件的外部,可以在 SocketIOClient.cpp SocketIOClient.h 文件中找到:

SocketIOClient client; 
StaticJsonBuffer<300> jsonBuffer;
extern String RID;
extern String Rname;
//extern String Rcontent;
unsigned long previousMillis = 0;
long interval = 100;
unsigned long lastreply = 0;
unsigned long lastsend = 0;

用于通知我们需要将配置保存到 SPIFFS 上的 config.json 文件的回调函数是:

void saveConfigCallback() {
  Serial.println("Should save config");
  shouldSaveConfig = true; 
}

setup()函数中,它将初始化并设置 ADXL345 芯片:

void setup( )
{
  // 将您的设置代码放在这里,运行一次:
  Serial.begin(115200); delay(10);
  Serial.println();
  pinMode(A0, INPUT);
  pinMode(SIGNAL_PIN, OUTPUT); 
  digitalWrite(SIGNAL_PIN, LOW);
  

初始化传感器。如果传感器未连接到ESP8266板,请等待:

  if(!accel.begin())
  {
    //检测到ADXL345检查连接时出现问题
    Serial.println("Ooops, no ADXL345 detected . . .Check your wiring!");
    while(1);
  }

将范围设置为适合您的项目的范围。 ADXL345最高可支持+ -16g。根据您的应用程序,您可以通过更改SetRange函数的参数来选择不同的值:

accel.setRange(ADXL345_RANGE_16_G);
//accel.setRange(ADXL345_RANGE_8_G);
//accel.setRange(ADXL345_RANGE_4_G);
//accel.setRange(ADXL345_RANGE_2_G); 
Just for
  if(clean_g)
    SPIFFS.format();

接下来,从SPIFFS config.json 文件中读取配置。如果找不到配置文件,则 ESP8266 会假定它未配置,因此它将以接入点模式启动,并等待用户设置Wi-Fi SSID,Wi-Fi密码,服务器名称和服务器的端口,用于连接到:


if(SPIFFS.begin())
{
  Serial.println(F("mounted file system"));
  if(SPIFFS.exists("/config.json"))
  {
    //file exists, reading and loading
    Serial.println("reading config file");
    File configFile = SPIFFS.open("/config.json", "r");
    if (configFile) {
      Serial.println("opened config file");
      size_t size = configFile.size();
      //Allocate a buffer to store contents of the file .
      std::unique_ptr<char[]> buf (new char[size]);
      configFile.readBytes(buf.get(),size);
      DynamicJsonBuffer jsonBuffer;
      JsonObject& json = jsonBuffer.parseObject(buf.get());
      json.printTo(Serial);
        if(json.success()) {
          Serial.println(F("nparsed json"));
          strcpy(acc_server,json["acc_server"]);
          strcpy( acc_port,json["acc_ port"]);
        } else {
        Serial.println(F("failed to load json config"));
        }
    }
  } else {
  Serial.println(F("failed to mount FS"));
}

使用自定义字段 配置WiFiManager,如服务器名称和服务器端口以及 Wi-Fi SSID和Wi-Fi密码将保存到SPIFFS中,以便每次重新启动ESP8266时自动连接:

WiFiManagerParameter custom_accserver("server", "RAM IP" , acc_server ,40); ;
WiFiManagerParameter custom_acc_port("port" ," RAM port" acc_port ,5);
WiFiManager wifiManager;
wifiManager.setSaveConfigCallback(saveConfigCallback);
wifiManager.addParameter(&custom_acc_server);
wifiManager.addParameter(&custom_acc_port);
if(clean_g)
  wifiManager.resetSettings();
  sprintf(dev_name, ACC_CLIENT_ID, ESP.getChipId());
  INFO(". .DEV:%s n",dev_name);
  if(!wifiManager.autoConnect(dev_name))
  {
    Serial.println(F("failed to connect and hit timeout"));
    delay(3000);
    //reset and try again, or maybe put it to  deep sleep
    ESP.reset();
    delay(5000);
    // if you get here you have connected to the WiFi
    Serial. println("connected. . .yeey :)");
    //read updated par ameters
    strcpy(acc_server, custom_acc_server.getValue());
    strcpy(acc_port, custom_acc_port.getValue());

 Now we have all the information that will be saved to the SPIFFS. This part will only be called the first time the ESP8266 is configured. Information introduced will be persistent since it is now saved and retrieved on every boot:

if (shouldSaveConfig)
{
  Serial.println(" saving config") ;
  DynamicJsonBuffer jsonBuffer;
  JsonObject& json = jsonBuffer.createObject();
  json["acc_server"] = acc_server;
  json["acc_port"] = acc_port;
  File configFile = SPIFFS.open("/config.json","w");
  if (!configFile) {
    Serial. println("failed to open config file for writing");
  }
    json.printTo(Serial);
    json.printTo(configFile);
    configFile.close();
}

现在我们将连接到服务器,之后我们将发送一条连接消息,其中包含从ESP8266的MAC地址派生的唯一标识。
服务器可以使用此消息来识别ESP8266并动态构建一些Web界面。在这种情况下,如果服务器收到连接消息,它将构建一个图形,该图形将实时显示所有三个轴的接收值:



  if(!client.connect(acc_server,atoi(acc_port)))
  {
    Serial.println(F("connection failed"));
    return;
  }
  if(client.connected())
  {
    client.sendJSON ("connection", "{\"acc_id\":\""+String(devname)+"\"]");
  }
}

在主循环中,我们将:

  • 读取每个间隔的加速值,并构造一个将发送到服务器的JSON消息。
  • 检查来自服务器的任何传入消息。请记住,websocket是双工协议。您也可以从服务器控制ESP8266;您可以设置一些参数,重启ESP8266,触发某个GPIO,甚至通过格式化SPIFFS将ESP8266重置为默认值。
  • 检查连接状态,如果有必要,重新连接到服务器

此外,如果有必要 在loop()函数中将检查连接的状态,如果连接丢失,则重新连接到服务器:

void loop( )
{
  unsigned long currentMillis = millis();
  if(currentMillis previousMillis > interval)
  previousMillis = currentMillis;
  sensors_event_t event;
  accel.getEvent(&event);
  String acc_data;
  StaticJsonBuf fer<100> jsonDeviceStatus;
  JsonObject& jsondeviceStatus = jsonDeviceStatus.createObject();
  jsondeviceStatus ["device_name"] = dev_name;
  jsondeviceStatus["x"] = event.acceleration.x; // x;
  jsondeviceStatus["y"] = event.acceleration.y; //y;
  jsondeviceStatus ["z"] = event.acceleration.z; //z;
  jsondeviceStatus.printTo(acc_data);
  client.sendJSON("JSON", acc_data);
}

检查来自服务器的任何传入消息:

if(client.monitor())
{
  lastreply = millis();

如果ESP8266收到名为 welcome 的消息,它将使用名为 connection 的消息及其唯一ID进行响应:

  
  if( strcmp(String(RID).c_ str() , "welcome") == 0)
  {
  client.sendJSON("connection", "{\"acc_id":\""+String(devname)+"\"}");
  if(RID != "")
  {
    Serial.print(F("Message:")); Serial.println(RID);


如果收到的消息是 resetModule ,那么EPS8266将重置自己。可以在此处添加许多消息,以更改GPIO的状态,读取GPIO状态,从A0读取值或将PWM写入GPIO:

if (strcmp(String(RID).c_str(),"resetModule") == 0)
{
  //reset the module delay(1000);
  ESP.reset();
}}
}

检查与服务器的连接,如果有必要,重新连接到它:

if(!client.connected())
{
  Serial.println("LOOP: Client not connected ,try to reconnect");
  client.connect(acc_server,atoi(acc_port));
  while(!client.connected())
  {
    client.connect(acc_server,atoi(acc_port));
    delay(1000);
    client.sendJSON("connection", "{\"acc_id\" :\"" + String(dev_name) + "\"}");
  }
}

用于 WebSocket 连接的服务器?对于服务器部分,我选择了 Node.JS 和 ExpressJS 。可以在以下链接找到服务器的代码:https://github.com/bcatalin/esp8266-book/tree/master/Chapter7

启动服务器的步骤如下:
1.安装Node.js和npm。验证系统上是否存在两者:

7-2-2-1 ESP8266代码

2.使用命令 npm -v 安装服务器的依赖项:

7-2-2-1 ESP8266代码

3.使用您的服务器IP地址和使用的端口编辑文件 websocketserver/public/services/wsDataService.js

7-2-2-1 ESP8266代码

4.使用 websocketserver 目录中发出的命令 node server.js 启动服务器:

7-2-2-1 ESP8266代码

 

在上面的屏幕截图中,您可以看到两个连接:一个来自Web,其中包含Web Socket ID HgmjiF_fAE3XE_3AAAAA,另一个来自ESP8266模块,其中包含套接字ID:7-xIce zugppEdDXgAAAB。
打开浏览器并将其指向服务器的IP地址和端口,您将看到 smoothieJS 提供的漂亮图表上的加速度:

7-2-2-1 ESP8266代码

按重启 ESP8266 将远程重启模块,如果您从网页上按下 Reinit ESP8266 按钮,ESP8266将重置Wi-Fi凭证,IP地址和端口号的所有数据。


您可以在同一台服务器上添加多个模块,对于每个新连接,服务器将为其添加新图形和新按钮。通过这种方式,您可以在同一页面中监控多个传感器,而无需刷新或采取任何操作。如果您想为家庭自动化平台提供一个漂亮的仪表板,这是非常好的。


作为改进,您可以添加一个时间序列数据库,例如InfluxDB(https://www.lusxdata.com/)来存储接收到的值,并使用您自己想要的持久性。要创建更精细的仪表板,您可以使用Grafana(https://qrafana.com/):

7-2-2-1 ESP8266代码

服务器代码由两部分组成:
1.后端代码,负责接收来自ESP8266模块和网页的连接。
2.前端代码连接到服务器并显示漂亮的图形。

 

 

 

 

 

 

相关文章: