i am using the GL865-DUAL GPRS module from Telit.
I'm trying to set up a HTTP POST request to a website with my location variables.
I am able to set up a working GPRS connection wit h the provider (got ip adres) but at the post at-command it goes wrong,
this is my command set:
"AT" //response: OK //build in delay of 5 seconds
Delay after each AT command set to 400miliseconds
"AT+CGMR //response: 16.00.152 OK
"AT#QSS?" //response: #QSS:0,1 OK
"AT#QSS=?" // response #QSS: (0-2) OK
"AT+CMEE=1" //response: OK
"AT+CMEE?" // response: +CMEE: 1
"AT+CPIN?" // response: +CPIN: READY OK
"AT+COPS?" // response: +COPS: 0,0,"PROXIMUS" OK
"AT+CSQ" // response: +CSQ: 20
"AT+cgatt=1" // response: OK
"AT+CGDCONT=1, \"IP\",\"internet.proximus.be\"" // response: OK // double quotes in c are expressed as \"
"AT+CGDCONT?" // response: +CGDCONT: 1,"IP","internet.proximus.be","",0,0 OK
"AT#SGACT?" // response: #SGACT: 1,0 OK
"AT#SCFG=?" //#SCFG: (1-6,(0-5),(0-1500),(0-65535),(10-1200),(0-255) OK
"AT#SCFG=1,1,300,90,600,50" // response: OK
"AT#SGACT?" //response: #SGACT: 1,0
"AT#SGACT = 1,1" //response: #SGACT: 178,144.233.116 OK
"AT#HTTPCFG=1,\"https://www.google.be/\",80,0,,,0,120,1" // response: OK
"AT#HTTPSND=1,0,\"search?q=yo\",4,\"1:charset=ISO-8859-1\"test" // response: CME Error 4
What am i doing wrong and is it possible to give a working example ?
Note: no Pin is required for the SIM card and no APN user and password is needed for my case.
Folowing documents could be helpful:
http://www.gaw.ru/pdf/DIA_Telecom/80000ST10028_Easy%20GPRS%20User%20Guide_r1.pdf
http://www4.telit.com/module/infopool/download.php?id=542
Thanks a lot!
Try removing the https:// and the trailing /. #HTTPCFG asks for a hostname or IP address, not a url.
I see two problems with your commands:
Your profile ID for HTTPCFG and HTTPSND don't match.
I think you need double quotes in your password and username fields
for HTTPCFG.
After AT#HTTPSND, the modem replies with >>> indicating that you need to supply Your data. The "test" at the end of that line shouldn't be there, it should be after a delay. you can try specifying just 1 for plain text and not the whole charset. Posting to google?
Related
This seems to cause strange behaviour when PUT has a body larger than a certain length (in my case it is 902 bytes), i.e. ejabberd trims the body (in my case it receives malformed JSON).
Github reference: https://github.com/processone/ejabberd/blob/master/src/ejabberd_http.erl#L403
If I change the case statement to:
case Method of
_AnyMethod ->
case recv_data(State) of
{ok, Data} ->
LQuery = case catch parse_urlencoded(Data) of
{'EXIT', _Reason} -> [];
LQ -> LQ
end,
{State, {LPath, LQuery, Data}};
error ->
{State, false}
end
end
then the body is parsed correctly.
Is this a configuration issue? How can I force Ejabberd to correctly parse the JSON body?
Looks like you've found a bug.
As you've noticed, for POST requests the function recv_data is called, which checks the Content-Length header and reads that many bytes from the socket. For PUT requests however, it only uses Trail, which is the data that has been already received while reading HTTP request headers. (This happens in the receive_headers function, which sends a length of 0 to the recv function, meaning that it won't wait for any specific amount of data.)
How much of the request body is received is going to depend on the size of the headers, as well as the way the client sends the request. If for example the client first sends the headers in one network packet, and then the request body in the next network packet, ejabberd wouldn't pick up the request body at all.
I programmed my ESP8266 to read the soil moisture. Depending on the moisture a water pump gets activated. Now I wanted the ESP to tweet different sentences, depending on the situation.
Therefore I connected my twitter account to thingspeak.com and followed this code
Connecting to the internet works fine.
Problems:
It does not tweet every time and if it tweets, only the first word from a sentence shows up at twitter.
According to the forum, where I found the code, I already tried to replace all the spaces between the words with "%20". However then nothing shows up at twitter at all. Also single words are not always posted to twitter.
This is the code I have problems with:
// if connection to thingspeak.com is successful, send your tweet!
if (client.connect("184.106.153.149", 80))
{
client.print("GET /apps/thingtweet/1/statuses/update?key=" + API + "&status=" + tweet + " HTTP/1.1\r\n");
client.print("Host: api.thingspeak.com\r\n");
client.print("Accept: */*\r\n");
client.print("User-Agent: Mozilla/4.0 (compatible; esp8266 Lua; Windows NT 5.1)\r\n");
client.print("\r\n");
Serial.println("tweeted " + tweet);
}
I don't get any error messages.
Maybe you could help me to make it visible if the tweet was really sent and how I manage to tweet a whole sentence.
I am using the Arduino IDE version 1.8.9 and I am uploading to this board
The rest of the code works fine. The only problem is the tweeting.
Update
I now tried a few different things:
Checking server response
Works and helps a lot. The results are:
Single words as String don't get any response at all
Same for Strings like "Test%20Tweet"
Strings with multiple words like "Test Tweet" get the following response and the first word of the String shows up as a tweet
HTTP/1.1 200 OK
Server: nginx/1.7.5
Date: Wed, 19 Jun 2019 18:44:22 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 1
Connection: keep-alive
Status: 200 OK
X-Frame-Options: SAMEORIGIN
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, OPTIONS, DELETE, PATCH
Access-Control-Allow-Headers: origin, content-type, X-Requested-With
Access-Control-Max-Age: 1800
ETag: W/"RANDOM_CHARS"
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: THE_ID
1
I think the Content-Length might be the problem?
But I don't know how to change it in this code.
Checking if the connection succeded
I implemented this into my code an it never shows up on the monitor. So I think i never have a problem with not connecting.
Use a hostname instead of IP address
I tried it and never got a bad request. On the other hand nothing shows up on twitter at all.
Check if your tweet variable contains any new-line characters (carriage return or line feed). For example, the following variable would cause problems
String tweet = "Tweet no. 1\r\n";
due to the new-line characters at the end. These characters will cause the first line of the HTTP request to be cut short. I.e., instead of
GET /apps/thingtweet/1/statuses/update?key=api_key&status=Tweet no. 1 HTTP/1.1\r\n
it would become
GET /apps/thingtweet/1/statuses/update?key=api_key&status=Tweet no. 1\r\n
and the server would reject it with a 400 (Bad request) error.
On the other hand
String tweet = "Tweet no. 1";
would be fine.
If your tweets may contain such characters, then try encoding them before passing them to client.print():
tweet.replace("\r", "%0D");
tweet.replace("\n", "%0A");
Use a hostname instead of IP address
According to https://uk.mathworks.com/help/thingspeak/writedata.html, the relevant hostname for the API you are using is api.thingspeak.com. Use that instead of the IP address. This is preferable because the IP address a hostname points to can change regularly. (The IP address you are using doesn't even seem to be correct - and may already be out of date.)
I.e., change
if (client.connect("184.106.153.149", 80)) {
to
if (client.connect("api.thingspeak.com", 80)) {
API endpoint
Are you sure you are using the correct API endpoint? According to the link above, it looks like the API endpoint you need is https://api.thingspeak.com/update.json - so you may need to change
client.print("GET /apps/thingtweet/1/statuses/update?key=" + API + "&status=" + tweet + " HTTP/1.1\r\n");
to
client.print("GET /update.json?api_key=" + API + "&status=" + tweet + " HTTP/1.1\r\n");
Check if the connection succeeded
Presently, your device sends the HTTP request if connects to the server successfully - but doesn't give any indication if the connection fails! So add an else block to handle that scenario and notify the user via the serial console.
if (client.connect("api.thingspeak.com", 80)) {
client.print("GET /apps/thingtweet/1/statuses/update?key=" + API + "&status=" + tweet + " HTTP/1.1\r\n");
// etc.
}
else {
Serial.println("Connection to the server failed!");
}
Checking server response
To check the response from the server, add the following block to your main loop - which will print the server response via the serial console.
delay(50);
while (client.available()) {
String response_line = client.readString();
Serial.println(response_line);
}
To clarify: that code should go inside your loop() function.
The response should include a status line - such as HTTP/1.1 200 OK if the request was successful, or HTTP/1.1 400 Bad Request if there was a problem.
In the case of a Bad request response, the full message will quite likely contain more information about the precise reason the request failed.
HTTP vs HTTPs
Lastly, are you sure that the API supports (plain, unencrypted) HTTP as well as HTTPs? If not, that may be your problem.
I am using nodemcu with an esp-32 and recently came across an annoying problem. I refer to this sample from the NodeMCU Github page:
-- a simple HTTP server
srv = net.createServer(net.TCP)
srv:listen(80, function(conn)
conn:on("receive", function(sck, payload)
print(payload)
sck:send("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n<h1> Hello, NodeMCU.</h1>")
end)
conn:on("sent", function(sck) sck:close() end)
end)
This doesn't seem to work in every case.
If I try it with telnet, there is no issue:
$ telnet 172.17.10.59 80
Trying 172.17.10.59...
Connected to 172.17.10.59.
Escape character is '^]'.
GET / HTTP/1.1
HTTP/1.0 200 OK
Content-Type: text/html
<h1> Hello, NodeMCU.</h1>
Connection closed by foreign host.
But when using wget, it hangs most of the time:
$ wget http://172.17.10.59/
--2017-05-12 15:00:09-- http://172.17.10.59/
Connecting to 172.17.10.59:80... connected.
HTTP request sent, awaiting response...
After some research, the root cause seems to be, that the receive callback is registered after the first data was received from the client. This doesn't happen when testing manually with telnet, but with a client like wget or a browser, the delay between connecting and receiving the first data seems to be too small to register the receive handler first.
I have looked into the nodemcu code and there doesn't seem to be an easy way to work around this problem. Or do I miss something here?
In HTTP/1.0, you need the "Content-Length" in the HTTP header when there is a message-body.
For example:
"HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nContent-Length: 25 \r\n\r\n<h1> Hello, NodeMCU.</h1>"
ref: https://www.w3.org/Protocols/HTTP/1.0/spec.html#Content-Length
I'm working on a program for the iPhone and I ran into a bit of a snafu. I want to load a URL into a WebView, however, I want to make sure that the URL actually exists and is working before trying to load it into the view.
Imagine you have 200 servers and you know your file exists you just don't know which server. It is at http://serverXXX.mydomain.com/myfile.html where XXX is the server # 0 through 200
I wrote a bash script that uses cURL to loop through the servers checking the HEAD request of each iteration of the url and timing out after 1 second:
http://server1.mydomain.com/myfile.html
http://server2.mydomain.com/myfile.html
...
http://server199.mydomain.com/myfile.html
http://server200.mydomain.com/myfile.html
When it gets back a response it greps the response and compares it. If the response is OK it loads the URL in an external program and exits the script. How do I do this in Objective-C without the error "The requested URL was not found on this server." popping up?? I don't want to click OK 200 times while it tries to find the correct URL.
You can do the same as your script with an instance of NSMutableURLRequest and a NSURLConnection. You can set the request to HEAD (setHTTPMethod:) and iterate over the server URLs updating the request after each response (connection:didReceiveResponse:) is received.
I followed the demo and things are working just fine. My client has a single function to send commands to the server and handle the response.
That was fine for the first few command and I handle it by
var result : String;
TCPclient.SendCmd(theMessage);
TCPclient.GetResponse(Result);
if Result <> 'OK' then ....
Where the server is sending
ASender.Reply.SetReply(200, 'OK'); ... or ...
ASender.Reply.SetReply(400, 'NAK');
Now, I want to add a new command and the result will be either NAK or ACK PLUS a value 0, 1 or 2
I am hazy on response codes which seem to have two parameters, one numerical and one textual ....
I could just kludge and send 'Ok0', 'OK1', or 'OK2', but that is very ugly (and probably A Bad Thing)
I think I though to use 200 for success and send 0, 1 or 2 in the textual parameter (or use 'OK' and send 0, 1 or 2 as numeric code, or use 200, 201, 202 as numeral code)?
Can someone please help me understand what I ought to be coding and why? (Or just point me at a URL) Thanks
SendCmd() reads the response from the server for you, so DO NOT call GetResponse() after SendCmd() unless the server actually sends two separate responses.
Responses typically take the form:
<Response Code> <Optional Text>
Where the response code is either a number or a textual keyword.
If the server sends numeric response codes, handle it like this:
Server:
// sends:
//
// 200 1
//
ASender.Reply.SetReply(200, '1');
Client:
if TCPclient.SendCmd(theMessage) = 200 then
Value := StrToInt(TCPclient.LastCmdResult.Text.Text);
Or:
// raises an exception if a non-200 response is received
TCPclient.SendCmd(theMessage, 200);
Value := StrToInt(TCPclient.LastCmdResult.Text.Text);
If the server sends textual response codes, handle it like this:
Server:
// sends:
//
// OK 1
//
ASender.Reply.SetReply('OK', '1');
Client:
if TCPclient.SendCmd(theMessage, '') = 'OK' then
Value := StrToInt(TCPclient.LastCmdResult.Text.Text);
Or:
// raises an exception if a non-OK response is received
TCPclient.SendCmd(theMessage, ['OK']);
Value := StrToInt(TCPclient.LastCmdResult.Text.Text);
The optional text of the response, if present, can be accessed in the TCPclient.LastCmdResult.Text property, which is a TStrings as it is possible to send multi-line responses in the form:
<Response Code>-<Optional Text>
<Response Code>-<Optional Text>
...
<Response Code> <Optional Text>
Server:
// sends:
//
// 200-The value is
// 200 1
//
ASender.Reply.SetReply(200, 'The value is');
ASender.Reply.Text.Add('1');
Client:
TCPclient.SendCmd(theMessage, 200);
Value := StrToInt(TCPclient.LastCmdResult.Text[1]);
You can also send secondary multi-line text after the responses in this form:
<Response Code> <Optional Text>
<Secondary Text>
.
Server:
// sends:
//
// 200 Data follows
// Hello world
// How are you?
// .
//
ASender.Reply.SetReply(200, 'Data follows');
ASender.Reply.Response.Add('Hello world');
ASender.Reply.Response.Add('How are you?');
Client:
TCPclient.SendCmd(theMessage, 200);
TCPclient.IOHandler.Capture(SomeTStringsObj);