ESP8266 send GET request to remote server - php

http://www.universalcard.byethost7.com is my server. Where I kept index.php file. Code is as given below
<?php
if(isset($_GET['username']) && isset($_GET['pin']) && isset($_GET['cost'])) {
$username = $_GET['username'];
$pin = $_GET['pin'];
$cost = $_GET['cost'];
$filecontent = "Username is: ".$username." and PIN is: ".$pin." and cost is: ".$cost."\n";
$filestatus = file_put_contents('uc.txt',$filecontent,FILE_APPEND);
if($filestatus != false )
{
echo "Data written to file..";
}else{
echo "Ohh sorry..";
}
} else {
echo "Something went wrong..";
}
?>
And I want to send a GET request from ESP8266 with Arduino IDE.
In this GET request, I am sending 3 variables 'username' , 'pin' and 'cost' with some values (data type is String). And these values are appending to a file "uc.txt". So when I send a request using a browser, values will append to the text file.
But when I tried to send using ESP8266 it is not appending
Arduino Code is below
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
const char* ssid = "rainbow";
const char* password = "12345678";
const char* host = "universalcard.byethost7.com";
const int httpsPort = 443;
// Use web browser to view and copy
// SHA1 fingerprint of the certificate
//const char* fingerprint = "CF 05 98 89 CA FF 8E D8 5E 5C E0 C2 E4 F7 E6 C3 C7 50 DD 5C";
void setup() {
Serial.begin(115200);
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");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
// Use WiFiClientSecure class to create TLS connection
WiFiClientSecure client;
Serial.print("connecting to ");
Serial.println(host);
if (!client.connect(host, httpsPort)) {
Serial.println("connection failed");
return;
}
String url = "/index.php?username=2bv14is114&pin=5555&cost=1111";
Serial.print("requesting URL: ");
Serial.println(url);
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"User-Agent: BuildFailureDetectorESP8266\r\n" +
"Connection: close\r\n\r\n");
Serial.println("request sent");
while (client.connected()) {
String line = client.readStringUntil('\n');
if (line == "\r") {
Serial.println("headers received");
break;
}
}
String line = client.readStringUntil('\n');
if (line.startsWith("{\"state\":\"success\"")) {
Serial.println("esp8266/Arduino CI successfull!");
} else {
Serial.println("esp8266/Arduino CI has failed");
}
Serial.println("reply was:");
Serial.println("==========");
Serial.println(line);
Serial.println("==========");
Serial.println("closing connection");
}
void loop() {
}
And the output in Serial monitor is below

Your host has some sort of protection (maybe against bots), that expects a _test cookie set by JavaScript, if not present.
You could acquire the cookie, by first visiting the site with the browser and copy paste the cookie into your code.
You would need to do it from the same IP, that your ESP8266 will be introduced to the server, since the cookie is IP bound.
In this case you would have a problem, if you have a dynamic IP and also the longevity of the cookie is unknown.
You could also acquire the cookie by parsing the response, but the cookie is AES encrypted and that would be somewhat complicated.
The most sensible solution would be to switch to a host without such protection.
This is a solution to basically the same problem in this and this question.

Related

file_get_contents does not send data content in a POST request

I am attempting to send a POST request to an arduino from a PHP script that is called by a web page. I am using file_get_contents() to accomplish this. I have read the examples from the PHP manual here: Here. It appears that the Arduino is receiving the POST request but there is no content included in the data stream, only headers and content parameters. Here is my relevant php
// send database updates to the arduino
$url = 'http://'.$ip;
$options = array(
'http' => array(
'header' => "Content-type: application/x-www/form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($responseText)
),
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
currently on the Arduino I am just dumping the entire POST request to the terminal so that I can verify that it is being received. Here is the output of the Arduino terminal.
Ethernet WebServer Example
server is at 192.168.3.3
new client
POST / HTTP/1.0
Host: 192.168.3.3
Connection: close
Content-Length: 80
Content-type: application/x-www/form-urlencoded
client disconnected
As you can see the entire POST request is there accept the content. It shows the Content-Length but no actual content.
Here is the Arduino code that produced the terminal output. It is nothing more than the Web Server example that comes with the Arduino IDE.
/*
Web Server
A simple web server that shows the value of the analog input pins.
using an Arduino Wiznet Ethernet shield.
Circuit:
* Ethernet shield attached to pins 10, 11, 12, 13
* Analog inputs attached to pins A0 through A5 (optional)
created 18 Dec 2009
by David A. Mellis
modified 9 Apr 2012
by Tom Igoe
modified 02 Sept 2015
by Arturo Guadalupi
*/
#include <SPI.h>
#include <Ethernet.h>
// 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, 3, 3);
// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);
String postData;
void setup() {
// You can use Ethernet.init(pin) to configure the CS pin
Ethernet.init(10); // Most Arduino shields
//Ethernet.init(5); // MKR ETH shield
//Ethernet.init(0); // Teensy 2.0
//Ethernet.init(20); // Teensy++ 2.0
//Ethernet.init(15); // ESP8266 with Adafruit Featherwing Ethernet
//Ethernet.init(33); // ESP32 with Adafruit Featherwing Ethernet
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
Serial.println("Ethernet WebServer Example");
// start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
// Check for Ethernet hardware present
if (Ethernet.hardwareStatus() == EthernetNoHardware) {
Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :(");
while (true) {
delay(1); // do nothing, no point running without Ethernet hardware
}
}
if (Ethernet.linkStatus() == LinkOFF) {
Serial.println("Ethernet cable is not connected.");
}
// start the server
server.begin();
Serial.print("server is at ");
Serial.println(Ethernet.localIP());
}
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();
//postData = postData + c;
Serial.write(c);
// 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
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();
/*client.println("<!DOCTYPE HTML>");
client.println("<html>");
// output the value of each analog input pin
for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
int sensorReading = analogRead(analogChannel);
client.print("analog input ");
client.print(analogChannel);
client.print(" is ");
client.print(sensorReading);
client.println("<br />");
}
client.println("</html>");*/
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
delay(1);
Serial.println("client disconnected");
}
}
What is causing the content of the POST request to not be sent from the PHP?
After I let my brain rest for about half a day I determined the cause of my problem. It was not in the PHP at all. It was being caused by this IF block in the Arduino code
if (c == '\n' && currentLineIsBlank) {
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
//client.println("Refresh: 5");
client.println();
/*client.println("<!DOCTYPE HTML>");
client.println("<html>");
// output the value of each analog input pin
for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
int sensorReading = analogRead(analogChannel);
client.print("analog input ");
client.print(analogChannel);
client.print(" is ");
client.print(sensorReading);
client.println("<br />");
}
client.println("</html>");*/
break;
}
it was causing while loop that it is nested in to terminate at the blank line between the header and the content. My new working code for the Arduino is
#include <SPI.h>
#include <Ethernet.h>
// 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, 3, 3);
// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);
String postData;
void setup() {
// You can use Ethernet.init(pin) to configure the CS pin
Ethernet.init(10); // Most Arduino shields
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
Serial.println("Ethernet WebServer Example");
// start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
// Check for Ethernet hardware present
if (Ethernet.hardwareStatus() == EthernetNoHardware) {
Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :(");
while (true) {
delay(1); // do nothing, no point running without Ethernet hardware
}
}
if (Ethernet.linkStatus() == LinkOFF) {
Serial.println("Ethernet cable is not connected.");
}
// start the server
server.begin();
Serial.print("server is at ");
Serial.println(Ethernet.localIP());
}
void loop() {
// listen for incoming clients
EthernetClient client = server.available();
if (client) {
Serial.println("new client");
while (client.connected()) {
while (client.available()) {
char c = client.read();
postData = postData + c;
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();
}
client.stop();
}
// give the web browser time to receive the data
delay(1);
Serial.println("\r\nclient disconnected");
Serial.println(postData);
Serial.println(postData.substring(postData.indexOf("status=")+7, postData.indexOf("status=")+8 ));
}
}

How to send data from Ardunio Nano using ENC28J60 to PHP

I am trying to send the sensor data from Arduino Nano connected with ENC28J60 module for Ethernet connection, the Nano get the IP addresses from my router without any issue, but when I want to send the data to my php page it didn't work!
I tried the link in Postman and work but in Arduino Nano not work:
my code :
#include <UIPEthernet.h>
#include <ArduinoHttpClient.h>
#include "utility/logging.h"
EthernetClient client;
unsigned long next;
char serverAddress[] = "test.tech"; // server address
int port = 8080;
void setup() {
Serial.begin(115200);
uint8_t mac[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
// Ethernet.init(3); Serial.println("cs pin");
Ethernet.begin(mac);
Serial.println("Initiliazed");
Serial.print(("localIP: "));
Serial.println(Ethernet.localIP());
Serial.print(("subnetMask: "));
Serial.println(Ethernet.subnetMask());
Serial.print(("gatewayIP: "));
Serial.println(Ethernet.gatewayIP());
Serial.print(("dnsServerIP: "));
Serial.println(Ethernet.dnsServerIP());
next = 0;
}
HttpClient client1 = HttpClient(client, serverAddress, port);
void loop()
{
Serial.println("making GET request");
client1.get("/Sensor/insert.php?temp=20&time=2020-08-10 19:58:46&Date=2020-08-10&Clock=19:58:46");
int statusCode = client1.responseStatusCode();
String response = client1.responseBody();
Serial.print("Status code: ");
Serial.println(statusCode);
Serial.print("Response: ");
Serial.println(response);
Serial.println("Wait five seconds");
delay(5000);
}
Thanks for all:
this code it works with me using ENC28J60 and aI can send the data to PHP server, and I hope some one will find it usefull:
#include <Time.h> //http://www.pjrc.com/teensy/td_libs_Time.html
#include <TimeLib.h> //TimeLib library is needed https://github.com/PaulStoffregen/Time
#include <UIPEthernet.h> //UIPE ETHERNT LIBRARY FOR THE ETHERNET MODULE ENC28J60
#define DHTPIN 2
#define DHTTYPE DHT11 // DHT 22 (AM2302), AM2321
#define DEBUG // TURN DEBUGGING ON OR OFF, TO TURN IT OFF JUST COMMENT THIS LINE
DHT dht(DHTPIN, DHTTYPE);
/* ETHERNET SETTINGS
ARDUINO UNO PINS USED FOR THE ENC28J60 MODULE: 10=CS, 11=MOSI, 12=MISO, 13=SCK
THE ETHERNET MAC ADDRESS MUST BE UNIQUE IN THE PRIVATE LOCAL NETWORK
REMEMBER THAT THE MAC ADDRESS IS IN HEXADECIMAL FORMAT
IN THIS EXAMPLE WE USE THE FOLLOWING MAC ADDRESS : OE:96:03:38:94:92 */
byte mac[] = { 0x0E, 0x96, 0x03, 0x38, 0x94, 0x92 };
EthernetClient client; // CREATES A CLIENT WHICH CAN CONNECT TO A SPECIFIED INTERNET IP ADDRESS AND PORT
char server[] = "www.mydomain.tech"; /// IP ADDRESS OF THE LOCAL SERVER WE CONNECT AND SEND DATA TO
int interval = 18000; // DELAY INTERVAL TO SAVE THE DATA IN THE DATABSE
long myinterval = 18000; //3 Minutes-> 180000ms INTERVAL BETWEEN DATA READINGS, I SET IT IN 6 SECONDS FOR TESTING PURPOSES
long previousMillis = 0;
int status = -2; // INITIALIZE THE CONNECTION STATUS VARIABLE
void setup() {
Serial.begin(115200); // OPEN SERIAL COMMUNICATIONS AND WAIT FOR A PORT TO OPEN
Ethernet.begin(mac); // INITIALIZES THE ETHERNET LIBRARY AND NETWORK SETTINGS
/* ETHERNET SERIAL PRINTS
INFORMATION ABOUT CLIENTS IP ADDRESS, THE SUBNET MASK OF THE NETWORK, THE GATEWAYS
IP ADDRESS AND FINALLY THE DNS SERVER IP ADDRESS WHICH IS THE SAME AS THE GATEWAYS IP
THESE INFORMATION WILL ONLY BE VISIBLE WHEN DEBUGGING IS ON */
dht.begin();
#ifdef DEBUG
Serial.println("Temperature Logger");
Serial.println("*********************");
Serial.print("IP Address : ");
Serial.println(Ethernet.localIP());
Serial.print("Subnet Mask : ");
Serial.println(Ethernet.subnetMask());
Serial.print("Default Gateway IP: ");
Serial.println(Ethernet.gatewayIP());
Serial.print("DNS Server IP : ");
Serial.println(Ethernet.dnsServerIP());
#endif
}
void loop() {
unsigned long currentMillis = millis();
// RESET ENC28J60 IN CASE OF FAILURE TO CONNECT WITH THE LOCAL SERVER
if (!client.connect(server, 80)) {
#ifdef DEBUG
Serial.println("Connection Failure: Resetting ENC28j60!");
#endif
Enc28J60.init(mac); //RESET AND INITIALIZE THE ENC28J60 AND STARTS PACKET TRANSMISSION-RECEPTION
} else {
client.stop();
}
/* CONNECT TO THE SPECIFIED IP ADDRESS AND PORT
IF A CONNECTION IS ESTABLISHED START SENDING DATA EVERY 3 MINUTES
DATA WILL BE SENT AFTER THE FIRST 3 MINUTES
ALSO WE CHECK THE STATUS OF THE SERVER
THE FUNCTION CONNECT() RETURNS AN INT INDICATING CONNECTION STATUTS:
SUCCESS (1)
TIMED_OUT (-1)
INVALID SERVER (-2)
TRUNCATED (-3)
INVALID RESPONSE (-4)*/
status = client.connect(server, 80);
if (status == 1) {
#ifdef DEBUG
Serial.println("\nConnection Success");
#endif
if (currentMillis - previousMillis > myinterval) {
previousMillis = currentMillis;
//READ DATA FROM THE DHT11 SENSOR
/* THE READ11() FUNCTION RETURNS:
DHTLIB_OK (0): THE SENSOR SAMPLE AND ITS CHECKSUM ARE OK
DHTLIB_ERROR_CHECKSUM (-1): THE CHECKSUM TEST FAILED. THIS MEANS THE DATA WAS RECEIVED BUT MAY NOT BE CORRECT
DHTLIB_ERROR_TIMEOUT (-2): A TIME OUT OCCURRED AND COMMUNICATION HAS FAILED
BELOW WE CHECK THE STATUS OF THE SENSOR */
#ifdef DEBUG
#endif
// PRINT THE HUMIDITY AND TEMPERATURE VALUES IN THE SERIAL MONITOR
#ifdef DEBUG
Serial.print("\nValues: ");
Serial.print(dht.readHumidity(), 1);
Serial.print(",\t");
Serial.println(dht.readTemperature(), 1);
Serial.println("Connected...sendingData");
#endif
// MAKE A HTTP REQUEST
// SPECIFY THE PHP FILE LOCATION IN THE SERVER
//PRINT DATA TO THE SERVER THE CLIENT IS CONNECTED TO
//STRUCTURE: "GET /filepath/yourfile.php?"
client.print( "GET /temptest/write_data.php?");
client.print("temp=");
client.print(dht.readTemperature(), 1); //THE VALUE TO WRITE IN THE DATABSE FOR TEMPERATURE
client.print("&&");
client.print("hum="); //DATABASE VARIABLE IS USED
client.print(dht.readHumidity(), 1); //THE VALUE TO WRITE IN THE DATABSE FOR HUMIDITY
client.println( " HTTP/1.1");
client.print( "Host: " );
client.println(server);
client.println( "Connection: close" );
client.println();
client.println();
client.stop(); // DISCONNECT FROM THE SERVER
delay(interval); //SOME INTERVAL FOR THE DATA TO BE WRITTEN IN THE DATABASE
}
}
// IN CASE OF A TIME_OUT
else if (status == -1) {
#ifdef DEBUG
Serial.println("Connection Timed Out !");
#endif
}
// IN CASE OF AN INVALID SERVER
else if (status == -2) {
#ifdef DEBUG
Serial.println("Invalid Server !");
#endif
}
// IN CASE OF TRUNCATION
else if (status == -3) {
#ifdef DEBUG
Serial.println("Truncated !");
#endif
}
// IN CASE OF AN INVALID RESPONSE
else if (status == -4) {
#ifdef DEBUG
Serial.println("Invalid Response !");
#endif
}
// IN CASE OF AN UNKNOWN ERROR
else {
#ifdef DEBUG
Serial.println("Unknown Error !");
#endif
}
}

Debugging POST request ESP8266 PHP

I used Postman to debug my PHP POST API, and it works (ignoring the json versos non-json input).
<?php
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
//
// include database and object files
require_once '../config/database.php';
require_once '../objects/resdatalog.php';
// instantiate database and resdatalog object
$database = new Database();
$db = $database->getConnection();
// initialize object
$rdl = new Resdatalog($db);
$rdl->Location = $_GET['Location'];
$rdl->Temperature = $_GET['Temperature'];
$rdl->Humidity = $_GET['Humidity'];
$rdl->Pressure = $_GET['Pressure'];
$rdl->RecDate = $_GET['RecDate'];
$rdl->AmbientTemp = $_GET['AmbientTemp'];
$rdl->AmbientHum = $_GET['AmbientHum'];
$rdl->AmbientPressure = $_GET['AmbientPressure'];
$ret=$rdl->insert();
?>
But, the client needs to be an ESP8266 module monitoring the environmentals in various locations. I have been trying to make that work, but debugging has just baffled me. No matter what I display on the client side, it looks OK. But it seems never to actually get to the web page. I put code in the web page to "echo" confirmations, but nothing shows up in the client. What is the best way to debug this setup:
/*
BME280 I2C Test.ino
This code shows how to record data from the BME280 environmental sensor
using I2C interface. This file is an example file, part of the Arduino
BME280 library.
GNU General Public License
Written: Dec 30 2015.
Last Updated: Oct 07 2017.
Connecting the BME280 Sensor:
Sensor -> Board
-----------------------------
Vin (Voltage In) -> 3.3V
Gnd (Ground) -> Gnd
SDA (Serial Data) -> A4 on Uno/Pro-Mini, 20 on Mega2560/Due, 2 Leonardo/Pro-Micro
SCK (Serial Clock) -> A5 on Uno/Pro-Mini, 21 on Mega2560/Due, 3 Leonardo/Pro-Micro
*/
#include <BME280I2C.h>
#include <Wire.h>
#include <ESP8266WiFi.h>
#include <Arduino.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClient.h>
#include <ArduinoJson.h>
#include <ezTime.h>
// ESP8266WiFiMulti WiFiMulti;
#define SERIAL_BAUD 115200
BME280I2C bme; // Default : forced mode, standby time = 1000 ms
// Oversampling = pressure ×1, temperature ×1, humidity ×1, filter off,
Timezone Charlotte;
String Location;
String Temperature;
String Humidity;
String Pressure;
String RecDate;
String AmbientTemp="0";
String AmbientHum="0";
String AmbientPressure="0";
const char* ssid = "mySSID"; // The SSID (name) of the Wi-Fi network you want to connect to
const char* password = "mySSIDPW"; // The password of the Wi-Fi network
//////////////////////////////////////////////////////////////////
void setup()
{
//set up the serial output
Serial.begin(SERIAL_BAUD);
for (uint8_t t = 4; t > 0; t--) {
Serial.printf("[SETUP] WAIT %d...\n", t);
Serial.flush();
delay(1000);
}
WiFi.begin(ssid, password); // Connect to the network
Serial.print("Connecting to ");
Serial.print(ssid); Serial.println(" ...");
int i = 0;
while (WiFi.status() != WL_CONNECTED) { // Wait for the Wi-Fi to connect
delay(1000);
Serial.print(++i); Serial.print(' ');
}
Serial.println('\n');
Serial.println("Connection established!");
Serial.print("IP address:\t");
Serial.println(WiFi.localIP()); // Send the IP address of the ESP8266 to the computer
waitForSync();
// Begin the BME setup:
Wire.begin(4,5);
while(!bme.begin())
{
Serial.println("Could not find BME280 sensor!");
delay(1000);
}
// bme.chipID(); // Deprecated. See chipModel().
switch(bme.chipModel())
{
case BME280::ChipModel_BME280:
Serial.println("Found BME280 sensor! Success.");
break;
case BME280::ChipModel_BMP280:
Serial.println("Found BMP280 sensor! No Humidity available.");
break;
default:
Serial.println("Found UNKNOWN sensor! Error!");
}
}
//////////////////////////////////////////////////////////////////
void loop()
{
printBME280Data(&Serial);
delay(500);
}
//////////////////////////////////////////////////////////////////
void printBME280Data(Stream* serialclient)
{
float temp(NAN), hum(NAN), pres(NAN);
BME280::TempUnit tempUnit(BME280::TempUnit_Fahrenheit);
BME280::PresUnit presUnit(BME280::PresUnit_inHg);
bme.read(pres, temp, hum, tempUnit, presUnit);
Charlotte.setLocation("America/New_York");
String localdatetime = Charlotte.dateTime("Y-m-d H:i:s");
serialclient->print("\tTemp: ");
serialclient->print(temp);
serialclient->print("°"+ String(tempUnit == BME280::TempUnit_Celsius ? 'C' :'F'));
serialclient->print("\t\tHumidity: ");
serialclient->print(hum);
serialclient->print("% RH");
serialclient->print("\t\tPressure: ");
serialclient->print(pres);
serialclient->print(" Inches Hg");
serialclient->println(" Date/Time: "+ localdatetime);
// Now, I'll try to build and post an HTTP command to my cloud API
//
Location="TiVo Cabinet";
Temperature=String(temp);
Humidity=String(hum);
Pressure=String(pres);
RecDate=localdatetime;
AmbientTemp=String(AmbientTemp);
AmbientHum=String(AmbientHum);
AmbientPressure=String(AmbientPressure);
String content =
"{\"Location\": \"" + String(Location) + "\"" +
" , \"Temperature\" : \"" + String(Temperature) + "\"" +
" , \"Humidity\" : \"" + String(Humidity) + "\"" +
" , \"Pressure\" : \"" + String(Pressure) + "\"" +
" , \"RecDate\" : \"" + String(RecDate) + "\"" +
" , \"AmbientTemp\" : \"" + String(AmbientTemp) + "\"" +
" , \"AmbientHum\" : \"" + String(AmbientHum) + "\"" +
" , \"AmbientPressure\" : \"" + String(AmbientPressure) + "\"" +
"}";
serialclient->println("Content: " + content);
// Now, we're gonna try to send this line to the server....
WiFiClient client;
if (!client.connect("telemetry.shafferassoc.com", 80)) {
Serial.println("WiFiClient connection failed");
delay(5000);
} else {Serial.println("WiFiClient connection OK");
}
client.println("Host: telemetry.shafferassoc.com:80\r\n");
client.println("POST TelemetryWebSite/API/Resdatalog/Insert.php HTTP/1.1");
client.println("Accept: */*");
client.println("Content-Length: " + String(content.length()));
client.println("Content-Type: application/json");
// client.println();
client.println(content);
Serial.println("Length: " +String(content.length()));
Serial.println(content);
Serial.println("receiving from remote server");
// not testing 'client.connected()' since we do not need to send data here
while (client.available()) {
char ch = static_cast<char>(client.read());
Serial.print(ch);
}
delay(5000);
}
Here is a snippet of the Serial output:
11:06:49.892 -> WiFiClient connection OK
11:06:49.892 -> Length: 204
11:06:49.892 -> {"Location": "TiVo Cabinet" , "Temperature" : "73.27" , "Humidity" : "0.00" , "Pressure" : "29.57" , "RecDate" : "2020-04-28 11:06:50" , "AmbientTemp" : "0" , "AmbientHum" : "0" , "AmbientPressure" : "0"}
11:06:49.933 -> receiving from remote server`

ESP8266 reads JSON, but doesn't read the PHP file

There is a code for ESP8266, which parses the data on my site and performs the switching on / off of the led. When it was a static JSON file, it all worked without problems. But when I transferred a file to PHP that dynamically updates the data and displays it in JSON format, the script doesn't get it to read. What could be the problem?
#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
#define pin 5
const char* ssid = "ssid";
const char* password = "password";
const char* host = "www.site.ru"; // domain
String path = "/lightAPI.php";
void setup() {
pinMode(pin, OUTPUT);
pinMode(pin, HIGH);
digitalWrite(5, HIGH);
Serial.begin(9600);
delay(10);
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
int wifi_ctr = 0;
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("WiFi connected");
Serial.println("IP address: " + WiFi.localIP());
}
void loop() {
WiFiClient client;
const int httpPort = 80;
if (!client.connect(host, httpPort)) {
Serial.println("connection failed");
return;
}
client.print(String("GET ") + path + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: keep-alive\r\n\r\n");
delay(2000); // wait for server to respond
// read response
String section="header";
while(client.available()){
String line = client.readStringUntil('\r');
// Serial.print(line);
// we’ll parse the HTML body here
if (section=="header") { // headers..
Serial.print("");
if (line=="\n") { // skips the empty space at the beginning
section="json";
}
}
else if (section=="json") { // print the good stuff
section="ignore";
String result = line.substring(1);
// Parse JSON
int size = result.length() + 1;
char json[size];
result.toCharArray(json, size);
StaticJsonBuffer<200> jsonBuffer;
JsonObject& json_parsed = jsonBuffer.parseObject(json);
if (!json_parsed.success())
{
Serial.println("parseObject() failed");
return;
}
// Make the decision to turn off or on the LED
if (strcmp(json_parsed["light"], "OFF") == 0) {
digitalWrite(5, HIGH);
Serial.println("LED OFF");
}
else {
digitalWrite(5, LOW);
Serial.println("LED ON");
}
}
}
}
PHP file
<?php
header('Content-Type: application/json');
$status = file_get_contents('txt/lightStatus.txt');
$json = array('light' => $status, 'time' => date("G"));
echo json_encode($json);
?>
There's something wrong with handling the response. It works when connecting to my server but it doesn't work when connecting to yours.
This is what ESP8266 gets when connecting to my server:
HTTP/1.1 200 OK
Date: Sat, 17 Jun 2017 18:21:37 GMT
Server: Apache/2.4.17 (Win32) OpenSSL/1.0.2d PHP/5.6.19
X-Powered-By: PHP/5.6.19
Content-Length: 31
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: application/json
{"light":"OFF","time":"20"}
And this is what it gets when connecting to yours:
HTTP/1.1 200 OK
Server: nginx admin
Date: Sat, 17 Jun 2017 18:25:53 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
28
{"light":"OFF","online":"0","time":"21"}
0
Unfortunately, I don't have time now to investigate the problem with your code but meanwhile here is a working one which uses HTTPClient to handle request and response (I would recommend using this anyway):
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>
#define pin 5
const char* ssid = "ssid";
const char* password = "password";
void setup() {
pinMode(pin, OUTPUT);
pinMode(pin, HIGH);
digitalWrite(5, HIGH);
Serial.begin(9600);
delay(10);
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
int wifi_ctr = 0;
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("WiFi connected");
Serial.println("IP address: " + WiFi.localIP());
}
void loop() {
HTTPClient http;
http.begin("http://bot.erm.today/lightAPI.php");
int statusCode = http.GET();
StaticJsonBuffer<200> jsonBuffer;
JsonObject& json_parsed = jsonBuffer.parseObject(http.getString());
http.end();
if (!json_parsed.success())
{
Serial.println("parseObject() failed");
return;
}
// Make the decision to turn off or on the LED
if (strcmp(json_parsed["light"], "OFF") == 0) {
digitalWrite(5, HIGH);
Serial.println("LED OFF");
}
else {
digitalWrite(5, LOW);
Serial.println("LED ON");
}
}
Json is simply a format, a structure, it needs no processing. PHP on the other hand is a server side language that means that is is interpreted by another application and it is actually that application that is interpreting the code that does the work. The esp8266 lacks that application. And will not be able to run your PHP file. I would recommend looking into making an API in php that is stored on a server somewhere and have your esp call out to that. Or see if you can implement your code right on the esp, though you may be limited by CPU, memory, and processing power. Good luck!

How do I read a string sent from PHP through a socket to a Qt server application?

I am having a really hard time reading character input that is sent through a socket connection to a Qt server application. The data is sent from PHP.
I understand the principles of reading streamdata because I already asked this on stack. I also got it working using a server and client written both in Qt.
The method I use is to append the bytesize of the data i want to send before the actual data. Then when the data comes in, I first read the length parth so that I know exactly how much bytes I have to read in order to have correctly formed data.
it looks like this:
send function:
void Client::sendNewMessage(){
qDebug() << "sendNewMessage()";
QString string(messageLineEdit->text());
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_0);
out << quint16(0);
out << string;
out.device()->seek(0);
out << (quint16)(block.size() - sizeof(quint16));
tcpSocket->write(block);
}
receive function:
QDataStream in(tcpServerConnection);
in.setVersion(QDataStream::Qt_4_0);
qDebug() << "bytes available = " << tcpServerConnection->bytesAvailable();
if (blockSize == 0) {
int size = (int) sizeof(quint16);
qDebug() << "size = " << size;
if (tcpServerConnection->bytesAvailable() < (int)sizeof(quint16)){
qDebug() << "less bytes than size...";
return;
}
qDebug() << "bytes available=" << tcpServerConnection->bytesAvailable();
in >> blockSize;
}
if (tcpServerConnection->bytesAvailable() < blockSize){
qDebug() << "less bytes available than blocksize, bytes="
<< tcpServerConnection->bytesAvailable();
return;
}
QString data;
in >> data;
qDebug() << "data = " << data;
Okay, this all works so I tried doing it with PHP but it failed
this is one of my attempts:
<?php
$addr = gethostbyname("127.0.0.1");
$client = stream_socket_client("tcp://$addr:*****", $errno, $errorMessage);
if ($client === false) {
throw new UnexpectedValueException("Failed to connect: $errorMessage");
}
$data = 'a';
$datatopost = serialize($data);
fwrite($client, strlen($data));
fwrite($client, base64_encode($data));
echo stream_get_contents($client);
fclose($client);
In Qt I have tried various combinations of quint8, 16, 32, 64, sizeof(char), sizeof(int).
in PHP I have tried serializing the data, encoding it, and also sending it without all that stuff. But i can not get it to work. I must be very close though because the data is actually sent as there are bytes available but I have no idea how to encode/decode correctly for it to work.
After asking various question concerning this topic I do feel that my understanding has gone up a lot but an important piece of information on how to actually do things is still missing for me.
So my question: What is going wrong here and what steps need to be taken to be able to read data from PHP to Qt/C++?
Details are highly apreciated as I really like to know how things work from the inside out.
side-note after sending data from the PHP script, the server sends data back aswel and that works. So the connection is made succesfuly
UPDATE
this is the working php script that actually also receives a reply back:
<?php
if(!($sock = socket_create(AF_INET, SOCK_STREAM, 0)))
{
perror("Could not create socket");
}
echo "Socket created n";
//Connect socket to remote server
if(!socket_connect($sock , '127.0.0.1' , *****))
{
perror("Could not connect");
}
echo "Connection established n";
$message = "aa";
//Send the message to the server
if( ! socket_send ( $sock , $message , strlen($message) , 0))
{
perror("Could not send data");
}
echo "Message send successfully n";
//Now receive reply from server
if(socket_recv ( $sock , $buf , 500 , MSG_WAITALL ) === FALSE)
{
perror("Could not receive data");
}
echo $buf;
///Function to print socket error message
function perror($msg)
{
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
die("$msg: [$errorcode] $errormsg n");
}
The script reply when executed from browser url:
Socket created nConnection established nMessage send successfully n hello
It's not that surprising the PHP code does not integrate. As mentioned you have to be aware that QDataStream implements a custom serialization. And as also mentioned you probably want to use (read|write)RawData, or (read|write)Bytes, if your reading something not previously serialized with QDataStream in general. However, the general idea of the way your trying to write string data from PHP should be compatible with the way Qt encodes strings (length then a series of characters. That is what the manual says anyway..). But there some issues.
QString is 2Byte Unicode.
PHP Strings are byte arrays of an arbitrary kind of ASCII compatible data - PHP String details.
There is a few things wrong with this bit:
fwrite($client, strlen($data));
fwrite($client, base64_encode($data));
strlen() returns the number of bytes in the underlying storage (which is the actual byte length for a ASCII string). base64_encode() changes the number of bytes in the string. And your assuming fwrite() is writing a four byte integer. Its type casting and writing a string.
We are still guessing at how
QString data;
in >> data;
really works.
General advice is, you've got to carefully define external binary APIs.
Do you need data serialization for this task at all? Your PHP client and Qt server are probably using different formats for it.
Try to send and receive raw data.
Here is a simple QTcpServer exmaple:
class DataReceiver : public QObject
{
Q_OBJECT
public:
explicit DataReceiver(QObject *parent = 0);
public slots:
void start(quint16 port = 9090);
private slots:
void newTcpConnection();
private:
QTcpServer server;
};
DataReceiver::DataReceiver(QObject *parent) :
QObject(parent)
{
connect(&server, SIGNAL(newConnection()), this, SLOT(newTcpConnection()));
}
void DataReceiver::start(quint16 port)
{
bool isOk = server.listen(QHostAddress::Any, port);
if (isOk && server.isListening())
{
qDebug() << "QTcpServer started on port" << port;
}
else
{
qCritical() << "Failed to start QTcpServer";
}
}
void DataReceiver::newTcpConnection()
{
qDebug() << "New incoming connection";
QTcpSocket *socket = server.nextPendingConnection();
QByteArray data;
while (true)
{
QByteArray tmp = socket->readAll();
data += tmp;
if (tmp.isEmpty() && !socket->waitForReadyRead())
{
break;
}
}
socket->deleteLater();
qDebug("Data received: %s (len = %d)", data.constData(), data.length());
}
Launching server:
#include <QCoreApplication>
#include "data_receiver.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
DataReceiver d;
d.start();
return a.exec();
}
You can use a PHP client to send data to it:
<?php
$addr = gethostbyname("127.0.0.1");
$port = 9090;
$data = 'hello from php';
$client = stream_socket_client("tcp://$addr:$port", $errno, $errorMessage);
if ($client === false) {
throw new UnexpectedValueException("Failed to connect: $errorMessage");
}
fwrite($client, $data);
fclose($client);
Or you can use the nc utility:
echo -n "hello from nc" | nc 127.0.0.1 9090
Here is server output for both cases:
QTcpServer started on port 9090
New incoming connection
Data received: hello from php (len = 14)
New incoming connection
Data received: hello from nc (len = 13)

Categories