[Solved] Failing to update spark.variable

Hi,

I am trying to update a variable with the attached code but when I read the variable it it always shows high.I know the if statement is working because the LED flashes. Can you help me understand what I am doing wrong in my code below?

Best regards,
Clive

//Test spark.variable

int periodSlice = 10000;
char *status;
unsigned long lastRun = 0;
int state = 1;
int ledPin = D7;

void setup()
{
    pinMode(ledPin, OUTPUT);
}

void loop()
{

    Spark.variable("LED_State", status, STRING);

    if ((millis() - lastRun < periodSlice  && lastRun != 0) && millis() >= lastRun) return; //Check once every periodSlice, unless we havent checked yet, or if time since overflow of millis is less than last time we checked

    lastRun = millis();

    //Toggle LED

    digitalWrite(ledPin, state);

    if (state == 1)
    {
        status = "HIGH";
        state = 0;
    }
    else
    {
        status = "LOW";
        state = 1;
    }
}

A couple of issues:

  1. Spark.variable goes in the setup. It shouldn’t be called every loop
  2. You can expose your state variable directly. You don’t need a second status variable. See modified code below. TBH it isn’t tested so feel free to come back with issues
    int periodSlice = 10000;
    unsigned long lastRun = 0;
    int state = 1;
    int ledPin = D7;

    void setup()
    {
        pinMode(ledPin, OUTPUT);
        Spark.variable("state", &state, INT);
    }

    void loop()
    {
        if ((millis() - lastRun < periodSlice  && lastRun != 0) && millis() >= lastRun) return; //Check once every periodSlice, unless we havent checked yet, or if time since overflow of millis is less than last time we checked
   
        lastRun = millis();
    
        //Toggle LED
    
        digitalWrite(ledPin, state);
    
        if (state == 1)
        {
            state = 0;
        }
        else
        {
            state = 1;
        }
    }
1 Like

Hi,

Many thanks for this it works but gives me the inverse of what I am looking for. That is why I set up the secondary variable. I can fix that in my local code so no issue really.
May I ask can a bool be advertised with spark.variable too?

best regards
Clive

Hi,

Sorry I just saw in the docs that bool is not supported.

best regards,
Clive

Glad you got everything sorted! I’m going to go ahead and mark this [Solved]. If that’s not right just respond and we’ll keep figuring this out.

Hi,

Sorry I set up a second int that mirrors this and use it in the variable it works great. I tried again with a string and it only ever shows high, in my original code have I done something wrong in defining or utilising the char *variable and string?

Many thanks,
Clive

im sorry its still not working… ill try to get to it first thing in the morning.

@casm, I guess your problem with the string version comes from your use of an uninitialized pointer char*.
With your code you might even corrupt some memory you haven’t claimed propperly.

Try to declare char status[5]; and use strcpy(status, "HIGH"); and strcpy(status, "LOW"); instead.

As I understand it with your code, the string assignment status = "HIGH"; does not actually copy the four chars (plus one zero terminator '/0') into the place *status is pointing at, but rather moves the pointer to the memory location where the compiler had placed the ´"HIGH"´ literal at compile time.
When later on "LOW" is assigned the pointer gets redirected again, but by that time the Spark.variable() call will not touch the already saved pointer anymore and so it will always return the contents of the original mem location.

1 Like

@ScruffR is correct! Because you are only passing the initial pointer’s value (what it is pointing to ie, a memory address) to Spark.variable() when you attempt to “GET” the variable using the cloud the spark only knows to return what’s at the memory address. Changing the pointer’s value later using assignment like

status = "High"

changes the pointers value only. If the spark api allowed us to instead pass the pointer’s memory location (&status) and then deferenced that (twice I think?) when doing the GET then what you attempted to do @casm would work!

Here’s an updated code snippet that does what you want (I think) using what @ScruffR suggested.

int periodSlice = 10000;

char status[5] = "INIT";

unsigned long lastRun = 0;
int state = 1;

void setup()
{
    Spark.variable("LED_State", status, STRING);
    RGB.control(true);
}

void loop()
{
    if ((millis() - lastRun < periodSlice  && lastRun != 0) && millis() >= lastRun) return; //Check once every periodSlice, unless we havent checked yet, or if time since overflow of millis is less than last time we checked

    lastRun = millis();

    if (state == 1)
    {
        strcpy(status, "HIGH");
        state = 0;
        RGB.color(255, 255, 0);
    }
    else
    {
        strcpy(status, "LOW");
        state = 1;
        RGB.color(0, 255, 255);
    }
}

Thanks very much to everyone for helping with this. I am quite new to programming the spark.core. I think I need to read up on this some more.

Best regards,
Clive

Alright. I’m going to mark this topic [Solved] but feel free to come back with any additional questions!

Hi

Attached is the final working code should anyone need it. many thanks to both of you.

best regards,
Clive

 int periodSlice = 600000;
unsigned long lastRun = 0;
int state = 1;
char status[5];
int ledPin = D7;

void setup()
{
    pinMode(ledPin, OUTPUT);
    Spark.variable("LED_state", status, STRING);
}

void loop()
{
    if ((millis() - lastRun < periodSlice  && lastRun != 0) && millis() >= lastRun) return; //Check once every periodSlice, unless we havent checked yet, or if time since overflow of millis is less than last time we checked

    lastRun = millis();

    //Toggle LED

    digitalWrite(ledPin, state);

    if (state == 1)
    {
        state = 0;
        strcpy(status, "ON");
    }
    else
    {
        state = 1;
        strcpy(status, "OFF");
    }
}
2 Likes