I want get json from my website. I am trying send POST request for authentication and after it i want to send GET request for getting json, but i can't do it, because it gives me en error 401 unauthorized (cookies doesn't saved) . How can i keep session with Arduino ,ethernet shield and WebClien?
Source:
#include <SPI.h>
#include <Ethernet.h>
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
//Change to your server domain
char serverName[] = "bh.quickle.me";
// change to your server's port
int serverPort = 80;
// change to the page on that server
char pageName[] = "/users/sign_in";
char sensorPage[] = "/api/v1/sensors";
EthernetClient client;
int totalCount = 0;
// insure params is big enough to hold your variables
char params[68];
// set this to the number of milliseconds delay
// this is 30 seconds
#define delayMillis 30000UL
unsigned long thisMillis = 0;
unsigned long lastMillis = 0;
void setup() {
Serial.begin(9600);
// disable SD SPI
pinMode(4,OUTPUT);
digitalWrite(4,HIGH);
pinMode(7,OUTPUT);
digitalWrite(7,HIGH);
Serial.print(F("Starting ethernet..."));
if(!Ethernet.begin(mac)) Serial.println(F("failed"));
else Serial.println(Ethernet.localIP());
delay(2000);
Serial.println(F("Ready"));
sprintf(params,"{\"user\": {\"email\": \"EgorkZe#gmail.com\",\"password\": \"1234asdf\"}}");
postPage(serverName,serverPort,pageName,params);
}
void loop()
{
thisMillis = millis();
if(thisMillis - lastMillis > delayMillis)
{
lastMillis = thisMillis;
getPage(serverName, serverPort, sensorPage);
}
}
byte postPage(char* domainBuffer,int thisPort,char* page,char* thisData)
{
int inChar;
char outBuf[64];
Serial.print(F("connecting..."));
if(client.connect(domainBuffer,thisPort))
{
Serial.println(F("connected"));
// send the header
sprintf(outBuf,"POST %s HTTP/1.1",page);
client.println(outBuf);
sprintf(outBuf,"Host: %s",domainBuffer);
client.println(outBuf);
client.println(F("Connection: close\r\nContent-Type: application/json"));
sprintf(outBuf,"Content-Length: %u\r\n",strlen(thisData));
client.println(outBuf);
// send the body (variables)
client.print(thisData);
}
else
{
Serial.println(F("failed"));
return 0;
}
int connectLoop = 0;
while(client.connected())
{
while(client.available())
{
inChar = client.read();
Serial.write(inChar);
connectLoop = 0;
}
delay(1);
connectLoop++;
if(connectLoop > 10000)
{
Serial.println();
Serial.println(F("Timeout"));
client.stop();
}
}
Serial.println();
Serial.println(F("disconnecting."));
client.stop();
return 1;
}
byte getPage(char* domainBuffer, int thisPort, char* page)
{
int inChar;
char outBuf[128];
Serial.print(F("connecting..."));
if(client.connect(domainBuffer,thisPort))
{
Serial.println(F("connected"));
sprintf(outBuf,"GET %s HTTP/1.1",page);
client.println(outBuf);
sprintf(outBuf,"Host: %s",serverName);
client.println(outBuf);
client.println(F("Connection: close\r\n"));
}
else
{
Serial.println(F("failed"));
return 0;
}
// connectLoop controls the hardware fail timeout
int connectLoop = 0;
while(client.connected())
{
while(client.available())
{
inChar = client.read();
Serial.write(inChar);
// set connectLoop to zero if a packet arrives
connectLoop = 0;
}
connectLoop++;
// if more than 10000 milliseconds since the last packet
if(connectLoop > 10000)
{
// then close the connection from this end.
Serial.println();
Serial.println(F("Timeout"));
client.stop();
}
// this is a delay for the connectLoop timing
delay(1);
}
Serial.println();
Serial.println(F("disconnecting."));
// close client end
client.stop();
return 1;
}
To begin, yes, the Arduino Ethernet is capable to store and send back cookies.
You have to catch the cookies from the authentication request and send them back in the header of the second HTTP request (the GET one).
Have a look at informations about RFC HTTP Protocol
You can also look at :
http://en.wikipedia.org/wiki/HTTP_cookie#Setting_a_cookie
Related
i've been trying to build a system that detects in one room of the house the temperature using an esp8266 and a dht11 sensor, this esp sends the data to a webserver while the ESP12F grabs this data and should turn the relay on when a certain value is reached, however i can't get the relay to work, as soon as i upload the code, the led on the module turns but not at its full power, i tried with another code to see if it was just a faulty relay, but it works perfectly with the same connections. The code from the client side of the system is below:
#include "ESP8266WiFi.h"
#include "ESP8266HTTPClient.h"
#include "WiFiClient.h"
#include "ESP8266WiFiMulti.h"
ESP8266WiFiMulti WiFiMulti;
const char* ssid = "*******";
const char* password = "********";
//Your IP address or domain name with URL path
const char* serverNameTemp = "http://192.168.1.188/temperature";
const char* serverNameHumi = "http://192.168.1.188/humidity";
const char* serverNamePres = "http://192.168.1.188/pressure";
#include "Wire.h"
#include "Adafruit_GFX.h"
#include "Adafruit_SSD1306.h"
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
String temperature;
String humidity;
String pressure;
const int relay = 5;
float temp_int = temperature.toFloat();
unsigned long previousMillis = 0;
const long interval = 2000;
void setup() {
Serial.begin(115200);
Serial.println();
pinMode(relay,OUTPUT);
digitalWrite(relay,LOW);
// Address 0x3C for 128x64, you might need to change this value (use an I2C scanner)
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
display.clearDisplay();
display.setTextColor(WHITE);
int int_temp = temperature.toFloat();
WiFi.mode(WIFI_STA);
WiFiMulti.addAP(ssid, password);
while((WiFiMulti.run() == WL_CONNECTED)) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("Connected to WiFi");
}
void loop() {
unsigned long currentMillis = millis();
if(currentMillis - previousMillis >= interval) {
// Check WiFi connection status
if ((WiFiMulti.run() == WL_CONNECTED)) {
int int_temp = temperature.toFloat();
temperature = httpGETRequest(serverNameTemp);
humidity = httpGETRequest(serverNameHumi);
pressure = httpGETRequest(serverNamePres);
if(int_temp < 26){
digitalWrite(relay,LOW);
}
else if (int_temp > 26){
digitalWrite(relay,HIGH);
}
Serial.println("Temperature: " + temperature + " *C - Humidity: " + humidity + " % - Pressure: " + pressure + " hPa");
Serial.println(int_temp);
Serial.println(temperature.toFloat());
display.clearDisplay();
// display temperature
display.setTextSize(2);
display.setCursor(0,0);
display.print("T: ");
display.print(temperature);
display.print(" ");
display.setTextSize(1);
display.cp437(true);
display.write(248);
display.setTextSize(2);
display.print("C");
// display humidity
display.setTextSize(2);
display.setCursor(0, 25);
display.print("H: ");
display.print(humidity);
display.print(" %");
// display pressure
display.setTextSize(2);
display.setCursor(0, 50);
display.print("P:");
display.print(pressure);
display.setTextSize(1);
display.setCursor(110, 56);
display.print("hPa");
display.display();
// 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;
}
I have Arduino + Ethenet shield. I want to dynamically change the ip depending on that will come at the input com-port.
The main problem is - input string has a String type, and Ethernet.begin method accepts a byte array. In general, I can not understand how to convert this string correctly. Tried to make a bicycle(crutch) by moving the string in the char array, and then in the byte array. Did not work out. How convert string to byte[]?
#include <SPI.h>
#include <Ethernet.h>
String readString;
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte myserver[] = { 208, 104, 2, 86 }; // zoomkat web page server IP address
EthernetClient client;
void initEthernetConfig(byte ip[])
{
Ethernet.begin(mac, ip);
Serial.begin(9600);
Serial.println("Better client test 12/01/11"); // so I can keep track of what is loaded
Serial.println("Send an e in serial monitor to test"); // what to do to test
}
void setup(){
byte ip[] = { 10, 28, 33, 4 };
// initEthernetConfig(ip);
}
void loop(){
// check for serial input
while (Serial.available()) {
char c = Serial.read(); //gets one byte from serial buffer
readString += c; //makes the String readString
delay(2); //slow looping to allow buffer to fill with next character
}
if (readString.length() >0) {
byte inArray[4];
char * tokens;
int i = 0;
tokens = strtok(readString, ".");
while (tokens != NULL) {
inArray[i] = atoi(tokens);
tokens = strtok(NULL, ".");
i++;
}
initEthernetConfig(inArray);
}
}
This is a possible solution, it parses, dumps and sets an IPv4:
#include <SPI.h>
#include <Ethernet.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte myserver[] = { 208, 104, 2, 86 }; // zoomkat web page server IP address
EthernetClient client;
/**
* help functions declaration
*/
void get_ip(byte ip[4]);
void dump_ip(byte ip[4]);
void initEthernetConfig(byte ip[]);
/**
* setup && loop
*/
void setup(){
Serial.begin(9600);
}
void loop()
{
byte ip[4];
get_ip(ip);
dump_ip(ip);
initEthernetConfig(ip);
}
/**
* help function implementation
*/
void get_ip(byte ip[4])
{
for (byte i = 0; i < 4; ++i) {
while (Serial.available() <= 0) { };
ip[i] = (byte) Serial.parseInt();
if (i < 3) { Serial.read(); } // throw away dot
}
};
void dump_ip(byte ip[4]) {
for (byte i = 0; i < 4; ++i) {
Serial.print(ip[i]);
if (i < 3) {
Serial.print('.');
} else {
Serial.println();
}
}
};
void initEthernetConfig(byte ip[])
{
Ethernet.begin(mac, ip);
Serial.println("Better client test 12/01/11"); // so I can keep track of what is loaded
Serial.println("Send an e in serial monitor to test"); // what to do to test
};
Obviously, outside this testing application you should ensure that the Serial input is ready for sending an IPv4 in the first place, otherwise the function will likely return 0.0.0.0. An idea would be to enrich your communication protocol with string-based commands, e.g. ip: would signal the start of an IPv4 input.
Try this:
while (tokens != NULL) {
inArray[i++] = atoi(tokens) & 0xFF;
tokens = strtok(NULL, ".");
}
Which will get only the last byte of the integer, but that is all you want in the case of values 0-255.
But then again why not just read it in as bytes...
void loop(){
byte inArray[4];
int i = 0;
// check for serial input
while (Serial.available()) {
inArray[i++] = (byte) Serial.read(); //gets one byte from serial buffer
delay(2); //slow looping to allow buffer to fill with next character
}
initEthernetConfig(inArray);
}
I'm testing with my arduino and MQTT cloud.
For the publish everything goes well, the arduino publishes "hello world"
But with the void callback function nothing happens.
With my MQTT.fx client, I'm subscribed to the topics "status" and "commando".
At the "status" I see that the arduino is a live.
When I publish with my MQTT.fx client to the topic "commando".
I can see it arrived in my client, but not in the serial monitor of the arduino.
Why is the void callback function not used?
#include <SPI.h>
#include <PubSubClient.h>
#include <Ethernet.h>
#define server "m20.cloudmqtt.com"
int port = 13365;
// Update these with values suitable for your network.
byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
byte ip[] = { 192, 168, 0, 120 };
unsigned long time;
char message_buff[100];
EthernetClient ethClient;
PubSubClient client(server, port, callback, ethClient);
void setup()
{
// init serial link for debugging
Serial.begin(115200);
Ethernet.begin(mac, ip);
if (client.connect("arduino-MQTT","test","test")) {
client.publish("/arduino/status/","hello world");
client.subscribe("/arduino/commando/");
Serial.println("Connected");
}
if (Ethernet.begin(mac) == 0)
{
Serial.println("Failed to configure Ethernet using DHCP");
return;
}
}
void loop()
{
// MQTT client loop processing
client.loop();
}
void callback(char* topic, byte* payload, unsigned int length) {
if (strcmp(topic, "/arduino/commando/") == 0) {
String msg = toString(payload, length);
Serial.println(msg);
}else{
Serial.println("arduino topic not found");
}
}
//
// toString function
//
String toString(byte* payload, unsigned int length) {
int i = 0;
char buff[length + 1];
for (i = 0; i < length; i++) {
buff[i] = payload[i];
}
buff[i] = '\0';
String msg = String(buff);
return msg;
}
I have just tested your code with RSMB broker and it works. I do not have DHCP on my computer so I had to comment out DHCP handling code - Ethernet.begin(mac). I think that's where your bug is. Because:
You assign static IP to your Ethernet
Connect to mqtt broker, and subscribe to a topic
Query DHCP for a new IP. Probably at this point your Arduino gets a different IP than statically configured and the broker cannot reach your Arduino any more to publish subscribed topic.
Fix your Ethernet handling code. I like this formula:
// Start the Ethernet connection:
Serial.println(F("Querying DHCP"));
if ( Ethernet.begin( mac ) == 0 ) {
Serial.println(F("DHCP failed, fallback to static IP"));
// When DHCP fails, fallback to static configuration ;
Ethernet.begin( mac, ip ) ;
}
printIp() ;
And printIp function:
void printIp() {
// Print local IP address
Serial.print(F("My IP "));
for (byte thisByte = 0; thisByte < 4; thisByte++) {
// print the value of each byte of the IP address:
Serial.print(Ethernet.localIP()[thisByte], DEC);
Serial.print('.');
}
}
I have project where I'm getting data over nRF24L01 and using Mirf to that. Now I'm working for Hub which need to send data to my webservice. For ethernet my choice was ENC28j60 with ethercard library.
Question : How I can wait data from Mirf and just send data forward with Ethercard browseUrl? I can send data without Mirf but there's some loop which I'm not understand.
My code :
#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
#include <EtherCard.h>
// Set network settings
static byte mymac[] = { 0x74, 0x69, 0x69, 0x2D, 0x30, 0x31 };
byte Ethernet::buffer[700];
static uint32_t timer;
// My webservice
const char website[] PROGMEM = "my.webservice.com";
// Mirf variables
int tmpVal1;
// Local components
const int Yellow = 6;
const int Blue = 5;
void setup() {
Serial.begin(57600);
// Setup leds
pinMode(Yellow, OUTPUT);
digitalWrite(Yellow, LOW);
pinMode(Blue, OUTPUT);
digitalWrite(Blue, LOW);
setupMirf();
setupEthernet();
}
void loop() {
// Waiting to get date from Mirf
while (!Mirf.dataReady()) {
//ether.packetLoop(ether.packetReceive());
}
Mirf.getData((byte *)&tmpVal1);
Serial.print(tmpVal1);
Serial.println(F(" C"));
// Receive responses
ether.packetLoop(ether.packetReceive());
if (millis() > timer) {
timer = millis() + 5000;
//Serial.println();
Serial.println("Sending data to webservice : ");
ether.browseUrl(PSTR("/sendingdata.asmx/sendingdata?"), "Device=100&DeviceValue=80", website, my_callback);
}
//ShowLedNotification();
}
// called when the client request is complete
static void my_callback (byte status, word off, word len) {
Serial.println(">>>");
Ethernet::buffer[off+300] = 0;
Serial.print((const char*) Ethernet::buffer + off);
Serial.println("...");
digitalWrite(Blue,HIGH);
delay(200);
digitalWrite(Blue,LOW);
}
void ShowLedNotification() {
if (tmpVal1 > 0 ) {
digitalWrite(Yellow, HIGH);
delay(1000);
digitalWrite(Yellow, LOW);
}
else
{
digitalWrite(Blue, HIGH);
delay(1000);
digitalWrite(Blue, LOW);
}
}
long readVcc() {
long result;
// Read 1.1V reference against AVcc
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
delay(2); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Convert
while (bit_is_set(ADCSRA,ADSC));
result = ADCL;
result |= ADCH<<8;
result = 1126400L / result; // Back-calculate AVcc in mV
return result;
}
//Setting up network and getting DHCP IP
void setupEthernet() {
Serial.println(F("Setting up network and DHCP"));
Serial.print(F("MAC: "));
for (byte i = 0; i < 6; ++i) {
Serial.print(mymac[i], HEX);
if (i < 5)
Serial.print(':');
}
Serial.println();
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
Serial.println(F("Failed to access Ethernet controller"));
Serial.println(F("Setting up DHCP"));
if (!ether.dhcpSetup())
Serial.println(F("DHCP failed"));
ether.printIp("My IP: ", ether.myip);
ether.printIp("Netmask: ", ether.netmask);
ether.printIp("GW IP: ", ether.gwip);
ether.printIp("DNS IP: ", ether.dnsip);
// Check network connection
if (!ether.dnsLookup(website))
Serial.println("DNS failed");
ether.printIp("SRV: ", ether.hisip);
}
void setupMirf() {
//Initialize nRF24
Serial.println(F("Initializing Mirf"));
Mirf.spi = &MirfHardwareSpi;
Mirf.init();
Mirf.setRADDR((byte *)"serv1");
Mirf.payload = sizeof(tmpVal1);
// we use channel 90 as it is outside of WLAN bands
// or channels used by wireless surveillance cameras
Mirf.channel = 90;
Mirf.config();
}
Did get that work. Now using if clause not while Mirf.dataReady()
void loop() {
if (Mirf.dataReady()) {
Mirf.getData((byte *)&tmpVal1);
Serial.print(tmpVal1);
Serial.println(F(" C"));
ShowLedNotification();
// Send data to webservice
if (millis() > timer) {
timer = millis() + 5000;
Serial.println("Sending data to webservice");
String myVarsStr = "Device=";
myVarsStr += myDeviceID;
myVarsStr += "&DeviceValue=";
myVarsStr += tmpVal1;
char myVarsCh[40];
myVarsStr.toCharArray(myVarsCh, 40);
ether.browseUrl(PSTR("/receivedata.asmx/ReceiveData?"), myVarsCh, website, my_callback);
}
}
else
{
word pos = ether.packetReceive();
word len = ether.packetLoop(pos);
delay(200);
}
}
I have ethernet shield w5100. Second day I try connecting to internet. But have no result.
My example:
#include <SPI.h>
#include <Ethernet.h>
byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x01 };
IPAddress ip(192,168,1,20);
EthernetClient client;
const unsigned long requestInterval = 60000; // delay between requests
char serverName[] = "api.twitter.com"; // twitter URL
boolean requested;
unsigned long lastAttemptTime = 0;
String currentLine = ""; // string to hold the text from server
String tweet = ""; // string to hold the tweet
boolean readingTweet = false;
void setup() {
currentLine.reserve(256);
tweet.reserve(150);
// Open serial communications and wait for port to open:
Serial.begin(9600);
// attempt a DHCP connection:
Serial.println("Attempting to get an IP address using DHCP:");
if (!Ethernet.begin(mac)) {
// if DHCP fails, start with a hard-coded address:
Serial.println("failed to get an IP address using DHCP, trying manually");
Ethernet.begin(mac, ip);
}
Serial.print("My address:");
Serial.println(Ethernet.localIP());
// connect to Twitter:
connectToServer();
}
void loop()
{
if (client.connected()) {
if (client.available()) {
// read incoming bytes:
char inChar = client.read();
// add incoming byte to end of line:
currentLine += inChar;
// if you get a newline, clear the line:
if (inChar == '\n') {
currentLine = "";
}
// if the current line ends with <text>, it will
// be followed by the tweet:
if ( currentLine.endsWith("<text>")) {
// tweet is beginning. Clear the tweet string:
readingTweet = true;
tweet = "";
}
// if you're currently reading the bytes of a tweet,
// add them to the tweet String:
if (readingTweet) {
if (inChar != '<') {
tweet += inChar;
}
else {
// if you got a "<" character,
// you've reached the end of the tweet:
readingTweet = false;
Serial.println(tweet);
// close the connection to the server:
client.stop();
}
}
}
}
else if (millis() - lastAttemptTime > requestInterval) {
// if you're not connected, and two minutes have passed since
// your last connection, then attempt to connect again:
connectToServer();
}
}
void connectToServer() {
// attempt to connect, and wait a millisecond:
Serial.println("connecting to server...");
if (client.connect(serverName, 80)) {
Serial.println("making HTTP request...");
// make HTTP GET request to twitter:
client.println("GET /1/statuses/user_timeline.xml?screen_name=arduino& count=1 HTTP/1.1");
client.println("HOST: api.twitter.com");
client.println("Connection: close");
client.println();
}
// note the time of this connect attempt:
lastAttemptTime = millis();
}
OUTPUT = failed to get an IP address using DHCP, trying manually
(connect to switch)
How can I resolve this problem?