Registering variables problem

Hi,

I have a number of Photon apps which register ‘Variables’. Works very well - UNTIL I decided to clean up one of these projects :-((.

Using 0.4.9

I though why not create a static class (call it ‘Cloud’). Create a set of static Strings and declare these are cloud variables.

I declared these as static ‘var_info’ etc.

When I call the ‘Startup’ function, all vars get registered and all report TRUE, so I print a message on my Serial1 port (used for debug).

Open up a CLI and type ‘particle list’ and my device says its on-line but has no vars :-((.

So - does a Cloud Var String HAVE to be declared in the top-level ino file ???.

Tried (individually)
res &= Particle.variable(“info”, var_info);
res &= Particle.variable(“info”, Cloud::var_info);
res &= Particle.variable(“info”, *Cloud::var_info);

All of these result in True

SO - this suggests to me that a class member cannot be used for a Cloud Var ???. OR that I don’t know how to pass the var into the register function :-O.

Anyone any pointers please ??? ('scuse the pun).

I need to set values for different vars in a few locations in my code, so a static ‘Cloud’ class seemed to make some sense (to me anyway) - better than global vars :-O.

Thanks

BR

Graham

There is no problem in general with making static class members cloud variables. You should just post your code so we don’t have to guess what might be wrong.

Hi,

OK —

   class Cloud
{
public:
  static bool NetworkConnected;
  static char version[100];
  static char sysinfo[622];
  static char cloudup[30];
  //these are the holding vars for the cloud 'Variables'
  static String var_info;
  static String var_config;

  static void Startup(void);

private:
};

    #include "cloud.h"

String Cloud::var_info = String("No info yet");
String Cloud::var_config = "";

bool Cloud::NetworkConnected = false;
char Cloud::version[100];
char Cloud::sysinfo[622];
char Cloud::cloudup[30];

void Cloud::Startup(void)
{
  delay(2000);
  bool res = true;
  res &= Particle.variable("info", var_info);
  delay(100);
  res &= Particle.variable("config", var_config);
  if (res == false)
    Serial1.print("\r\nRegister variables Failed\r\n");
  else
    Serial1.print("\r\nRegister variables OK\r\n");
}

Where do you call Cloud::Startup()? You can really only call it from setup() or loop() (once, controlled by a flag). You can’t call it from a constructor for a globally declared object or STARTUP block.

Hi,

Its called directly from Setup and even waits for a connection

while (Particle.connected() != true)
{
  Serial1.printf("\r\nWaiting for connect...");
  delay(1000);
}
g_HW.Init();
Cloud::Startup();
delay(100);
Serial1.print(ip);

But the point is that the register call says it was fine :open_mouth:

Not sure what’s wrong. I reduced it down to this code and it works fine for me. The variables show up in particle list as expected.

#include "Particle.h"

class Cloud {
public:
	static String var_info;
	static String var_config;

	static void startup(void);
};

String Cloud::var_info;
String Cloud::var_config;

void Cloud::startup() {
	Particle.variable("info", var_info);
	Particle.variable("config", var_config);
}

void setup() {
	Cloud::startup();
}

void loop() {

}

1 Like

Hmmmm interesting :open_mouth:

If I add the line below (before my call to startup, test gets registered and also accepts data being pushed into it :smile:

Serial1.printf("Registering test = %d", Particle.variable("test", Cloud::var_info));
Cloud::Startup();

So it HAS to be my startup function then :open_mouth:

OK then - so its the delay(2000) which is killing the registration process :-O. Take out that line and all is fine :-O,

I am using threading :open_mouth:
SYSTEM_THREAD(ENABLED);
//SYSTEM_THREAD(DISABLED);
SYSTEM_MODE(MANUAL);
STARTUP(CleanStartIOpins());

How bizarre - note for developers I guess - unless someone has a wild explanation ;-).

Thanks for your help…:wink:

Graham

Hi @GrahamS

You can see the same effect by having your Particle variable declarations in setup() after a long delay. When you think about what declaring a variable does, it just enters stuff into an internal data structure. The actual cloud connection mechanism is not synced to the setup() call, and too much delay means the declaration message to the cloud has already happened.

Hi @bko,

Thanks for this clarification - its exactly what I assumed was happening - AFTER finding the issue with delay :-O.

What it DOES however highlight (IMO) is that it is not clear in the docs that a variable cal ONLY be defined at app startup - NOR do we know how long we might have to complete that process. By returning TRUE - the ‘Particle.variable’ suggests to us that all is OK :-O. Had it returned FALSE - I would have known immediately :wink:

This means that a variable cannot be defined at some time later than this - say when a photon (etc.) has decided what it wants ‘to be’ based on some other external influence.

For example - it might want to ‘discover’ what is has connected to it before registering the vars to define results etc.

I may for example want to ‘poll’ on a serial but to see whats connected to that bus - and then declare a variable dependent on what I found ;-)).

NB I don’t see this as a problem - just something a developer needs to be aware of ;-)) - I obviously wasn’t…

If we were to allow ‘late declaration’ - we might also want a function to ‘unregister’ a previously defined var (to free up space maybe) ;-)). This capability would thus allow an external device to be connected, register itself with a variable, and then removed again, cleaning up when done, thus allowing some other device to be connected.

I DO provide serial buses on my photon devices - including RS485 devices, which can simply be plugged in and addressed…

Thanks again for all help received…

Best regards

Graham

I was under the impression that you could use Particle.variable() in loop(), as long as you only call it once per variable, but that does not appear to be the case, at least with 0.4.9 on the Photon as tested below. I thought that “loop” would be registered as a variable when D0 is brought low. It returns true, but the registration does not occur. What’s interesting is that if you tie D0 low so the code gets executed immediately, on the first loop after reset, it does get registered! I’ll have to dig into this some more when I have more time, because that doesn’t sound like the correct behavior to me.

#include "Particle.h"

bool loopRegistered = false;
int loopValue = 0;

void setup() {
	Serial.begin(9600);

	pinMode(D0, INPUT_PULLUP);
}

void loop() {
	if (digitalRead(D0) == LOW && !loopRegistered) {
		bool result = Particle.variable("loop", loopValue);
		Serial.printlnf("registering loop result=%d", result);

		loopRegistered = true;
	}
	loopValue++;
}

Hi @rickas7,

Well if its as @bko said - then this would happen. Seems there is a ‘time window’ when vars can actually be successfully registered :-O.

If so then the BUG is that it returns TRUE even when its NOT registered.

Seems that the var list is ONLY registered during startup. Maybe ??? if the cloud was disconnected - then connected again, this process would run again :open_mouth: - who knows (without diving into the code :open_mouth: ).

Thanks for your help though…

Graham

The result from Particle.variable() and Particle.function() isn’t really intended to be a flag that indicates that the cloud function actually succeeded, because that’s unknowable since it will happen some time in the future. It really only returns true if a few basic conditions are met, namely that the name is short enough (12 characters) and that the variable isn’t passed by reference (Particle.variable(“loop”, &loopValue)). That is working correctly, though it probably should be documented better.

One additional criterion to be met is that there has to be room to register an extra function/variable in the device (fixed len arrays).

The registration of fn/var has two sides.
The local part in the device itself can happen at any time (with or without cloud connection)
and
the remote part which is not actually done by the respective Particle.xxx() (since this doesn’t require cloud - as said above) calls but happens during “enumeration” some time after the connection got established.
So if you pull down the connection after registering a new fn/var, wait till the cloud side realizes the disconnect and then reestablish the connection, you should see the new fn/var.

I’m not sure if there might even be a spark/device/... event that could trigger a “re-enumerate”.

Maybe something for @mdma.

A while back, Dave explained the timing of the cloud registration of Functions&Variables here Case of the Missing Variables (emphasis added):

Unless this has changed - it means you have about 1s on startup before you need to have done the registration. This explains why delay(2000) stopped it from working :slight_smile:

1 Like

Correct, the variable / function registration is an all or nothing event that needs to either happen early in startup, or later. Make sure you don’t have any delays between registering functions or variables in a block, because if you have at least 1 func / var when the cloud asks, it’ll assume that’s all your firmware had. The cloud does support getting updates on that information at runtime, but the firmware doesn’t yet volunteer / push that information on change.

Thanks!
David

2 Likes

@Dave, how about my suggested “workaround” to disconnect/reconnect and even more what about a proposal for a re-register event that could be published by application code and a subscribe handler to make the firmware volunteer?

You could reconnect after registering a new func / var, but that would be a pretty big overkill / pretty expensive and would cause connection downtime in the firmware. :confused:

Thanks!
David

Hence “workaround” :wink:
And the event?

1 Like

I think it’s maybe easier to just register things early, no, and / or fix it in the system firmware. I guess I’m not sure what you mean by the event?

Thanks,
David