Sending reliable HTTP request with Arduino Wifi Client - arduino

When a sensor on my Arduino MKR1000 is triggered, I send an email:
//....
WiFiClient client;
char server[] = "www.myserver.com";
//....
void setup() {
//... Connect to wifi ....
}
void loop() {
// when sensor triggered =>
if (client.connect(server, 80)) {
Serial.println("Sending email");
client.print("GET /WaterOff/sendGridCall.php");
client.print("?valve=");
client.print(valve);
client.print("&position=");
client.print(position);
client.println(" HTTP/1.1");
client.print("Host: ");
client.println(server);
client.println("User-Agent: Arduino");
client.println("Connection: close");
client.println();
}
delay(6000);
}
However, it only works the first couple of times ("Sending email" is printed) and after that it does not execute the request ("Sending email" is not printed). Am I supposed to take some additional steps to make it reliable.

You never close the connection. But blocking to wait for email confirmation can take forever. You should consider a small state machine for your network connection to work.
void loop()
{
// when sensor triggered =>
if (client.connect(server, 80)) { // You connect to client, but it's already
// connected the second time around
// send ...
// client() should wait for response, and client.disconnect()
}
// ...
delay(6000); // tip: avoid blocking the main loop, this blocks your ability to
// read your sensor while sending emails.
}
A state machine for your app could look like this:
enum EmailState {
emIdle, emSendMail, emCheckMailSent, emEmailOK, emEmailError,
};
EmailState email_state;
unsigned long long mail_timer; // can be shared between states.
// small state handlers that do a bit at a time,
// check for an event, wait on some delay (use millis())
// avoid blocking the instruction flow as much as possible.
static void on_emIdle()
{
// read sensor, check timer?
email_state = (triggered) ? emSendMail : emIdle;
}
static void on_sendMail()
{
if (client.connect())
{
// ... prints
email_state = emCheckMailSent;
return;
}
email_state = emEmailError;
}
static void on_emCheckMailSent()
{
// receive HTTP response... can have a long timeout without blocking.
email_state = emCheckMailSent;
// or emEmailOK or emEmailError or retry emSendMail
}
static void on_emEmailOK()
{
if (/*client is connected?*/)
client.disconnect();
if (!mail_timer)
mail_timer = millis();
if (millis() - mail_timer < 6000) // stay in this state for 6 seconds...
{
email_state = emEmailOK;
return;
}
mail_timer = 0; // always reset the timer so it can be used by other states
email_state = emIdle;
}
static void on_emEmailError()
{
if (/*client is connected?*/)
client.disconnect();
// keep a log ?
email_state = emIdle; // or another timer
}
//...
void loop()
{
// update readings, manage other things...
// ...
switch(email_state)
{
default:
case emIdle: on_emIdle(); break;
case emSendMail: on_emSendMail(); break;
case emCheckMailSent: on_emCheckMailSent(); break;
case emEmailOK: on_emEmailOK(); break;
case emEmailError: on_emEmailError(); break;
}
}

Related

How to pass the this pointer to a task inside a class?

I am creating a library to manage our wifi network connection on many ESP32 devices.
Inside my library, i have a task that is looping with a 1 second pause started with an xTaskCreate inside my .begin() function. The problem is that i can't start the task if i haven't make it static in my .h file. So once the task is declared as static, i don't have access to the this-> pointer inside this task. Is there anyway i can send the this-> pointer inside my task like in parameters or something like that ?
Here is some code:
class EraWiFi{
public:
EraWiFi();
/*!
* #brief Initialize WiFi
* #return Returns true if successful
*/
bool begin(fs::FS &fs);
/*!
* #brief Start EraWiFi service
* #return Returns true if successful
*/
void downloadWiFi();
private:
static void wifiTask(void * parameter);
};
bool EraWiFi::begin(fs::FS &fs){
File file = fs.open("/WiFi.json", FILE_READ);
if(file){
DynamicJsonDocument wifi(2048);
DeserializationError error = deserializeJson(wifi, file);
file.close();
if (!error){
Serial.println("We have a VALID WiFi.json configurations file!");
Serial.println("Adding wifi networks:");
for (JsonArray arr : wifi.as<JsonArray>()){
Serial.print("SSID: ");
Serial.print(arr[0].as<char*>());
Serial.print(", KEY: ");
Serial.println(arr[1].as<char*>());
wifiMulti.addAP(arr[0].as<char*>(), arr[1].as<char*>());
}
}else{
Serial.println("We don't have a VALID WiFi.json configurations file!");
}
}else{
Serial.println("There is no WiFi.json configurations file!");
}
wifiMulti.addAP("Testing", "1234");
xTaskCreate(
this->wifiTask, // Function that should be called
"WiFiTask", // Name of the task (for debugging)
10000, // Stack size (bytes)
(void*)&this, // Parameter to pass
1, // Task priority
NULL // Task handle
);
return true;
}
void EraWiFi::downloadWiFi(){
Serial.println("Downloading WiFi.json from ErabliTEK Server.");
HTTPClient http;
// Send request
http.useHTTP10(true);
String url = "https://testing.testing.com/wifis/getWiFi/";
http.begin(url);
int httpResponseCode = http.GET();
if(httpResponseCode == HTTP_CODE_OK){
// Parse response
DynamicJsonDocument doc(2048);
DeserializationError error = deserializeJson(doc, http.getStream());
// Disconnect
http.end();
if (!error){
File file = fs.open("/WiFi.json", FILE_WRITE);
if(file){
// Serialize JSON to file
if (serializeJson(doc, file) == 0) {
Serial.println("Error saving WiFi.json!");
Serial.println(http.getString());
}else{
Serial.println("Succesfully saved WiFi.json!");
}
}
// Close the file
file.close();
}else{
Serial.println("Error downloading WiFi.json");
}
}else{
Serial.println("Problem connecting to " + url + " with http code: " + String(httpResponseCode));
}
}
void EraWiFi::wifiTask(void * parameters){
bool wifiConnected = false;
for(;;){
uint8_t wifiStatus = wifiMulti.run();
if((wifiStatus != WL_CONNECTED) and wifiConnected) {
wifiConnected = false;
Serial.println("WiFi not connected!");
}else if((wifiStatus == WL_CONNECTED) and !wifiConnected){
wifiConnected = true;
Serial.println("WiFi Connected.");
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
Serial.print("KEY: ");
Serial.println(WiFi.psk());
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
EraWiFi::downloadWiFi();
}
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
You're already doing that, you just don't realize it. Have a look at the FreeRTOS documentation on xTaskCreate() which explains how the fourth parameter pvParameters is a void pointer that gets passed on to the new task as its (one and only) input parameter.
The commented line here means you're taking the address of your EraWiFi object and passing it to the task:
xTaskCreate(
this->wifiTask,
"WiFiTask",
10000,
(void*)&this, //< Pointer gets forwarded to the task
1,
NULL
);
To use the pointer inside your task, you only need to cast it back from void*:
void EraWiFi::wifiTask(void * parameters){
EraWifi* p = static_cast<EraWifi*>(parameters); //< That's the same pointer
p->someMethod();
...
PS. Also note (before you poke at the same object from different threads, possibly causing hard-to-find bugs) that FreeRTOS provides excellent inter-thread communication facilities - the queues and task notifications often being the most useful ones. Check out their tutorial/book for an explanation.

ESP32 Arduino BLE DeepSleep

I am working on a project involving 2 ESP32 Wemos D1 Mini boards. I am using the BLE feature to transmit a sensor reading from the "server" to the "client". I use a Characteristic Notify to the client which receives the sensor reading. If I want to implement deep sleep functionality to the server, what would happen to the client? Does the client also have to reset at some point?
Also, is it advisable to use Characteristic.Notify in a deep sleep scenario?
Thanks.
Server code:
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include "DHT.h"
#define DHTPIN 4
#define DHTTYPE DHT22
#define uS_TO_S_FACTOR 1000000 //Conversion factor for micro seconds to seconds
#define TIME_TO_SLEEP 15 //Time ESP32 will go to sleep (in seconds)
RTC_DATA_ATTR int bootCount = 0;
DHT dht(DHTPIN, DHTTYPE);
BLECharacteristic *pCharacteristic;
bool deviceConnected = false;
uint8_t txValue = 50;
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
}
};
//Function that prints the reason by which ESP32 has been awaken from sleep
void print_wakeup_reason(){
esp_sleep_wakeup_cause_t wakeup_reason;
wakeup_reason = esp_sleep_get_wakeup_cause();
switch(wakeup_reason)
{
case 1 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
case 2 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
case 3 : Serial.println("Wakeup caused by timer"); break;
case 4 : Serial.println("Wakeup caused by touchpad"); break;
case 5 : Serial.println("Wakeup caused by ULP program"); break;
default : Serial.println("Wakeup was not caused by deep sleep"); break;
}
}
void setup() {
Serial.begin(115200);
Serial.println(F("initating DHT22..."));
dht.begin();
// Create the BLE Device
BLEDevice::init("UART"); // Name must not be longer than 5 chars!!!
// Create the BLE Server
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// Create the BLE Service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Create a BLE Characteristic
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_NOTIFY|BLECharacteristic::PROPERTY_READ|BLECharacteristic::PROPERTY_WRITE
);
BLE2902 *desc = new BLE2902();
desc->setNotifications(true);
pCharacteristic->addDescriptor(desc);
// Start the service
pService->start();
pServer->getAdvertising()->addServiceUUID(SERVICE_UUID);
// Start advertising
pServer->getAdvertising()->start();
Serial.println(pService->getUUID().toString().c_str());
Serial.println("Waiting a client connection to notify...");
if (deviceConnected) {
float f = dht.readTemperature(true);
char fStr[10];
sprintf(fStr, "%4.4f", f);
Serial.print("Temperature reading: ");
Serial.println(fStr);
Serial.printf("*** Sent Value: %d ***\n", fStr);
pCharacteristic->setValue(fStr);
pCharacteristic->notify();
//Set timer to 5 seconds
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) +
" Seconds");
//Go to sleep now
esp_deep_sleep_start();
}
//delay(60000);
}
void loop() {}
Client code:
#include "BLEDevice.h"
#include <WiFi.h>
// The remote service we wish to connect to.
static BLEUUID serviceUUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E");
static BLEUUID charUUID("6E400003-B5A3-F393-E0A9-E50E24DCCA9E");
static BLEAddress *pServerAddress;
static boolean doConnect = false;
static boolean connected = false;
static BLERemoteCharacteristic* pRemoteCharacteristic;
const char* ssid = "Kings";
const char* password = "GoCanada";
const char* host = "menezes-service.herokuapp.com";
WiFiClient client;
static void notifyCallback(
BLERemoteCharacteristic* pBLERemoteCharacteristic,
uint8_t* pData,
size_t length,
bool isNotify) {
Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str());
Serial.print(" of data length ");
Serial.println(length);
//std::string value = pBLERemoteCharacteristic->readValue();
byte buffer[42];
Serial.print("The characteristic value sent was: ");
//Serial.println(pBLERemoteCharacteristic->readValue().c_str());
//Serial.println(pBLERemoteCharacteristic->readUInt8());
std::string farhenheight = pRemoteCharacteristic->readValue();
Serial.print("Farheinheight: ");
Serial.println(farhenheight.c_str());
Serial.println(F("Posting to api!"));
Serial.println();
Serial.println("closing connection");
}
class MyClientCallback : public BLEClientCallbacks {
void onConnect(BLEClient* pclient) {
Serial.println("connected again ... ");
}
void onDisconnect(BLEClient* pclient) {
connected = false;
Serial.println("onDisconnect");
}
};
bool connectToServer(BLEAddress pAddress) {
Serial.print("Forming a connection to ");
Serial.println(pAddress.toString().c_str());
BLEClient* pClient = BLEDevice::createClient();
Serial.println(" - Created client");
pClient->setClientCallbacks(new MyClientCallback());
// Connect to the remove BLE Server.
pClient->connect(pAddress);
Serial.println(" - Connected to server");
// Obtain a reference to the service we are after in the remote BLE server.
BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
Serial.println(pRemoteService->toString().c_str());
if (pRemoteService == nullptr) {
Serial.print("Failed to find our service UUID: ");
Serial.println(serviceUUID.toString().c_str());
return false;
}
Serial.println(" - Found our service");
// Obtain a reference to the characteristic in the service of the remote BLE server.
pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
if (pRemoteCharacteristic == nullptr) {
Serial.print("Failed to find our characteristic UUID: ");
Serial.println(charUUID.toString().c_str());
return false;
}
Serial.println(" - Found our characteristic");
pRemoteCharacteristic->registerForNotify(notifyCallback);
}
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice advertisedDevice) {
Serial.print("BLE Advertised Device found: ");
Serial.println(advertisedDevice.toString().c_str());
//Serial.print(advertisedDevice.haveServiceUUID());
if(advertisedDevice.haveServiceUUID()){
Serial.println(advertisedDevice.getServiceUUID().toString().c_str());
}
// We have found a device, let us now see if it contains the service we are looking for.
if (advertisedDevice.haveServiceUUID() && advertisedDevice.getServiceUUID().equals(serviceUUID)) {
//
Serial.print("Found our device! address: ");
advertisedDevice.getScan()->stop();
pServerAddress = new BLEAddress(advertisedDevice.getAddress());
doConnect = true;
} // Found our server
} // onResult
}; // MyAdvertisedDeviceCallbacks
void setup() {
Serial.begin(115200);
Serial.println("Starting Arduino BLE Client application...");
BLEDevice::init("");
BLEScan* pBLEScan = BLEDevice::getScan();
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setActiveScan(true);
pBLEScan->start(30);
} // End of setup.
// This is the Arduino main loop function.
void loop() {
if (doConnect == true) {
if (connectToServer(*pServerAddress)) {
Serial.println("We are now connected to the BLE Server.");
connected = true;
} else {
Serial.println("We have failed to connect to the server; there is nothin more we will do.");
}
//doConnect = false;
}
if (connected == false){
BLEDevice::getScan()->start(0);
}
else{
doConnect = false;
}
delay(1000); // Delay a second between loops.
} // End of loop
Please see answers to your questions below:-
If I want to implement deep sleep functionality to the server, what would happen to the client? Does the client also have to reset at some point?
No the client does not have to reset, but you may have to reconnect to the server because in deep sleep the BLE connection is lost. If you want the connection to be established automatically as soon as the server wakes up, then you have to update the client code so that it continuously attempts to reconnect to the server. This way, as soon as the server wakes up, the client would connect to it and continue receiving notifications.
Also, is it advisable to use Characteristic.Notify in a deep sleep scenario?
In deep sleep the CPU will be off, therefore you will not be able to send notifications in this state. In this mode you will only be able to wake up the CPU through a timer or an external peripheral (e.g. touch pins). Please see the link below for more information:-
https://lastminuteengineers.com/esp32-deep-sleep-wakeup-sources/
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/sleep_modes.html
https://randomnerdtutorials.com/esp32-deep-sleep-arduino-ide-wake-up-sources/
I hope this helps.

Send data periodically as a server to my client in arduino ESP8226

I'm using NodeMCU board to communicate a laptop through WiFi. Basic communication is ok with a code like this:
void loop (){
WiFiClient client = server.available();
if (client) {
while (client.connected()){
client.println(Data_mem[0]);
delay(2000);
}
client.stop(); // tarminates the connection with the client
}
}
But when I want to send data a Timer Tick, it seems the client couldn't connect to me.
void setup(){
....
//Initialize Ticker every 40ms
Data_Rec.attach_ms(40, 40ms_Data );
}
void 40ms_Data (){
WiFiClient client = server.available();
Serial.println("40ms_Data A");
if (client) {
Serial.println("40ms_Data B");
if (client .connected()){
Serial.println("40ms_Data C");
client.println(40ms_Data [0]);
}
else{
client.stop();
}
}
}
I arduino serial monitor, i see only this:
40ms_Data A \r\n
40ms_Data A \r\n
....
So, could anyone help me? maybe it a problem of WiFiClient deceleration in a non-forever loop (like example 1). But I have no idea to fix it.
According to M.R.'s idea, this is my complete new code:
#include <ESP8266WiFi.h>
#include <Ticker.h>
/* Put your SSID & Password */
const char* ssid = "NodeMCU"; // Enter SSID here
const char* password = "12345678"; //Enter Password here
/* Put IP Address details */
IPAddress local_ip(192,168,1,1);
IPAddress gateway(192,168,1,1);
IPAddress subnet(255,255,255,0);
WiFiServer server(80);
const int CLIENT_TIMEOUT = 2000;
Ticker Data_Rec;
bool Sending_40ms_Start_Flag = false;
void setup() {
Serial.begin(115200);
pinMode(D0, OUTPUT);
WiFi.softAP(ssid, password);
WiFi.softAPConfig(local_ip, gateway, subnet);
delay(100);
server.begin();
Serial.println("HTTP server started");
Data_Rec.attach_ms(500, flag_enable);//500ms is for test
}
void flag_enable(){
//Read FPGA Data from SPI
//...
Sending_40ms_Start_Flag = true;
}
void loop(){
WiFiClient client = server.available();
if (client) {
while(client.connected()){
Serial.println("40ms_Data B");
if (Sending_40ms_Start_Flag){
client.println("Server listening.\r");
Sending_40ms_Start_Flag = false;
}
delay(1);//without this delay, ESP would be reset(because it cannot handle background processes)
}
// else{
// client.stop();
// }
}
}
This code worked. But the server RST the TCP connection after sending one,two or tree "Server listening." as Wireshark shows: Wireshark Capture
What is probable cause of TCP Reset from ESP?
Besides that some syntax errors in your code:
A good solution is to create a static pointer object from client and pass it as an argument to ms40_Data function:
void ms40_Data(WiFiClient *client)
{
Serial.println("40ms_Data A");
if (*client)
{
Serial.println("40ms_Data B");
if (client->connected())
{
Serial.println("40ms_Data C");
//client.println(40ms_Data [0]);
}
else
{
client->stop();
}
}
}
void setup()
{
...
// create a static object from WiFiClient
static WiFiClient client = server.available();
//Initialize Ticker every 40ms
Data_Rec.attach_ms(40, ms40_Data, &client);
}
void loop()
{
}
Another solution is, you can set a flag inside your ticker and then call your ms40_Data function:
bool start_40ms_Data = false;
void ms40_Data()
{
static WiFiClient client = server.available();
Serial.println("40ms_Data A");
if (client)
{
Serial.println("40ms_Data B");
if (client.connected())
{
Serial.println("40ms_Data C");
//client.println(40ms_Data [0]);
}
else
{
client.stop();
}
}
}
void flag_enable()
{
start_40ms_Data = true;
}
void setup()
{
...
//Initialize Ticker every 40ms
Data_Rec.attach_ms(40, flag_enable);
}
void loop()
{
if (start_40ms_Data)
{
ms40_Data();
start_40ms_Data = false;
}
}
The point is to adding this to setup function:
WiFi.mode(WIFI_AP);
Full explanation: Here
Thank you,

The WiFi ESP8266 modifies my power values in Arduino monitor

Here is a link to openenergy monitor where I got the current sensor, you can find the type CT3100.
I'm working on an energy monitor using an Arduino Uno. I'm already able to get values (which are correct) of total power in the Arduino monitor. I would like to send that data to a database using an ESP8266 WiFi module.
The problem that occurs is when I add ESP module to Arduino, the values of total power I get in the monitor are not correct anymore.
void setup(){
wifi.setBootMarker(F("Version:0.9.2.4]\r\n\r\nready"));
softser.begin(9600); // Soft serial connection to ESP8266
Serial.begin(9600);;
emon1.current(1, 55.6); // Current: input pin, calibration.
char buffer[50];
Serial.print(F("Hard reset..."));
if(!wifi.hardReset()) {
Serial.println(F("no response from module."));
for(;;);
}
Serial.println(F("OK."));
Serial.print(F("Soft reset..."));
if(!wifi.softReset()) {
Serial.println(F("no response from module."));
for(;;);
}
Serial.println(F("OK."));
Serial.print(F("Checking firmware version..."));
wifi.println(F("AT+GMR"));
if(wifi.readLine(buffer, sizeof(buffer))) {
Serial.println(buffer);
wifi.find(); // Discard the 'OK' that follows
} else {
Serial.println(F("error"));
}
Serial.print(F("Connecting to WiFi..."));
if(wifi.connectToAP(F(ESP_SSID), F(ESP_PASS))) {
Serial.print(F("OK\nChecking IP addr..."));
wifi.println(F("AT+CIFSR"));
if(wifi.readLine(buffer, sizeof(buffer))) {
Serial.println(buffer);
wifi.find(); // Discard the 'OK' that follows
}
}
}
void loop(){
Serial.print(F("Connecting to host..."));
if(wifi.connectTCP(F(HOST), PORT)) {
Serial.print(F("OK\nRequesting page..."));
double Irms = emon1.calcIrms(1480); //extract Irms into Variable
double power = Irms*208;
String data;
data+="{\"IdClient\":";
data+=Client_id;
data+=",\"Nom\":\"";
data+=Nom;
data+="\",\"Irms\":";
data+=Irms;
data+=",\"Power\":";
data+=power;
data+="}";
softser.print(data);
String Post="POST / HTTP/1.1\r\nHost: 13.81.244.50\r\nContent-Type:
application/json\r\nContent-Length:";
Post+=String(data.length());
Post+="\r\n\r\n";
Post+=data;
Post+="\r\n\r\n";
String Send = "AT+CIPSEND=";
Send+=String(Post.length());
wifi.println(Send);
if (wifi.find(F(">"))){
wifi.print(Post);
}
//Test
if(wifi.find(F("OK"), true)) {
Serial.println(F("found!"));
} else {
Serial.println(F("not found."));
}
wifi.closeTCP();
} else { // TCP connect failed
Serial.println(F("D'oh!"));
}
delay(1000);
}

ethernet webserver example, client.stop causes lag time issues

Using the ethernet WebServer example code, I've got my arduino to host a website stored on an SD card. The website uses jquery to post the position of the mouse in the webbrowser back to the arduino. I would ultimately like to use this info to control a servo motor, however, the problem I have is that the client.stop line in each iteration of the void loop causes a large lag time in between when the mouse moves and when the arduino gets the information.
Is there a way to make this code only use the execute the stop.client line when the mouse stops moving. So effectively when there no information being sent from the to the arduino via the post method?
Here is my code.
#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>
String POST = "";
int count = 0;
const int chipSelect = 4;
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,178,30);
// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);
EthernetClient client;
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
Serial.setTimeout(10);
//start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
client.setTimeout(1);
server.begin();
Serial.print("server is at ");
Serial.println(Ethernet.localIP());
//SD card stuff
Serial.print("Initializing SD card...");
// see if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
// don't do anything more:
return;
}
Serial.println("card initialized.");
}
void loop() {
// listen for incoming clients
EthernetClient client = server.available();
if (client) {
Serial.println("new client");
// an http request ends with a blank line
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n' && currentLineIsBlank) {
// send a standard http response header
String POST = "";
while(client.available()){
c = client.read();
// save the variables somewhere
POST += c;
}
if(POST != ""){
Serial.println(POST);
}
//load html/css/js for website only once
if (count <= 0){
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close"); // the connection will be closed after completion of the response
//client.println("Refresh: 5"); // refresh the page automatically every 5 sec
client.println();
File dataFile = SD.open("site.txt");
// if the file is available, write to it:
if (dataFile) {
while (dataFile.available()) {
//Serial.write(dataFile.read());
client.write(dataFile.read());
}
dataFile.close();
}
// if the file isn't open, pop up an error:
else {
Serial.println("error opening site.txt");
}
}
//count = 1;
break;
}
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
}
else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
if (count == 0){
delay(500);
}
else{
delay(1);
}
count=1;
// close the connection:
client.stop();
Serial.println("client disonnected");
}
}
yes, is possible but realy hard as you have to implement HTTP\1.1, also this will reamin slow as for every mouse position, browser have to send a full HTTP request, arduino read and intepretate it.
Best solution is to use websocket (there are already some serbsocket server lybrary for arduino), once a websocket is setted-up, you have a two way communication exactly like a Serial!

Resources