R-A
Posts: 18
Joined: Sun Sep 11, 2016 4:59 pm

how to post data to URL?

Sun Oct 01, 2017 6:34 pm

Hi,

I wonder if someone can help me?

I found some code on the internet (github) to read values from my solar inverter, but it's written in C. And I don't know C, but rather some PHP and Python.
So I want to modify the script to upload the values to http://www.emoncms.com either a GET or POST request. Their API supports the following format:

GET: https://emoncms.org/input/post?node=emo ... xxxxxxxxxx

POST: curl --data "node=1&data={power1:100,power2:200,power3:300}&apikey=xxxxxxxxxxxxxxxx" "https://emoncms.org/input/post"

API samples: https://emoncms.org/site/api#input

I can do this in Python, as follows:

Code: Select all

     r = requests.get("https://emoncms.org/input/post.json?node=1&json={Bedroom1Roof:" + str(myTempBed1Roof) + "}&apikey=" + APIKEY)
#      print(r.url)
#      r.status_code == requests.codes.ok
#      print(r.status_code)
"str(myTempBed1Roof)" is a variable string which I get from a DS18B20 temp sensor.


But, as I said, the current script is written in C, and I don't know how to accomplish this. Nor do I know how to re-write this code in Python.

Any help would be highly appreciated. I have searched the forums but the code I found is all for Python.

R-A
Posts: 18
Joined: Sun Sep 11, 2016 4:59 pm

Re: how to post data to URL?

Wed Oct 04, 2017 8:45 pm

Any help with this would be highly appreciated

ghans
Posts: 7438
Joined: Mon Dec 12, 2011 8:30 pm
Location: Germany

Re: how to post data to URL?

Wed Oct 04, 2017 10:08 pm

Use subprocess.Popen() to execute the C program and read its output.

ghans
• Don't like the board ? Missing features ? Change to the prosilver theme ! You can find it in your settings.
• Don't like to search the forum BEFORE posting 'cos it's useless ? Try googling : yoursearchtermshere site:raspberrypi.org

6by9
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 4604
Joined: Wed Dec 04, 2013 11:27 am
Location: ZZ9 Plural Z Alpha, aka just outside Cambridge.

Re: how to post data to URL?

Thu Oct 05, 2017 8:39 am

Post a link to the C code and someone may be helpful enough to do at least a cursory conversion to Python, or at least give some guidance as to what the C is doing and how you might replicate it in Python.
Software Engineer at Raspberry Pi Trading. Views expressed are still personal views.
Please don't send PMs asking for support - use the forum.
I'm not interested in doing contracts for bespoke functionality - please don't ask.

R-A
Posts: 18
Joined: Sun Sep 11, 2016 4:59 pm

Re: how to post data to URL?

Fri Oct 06, 2017 7:26 pm

6by9 wrote:
Thu Oct 05, 2017 8:39 am
Post a link to the C code and someone may be helpful enough to do at least a cursory conversion to Python, or at least give some guidance as to what the C is doing and how you might replicate it in Python.
I didn't write the code, so I didn't think I could post the URL, but it's on github.com/manio/skymax-demo
The important piece of code is on https://github.com/manio/skymax-demo/bl ... r/main.cpp

c++ is a bit difficult for me to understand, though I understand and can code some (limited) Python.

ghans
Posts: 7438
Joined: Mon Dec 12, 2011 8:30 pm
Location: Germany

Re: how to post data to URL?

Sat Oct 07, 2017 12:49 pm

Why don't install that piece of software and play around a bit. This is what the Pi is about , after all.

Code: Select all

sudo apt-get update
sudo apt-get install cmake
git clone git://github.com/manio/skymax-demo.git
cd skymax-demo
mkdir out
cd out
cmake ..
make
(instructions copied nearly verbatim from the github page)

ghans
• Don't like the board ? Missing features ? Change to the prosilver theme ! You can find it in your settings.
• Don't like to search the forum BEFORE posting 'cos it's useless ? Try googling : yoursearchtermshere site:raspberrypi.org

R-A
Posts: 18
Joined: Sun Sep 11, 2016 4:59 pm

Re: how to post data to URL?

Wed Oct 25, 2017 6:59 am

ghans wrote:
Sat Oct 07, 2017 12:49 pm
Why don't install that piece of software and play around a bit. This is what the Pi is about , after all.

Code: Select all

sudo apt-get update
sudo apt-get install cmake
git clone git://github.com/manio/skymax-demo.git
cd skymax-demo
mkdir out
cd out
cmake ..
make
(instructions copied nearly verbatim from the github page)

ghans
Why don't you re-read my question? I HAVE installed that script, but I want to MODIFY it to post data to Emoncms. And I don't know how to code C++

User avatar
topguy
Posts: 3713
Joined: Tue Oct 09, 2012 11:46 am
Location: Trondheim, Norway

Re: how to post data to URL?

Wed Oct 25, 2017 1:36 pm

In theory you only need to learn two C functions.
* snprintf() - function that lets you format the contents of a string. ( understanding this is the hard part )
* system() - function that calls a command similar to running in on the command line.

So in the main function of the demo program:
- Allocate a buffer for the string.
- create the "curl" command needed to post the data.
- run the "curl" command.

Code: Select all

// Allocate buffer for the string.
char postcmd[1024];   // alternative: char * postcmd = calloc(1024);

// Format the curl command to post data.
snprintf( postcmd, 1024,  "/usr/bin/curl --data \"node=1&data={power1:%d,power2:%d,power3:%d}&apikey=xxxxxxxxxxxxxxxx\" \"https://emoncms.org/input/post\"", load_percent, heatsink_temp, voltage_batt );

//print command for debug
printf( "debug: %s\n", postcmd);

//run the command
system(postcmd); 

R-A
Posts: 18
Joined: Sun Sep 11, 2016 4:59 pm

Re: how to post data to URL?

Wed Oct 25, 2017 8:32 pm

topguy wrote:
Wed Oct 25, 2017 1:36 pm
In theory you only need to learn two C functions.
* snprintf() - function that lets you format the contents of a string. ( understanding this is the hard part )
* system() - function that calls a command similar to running in on the command line.

So in the main function of the demo program:
- Allocate a buffer for the string.
- create the "curl" command needed to post the data.
- run the "curl" command.

Code: Select all

// Allocate buffer for the string.
char postcmd[1024];   // alternative: char * postcmd = calloc(1024);

// Format the curl command to post data.
snprintf( postcmd, 1024,  "/usr/bin/curl --data \"node=1&data={power1:%d,power2:%d,power3:%d}&apikey=xxxxxxxxxxxxxxxx\" \"https://emoncms.org/input/post\"", load_percent, heatsink_temp, voltage_batt );

//print command for debug
printf( "debug: %s\n", postcmd);

//run the command
system(postcmd); 

Thank you!

That help a lot, although I'm getting really strange values from the snprintf formatted string:

Here's the (modified to work) code:

Code: Select all

  //parse and display values
        sscanf(reply->c_str(), "%f %f %f %f %d %d %d %d %f %d %d %d %d %f %f %d", &voltage_grid, &freq_grid, &voltage_out, &freq_out, &load_va, &load_watt, &load_percent, &voltage_bus, &voltage_batt, &batt_charge_current, &batt_capacity, &temp_heatsink, &pv1, &pv2, &scc, &batt_discharge_current);
        printf("\tAC Grid voltage: %.1f\n", voltage_grid);
        printf("\tAC Grid frequency: %.1f\n", freq_grid);
        printf("\tAC out voltage: %.1f\n", voltage_out);
        printf("\tAC out frequency: %.1f\n", freq_out);
        printf("\tLoad [%]: %d\n", load_percent);
        printf("\tLoad [W]: %d\n", load_watt);
        printf("\tLoad [VA]: %d\n", load_va);
        printf("\tBus voltage: %d\n", voltage_bus);
        printf("\tHeatsink temperature: %d\n", temp_heatsink);
        printf("\tBattery capacity [%]: %d\n", batt_capacity);
        printf("\tBattery voltage: %.2f\n", voltage_batt);
        printf("\tBattery charge current [A]: %d\n", batt_charge_current);
        printf("\tBattery discharge current [A]: %d\n", batt_discharge_current);


        // Allocate buffer for the string.
        char postcmd[1024];   // alternative: char * postcmd = calloc(1024);

        // Format the curl command to post data.
        snprintf( postcmd, 1024,  "/usr/bin/curl --data \"node=0&data={loadwatts:%d,gridvoltage:%d,inverter_voltage:%d}&apikey=xxxxxxxxxxxx\" \"https://emoncms.org/input/post\"", load_watt, voltage_grid, voltage_bus );


And as you can see from the output, it gives different values from the original code:
Wed Oct 25 22:31:36 2017 MAIN LOOP
Skymax: QPIGS: 110 bytes read: (218.6 50.1 218.6 50.1 0262 0224 005 436 54.00 000 100 0060 0000 000.0 00.00 00000 00010101 00 00 00000 110
Skymax: QMOD: 5 bytes read: (L
AC Grid voltage: 218.6
AC Grid frequency: 50.1
AC out voltage: 218.6
AC out frequency: 50.1
Load [%]: 5
Load [W]: 224
Load [VA]: 262
Bus voltage: 436
Heatsink temperature: 60
Battery capacity [%]: 100
Battery voltage: 54.00
Battery charge current [A]: 0
Battery discharge current [A]: 0
debug: /usr/bin/curl --data "node=0&data={loadwatts:224,gridvoltage:1073741824,inverter_voltage:1080775475}&apikey=xxxxxxxxxxxx" "https://emoncms.org/input/post"
ok

I am reading up on snprintf to see how I can fix it although I haven't found anything that helps, yet. This is still a bit unclear to me.

User avatar
Paeryn
Posts: 1685
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: how to post data to URL?

Wed Oct 25, 2017 9:58 pm

From your initial reading voltage_grid is a float (or a double)

Code: Select all

        sscanf(reply->c_str(), "%f %f %f %f %d %d %d %d %f %d %d %d %d %f %f %d", &voltage_grid, &freq_grid, &voltage_out, &freq_out, &load_va, &load_watt, &load_percent, &voltage_bus, &voltage_batt, &batt_charge_current, &batt_capacity, &temp_heatsink, &pv1, &pv2, &scc, &batt_discharge_current);
        printf("\tAC Grid voltage: %.1f\n", voltage_grid);
But when you print it with snprintf() you have told it to expect an integer %d

Code: Select all

        // Format the curl command to post data.
        snprintf( postcmd, 1024,  "/usr/bin/curl --data \"node=0&data={loadwatts:%d,gridvoltage:%d,inverter_voltage:%d}&apikey=xxxxxxxxxxxx\" \"https://emoncms.org/input/post\"", load_watt, voltage_grid, voltage_bus );
The problem is that the compiler will pass the values directly according to the type they have but snprintf will interpret the values according to what you gave in the string. The error with the value of voltage_bus is twofold, (a) because you are passing a float/double not an int, and (b) because C always promotes a float to a double when passing to vararg functions so a 64-bit floating point number was passed but snprintf was told to expect a 32-bit int so half of the data representing the number will be used as if it were an int (which is why the value is nothing like the original). Since snprintf only consumed 32-bits of this 64-bit value every subsequent argument will be wrong because it will no longer be reading the correct memory addresses.

If you want snprintf to print a float you need to use %f for that argument, not %d.

Code: Select all

        // Format the curl command to post data.
        snprintf( postcmd, 1024,  "/usr/bin/curl --data \"node=0&data={loadwatts:%d,gridvoltage:%f,inverter_voltage:%d}&apikey=xxxxxxxxxxxx\" \"https://emoncms.org/input/post\"", load_watt, voltage_grid, voltage_bus );
She who travels light — forgot something.

R-A
Posts: 18
Joined: Sun Sep 11, 2016 4:59 pm

Re: how to post data to URL?

Thu Oct 26, 2017 9:24 am

Paeryn wrote:
Wed Oct 25, 2017 9:58 pm
From your initial reading voltage_grid is a float (or a double)

Code: Select all

        sscanf(reply->c_str(), "%f %f %f %f %d %d %d %d %f %d %d %d %d %f %f %d", &voltage_grid, &freq_grid, &voltage_out, &freq_out, &load_va, &load_watt, &load_percent, &voltage_bus, &voltage_batt, &batt_charge_current, &batt_capacity, &temp_heatsink, &pv1, &pv2, &scc, &batt_discharge_current);
        printf("\tAC Grid voltage: %.1f\n", voltage_grid);
But when you print it with snprintf() you have told it to expect an integer %d

Code: Select all

        // Format the curl command to post data.
        snprintf( postcmd, 1024,  "/usr/bin/curl --data \"node=0&data={loadwatts:%d,gridvoltage:%d,inverter_voltage:%d}&apikey=xxxxxxxxxxxx\" \"https://emoncms.org/input/post\"", load_watt, voltage_grid, voltage_bus );
The problem is that the compiler will pass the values directly according to the type they have but snprintf will interpret the values according to what you gave in the string. The error with the value of voltage_bus is twofold, (a) because you are passing a float/double not an int, and (b) because C always promotes a float to a double when passing to vararg functions so a 64-bit floating point number was passed but snprintf was told to expect a 32-bit int so half of the data representing the number will be used as if it were an int (which is why the value is nothing like the original). Since snprintf only consumed 32-bits of this 64-bit value every subsequent argument will be wrong because it will no longer be reading the correct memory addresses.

If you want snprintf to print a float you need to use %f for that argument, not %d.

Code: Select all

        // Format the curl command to post data.
        snprintf( postcmd, 1024,  "/usr/bin/curl --data \"node=0&data={loadwatts:%d,gridvoltage:%f,inverter_voltage:%d}&apikey=xxxxxxxxxxxx\" \"https://emoncms.org/input/post\"", load_watt, voltage_grid, voltage_bus );
It was late last night when I posted my reply, so this morning I played with the code again and just copied what the previous writer did and it now gives me the output I expect. Almost, the last value is still wrong.
okSkymax: QPIGS: 110 bytes read: (217.6 49.9 230.0 49.9 0276 0147 005 431 53.80 001 100 0058 0004 102.0 53.94 00000 00110110 00 00 00226 110
Skymax: QMOD: 5 bytes read: (B
AC Grid voltage: 217.6
AC Grid frequency: 49.9
AC out voltage: 230.0
AC out frequency: 49.9
Load [%]: 5
Load [W]: 147
Load [VA]: 276
Bus voltage: 431
Heatsink temperature: 58
Battery capacity [%]: 100
Battery voltage: 53.80
Battery charge current [A]: 1
Battery discharge current [A]: 0
debug: /usr/bin/curl --data "node=0&data={loadwatts:147,gridvoltage:217.6,inverter_voltage:230.0,grid_frequency:49.9,inverter_frequency:49.9,load_va:276,loadpercentage:5,voltage_bus:431,batteryvolts:53.80,Battery_ChargeCurrent:1,Battery_Capacity:100,Inverter_Temp:58,PV_Amp:102.0,PV_Volt:53.9,SCC:0,Battery_DischargeCurrent:1992596456}&apikey=4298750438d23d97bfdc1611c52cd609" "https://emoncms.org/input/post"
As you can see, Battery_DischargeCurrent:1992596456 where it should be Battery_DischargeCurrent:0 instead.

The code I have is this:

Code: Select all



snprintf( postcmd, 1024,  "/usr/bin/curl --data \"node=0&data={loadwatts:%d,gridvoltage:%.1f,inverter_voltage:%.1f,grid_frequency:%.1f,inverter_frequency:%.1f,load_va:%d,loadpercentage:%d,voltage_bus:%d,batteryvolts:%.2f,Battery_ChargeCurrent:%d,Battery_Capacity:%d,Inverter_Temp:%d,PV_Amp:%.1f,PV_Volt:%.1f,SCC:%d,Battery_DischargeCurrent:%d}&apikey=4298750438d23d97bfdc1611c52cd609\" \"https://emoncms.org/input/post\"", load_watt, voltage_grid, voltage_out, freq_grid, freq_out,load_va, load_percent, voltage_bus, voltage_batt, batt_charge_current, batt_capacity, temp_heatsink,pvvolt, pvamp, scc, batt_discharge_current);
I did use %d on Battery_DischargeCurrent so I'm not sure why it's doing that.


Last question:

How I multiply 2 values, before I submit it to the URL?
i.e. I want to multiply pv_volt & pv_amp and post the value.

User avatar
Paeryn
Posts: 1685
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: how to post data to URL?

Thu Oct 26, 2017 9:58 am

R-A wrote:
Thu Oct 26, 2017 9:24 am
As you can see, Battery_DischargeCurrent:1992596456 where it should be Battery_DischargeCurrent:0 instead.

I did use %d on Battery_DischargeCurrent so I'm not sure why it's doing that.
You read scc as a float but try printing as an int, that is hitting the providing a 64 bit value but consuming a 32 bit error making the final value for Battery_DischargeCurrent to be read from the wrong place. You were (un)lucky in that scc had a value of zero so you didn't see that value printed wrong.
R-A wrote:
Thu Oct 26, 2017 9:24 am
Last question:

How I multiply 2 values, before I submit it to the URL?
i.e. I want to multiply pv_volt & pv_amp and post the value.
You can pass the multiplied value to the snprintf

Code: Select all

snprintf(postcmd, 1024, "pv_volt=%f, pv_amp=%f, pv_volt*pv_amp=%f", pv_volt, pv_amp, pv_volt * pv_amp);
or store the multiplied value in another variable and pass that.
She who travels light — forgot something.

Return to “C/C++”

Who is online

Users browsing this forum: No registered users and 10 guests