ESP8266 code

Since the sketch has also some extra classes for the WebSocket connection, here the essential part of the .ino file will just be shown. For the entire project, please see the following GitHub address:

https://github.com/bcatalin/esp8266-book/tree/master/Chapter7.

Necessary included files are:

#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> 

Instantiate an accel object and create a unique identification as a parameter for the class constructor:

Adafruit_ADXL345_Unified accel = Adafruit_ADXL345_Unified(121212); 

Allocate space for the server name or its IP address, and set the default port to 1234. Later, users will be able to select one during the Wi-Fi setup procedure:

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

Declare global variables that will be used:

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

Set the clean_g to 1 if you want to format the SPIFFS and flash the sketch once again to ESP8266:

int clean_g = 0;  
//flag for saving data 
bool shouldSaveConfig = false; 

The client object will be used to send and receive data over the websocket protocol. Class implementation is external to this file and will be found in the SocketIOClient.cpp and SocketIOClient.h files:

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; 

The Callback function for notifying us of the need to save the configuration to config.json file on SPIFFS is:

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

In the setup() function, it will initialize and set up the ADXL345 chip:

void setup()  
{ 
  // put your setup code here, to run once: 
  Serial.begin(115200); delay(10); 
  Serial.println(); 
  pinMode(A0, INPUT); 
  pinMode(SIGNAL_PIN, OUTPUT); digitalWrite(SIGNAL_PIN, LOW);

Initialize the sensor. If the sensor is not connected to the ESP8266 board then wait for it:

  if(!accel.begin()) 
 { 
 /* There was a problem detecting the ADXL345 ... check your connections */ 
 Serial.println("Ooops, no ADXL345 detected ... Check your wiring!"); 
 while(1); 
 } 

Set the range to whatever is appropriate for your project. ADXL345 can support up to ±16g. Depending on your application, you can choose a different value by changing the SetRange function’s parameter:

 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(); 

Next, read the configuration from the SPIFFS config.json file. If the configuration file is not found, then ESP8266 assumes that it is not configured, so it will start itself in access point mode and will wait for the user to set up the Wi-Fi SSID, Wi-Fi password, server name, and server's port, that will be used to connect to:

  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("
parsed 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")); 
  } 

Configure the WiFiManager with custom fields such as server name and server port, along with the Wi-Fi SSID and Wi-Fi password that will be saved to the SPIFFS in order to connect automatically every time ESP8266 is restarted:

  WiFiManagerParameter custom_acc_server("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 
",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 parameters 
  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(); 
  } 

Now we'll connect to the server, and after that we will send a connection message that contains our unique identification derived from the MAC address of the ESP8266.

The server can use this message to identify the ESP8266 and to dynamically construct some web interface. In this case, if the server receives a connection message it will construct a graphic that will show the received values for all the three axes in real time:

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

In the main loop we'll:

  • Read the values for the acceleration every interval and will construct a JSON message that will be sent to the server.
  • Check for any incoming messages from the server. Remember that the websocket is a duplex protocol. You can also control the ESP8266 from the server; you can set some parameters, reboot the ESP8266, trigger a certain GPIO, or even reset the ESP8266 to its default values by formatting the SPIFFS.
  • Check the state of the connection and if it is necessary, reconnect to the server.

Also, in the loop() function will check the state of the connection and if necessary, reconnect to the server if the connection has been lost:

void loop()  
{ 
  unsigned long currentMillis = millis(); 
  if (currentMillis - previousMillis > interval) 
  { 
    previousMillis = currentMillis; 
 
    sensors_event_t event;  
    accel.getEvent(&event); 
    String acc_data; 
    StaticJsonBuffer<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);  
  }  

Check for any incoming messages from the server:

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

If the ESP8266 receives a message named welcome, it will respond with a message named connection and with its unique ID:

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

If the received message is resetModule, then the EPS8266 will reset itself. A lot of messages can be added here, to change the status of a GPIO, to read a GPIO status, to read the value from A0, or to write a PWM to a GPIO:

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

Check the connection with the server and if it is necessary, reconnect to it:

  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) + "" }" ); 
  } 
} 

Server for the WebSocket connection? for the server part, I've chosen Node.JS and ExpressJS. The code for the server can be found at this link: https://github.com/bcatalin/esp8266-book/tree/master/Chapter7.

The steps to start the server are:

  1. Install Node.js and npm. Verify that both are present on your system:
  1. Install a server's dependencies using the command npm -v:
  1. Edit the file websocketserver/public/services/wsDataService.js with your IP address of the server and the port used:
  1. Start the server with the command node server.js issued in the websocketserver directory:

In the preceding screenshot, you can see two connections: one from the web with the Web Socket ID HgmjiF_fAE3XE_3AAAAA and another one from the ESP8266 module with the socket id: 7- xIcezugppEdDXgAAAB.

Open a browser and point it to your server's IP address and port and you will see the acceleration on a nice graph provided by smoothieJS:

Pressing Reboot ESP8266 will remotely reboot your module, and if you press the Reinit ESP8266 button from the web page, the ESP8266 will reset all the data for Wi-Fi credentials, IP address, and port number.

You can add multiple modules on the same server, for each new connection, the server will add a new graphic and new buttons for it. In this way, you can monitor multiple sensors in the same page without refreshing it, or taking any action. This is very good if you want to provide a nice dashboard for your home automation platform.

As an improvement, you can add a time-series database such as InfluxDB (https://www.influxdata.com/) to store the received value, with your own desired persistence. To create a more elaborate dashboard, you can use Grafana (https://grafana.com/):

The server code consists of two parts:

  1. Backend code that is responsible for receiving the connections from ESP8266 modules and web pages.
  2. Frontend code that connects to the server and shows the nice graphs.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset