ESP sleep/wake cycle and packet delivery issues

7 years 11 months ago #3635 by essenemari
Hello Guys!

EasyIoT Team, thanks a lot for your work and for EasyIoT project that you prepared! Awesome work!

I would like to ask you for a help in regards to my issue. Maybe someone from Community would be willing to help.

Goal: to have ESP RF on for 15s in every 5 minutes, 10 minutes 15 minutes and so on with up to 99% message deliverability from Server.

I am using EasyIot Server, on RPI and EasyIoT solution: "ESP8266 WiFi relay switch" however i would like to achieve goal which is minimization of ESP8266s WiFi radiation.
Since for most nodes, it is OK for me to wait 5 minutes for relay action, my assumption was turn OFF ESP RF for 5 minutes then turn RF ON for 15s to receive data from Server to set GPIO2 ON or OFF depends on status in EasyIoT GuI interface. GPIO2 should stay stable until next status change request.

Approach:
ESP8266:
From ESP cycle perspective, I modified the Sketch only by adding Ticker.h library and WiFi.forceSleepBegin();/WiFi.forceSleepWake(); in some loops. That’s works since while ESP is sleeping, ping shows that and current is significantly lower, so i assume that RF is off. If ESP is woken up, it correctly receives orders from the server. However...

ISSUE:
I got stuck with sending data from EasyIoT server ‘when ESP is sleeping’ then request is lost. For example: when ESP is sleeping and I switching a Virtual switch ON on the Web interface, then the command does not reach the ESP after RF is woken up. While hundreds of tests, i noticed that sometimes message from server somehow reach the ESP but overall the efficiency was extremely low.

Automation:
I would not like to use CRON since it can be triggered only every 1 min, so hit the 15 s window seems to be not possible.
Tried to ping ESP and then send p.value when ESP is reachable but it doesn’t work properly, means data is delivered only when ping is success. Tried also to put sending function in loop, however then ESP crashes (wdt resets, PIN resets). Serial monitor shows that ESP receives random 0 or 1 and of course, if relay is connected, then it is getting crazy.

Could you, please, help me with automation program/sketch to always deliver appropriate value which is in GUI Interface (ON/OFF) when ESP is woken up?
Any hints would be very appreciated!

Thanks in Advance,
Artur

Sketch:
#include <ESP8266WiFi.h>
#include <Ticker.h>
Ticker cykl_ticker;
int cykl_counter=80;
const char* ssid = "";
const char* password = "";


//-----------------------
extern "C" {
#include "user_interface.h"
}
//-----------------------

// Create an instance of the server
// specify the port to listen on as an argument
WiFiServer server(80);

void setup() {
  Serial.begin(115200);
  delay(10);
 
  // prepare GPIO2
  pinMode(2, OUTPUT);
  digitalWrite(2, 0);
  polaczenieWiFi();
  delay(10);
  cykl_ticker.attach(1,cykl);
  delay(10);
}
void loop() {
 
// Check if a client has connected
  WiFiClient client = server.available();
  if (!client) {
    return;
  }
  
  // Wait until the client sends some data
  Serial.println("new client");
  while(!client.available()){
    delay(1);
  }
  
  // Read the first line of the request
  String req = client.readStringUntil('\r');
  Serial.println(req);
  client.flush();
  
  // Match the request
  int val;
  if (req.indexOf("/gpio/0") != -1)
    val = 0;
  else if (req.indexOf("/gpio/1") != -1)
    val = 1;
  else {
    Serial.println("invalid request");
    client.stop();
    return;
  }

  // Set GPIO2 according to the request
  digitalWrite(2, val);
  
  client.flush();

  // Prepare the response
  String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\nGPIO is now ";
  s += (val)?"high":"low";
  s += "</html>\n";

  // Send the response to the client
  client.print(s);
  delay(1);
  Serial.println("Client disconnected");


  // The client will actually be disconnected 
  // when the function returns and 'client' object is detroyed
}

void polaczenieWiFi() {
  // Connect to WiFi network
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");

  // Start the server
  server.begin();
  Serial.println("Server started");

  // Print the IP address
  Serial.println(WiFi.localIP());
}

void cykl ()
{
  if (cykl_counter==70) {
  WiFi.forceSleepBegin();
  delay(100); 
  }; 
  if(cykl_counter==35) {
    WiFi.forceSleepWake();
    delay(100);
  };
  if (cykl_counter <0)
  {
    cykl_counter=80;
  };
  cykl_counter--;
}

Automation:
const String ESP8266_IP_ADDRESS = "192.168.0.131";
const String MODULE_ADDRESS = "N3S0"; 
/*
  This code is running one time when program is enabled
*/
public void Setup()
{
  System.Diagnostics.Process.Start("CMD.exe","");
  EventHelper.ModuleChangedHandler((o, m, p) =>
    {
      System.Net.NetworkInformation.Ping pingTest = new System.Net.NetworkInformation.Ping();
    System.Net.NetworkInformation.PingReply pingOdpowiedz = pingTest.Send("192.168.0.131");

    Console.WriteLine(m.Domain +" "+ m.Address + " in program id "+ Program.ProgramId.ToString()+ " property "+ p.Property + " value " + p.Value);
      if (m.Domain == "Virtual" && m.Address == MODULE_ADDRESS && p.Property == "Sensor.DigitalValue") {
connectionCheck:
      if (pingOdpowiedz.Status.ToString() == "Success")
        {
	sendCommand(p.Value);
        }
        else
        {
            Console.WriteLine (pingOdpowiedz.Status);
            System.Threading.Thread.Sleep(5000);
	goto connectionCheck;
        }
        }
return true;
    });
}
/*
  This code is running periodicaly when program is enabled. 
  Cron job detirmine running period.
*/
public void Run()
{
} 
private void sendCommand(string value)
{
sendToServer("/gpio/"+value);
}
private void sendToServer(String message)
{
  try
  {
  //Console.WriteLine("TCP client command:" + message);
   Int32 port = 80;
   System.Net.Sockets.TcpClient client = new System.Net.Sockets.TcpClient( ESP8266_IP_ADDRESS, port);
   Byte[] data = System.Text.Encoding.ASCII.GetBytes(message); 
   System.Net.Sockets.NetworkStream stream = client.GetStream();
   stream.Write(data, 0, data.Length);
   // Close everything.
   stream.Close();         
   client.Close();
  }
  catch(Exception e)
  {
    Console.WriteLine(e.StackTrace);
  }
}

Please Log in or Create an account to join the conversation.

7 years 11 months ago - 7 years 11 months ago #3638 by EasyIoT

essenemari wrote: Hello Guys!

EasyIoT Team, thanks a lot for your work and for EasyIoT project that you prepared! Awesome work!

I would like to ask you for a help in regards to my issue. Maybe someone from Community would be willing to help.

Goal: to have ESP RF on for 15s in every 5 minutes, 10 minutes 15 minutes and so on with up to 99% message deliverability from Server.

I am using EasyIot Server, on RPI and EasyIoT solution: "ESP8266 WiFi relay switch" however i would like to achieve goal which is minimization of ESP8266s WiFi radiation.
Since for most nodes, it is OK for me to wait 5 minutes for relay action, my assumption was turn OFF ESP RF for 5 minutes then turn RF ON for 15s to receive data from Server to set GPIO2 ON or OFF depends on status in EasyIoT GuI interface. GPIO2 should stay stable until next status change request.

Approach:
ESP8266:
From ESP cycle perspective, I modified the Sketch only by adding Ticker.h library and WiFi.forceSleepBegin();/WiFi.forceSleepWake(); in some loops. That’s works since while ESP is sleeping, ping shows that and current is significantly lower, so i assume that RF is off. If ESP is woken up, it correctly receives orders from the server. However...

ISSUE:
I got stuck with sending data from EasyIoT server ‘when ESP is sleeping’ then request is lost. For example: when ESP is sleeping and I switching a Virtual switch ON on the Web interface, then the command does not reach the ESP after RF is woken up. While hundreds of tests, i noticed that sometimes message from server somehow reach the ESP but overall the efficiency was extremely low.

Automation:
I would not like to use CRON since it can be triggered only every 1 min, so hit the 15 s window seems to be not possible.
Tried to ping ESP and then send p.value when ESP is reachable but it doesn’t work properly, means data is delivered only when ping is success. Tried also to put sending function in loop, however then ESP crashes (wdt resets, PIN resets). Serial monitor shows that ESP receives random 0 or 1 and of course, if relay is connected, then it is getting crazy.

Could you, please, help me with automation program/sketch to always deliver appropriate value which is in GUI Interface (ON/OFF) when ESP is woken up?
Any hints would be very appreciated!

Thanks in Advance,
Artur

Sketch:

#include <ESP8266WiFi.h>
#include <Ticker.h>
Ticker cykl_ticker;
int cykl_counter=80;
const char* ssid = "";
const char* password = "";


//-----------------------
extern "C" {
#include "user_interface.h"
}
//-----------------------

// Create an instance of the server
// specify the port to listen on as an argument
WiFiServer server(80);

void setup() {
  Serial.begin(115200);
  delay(10);
 
  // prepare GPIO2
  pinMode(2, OUTPUT);
  digitalWrite(2, 0);
  polaczenieWiFi();
  delay(10);
  cykl_ticker.attach(1,cykl);
  delay(10);
}
void loop() {
 
// Check if a client has connected
  WiFiClient client = server.available();
  if (!client) {
    return;
  }
  
  // Wait until the client sends some data
  Serial.println("new client");
  while(!client.available()){
    delay(1);
  }
  
  // Read the first line of the request
  String req = client.readStringUntil('\r');
  Serial.println(req);
  client.flush();
  
  // Match the request
  int val;
  if (req.indexOf("/gpio/0") != -1)
    val = 0;
  else if (req.indexOf("/gpio/1") != -1)
    val = 1;
  else {
    Serial.println("invalid request");
    client.stop();
    return;
  }

  // Set GPIO2 according to the request
  digitalWrite(2, val);
  
  client.flush();

  // Prepare the response
  String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\nGPIO is now ";
  s += (val)?"high":"low";
  s += "</html>\n";

  // Send the response to the client
  client.print(s);
  delay(1);
  Serial.println("Client disconnected");


  // The client will actually be disconnected 
  // when the function returns and 'client' object is detroyed
}

void polaczenieWiFi() {
  // Connect to WiFi network
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");

  // Start the server
  server.begin();
  Serial.println("Server started");

  // Print the IP address
  Serial.println(WiFi.localIP());
}

void cykl ()
{
  if (cykl_counter==70) {
  WiFi.forceSleepBegin();
  delay(100); 
  }; 
  if(cykl_counter==35) {
    WiFi.forceSleepWake();
    delay(100);
  };
  if (cykl_counter <0)
  {
    cykl_counter=80;
  };
  cykl_counter--;
}

Automation:
const String ESP8266_IP_ADDRESS = "192.168.0.131";
const String MODULE_ADDRESS = "N3S0"; 
/*
  This code is running one time when program is enabled
*/
public void Setup()
{
  System.Diagnostics.Process.Start("CMD.exe","");
  EventHelper.ModuleChangedHandler((o, m, p) =>
    {
      System.Net.NetworkInformation.Ping pingTest = new System.Net.NetworkInformation.Ping();
    System.Net.NetworkInformation.PingReply pingOdpowiedz = pingTest.Send("192.168.0.131");

    Console.WriteLine(m.Domain +" "+ m.Address + " in program id "+ Program.ProgramId.ToString()+ " property "+ p.Property + " value " + p.Value);
      if (m.Domain == "Virtual" && m.Address == MODULE_ADDRESS && p.Property == "Sensor.DigitalValue") {
connectionCheck:
      if (pingOdpowiedz.Status.ToString() == "Success")
        {
	sendCommand(p.Value);
        }
        else
        {
            Console.WriteLine (pingOdpowiedz.Status);
            System.Threading.Thread.Sleep(5000);
	goto connectionCheck;
        }
        }
return true;
    });
}
/*
  This code is running periodicaly when program is enabled. 
  Cron job detirmine running period.
*/
public void Run()
{
} 
private void sendCommand(string value)
{
sendToServer("/gpio/"+value);
}
private void sendToServer(String message)
{
  try
  {
  //Console.WriteLine("TCP client command:" + message);
   Int32 port = 80;
   System.Net.Sockets.TcpClient client = new System.Net.Sockets.TcpClient( ESP8266_IP_ADDRESS, port);
   Byte[] data = System.Text.Encoding.ASCII.GetBytes(message); 
   System.Net.Sockets.NetworkStream stream = client.GetStream();
   stream.Write(data, 0, data.Length);
   // Close everything.
   stream.Close();         
   client.Close();
  }
  catch(Exception e)
  {
    Console.WriteLine(e.StackTrace);
  }
}


This is issue of ESP8266WiFi library which is not under active development.

If you put ESP8266 in sleep commands can not reach ESP8266 after wake-up. I suggest you that after ESP8266 wake up in ESP8266 code execute function to read Raspberry Pi switch state (function requestValue or similar).

This is better solved in EasyIoT Cloud where MQTT broker is used. Even if ESP8266 is not connected (in sleep mode) message is automatically sent to ESP8266 after MQTT connection is established.
The following user(s) said Thank You: essenemari

Please Log in or Create an account to join the conversation.

7 years 11 months ago - 7 years 11 months ago #3658 by essenemari
@EasyIoT Administrator, thank You a lot for your hint. It is very helpful for me!

I know that your cloud services are more powerfull, however I would like to play a little bit with my RPI, espiecially that i would like to use GSM modules with it.

Please Log in or Create an account to join the conversation.

7 years 10 months ago #3717 by essenemari
Dear Team,

Thanks for your hint! I was able to get a Value from /Api/EasyIoT/Config/Module/List/ by using github.com/squix78/json-streaming-parser . This is exactly what I want, however one question occured: is it possible to modify the node's value (under /Api/EasyIoT/Config/Module/List/) by automation?

Please let me know.

Thanks!
Artur

Please Log in or Create an account to join the conversation.

7 years 10 months ago #3718 by EasyIoT

essenemari wrote: Dear Team,

Thanks for your hint! I was able to get a Value from /Api/EasyIoT/Config/Module/List/ by using github.com/squix78/json-streaming-parser . This is exactly what I want, however one question occured: is it possible to modify the node's value (under /Api/EasyIoT/Config/Module/List/) by automation?

Please let me know.

Thanks!
Artur


You have API to control module values. If you use the same API as WEB interface you have more options like:
/Api/EasyIoT/Control/Module/Esp8266/N1S10/ControlOn
/Api/EasyIoT/Control/Module/Esp8266/N1S10/ControlOff
/Api/EasyIoT/Control/Module/MySensors/N10S3/ControlLevel/34
The following user(s) said Thank You: essenemari

Please Log in or Create an account to join the conversation.

7 years 1 month ago #3878 by essenemari
Hello EasyIoT Team,
awesome! It works perfect!
Thanks!

Please Log in or Create an account to join the conversation.

Time to create page: 0.342 seconds

Forum latest

  • No posts to display.