Make a Post request with Authorization to drive a Cam

My cam is connected on my internal network, and I control it well with Postman, sending a simple POST request.
you could find below the preview of what Postman is sending:

POST /setSystemMotion HTTP/1.1
Host: 192.168.0.11
Authorization: Basic Yxxxxxxxxxxxxxxxxxxxxxzc=
Cache-Control: no-cache

ReplySuccessPage=motion.htm&ReplyErrorPage=motion.htm&MotionDetectionEnable=1&MotionDetectionScheduleDay=0&MotionDetectionScheduleMode=0&MotionDetectionSensitivity=90&ConfigSystemMotion=Save

Unfortunately I never succeed to translate that for the Spark Core, and since November I have headache with this issue!
bko already try to help me but this is always not working :frowning:

please find my code if someone could help me…

    TCPClient client;
    IPAddress server(192,168,0,11);
    int c=1;
    int Etat = A0;
    
    
    void setup() {
    Serial.begin(9600);
    pinMode(A0, INPUT_PULLDOWN);
    }
    
    void loop() {
      
   if(digitalRead(Etat) == LOW) {
        if (c == 1) {
            Serial.println("input = 0");
        }
        c=0;
    }
    if(digitalRead(A0) == HIGH  && c == 0) {
        Serial.println("input = 1");
        client.connect(server, 80);
        Serial.println("connection... ");
        Delay(200);
        if (client.connected()) {
            Serial.println("connection OK");
            client.println("POST /setSystemMotion HTTP/1.1");
            client.print("Host: ");
            client.println(server);
            client.println("Authorization: Basic xxxxxxxxxxxxxxxxxxx");
            client.println("Cache-Control: no-cache");
            client.println("Content-Type: text/plain");
            client.println("Content-Length: 190");
            client.println("Connection: Close");
            client.println();
            client.println("ReplySuccessPage=motion.htm&ReplyErrorPage=motion.htm&MotionDetectionEnable=1&MotionDetectionScheduleDay=0&MotionDetectionScheduleMode=0&MotionDetectionSensitivity=90&ConfigSystemMotion=Save");
            client.println();
            client.flush();
            client.stop();
        Serial.println("test finish");
        Serial.println("");
            c=1;
        } 
        else {
            client.stop();
            Serial.println("echec connection");
        }
      }
      
    } //end void loop()

I would suggest you use a service like RequestBin to make sure everything is being sent correctly. Try that and post back?

There are a couple of things that could be improved here… ill see what i can do tonight and get back to you

1 Like

the client print is pretty slow… give me 30mins… ill have some code for you to test

2 Likes

Hi @harrisonhjones, here is the result from RequestBin after some correction on my code

-The request coming from POSTMAN which is working with my cam:
-The request coming from the Spark Core which is not working with my cam:

Same result from my point of view… there is just the cookie which is not present on the spark requestPerhaps there is an issue of sending? It seems very long when I control the request with my serial port terminal application (time between: ā€œconnection okā€ and ā€œtest finishā€)

Give this a go and let me know how you get on… if you could post the info from the terminal window when you run it we may be able to

#include "application.h"
boolean DEBUG = true; // enable or disable Debug

IPAddress Server(192, 168, 0, 11);  
int Port = 80; // Port
char Path[] = "/setSystemMotion"; // path to file connecting to
char Logon[] = "YWRxxxxxxxxxxxxxxxxxxc="; // Username:Password base64 encoded

// Input and Output Pins 

int Etat = A0; // Doorbell button connects to D0 on the core
int LED = D7; // Built in LED

TCPClient client;
 
char reply[512];


void setup() {
    
    pinMode(Etat, INPUT_PULLDOWN); 
    
    pinMode(LED, OUTPUT); // sets LED as output
    
    if(DEBUG){
        digitalWrite(LED,HIGH); // Light the onboard LED so you know it's time to open your Serial Terminal
        Serial.begin(9600);
        while(!Serial.available()); // wait here for user to press ENTER in Serial Terminal
        digitalWrite(LED,LOW);

        Serial.print("SSID: ");
        Serial.println(WiFi.SSID());
        Serial.print("Core IP: ");
        Serial.println(WiFi.localIP());
        Serial.print("Gateway: ");
        Serial.println(WiFi.gatewayIP());
        Serial.print("Mask: ");
        Serial.println(WiFi.subnetMask());
        Serial.print("WiFi RSSI: ");
        Serial.println(WiFi.RSSI());
    }
    

}

void loop() {

        if(digitalRead(Etat) == HIGH) {  //read the button
            delay(50);
            if(digitalRead(Etat) == HIGH) {  // debounce check again to make sure 
                digitalWrite(LED,HIGH);
                cameraControl(Server, Port, Path, Logon); 
                digitalWrite(LED,LOW);
            }
        }

}

/*----------------------------------------------------------------------*/
/* out - outputs supplied string to TCPclient */
void out(const char *s) {

client.write( (const uint8_t*)s, strlen(s) );

if (DEBUG)Serial.write( (const uint8_t*)s, strlen(s) );

}
/*----------------------------------------------------------------------*/

/*----------------------------------------------------------------------*/
/* in - reads from TCPclient, with timeout */
void in(char *ptr, uint8_t timeout) {
        int pos = 0;
        unsigned long lastTime = millis();
        
        while( client.available()==0 && millis()-lastTime<timeout) { //timeout
        }  //do nothing
        lastTime = millis();
        unsigned long lastdata = millis();
        
        while ( client.available() || (millis()-lastdata < 500)) {  //500 millisecond timeout
            if (client.available()) {
                char c = client.read();
                if(DEBUG)Serial.print(c);
                lastdata = millis();
                ptr[pos] = c;
                pos++;
            }
            if (pos >= 512 - 1)
            break;
        }
        ptr[pos] = '\0'; //end the char array
        while (client.available()) client.read(); // makeshift client.flush()
        client.flush();  //for safety
        delay(400);
        client.stop();
        if(DEBUG){
            Serial.println();
            Serial.print("Done, Total bytes: ");
            Serial.println(pos);
        }
        
}
/*-----------------------------------------------------------------------*/


void cameraControl(IPAddress hostname, int port, char *url, char *logon) {
    
    char line[255];
    client.stop();

    if(DEBUG){Serial.print("connecting... ");}
    if (client.connect(hostname, port)) {
        if(DEBUG){
            Serial.print("connected to ");
            Serial.println(hostname);
        }
        delay(500);
        digitalWrite(LED, LOW);
        sprintf(line, "POST %s HTTP/1.1\r\n", url);
        out(line);

        sprintf(line, "Host: %d.%d.%d.%d:%d\r\n", hostname[0], hostname[1],hostname[2],hostname[3], port);
        out(line);

        sprintf(line, "Authorization: Basic %s\r\n", logon);
        out(line);
        
        out("Cache-Control: no-cache\r\nContent-Type: text/plain\r\n");
        
        sprintf(line, "Content-Length: %d\r\n", 190); //we will calculate this later to make it dynamic
        out(line);
        
        out("Connection: close\r\n\r\n");
        
        sprintf(line, "ReplySuccessPage=motion.htm&ReplyErrorPage=motion.htm&MotionDetectionEnable=1&MotionDetectionScheduleDay=0&MotionDetectionScheduleMode=0&MotionDetectionSensitivity=90&ConfigSystemMotion=Save\r\n");
        out(line);
        
        in(reply, 3000);
        
     }
    else {
        while (client.available()) client.read(); // makeshift client.flush()
        client.flush();
        client.stop();
        if(DEBUG)Serial.println("Could not connect");
    }
}

really sorry for the delay… my internet is very intermittent at the moment… i pushed reply 2 hours ago and it was still not sent when i got back to my desk!

what type of camera are you controlling? and what does the request above do? it would be awesome to see the whole api and know what the camera can do :slight_smile:

Thank you @Hootie81 for this reply (you didn’t have any deadline :wink: )
What should I put in the library application.h?
is this the declaration of void out(),void in() and void cameraControl() parts? I never see them in a spark core code.

I control a D-link cam over my private network (in wifi) to manage the Motion detection option.
A0 (Spark Core input) is connected to my alarm,
When alarm is activated, the Motion detection of my cam is enabled, and when disarm the Motion detection will be disabled.

Try adjusting the Content-Length and/or removing the \r\n at the end of the message.
It looks like you are setting up a 190 char message, setting C-L header to 190, but then sending 192 chars because of the \r\n?

Tim.

In my last post with RequestBin results, you can see that 190 bytes has been sent (after modification of the code).
This is still not working for the cam side with the Spark POST request. (it work with Postman)

When you use POSTMAN, what HTTP Response code do you get back - is it 200 OK?
What HTTP Response Code do you get back when you use Spark Core?

With Postman I have 200 OK
With the Spark core I don’t know how to read this response. do you have an idea?

If you check the raw data of the POST request you will see that the answer (body) from the cam is the same

ReplySuccessPage=motion.htm&ReplyErrorPage=motion.htm

I can’t change this raw data, otherwise the modification of the ā€œMotion detectionā€ parameter will not work.

the body is not the answer, the body is what you are sending

If you use the code i sent, you should see the reply come up in the terminal. when you power up the little blue led should come on letting you know to open a terminal, then open your terminal application and press any key to start the user code running again.

you should then see the outgoing request with all the connect and headers and then the body. if you wait a second you should see the reply, it should start with 200 OK or maybe 400 something because its not working… that will be the biggest clue to whats happening

I cannot compile your code @Hootie81 , there is to many error like if it miss an application.h for declaration??
I would like to test it, but it cannot compile:


In file included from …/inc/spark_wiring.h:29:0,
from …/inc/application.h:29,
from enable_cam_dlink.cpp:1:
…/…/core-common-lib/SPARK_Firmware_Driver/inc/config.h:12:2: warning: #warning ā€œDefaulting to Release Buildā€ [-Wcpp]
#warning ā€œDefaulting to Release Buildā€
^
enable_cam_dlink.cpp:6:20: error: ā€˜uint8_t’ has not been declared
void in(char *ptr, uint8_t timeout);
^
enable_cam_dlink.cpp:7:20: error: variable or field ā€˜cameraControl’ declared void
void cameraControl(IPAddress hostname, int port, char *url, char *logon);
^
enable_cam_dlink.cpp:7:20: error: ā€˜IPAddress’ was not declared in this scope
enable_cam_dlink.cpp:7:40: error: expected primary-expression before 'int’
void cameraControl(IPAddress hostname, int port, char *url, char *logon);
^
enable_cam_dlink.cpp:7:50: error: expected primary-expression before 'char’
void cameraControl(IPAddress hostname, int port, char *url, char *logon);
^
enable_cam_dlink.cpp:7:61: error: expected primary-expression before 'char’
void cameraControl(IPAddress hostname, int port, char *url, char *logon);
^
enable_cam_dlink.cpp:3:6: error: previous declaration of ā€˜void setup()’ with ā€˜C++’ linkage
void setup();
^
In file included from …/inc/spark_wiring.h:33:0,
from …/inc/application.h:29,
from enable_cam_dlink.cpp:1:
…/inc/spark_utilities.h:169:35: error: conflicts with new declaration with ā€˜C’ linkage
void setup() attribute ((weak));
^
enable_cam_dlink.cpp:4:6: error: previous declaration of ā€˜void loop()’ with ā€˜C++’ linkage
void loop();
^
In file included from …/inc/spark_wiring.h:33:0,
from …/inc/application.h:29,
from enable_cam_dlink.cpp:1:
…/inc/spark_utilities.h:170:34: error: conflicts with new declaration with ā€˜C’ linkage
void loop() attribute ((weak));
^
enable_cam_dlink.cpp: In function ā€˜void loop()’:
enable_cam_dlink.cpp:52:56: error: ā€˜cameraControl’ was not declared in this scope
}
^
make: *** [enable_cam_dlink.o] Error 1

Error: Could not compile. Please review your code.


hmmm thats weird! application.h should be in the main core firmware. it compiles no problem in the webIDE

are you using the webIDE or Dev?

I use the Spark Build (WebIDE if I’m right?)

My fault!! I’ve just see that there is a space before #include "application.h" and this make the fault
I will let you know soon what is the result

Here is the result:
It seems that the request syntax is incorrect (400 Bad Request)

connecting… connected to 192.168.0.11
POST /setSystemMotion HTTP/1.1
Host: 192.168.0.11:80
Authorization: Basic Yxxxxxxxxxxxxxxxxxc=
Cache-Control: no-cache
Content-Type: text/plain
Content-Length: 190
Connection: close

ReplySuccessPage=motion.htm&ReplyErrorPage=motion.htm&MotionDetectionEnable=1&MotionDetectionScheduleDay=0&MotionDetectionScheduleMode=0&MotionDetectionSensitivity=90&ConfigSystemMotion=Save
HTTP/1.0 400 Bad Request

Done, Total bytes: 26

try changing line 293 content type to this

out(ā€œCache-Control: no-cache\r\nContent-Type: application/x-www-form-urlencoded\r\nā€);

changed the line (129) and still 400 Bad Request
Do you think that the Cam server need ā€œUser-Agentā€ or ā€œOriginā€ information?