Page 1 of 1
Forum

Welcome to the Tweaking4All community forums!
When participating, please keep the Forum Rules in mind!

Topics for particular software or systems: Start your topic link with the name of the application or system.
For example “MacOS X – Your question“, or “MS Word – Your Tip or Trick“.

Please note that switching to another language when reading a post will not bring you to the same post, in Dutch, as there is no translation for that post!



a toggle button tha...
 
Share:
Notifications
Clear all

[Solved] a toggle button that updates a webserver status

34 Posts
2 Users
0 Reactions
11.8 K Views
(@murad)
Eminent Member
Joined: 4 years ago
Posts: 24
Topic starter  

hello evveryone i have the below code 

i have a code that recives from php server the status of the relay or (led) and if there is any change it applys it in arduino ,,,, 

 i managed to make it work with a physical button in my case it is (IR Infrared Obstacle Avoidance Sensor) 

now my issue is,, when i push the physical button which its attached to the rduino via pin, it works  BUT it doesnt send  to the php server to update the physical button status. so eventually in few seconds when the php code recheck with the arduino again to send the commands.. it  updates same status that on php server  without the order of the physical button so the physical button command gets over wrettin if its correct to say that, 

here is the code,

thank you folks.

 
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClient.h>
#include <Arduino_JSON.h>

#include <ESP8266WiFiMulti.h>
ESP8266WiFiMulti WiFiMulti;

////////////// Obstacle code//////////////
#define r1 4
int relay1 = LOW;
int obstaclePin = 5; // This is our input pin
int hasObstacle = HIGH;
////////////// Obstacle code//////////////

const char* ssid = "router SSID";
const char* password = "ROUTER password";

//Your IP address or domain name with URL path
const char* serverName = "http://example.com/esp-outputs-action.php?action=outputs_state&board=1";

// Update interval time set to 5 seconds
const long interval = 5000;
unsigned long previousMillis = 0;

String outputsState;

void setup() {
////////////// Obstacle code//////////////

pinMode(r1, OUTPUT);
pinMode(obstaclePin, INPUT);
////////////// Obstacle code//////////////
Serial.begin(115200);

WiFi.mode(WIFI_STA);
WiFiMulti.addAP(ssid, password);
while((WiFiMulti.run() == WL_CONNECTED)) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("Connected to WiFi");
}
////////////// Obstacle code//////////////

void buttons() {
hasObstacle = digitalRead(obstaclePin);
if (hasObstacle == LOW)
{
relay1 = ~ relay1;
digitalWrite(r1,relay1);
delay(1000);
}

delay(200);
}
////////////// Obstacle code//////////////

void http() {
unsigned long currentMillis = millis();

if(currentMillis - previousMillis >= interval) {
// Check WiFi connection status
if ((WiFiMulti.run() == WL_CONNECTED)) {
outputsState = httpGETRequest(serverName);
Serial.println(outputsState);
JSONVar myObject = JSON.parse(outputsState);

// JSON.typeof(jsonVar) can be used to get the type of the var
if (JSON.typeof(myObject) == "undefined") {
Serial.println("Parsing input failed!");
return;
}

Serial.print("JSON object = ");
Serial.println(myObject);

// myObject.keys() can be used to get an array of all the keys in the object
JSONVar keys = myObject.keys();

for (int i = 0; i < keys.length(); i++) {
JSONVar value = myObject[keys[i]];
Serial.print("GPIO: ");
Serial.print(keys[i]);
Serial.print(" - SET to: ");
Serial.println(value);
pinMode(atoi(keys[i]), OUTPUT);
digitalWrite(atoi(keys[i]), atoi(value));
}
// save the last HTTP GET Request
previousMillis = currentMillis;
}
else {
Serial.println("WiFi Disconnected");
}
}
}

String httpGETRequest(const char* serverName) {
WiFiClient client;
HTTPClient http;

// Your IP address with path or Domain name with URL path
http.begin(client, serverName);

// Send HTTP POST request
int httpResponseCode = http.GET();

String payload = "{}";

if (httpResponseCode>0) {
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
payload = http.getString();
}
else {
Serial.print("Error code: ");
Serial.println(httpResponseCode);
}
// Free resources
http.end();

return payload;
}

void loop(){
void buttons();
void http();
}
This topic was modified 4 years ago 2 times by murad

   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2728
 

Hi Murad!

Thank you for posting the code in the forum! 😊 

So if I understand your question correctly: the button push is not send to the server quick enough?
If so: I think this may be related to the way an Arduino/ESP8266 working sequential and not in a multitask like setting.

The ESP8266 however does have a timer functions that can make it [almost] behave like it can multitask.
See page 7 of this PDF:

 

Here some code I used in one of my projects::

...

// Timer
os_timer_t myTimer;
bool TimerTickOccured = false;

...

void setup() {
...
  TimerInit();
  Serial.println ( "Interrupt timer : Started" );
...
}

...

void TimerInit(void)
{
os_timer_setfn(&myTimer, timerCallback, NULL); // set callback function for when timer fires
os_timer_arm(&myTimer, 1000, true); // set the timer to fire every 1000 milliseconds
}

// Function to Fire when Timer is triggered; flags that another FX may have been selected
void timerCallback(void *pArg)
{
TimerTickOccured = true; // do something like maybe catch the button state here and store in global variable
}

So in this code I have the timer check every second.
I'm sure there is a more elegant and better way to do this.
But as you can see the documentation can be a little challenging.
During the "timerCallback" execution, I have found that you shouldn't be doing overly complex things.
So in you case just read the button status, and have the sending data done in a different function/location, since network activity will potentially screw up things.

So I have elsewhere in my code a function that is called frequently doing something like this

if(TimerTickOccured) 
{
  TimerTickOccured=false; // reset the TimerTickOccured variable
  server.handleClient(); // do something complex
}

Maybe these resources may be helpful as well:

 

I'm not sure if this is what you're looking for though.


   
ReplyQuote
(@murad)
Eminent Member
Joined: 4 years ago
Posts: 24
Topic starter  

actually my issue that i cant figure out how to send the commands to php ... 

i heared its about json POST command 

i really cant figure out how to post  with json 

the closest thing i got is this ,,,,  but i cant figure it out still ,,, i suppose it have to reverse the command from scrip that uses JSON GET 😥 

my physical button command gets over written by the php get coz the button command doesnt send update to php to change the status so when it resends the data back to arduino it will stay as button pressed no to be over written

if ((millis() - lastTime) > timerDelay) {
//Check WiFi connection status
if(WiFi.status()== WL_CONNECTED){
HTTPClient http;

// Your Domain name with URL path or IP address with path
http.begin(serverName);

// Specify content-type header
http.addHeader("Content-Type", "application/x-www-form-urlencoded");

// Prepare your HTTP POST request data
String httpRequestData = "SOMETHING HERE ";
Serial.print("httpRequestData: ");
Serial.println(httpRequestData);

// Send HTTP POST request
int httpResponseCode = http.POST(httpRequestData);
This post was modified 4 years ago by murad

   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2728
 

Hi Murad,

Note : I'm getting a lot of error messages from your email address (Mailbox size limit exceeded).

Sending info to your server can e done in 2 ways: POST and GET. (see also this article with ESP8266 examples)

With "GET" (it's a confusing name), you URL will be something like this:

 http://yourserver/somepage.html? variable1=value1&variable2=value2

The variables (variable1 and variable2) and their values (value1 and value2) are placed in the link.
This is very convenient to work with of course, but in a more public setting maybe not desirable as it reveals the variables and opens this approach more easily to malicious users tinkering with your server. In a private (at home) setting I'd assume this will be fine though.

Using "POST" does something similar, however the data is not placed in the link, but rather hidden for the enduser. (more secure)
In this case the JSON format can be used as the data "package".

The data will then be formatted something like this:

{ "variable1":"value1", "variable2":"value2" )

(a ":" between variable name and value, and the variable sets separated by a comma)

So in code (instead of double quote, you'll have to escape the double quote otherwise the string will break -> " becomes \")

http.POST("{\"variable1\":\"value1\",\"variable2\":\"value2\"}")

So your code:

String httpRequestData = "SOMETHING HERE ";

Becomes

String httpRequestData = "{\"variable1\":\"value1\",\"variable2\":\"value2\"}";

Of course you PHP server needs to read this data with $_POST (PHP manual).
For example something like this to make the values visible in your browser:

(PHP Code on your server!)

echo $_POST["variable1"];
echo "<br>";
echo $_POST["variable2"];

 

Is this what you're looking for?

 


   
ReplyQuote
(@murad)
Eminent Member
Joined: 4 years ago
Posts: 24
Topic starter  

@hans thank you sir for the help you are amazing,, are u the same guy who have books ? i googled ur name and a book writer showed 

i will try this method 

this is the variables from my website 

http://example.com/esp-outputs.php?name=touchless&board=3&gpio=5&state=0

String httpRequestData = "{\"name\":\"touchless\",\"board\":\"3\",\"gpio\":\"5\",\"state\":\"0\"}";

is that correct ? 

appreciated 

and i didn't get what you meant by my email ? is it bothering u ? 

 


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2728
 

Thank you for the compliment.
Just happy to help where I can 😊 

Posted by: @murad

are u the same guy who have books

No, that is not me haha ... nice find though!
That guy just has the same name, but seems very experienced with art (Van Gogh).

As for the email: every email my server sends to you (notification that there is a new post on your forum topic for example) is returned since your mailbox seems full.
Personally it doesn't bother me, but you may be missing the notifications, and if you ever want to change something on your account (like your password), you may not be able to complete these tasks since emails never arrive. 😉 

 

Coming back to your code ...

So this link actually uses the GET method.

 http://example.com/esp-outputs.php?name=touchless&board=3&gpio=5&state=0 

Where as this line is intended for the POST method.

String httpRequestData = "{\"name\":\"touchless\",\"board\":\"3\",\"gpio\":\"5\",\"state\":\"0\"}";

You should not mix these method, since that can be confusing and may not work as expected.

GET and POST are 2 different methods for transferring data from a browser (or in this case your ESP8266) to your server.
I know the names are a little confusing, I didn't make them up haha, but in essence they do the same thing, just in a different way.

 

Presuming we continue with the GET method ... so for now we drop everything JSON or POST related.
If you look at the link:

 http://example.com/ esp-outputs.php?name=touchless&board=3&gpio=5&state=0

then you'll see that after the page you're trying to open (esp-outputs.php), there will be a question mark (?), followed by a variable name = value (touchless).
After that you will see the ampersand symbol (&) which indicates that another variable+value will follow (board=3).
Then again an ampersand (&), indicating that yet another variable+value follows (gpi=5).
Then again an ampersand (&), indicating that yet another variable+value follows (state=0).

Now if you want to add a variable, for example let's call it "switch", with a value either "0" (off) of "1" (on) then you can add this like so.
First add an ampersand indicating that a variable+value will follow, then the variable name followed by the equal sign (=) and finally followed by the value (0 or 1):

 http://example.com/esp-outputs.php?name=touchless&board=3&gpio=5&state=0 &switch=1

Naturally, you will need to adjust your PHP code to actually read "switch" ($_GET["switch"]) and do something with it.

 

I think there are a few things you may want to look at.
Your code is a little bit of a mess, which I fully understand since you were struggling with POST vs GET and JSON.

I'd strongly recommend starting with a simple example, as seen in this paragraph of the link I gave you earlier.
Naturally, you'll need to have the PHP code on your server for that to work with it as well of course.

A few pointers:

1) Your URL definition already includes GET parameters. This doesn't need to be wrong, but a little unusual.
These GET parameters are usually added in code based on the values you'd like to send. You'll see that in this paragraph as well, where the add the parameters to the main link.

//Your IP address or domain name with URL path
const char* serverName = "http://example.com/esp-outputs-action.php?action=outputs_state&board=1";

2) Your code is mixing up the POST and GET methods. Better stick to one - the GET method is the easiest to begin with, and will not require any JSON complications.

 


   
ReplyQuote
(@murad)
Eminent Member
Joined: 4 years ago
Posts: 24
Topic starter  

@hans 

hey sir, 

honestly, that level of coding is out of my league  🙄 

i dont really understand the mechanisime ,

maybe if i send the php file it makes more sense to you  ? 

and about ur level of expertise ur awesome bro ,,, touch wood 🤓 

and i will be posting now a project i was working on and i just finished for the sake of your kindness 

here is my php script that sends the commands (esp-outputs.php)

<?php
include_once 'esp-database.php'; $action = $id = $name = $gpio = $state = ""; if ($_SERVER["REQUEST_METHOD"] == "POST") { $action = test_input($_POST["action"]); if ($action == "output_create") { $name = test_input($_POST["name"]); $board = test_input($_POST["board"]); $gpio = test_input($_POST["gpio"]); $state = test_input($_POST["state"]); $result = createOutput($name, $board, $gpio, $state); $result2 = getBoard($board); if (!$result2->fetch_assoc()) { createBoard($board); } echo $result; } else { echo "No data posted with HTTP POST."; } } if ($_SERVER["REQUEST_METHOD"] == "GET") { $action = test_input($_GET["action"]); if ($action == "outputs_state") { $board = test_input($_GET["board"]); $result = getAllOutputStates($board); if ($result) { while ($row = $result->fetch_assoc()) { $rows[$row["gpio"]] = $row["state"]; } } echo json_encode($rows); $result = getBoard($board); if ($result->fetch_assoc()) { updateLastBoardTime($board); } } elseif ($action == "output_update") { $id = test_input($_GET["id"]); $state = test_input($_GET["state"]); $result = updateOutput($id, $state); echo $result; } elseif ($action == "output_delete") { $id = test_input($_GET["id"]); $board = getOutputBoardById($id); if ($row = $board->fetch_assoc()) { $board_id = $row["board"]; } $result = deleteOutput($id); $result2 = getAllOutputStates($board_id); if (!$result2->fetch_assoc()) { deleteBoard($board_id); } echo $result; } else { echo "Invalid HTTP request."; } } function test_input($data) { $data = trim($data); $data = stripslashes($data); $data = htmlspecialchars($data); return $data; } ?>



   
ReplyQuote
(@murad)
Eminent Member
Joined: 4 years ago
Posts: 24
Topic starter  

i just added a post about touchless project and esp with alexa functionality but for a reason i cant see it pending can you please check it 😥 


   
ReplyQuote
(@murad)
Eminent Member
Joined: 4 years ago
Posts: 24
Topic starter  

so i managed to make it send a command when i toggle the button ,,,, 

but still i need to work on the if its high then push this status ,,,, and else ,,, push the off status to update the button on web 

here is the part ,,,, 

i know it looks messy im sorry 

////////////// Obstacle code//////////////

void buttons() {
hasObstacle = digitalRead(obstaclePin);
if (hasObstacle == LOW)
{
relay1 = ~ relay1;
digitalWrite(r1,relay1);
HTTPClient http;

http.begin(serverName);
http.addHeader("Content-Type", "application/json");
String httpRequestData = "{\"action\":\"output_update\",\"id\":\"8\",\"state\":\"1\"}";///// this is to turn it on ,,, when i toggle the physical button
// String httpRequestData = "{\"action\":\"output_update\",\"id\":\"8\",\"state\":\"0\"}";///// this is to turn it off
Serial.print("httpRequestData: ");
Serial.println(httpRequestData);
int httpResponseCode = http.POST(httpRequestData);
if (httpResponseCode>0) {
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
}
else {
Serial.print("Error code: ");
Serial.println(httpResponseCode);
}
delay(1000);
}

delay(200);

}

////////////// Obstacle code//////////////

   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2728
 

Hi Murad,

considering the code you're looking at, I assume you copied it from at least one other project.
It would be a better to either dig into the code and try to understand each step, or consult the writer of the code - after all it is quite time consuming for me to read and understand what is going on in the code.

The PHP code can handle both the POST and GET method.
And you last code is using the POST method on the Arduino.

From what I can read, without spending an excessive amount of time on it;

The button seems to be read in the buttons() function where we see that the variable "hasObstacle" holds the state of the button, which is either HIGH (on) or LOW (off).

void buttons() {
hasObstacle = digitalRead(obstaclePin);

Looking at how data is send (your last code) then you'd have to change these two line:

String httpRequestData = "{\"action\":\"output_update\",\"id\":\"8\",\"state\":\"1\"}";///// this is to turn it on ,,, when i toggle the physical button 
// String httpRequestData = "{\"action\":\"output_update\",\"id\":\"8\",\"state\":\"0\"}";///// this is to turn it off

To

if(hasObstacle==HIGH) {
String httpRequestData = "{\"action\":\"output_update\",\"id\":\"8\",\"state\":\"1\"}";///// this is to turn it on ,,, when i toggle the physical button
}
else
{
String httpRequestData = "{\"action\":\"output_update\",\"id\":\"8\",\"state\":\"0\"}";///// this is to turn it off
}

 

p.s. It is OK if your code is a little bit of a mess - this happens when copying and pasting code from different sources. However it will be helpful if you clean your code - this way it becomes easier to read. A helpful free online tool that I use myself for this is Codebeautify (link - select "C Formatter" or "C++ Formatter" for Arduino code, and "PHP Formatter" for PHP code).

p.s.2 If you're looking for a short course or reference material on coding on an Arduino (ESP8266) then feel free to look at my Arduino Coding for Beginners course. (in case you're not very familiar with the C programming language)


   
ReplyQuote
(@murad)
Eminent Member
Joined: 4 years ago
Posts: 24
Topic starter  

i cant post anymore ,,,, whatever i post it get deleted as i didnt post it 


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2728
 
Posted by: @murad

i cant post anymore ,,,, whatever i post it get deleted as i didnt post it 

That's weird ... I can see this post 😊 

In case you're trying to post code: on very rare occasions code may trigger the firewall (thinking it is malicious code).
You can try instead to attach the INO file to the message (instead of pasting it in the message).


   
ReplyQuote
(@murad)
Eminent Member
Joined: 4 years ago
Posts: 24
Topic starter  

@hans

yes brother but anything with url or code i cant post 

😫

 


   
ReplyQuote
(@murad)
Eminent Member
Joined: 4 years ago
Posts: 24
Topic starter  

even i added a new post a tutorial  on alexa with touchless sensor and it didnt get posted 


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2728
 

The first few posts will be strictly monitored - so it could be that this is the case here.
I think you need at least 5 (or was it 10?) posts approved by me before you can attach files or post links (I forgot the fine details).
Since you already did 9 posts, I'd expect links and attachments to work now.

Please try again. If it fails, post a small comment, and try again (so that you go beyond 10 posts).
Apologies for the inconvenience.

 


   
ReplyQuote
Page 1 / 3
Share: