Declaring variables a quicker way


#21

I see so just like we use i in each for loop it is local to that loop and can not be used outside the loop.

well thats great thank you very much for your help its hard to understand when you don’t entirely know what you are doing you kind of just go to what you know works but i suppose its all about thinking a bit deeper and getting the code to basically write itself.

thanks again…Ben


#22

You can’t do that, as it would just overwrite the entire string each iteration of your loop (and there actually is no element N)
If you want to keep the flexibility to change the number of inputs without changes to the active code, you could do this (warning: this may look confusing at first :wink: )

void publishDataToCloud() {
  char msg[256];
  strcpy(msg, "{ \"input\" : ["); // prefix
  for (int i = 0; i < N; i++)     // append data and separator(s)
    snprintf(msg, sizeof(msg), "%s %d%s", msg, dimpval[i], (i < N-1) ? "," : " ] }");

  Particle.publish("photonmonitor", msg, PRIVATE, NO_ACK);
}

First the prefix gets placed into the string and then we enter the loop.
Each iteration of loop we’ll take what’s already in the string (the first %s) and copy it into itself, then we append the actual value and then another string.
This is a tricky one.
The first few iterations we will append a comma (,) and in the final one we close the string.
That’s done via a so-called ternary operator (result = (condition ? true-value : false-value)).
While i is less than the final element number the true-value "," will be inserted in place of the last %s and when i has reached the final element the condition will be false and consequently " ] }" will be inserted.

This would create the JSON array I proposed above.
If you rather want to replicate this

you can do it just the same but instead of inputX would use input%d and substitute that for with i like this

  strcpy(msg, "{"); // prefix
  for (int i = 0; i < N; i++)     // append data and separator(s)
    snprintf(msg, sizeof(msg), "%s \"input%d\": %d%s", msg, i, dimpval[i], (i < N-1) ? "," : " }");

#23

I don’t understand that at all it is far beyond my coding knowledge. Is there an easyer way to do it I take it I can’t just write the string as it was dinval0 ? That variable should exist because we created it in the for loop


#24

I think I understand this one so we take 1 from the total size as it has the end of the string marker which counts as 1 byte?


#25

Sure you could just write

snprintf(msg, sizeof(msg)
        , "{\"input0\":%d, \"input1\":%d, \"input2\":%d, \"input3\":%d, \"input4\":%d, \"input5\":%d, \"input6\":%d}"
        , dimpval[0], dimpval[1], dimpval[2], dimpval[3], dimpval[4], dimpval[5], dimpval[6]);

But if you step through my code above step-by-step it’ll become all clear.
Lets assume dimpval[i] = 10*i

  strcpy(msg, "{ \"input\" : ["); // msg = "{ \"input\" : ["
  // seven times this
  //snprintf(msg, sizeof(msg), "%s %d%s", msg, dimpval[i], (i < N-1) ? "," : " ] }");
  // i == 0 ->                    //       "............... 0," because %d will be 10*0 and 0 < 6 (N-i) makes %s the comma
  // i == 1 ->                    //       ".................. 10," 
  // i == 2 ->                    //       "...................... 20," 
  // i == 3 ->                    //       ".......................... 30," 
  // i == 4 ->                    //       ".............................. 40," 
  // i == 5 ->                    //       ".................................. 50," 
  // i == 6 ->                    //       "...................................... 60 ] }" because %d will be 10*6 and
  //                              //                                                       is not 6 < 6 which makes %s " ] }"
  // final string                 // msg = "{ \"input\" : [ 0, 10, 20, 30, 40, 50, 60 ] }"

#26

I’m sorry I don’t have a clue it looks like you are copying it and running the loop but I just don’t fully understand it. I’m more than happy to use the long winded version as at least I understand that.


#27

That’s probably because you still don’t really understand how snprintf() works, but since that is an important concept to understand I’ll try again and so should you :wink:

snprintf(msg, sizeof(msg), "%s %d%s", msg, dimpval[i], (i < N-1) ? "," : " ] }");

The format parameteter "%s %d%s" tells the function how to insert the following “value” parameters into the target string - format placeholder %s means that a string should be placed there while %d denotes a “decimal” (base 10) number will be put there
So this means

  "%s %d%s", msg, dimpval[i], "," 
// ^  ^  ^
// |  |  |
// |  |  +-- 3rd placeholder = 3rd value parameter = "," (in case of the last element this will be " ] }")
// |  +----- 2nd placeholder = 2nd value parameter = value of dimpval[i]
// +-------- 1st placeholder = 1st value parameter = contents of msg itself from previous iterations
//                                                   denoted in my demo above as ........

For a more elaborate explanation of formatting strings you can look at printf() which shows the basic logic also used in snprintf().

BTW

Yes exactly that. First copying the previous content and then appending the new data for each of the iterations through your data array.
That’s what I said above


#28

I understand whats going on i think but im not 100% on the layout of it

so we are copying input into msg
we then create a loop which runs N number of times which constructs the snprintf so in my program would it read like this
"{ “input” : [ 1, 0, 1, 1, 1, 1, 0 ] }" // depending on inputs

so we are copying “{ “input” : [” into the variable msg
its this bit that is getting me maybe im not 100 percent on this snprintf
am i right in saying…
we use snprintf to store the array which is called msg and has a size of msg which is 256 i our case
it has a format of string (which will be value, decimal (which will be dimpval0),string (this will be a ,because i is less than n - 1)
then i dont know how we are then re copying the string we have just created back in to msg but i guess we are and the for loop goes round again adding the string we just created msg and also adding the next value which is dimpval[1] then another , this happens untill i is == to N then it changes the , for a ] and the string is complete.
im not sure what the ? does or the : but im guessing it relates to the (i < N-1) being true ? put this ,

im sure i understand it a lot more than i did


#29

so i thought i wold give it a try but what im seing on the events is it is publishing every time round and only up to a max of 4 pieces { “input” : [ 0, 0, 0, 0, so im guessing i will have to check if the string is complete then Particle.publish(“photonmonitor”, msg, PRIVATE, NO_ACK); using N

not like this

void publishDataToCloud() {
  char msg[256];
  strcpy(msg, "{ \"input\" : ["); // prefix
  for (int i = 0; i < N; i++) {   // append data and separator(s)
    snprintf(msg, sizeof(msg), "%s %d%s", msg, dimpval[i], (i < N-1) ? "," : " ] }");

  Particle.publish("photonmonitor", msg, PRIVATE, NO_ACK);
}

like this


void publishDataToCloud() {
  char msg[256];
  strcpy(msg, "{ \"input\" : ["); // prefix
  for (int i = 0; i < N; i++) {   // append data and separator(s)
    snprintf(msg, sizeof(msg), "%s %d%s", msg, dimpval[i], (i < N-1) ? "," : " ] }");

if (i == N )
{
  Particle.publish("photonmonitor", msg, PRIVATE, NO_ACK);
}
}


#30

got it i need to run the publish outside the for loop so its only run when the loop is finished


#31

well i would just like to say a big thank you to you ScruffR I successfully have it working and not only that i understand how it was done, so thank-you very much. my next step is to try and get some analogs in the string so i will have a good go at that now i now what im up against.
once again thank you for devoting your time helping me out.


#32

The first parameter (msg) of snprintf() is the target where the created string should be copied to. And the fourth parameter (msg again) is a value paramter which will be the source of the data that should be copied to the target.
In other languages or with String you could achieve something similar by writing this

msg = msg + "1" + ",";

That’s due to the extra curly brace that sneaked its way in there

When you remove that, the loop will only span the one snprintf() statement and not the publish too.

So this should work without the extra if(i == N) block

void publishDataToCloud() {
  char msg[256];
  strcpy(msg, "{ \"input\" : ["); // prefix
  for (int i = 0; i < N; i++)     // append data and separator(s)
    snprintf(msg, sizeof(msg), "%s %d%s", msg, dimpval[i], (i < N-1) ? "," : " ] }");

  Particle.publish("photonmonitor", msg, PRIVATE, NO_ACK);
}

#33

so i am at this again now however i am now trying to get this data in to a mysql database surely i just take the string from the webhook and create an array then insert it into the database table as so.

<?php


$content = (file_get_contents("php://input"));

$decoded[] = json_decode($content, true);

$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 $sql = "INSERT INTO `monitorvalues` (`dimp0`, `dimp1`, `dimp2`, `dimp3`, `dimp4`, dimp5`, `dimp6` ) VALUES ('$decoded[0]', '$decoded[1]', '$decoded[2]', '$decoded[3]', '$decoded[4]', '$decoded[5]', '$decoded[6]')";

however my webhook gives me an error

{ “event”: “photonmonitor”, “url”: “http://mysite.php”, “requestType”: “POST”, “mydevices”: true, “noDefaults”: false, “coreid”: “core id was here”, “input”: “0,1,0,0,0,0,0”, }

i thought this part would be simple am i grabbing the string wrong, should i not use the array [] ?

Or should I be creating another variable array and like this

$arvalue[] = $decoded['input'];


#34

If you don’t get the results you expect it’s always good do print out what you get and compare that with your expectation.
In this case you should log the received data (e.g. decoded[]) to your PHP console.


#35

Hmm I will have to try that. I did try to display it on my php page but was then thinking I would have to refresh the page at exactly the same time as the webhook arrived. I have also tried dumping the data to a text file in my public folder where my php script resides it does create the text file but is always blank. I can do it the way I was doing before we used that loop to write the string and it works great but I do not want to go down that root really as the way you have shown me is much more future proof
Am I right in saying the Jason.decode is a string? And I don’t need to declare what type the php variable is so what I am doing makes sense in my head.


#36

I wouldn’t feel bad to “abuse” error_log() for that.


#37

this is the error log i am getting

INSERT INTO `monitorvalues` (`dimp0`, `dimp1`, `dimp2`, `dimp3`, `dimp4`, dimp5`, `dimp6` ) VALUES ('', '', '', '', '', '', '')<br>SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '`, `dimp6` ) VALUES ('', '', '', '', '', '', '')' at line 1

i have been watching a few turorials on json today on my way home from work and am thinking of creating a json file with the string i get in the webhook and see if i can print it out in the php file. its all very new to me all this json and php im more of an electrician so im just trying to relate my project to tutorials im looking at and trying to work out what is going on by kind of reverse engineering.

Thanks…Ben


#38

It looks like you’re missing the opening backtick on dimp5?


#39

Thanks for that, i have been staring at that code for ages and not seen that.

i now have it inserting in the database but all the values are zero i still can not seem to figure out what is wrong

<?php


$content = (file_get_contents("php://input"));

$decoded = json_decode($content, true);

//$newdecoded[] = $decoded['input'];




try {
$conn = new PDO("mysql:host=$localhost;dbname=$iotelect_monitoring", $iotelect_ben, $esmeh);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
File_put_contents("test1", $JSON." \n", FILE_APPEND);
 $sql = "INSERT INTO `monitorvalues` (`dimp0`, `dimp1`, `dimp2`, `dimp3`, `dimp4`, `dimp5`, `dimp6` ) VALUES ('$decoded[0]->input', '$decoded[1]->input', '$decoded[2]->input', '$decoded[3]->input', '$decoded[4]->input', '$decoded[5]->input', '$decoded[6]->input')";
//$sql = "INSERT INTO `photonvalues` (`value1`, `value2`) VALUES ('11', '12')";
 //$sql = "INSERT INTO `monitorvalues` (`dimp0`, `dimp1`, `dimp2`, `dimp3`, `dimp4`, `dimp5`, `dimp6` ) VALUES ('1', '0', '1', '0', '1', '0', '1')";
$conn->exec($sql);
//echo $value1;
//echo $characters[0]->name;
echo "Data Inserted";
}
catch(PDOException $e)
{
echo $sql . "<br>" . $e->getMessage();
}
$conn = null;
?>

#40

You are still not logging the incoming and decoded data.
Try this
http://php.net/manual/en/function.error-log.php

I’m pretty sure you either don’t actually catch the webhook data or you don’t decode it correctly.
The log will show.