[SOLVED] Particle.variable not working with function (*char var)

Hello,

I’m having an issue that may be a bug? I need help to confirm.

In short:

void handler(const char *Name, const char *Value) 
 {

  Particle.publish("Name", Value) //# Does works
  Serial.writeln("Name", Value) //# Does works

  Particle.variable("Name", Value); //# Does not work
  Particle.variable("Name", String(Value)); //# Does not work
  Particle.variable("Name", String(Value).c_str()); //# Does not work
  Particle.variable("Name", "123"; //# Does work

};

Verification is by API:
https://api.particle.io/v1/devices/180028001447343338333633/Value?access_token=########

Any help would be appreshated.

Mr.Deek

Your variables should be in your setup, not a separate function. Give that a try and see if it works for you.

Unless it’s for demonstration purposes, having multiple variables with the same name is a sure way to run into issues.

What are you expecting variables to do exactly, since therein might lie the source of confusion?

You should also ensure that the variable pointer is in global scope - if it’s allocated on the stack then the contents will be erased when the function returns.

The simplest way to ensure this is to declare a global variable:

char myvar[50];

void setup()
{
   Particle.variable("myvar", myvar);
}
1 Like

Hello Moors7,

Yes, the funny functions where made for this testing only. None of the combinations work? I've attached my cleaner code below too.

The below code is taken from the reference manual:
https://docs.particle.io/reference/firmware/photon/#ipaddress


```

void handler(const char *topic, const char *data) {
Serial.println("received " + String(topic) + ": " + String(data));
}

void setup() {
Serial.begin(115200);
for(int i=0;i<5;i++) {
Serial.println("waiting... " + String(5 - i));
delay(1000);
}

Particle.subscribe("spark/", handler);
Particle.publish("spark/device/ip");

}

<hr>

Here is my code below
<hr>

int LED = D7; // Onboard LED
String aString;

void setup()
{

pinMode(LED, OUTPUT);
digitalWrite(LED, HIGH);

Particle.subscribe("spark/", handler);
Particle.publish("spark/device/ip");
Particle.publish("spark/device/name");

}

void handler(const char *name, const char *value)
{

if (Serial.available()) // is only available when a connection & data has been recived.
    {
    Serial.printlnf("System version: %s", System.version().c_str());
    Serial.println("name: " + String::format("%s", String(name).c_str()));
    Serial.println("value: " + String::format("%s", String(value).c_str()));
    }

Particle.variable("Name", String(name).c_str());
Particle.variable("Value", String(value).c_str());
delay (1000);

}

void loop()
{

digitalWrite(LED, LOW);
delay(5000);
digitalWrite(LED, HIGH);
delay(5000);

}
<hr>

I just have quick second to write here so:

  • Serial.available() returns the number of characters that the Photon has recieved (i.e. you typed something) so that seems wrong.
  • You should declare your Particle.variables in setup() with global scope variables. You can assign to these in handler but the way your code is written now cannot work since the variable go out of scope and do not exist after you exit you handler routine.

Hello,

Serial.available() is working correctly ( it only sends back information if the serial interface is connected to usb ( it works and has no change on the output of Particle.variable if i remove it).

You may be correct on the Particle.variables? i’ll check for references but not sure how to correctly do this (i’m new to the photon ).

Thank you.
Mr.Deek

Hello,

Still not working… Still returning a blank value, see code below …

{
  "cmd": "VarReturn",
  "name": "Name",
  "result": "",
  "coreInfo": {
    "last_app": "",
    "last_heard": "2015-11-06T15:21:02.094Z",
    "connected": true,
    "last_handshake_at": "2015-11-06T15:20:41.264Z",
    "deviceID": "180028001447343338333633",
    "product_id": 6
  }
}

Code:


int LED = D7; // Onboard LED
  
void setup() 
    {
    
    pinMode(LED, OUTPUT);
    digitalWrite(LED, HIGH);

    Particle.variable("Name", "");
    Particle.variable("Value", "");
  
    Particle.subscribe("spark/", handler);
    Particle.publish("spark/device/ip");
    Particle.publish("spark/device/name");
    
    }


void handler(const char *Name, const char *Value) 
    {

    Particle.variable("Name", String(Name));
    Particle.variable("Value", String(Value));
    delay (1000);
    
    }


void loop() 
    {

    digitalWrite(LED, LOW);
    delay(5000);
    digitalWrite(LED, HIGH);
    delay(5000);

    }

@Moors7 now i’m wondering if that is why i’m having such issues pulling values at any time is that the values are only set very quickly and as you are saying not in the global scope The var would then be destroyed before the cloud polls the values?

I think there is a conceptual misunderstanding.

Particle.variables() are only set up once to expose a global variable and are not published (as you seem to be trying).
Once you've exposed a variable any change to the underlying variable will immediately be accessible via the Particle.variable().

Taking your code slightly refurbished

const int LED = D7;

String strName;
String strValue;

void setup() 
{
    pinMode(LED, OUTPUT);
    digitalWrite(LED, HIGH);

    Particle.variable("Name", strName);   // make strName available to the cloud
    Particle.variable("Value", strValue); // ditto for strValue
  
    Particle.subscribe("spark/", handler);
    Particle.publish("spark/device/ip");
    Particle.publish("spark/device/name");    
}


void handler(const char *Name, const char *Value) 
{
    strName = String(Name);   // new content will now be available as Particle.variable
    strValue = String(Value); // ditto
    // delay (1000); // NEVER delay a handler
}

To clarify for drivers-by: Since the Serial RX buffer is never read or flushed one byte entered will stay there and keep the expression TRUE forever.

1 Like

SOLVED: ANSWER:

Thank you very much i have a huge understanding now of how it is working …

Particle.variable is only a reference to the cloud to pull this variable when requested… and is not a push to the server of the current value as expected.

I’ve cleaned up my code for future working reference below.

Thank you again!


int LED = D7; // Onboard LED
String IP = "";
String NAME = "";

void setup() 
    {
    
    pinMode(LED, OUTPUT);
    digitalWrite(LED, HIGH);

    Particle.variable("IP", IP); // Tells the cloud to reference this global variable.
    Particle.variable("NAME", NAME); // Tells the cloud to reference this global variable.

    Particle.subscribe("spark/", handler); // Tells the cloud what information to listen for and what function to use.
    Particle.publish("spark/device/ip");   // Trigger to get this information (need to verify why it is needed) 
    Particle.publish("spark/device/name"); // Trigger to get this information (need to verify why it is needed) 
    
    }


void handler(const char *Name, const char *Value) 
    {

    if (String(Name).equalsIgnoreCase("spark/device/name"))
        {
        NAME = String(Value);
        }
    
    if (String(Name).equalsIgnoreCase("spark/device/ip"))
        {
        IP = String(Value);
        }

    }


void loop() 
    {

     if (Serial.available()) // is only available when a connection & data has been recived.
        {
        Serial.printlnf("System version: %s", System.version().c_str());
        Serial.println("Device Name: " + NAME);
        Serial.println("Device IP: " + IP);
        }
    
    digitalWrite(LED, LOW);
    delay(5000);
    digitalWrite(LED, HIGH);
    delay(5000);

    }
    
1 Like

The point here is that these infos are not available to the device itself but to the cloud (name is only stored there and the external IP is only visible from the "outside").

Any events starting with spark are reserved for Particle system use and so these two events actually are not directly meant for your device but instruct the cloud to send these events to your device with and add the referenced payload, so that you can subscribe to it.

My thoughts: Publishing to pull a value, seems a funny way of doing this? I would have expected to subscribe to 'spark/device/ip' to get the IP. Where if I subscribed to 'spark/device' i would get all underlying values.

I would have expected the syntax:

Particle.subscribe("spark/device", handler); //Expected result Array(ip=x,name=x, ...)
Particle.subscribe("spark/device/ip", handler);  //Expected result: 10.10.10.10
Particle.subscribe("spark/device/name", handler); //Expected result: DeviceName

It's just a little backward in my head :smile: but it does work!

Thank you.
Mr.Deek

Yes, but how would you instruct the cloud to publish an event that you have subscribed to?

Or would you expect them to be published on a regular basis? How often? For all Particle devices all over the world?

A subscription does not trigger anything, it just places a note in the cloud: “Whenever this event happens call my number”.
This does not cause the event to happen.

When you subscribe for a magazine, your subscription does not cause the magazine to be printed, but once it got printed you’ll get an issue delivered to the address you provided with your subscription.

And the publish to trigger a republish is like you want a historic issue of a mag you have subscribed to, so shoot them a letter and once the editor gets your letter (event) they will immediately send the already printed and archived issue.

Does this make more sense, seeing it this way?

1 Like

Yes but to get the information it requires a subscription and a trigger to instruct the cloud. Why not one line?

Example:
Particle.subscribe("spark/device/ip", handler);
Server Response:
Receives the registration and adds the IP to the feed queue to send back? They are special feeds, they could have special response triggers.

Were just taking about peace of programming mind not functionality....

Thank you.
Mr.Deek