I have a setup which uses the ESP8266 12E and it opens a web server at a specific port 200. I have used the port forwarding to route the incoming data to this server .And I have used the duckdns to register the IP and call the duckdns domain to trigger the ESP.
This works fine and I am able to trigger using the following
http://mydomain.duckdns.org:200/parseIFTTT
Using the postman tool, with the contentType as plain/text and the method as POST what ever contents I pass are getting parsed by parseIFTTT method in the ESP
void parseIFTTT() {
String message;
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
Serial.println(message);
server.send(200, "text/plain", "Success");
}
But when tried to integrate with IFTTT for any Facebook or gmail events, I am not able to parse the data from IFTTT.
The request goes to ESP8266 but the request data I am not able to parse.
The following is the request :
URL : http://mydomain.duckdns.org:200/parseIFTTT
Method : POST
Content Type: text/plain
Body : {{Message}}
In the body I have just added the {{Message}} only. In the serial monitor I get the op as blank
1
plain:
I found the issue after a lot of debugging.
The esp8266\hardware\esp8266\2.2.0\libraries\ESP8266WebServer\src\Parsing.cpp
in the core library for the Http server was using the 'Content-Length' and IFTTT was sending the request header with name as "content-length' and hence the content length was not retrieved and the parsed data was not retrieved.
Not sure whether its an issue with the IFTTT where they send this as a lower cased value.
Related
I'm using a NodeMCU and want to log data to my local Web2Py server.
The request: "http://minion.local:8000/ardulog/default/add/6476366/45643" works fine from the browser and returns a record id.
My Arduino can connect to my server but don't get any return data error or otherwise and nothing appears in my database.
// This will send the request to the server
samptime = millis();
rpm = (samptime + 333) % 96789;
String request = "10.0.0.244:8000/ardulog/default/add/"+String(samptime)+"/"+String(rpm)+" HTTP/1.1";
Serial.println("\ntrying: ");
Serial.println("GET " + request);
Serial.println("host: minion.local");
client.println("GET " + request);
client.println("host: minion.local");
// if there are incoming bytes available
// from the server, read them and print them:
while (client.available()) {
char c = client.read();
Serial.print(c);
}
Serial.println("closing connection");
client.stop();
I've tried every variant I can think of but get only the following:
connecting to minion.local
[hostByName] request IP for: minion.local
[hostByName] Host: minion.local IP: 10.0.0.244
Requesting:
GET 10.0.0.244:8000/ardulog/default/add/112725/16269 HTTP/1.1
host: minion.local
closing connection
wait 5 sec...
Why am I not reading anything retuned from the server?
SOLVED! Though I was unsuccessful POSTing to Google Sheets, simply changing the word from GET to POST worked with Web2Py without sending any body data:
if(client.connect(host,port))
client.println("POST /ardulog/default/add/" + String(samptime)+ "/" + String(rpm) + " HTTP/1.1");
(still not receiving a result page from the server though)
So I am using the Arduino Uno and the ESP8266 module. I am trying to get the module to send an HTTP get request using the AT serial firmware however I am not quite able to do so. The project gets data from a sensor and sends it in real time using the Pubnub Service by posting the data to the pubnub rest API.
I have the function:
void sendSerialCommand(String cmd, int t) {
int i=0;
while(1) {
Serial.println(cmd);
client.println(cmd);
while(client.available()) {
if(client.find("OK"))
i=8;
}
delay(t);
if(i>5)
break;
i++;
}
if(i==8)
Serial.println("OK");
else
Serial.println("Error");
}
Using this function, I set up a connection with the server as :
sendSerialCommand("AT+CIPMUX=1",100);
sendSerialCommand("AT+CIPSTART=0,\"TCP\",\"" + pubnubIP + "\",80",1000);
Serial.println("Established connection with DashBoard Servers.....");
Then I try:
sendSerialCommand("AT+CIPSEND=0," + String(getRequestLength) + "," + "http://" + pubnubIP + "/publish/<publish-key>/<sub-key>/0/water/0/<data>", 1000);
(I have put in the values for the publish and sub key in the actual code.)
The getRequestLength is the length of the data to be sent.
When I run the code, the output says wait..... and the the connection just closes. Could anyone please tell me the correct Syntax or method of sending the data?
I want to toggle some LEDs with my Android device. These LEDs are connected to the digital Pins of my Arduino which is also connected to a ESP8266. Now, my ESP8266 is defined as an AccessPoint and my Tablet can send HTTP requests (e.g. http://192.168.4.1:80/?pin=11).
I found the code here http://allaboutee.com/2015/01/20/esp8266-android-application-for-arduino-pin-control/
It works fine but my question is which HTTP header fields should be used? In this code he used some (e.g. Content-Length) but there are so much more possible (Date, Server, Content-Language,...).
Are these fields optional or which of these have to be used to build the right response?
Here is the piece of code I do not understand:
void sendHTTPResponse(int connectionId, String content)
{
String httpResponse;
String httpHeader;
httpHeader = "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n";
httpHeader += "Content-Length: ";
httpHeader += content.length();
httpHeader += "\r\n";
httpHeader +="Connection: close\r\n\r\n";
httpResponse = httpHeader + content + " ";
sendCIPData(connectionId,httpResponse);
}
It largely depends on the client (i.e. consumer) which fields are required and which are mandatory.
The only one that is always required is "HTTP/1.1 200 OK". Of course you need to replace that status code if you're not sending an OK message.
I am using the ESP8266 with Arduino IDE and have set up a server at port 200 . The IP is also defined as the same as 192.168.1.100.
ESP8266WebServer server(200);
IPAddress ip(192, 168, 1, 100); //Node static IP
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
server.on("/parseIFTTT", parseIFTTT);
void parseIFTTT() {
String message;
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
Serial.println(message);
Serial.println(server.argName(0));
Serial.println(server.arg(0));
server.send(200, "text/plain", "Success " + message);
}
is done to route the parseIFTTT request to this parseIFTTT() method.
I have done port forwarding and using the duckdns to access this server from outside.
This is my duckdns address
http://xxxxxx.duckdns.org:200/parseIFTTT
When I make a POST using a POSTMAN tool with content type as text/plain , the body contents are shown in the serial monitor as
plain
--body contents--
But when the same request is made from IFTTT the serial monitor shows nothing but plain as empty .Initially I felt the issue is with IFTTT.
But that is not the issue as when I use the WiFiWebServer example in the arduino , using the following code
String req = client.readString();
Serial.println(req);
client.flush();
I see the data from IFTTT as :
POST /parseIFTTT HTTP/1.1
Content-type: text/plain
host: xxxxxx.duckdns.org:200
content-length: 27
x-newrelic-id: XAMGV15QGwQJVllRDgQ=
x-newrelic-transaction: PxQFA1NbAQQJVwJWA1dSB0YdUFIOFQZOEgEPVA5ZBFYGXAwECFgFAFcUG0MHUwoLBAcDAxVs
Connection: close
{"value":"test data from IFTTT"}
So I believe I am doing something wrong with the server.args(). I am under the impression that server.args() should give the body contents used in the POST whether contentType is text/plain or x-www-form-urlencoded.
Am I doing something wrong or with the server.args() can't we get the body data from the POST request ?
There are a few 'gotchas' in the ESP8266WebServer's implementation. I have found the body shows up in the
server.arg("plain")
but only if the class cannot find any key value pairs. The ESP8266WebServer will look for an '=' and only if it cannot find one will it put the body in the "plain" arg.
This arg will contain the full body so you will have to parse the JSON yourself. I have found ArduinoJson to be a very easy to use library to do so.
Short example:
void handleRequest() {
StaticJsonBuffer<200> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(server.arg("plain"));
root.printTo(Serial);
}
On a sidenote. If you are testing with a POSTMAN like tool, do not forget to set the 'Content-length'. ESP8266WebServer will treat your body as empty (or of a different length) if it does not correspond with this header value.
Hope this answers your question.
Thanks the code solution for " how to get the IP client using ESP8266WebServer" is :
// HTTP Request Path, IRIA Entry Form
server.on("/", [](){
// As sending the form as a response to the client
server.send(200, "text/html",login_CASA);
String addy = server.client().remoteIP().toString();
Serial.println(addy);
});
I have some problems with connecting a qt client to an embedded jetty server.
At first, I use the following components:
Qt 4.4.3 (compiled with active openssl support)
jetty 8.8.1
java 6
I know, the versions are not most recent, but because of licencing issues and customer wishes I can not use newer one.
So, the scenario is that a qt client has to send http GET and POST requests to the jetty server. As long I use simple http with the QHttp object it works fine, the problems start when I switch to SSL.
My first try was to use the QSslSocket object for the GET request:
// Load certs + private key to socket
_pSocket = new QSslSocket(this);
_pSocket->setLocalCertificate(_certificate);
_pSocket->setPrivateKey(_privatekey);
_pSocket->addDefaultCaCertificate(_cacertificate);
connect (_pSocket, SIGNAL(encrypted()), this, SLOT(_encrypted()));
_pSocket->connectToHostEncrypted("localhost", 8000);
with the following slot function for the encrypted state:
void TestClient::_encrypted() {
QString _path("/testpath/list");
QByteArray buffer("GET ");
buffer.append(_path).append(" HTTP/1.1\r\n");
_pSocket->write(buffer);
}
Here I have my first problem:
This results in the following string, which is as far as I see compliant to RFC 2616:
"GET /testpath/list HTTP/1.1\r\n"
For some reason, the jetty server has a problem with that, keeping in a loop till the client close the connection because of a time out.
But if I use the following string, it works perfect:
"GET /testpath/list\r\n"
Here is my first question: Do you now an explanation for this behaviour ? I can live with it, but I want to know the reason
My second problem is the POST request, this fails always.
These examples I already tried:
"POST /testpath/receive/\r\n{"data":"hello world ?!"}\r\n"
"POST /testpath/receive/ HTTP/1.1\r\n{"data":"hello world ?!"}\r\n"
"POST /testpath/receive/\r\n\r\n{"data":"hello world ?!"}\r\n"
"POST /testpath/receive/ HTTP/1.1\r\n\r\n{"data":"hello world ?!"}\r\n"
I have the feeling, that the body is every time empty, so my server crashes because he tries to parse an empty string as json.
At least, the following log shows that:
2013-11-19 17:11:51.671, INFO, foo.bar.RepositoryHandler, qtp11155366-16 - /testpath/receive request type : /receive
2013-11-19 17:11:51.811, ERROR, foo.bar.RepositoryHandler, qtp11155366-16 - /testpath/receive missing or unknown elements in JSON request. Check JSON against documentation
2013-11-19 17:11:51.874, WARN, org.eclipse.jetty.server.AbstractHttpConnection, qtp11155366-16 - /testpath/receive /testpath/receive
java.lang.NullPointerException: null
at foo.bar.RepositoryHandler.decodeViewingRequest(RepositoryHandler.java:366) ~[MyServer.jar:na]
at foo.bar.RepositoryHandler.handle(RepositoryHandler.java:182) ~[MyServer.jar:na]
So, all together, I think I have several major errors in my requests. But which ?
My second try was to use the QHttp object and change the QSocket it uses with a QSslSocket I already initiated.
Here's the code of the main function:
QSslSocket* _pSocket;
QHttp* _pHttp;
int _id;
QBuffer* _pBuffer;
QByteArray _data;
_pSocket = new QSslSocket(this);
_pSocket->setLocalCertificate(_certificate);
_pSocket->setPrivateKey(_privatekey);
_pSocket->addDefaultCaCertificate(_cacertificate);
QUrl url;
url.setScheme("https");
url.setHost("localhost");
url.setPort(8001);
url.setPath("/testpath/receive");
connect (_pSocket, SIGNAL(encrypted()), this, SLOT(_encrypted()));
connect(_pHttp,SIGNAL(requestFinished(int,bool)),this,SLOT(_requestFinished(int,bool)));
connect(_pHttp,SIGNAL(done(bool)),this,SLOT(_done(bool)));
_pBuffer = new QBuffer(&_data);
_pHttp->setSocket(_pSocket);
_pSocket->connectToHostEncrypted(strHost, strPort.toInt());
_id = _pHttp->get(url.toString(),_pBuffer);
And the callbacks:
void _requestFinished(int id, bool error) {
if(id = _id)
qDebug() << "data=" << _data;
}
void _encrypted() {
qDebug() << "encrypted";
}
void _done(bool error) {
logInfo() << "_done";
if(_pHttp) {
_pHttp->abort();
delete _pHttp;
_pHttp = 0;
}
if(_pBuffer) {
delete _pBuffer;
_pBuffer = 0;
}
if(_pSocket) {
_pSocket->disconnectFromHost();
delete _pSocket;
_pSocket = 0;
}
}
I think, I only have to change the position of the _pHttp->get call, perhaps in the _encrypted callback, but I'm not sure.
Some good advise ?
Thanks,
Robert
Your HTTP request is incomplete, per RFC2616.
"GET /testpath/list HTTP/1.1\r\n"
That is invalid.
Try this instead.
"GET /testpath/list HTTP/1.1\r\n" + /* request line (required) */
"Host: localhost\r\n" + /* host header (required minimum) */
"\r\n" /* terminating CR + LF (required) */
As outlined in Section 5.1.2
The most common form of Request-URI is that used to identify a
resource on an origin server or gateway. In this case the absolute
path of the URI MUST be transmitted (see section 3.2.1, abs_path) as
the Request-URI, and the network location of the URI (authority) MUST
be transmitted in a Host header field. For example, a client wishing
to retrieve the resource above directly from the origin server would
create a TCP connection to port 80 of the host "www.w3.org" and send
the lines:
GET /pub/WWW/TheProject.html HTTP/1.1
Host: www.w3.org
The Request-URI line and Host header Header are mandated.