Unsuccessfully trying to make dashboard snappier

I am currently trying to make my dashboard snappier and save transmission data at the same time.

Some of my data are calculated from user inputs and will only change when a new user input happens.
I think that it is inefficient to show these data n a polled process.
My idea is to group the few user-related data into a PSON structure:
thing[“control”] >> [](pson & out)
{
out[“bat_CV”] = dashboard.CVbat;
out[“bat_CC”] = dashboard.CCbat;
//…
};
…and then start a thing.stream(“control”);
when variables are changed and only then.

The display in the dashboard should be set on “Stream by device”

   thing["scv"]  = [](pson & in, pson & out)
    {
      if (in.is_empty())
      {
        in = CVbat;
      } else {
        CVbat = in;
      }
      dashboard.CVbat = float(in) / 1000;
      thing.stream("control");
      out["batCV"] = dashboard.CVbat;
    };

That way to user data is just uploaded to Thinger when the user interacts.

But that did not work.
Isn’t that doable?
Which mistake did I do, that it does not update the data in the dashboard?

Thank you for your advice.
Laszlo

Hi, @rin67630, we have this solved in new IOTMP libraries that will be released soon. The dashboard now support input/output resources as control/source values. Previously this was not possible, and Arduino libraries were not prepared. Fortunately, this can be solved easily.

Please, modify your thinger.h library, at line 573:

Change this:

if(thing_resource->stream_enabled() && thing_resource->get_io_type()==thinger_resource::pson_in)

To this:

if(thing_resource->stream_enabled() && (thing_resource->get_io_type()==thinger_resource::pson_in || thing_resource->get_io_type()==thinger_resource::pson_in_pson_out))

This way, you can have an input/output resource like this:

  thing["input_output"] = [](pson& in, pson& out){
    static float current = 0;
    if(in.is_empty()){
      in = current;
    }else{
      current = in;
    }
    out = ((float)in)/10; 
  };

And set your control widget over this resource, and your text field or other widget taking the data from this resource also configured with Stream by Device.

This way, you can have a much more performant dash, taking calculated updates only when there changes. Then, you dont need an additional resource for calculated values, grouping them, etc.

Example of the above resource working with the applied patch:

Hope it helps!

1 Like

Just looking into this, I have modified the console to also support control values over resoruces with multiple input values (i.e., a resource that can take several input parameters). You will have to wait a little to see changes in public community version, but here its the example that can be working soon:

Example resource:

  thing["inputOutput"] = [](pson& in, pson& out){
    static int val1=0, val2=0;
    if(in.is_empty()){
      in["val1"] = val1;
      in["val2"] = val2;
    }else{
      if(!in["val1"].is_empty()){
        val1 = in["val1"];  
      }
      if(!in["val2"].is_empty()){
        val2 = in["val2"];    
      }
    }
    out["sum"] = val1+val2;
    out["mult"] = val1*val2;
  };
}

Example dash:

Thank you so much for being so reactive even on Sundays!
:heart::heart:

How is the text widget defined?
I have some difficulties to understand the logic behind.
What stands in the variable current?
The division by 10 was only for out, isn’t it?
Can I write it:

thing["input_output"] = [](pson& in, pson& out){
    static integer current = 0;
    float current_f = 0;
    if(in.is_empty()){
      in = current;
    }else{
      current = in;
    }
    current_f = ((float)in)/10; 
    out = current_f;
  };

Hi!, you are welcome @rin67630

the current variable is not required to be defined, it is defined just for the exmaple. In your case, the current would be CVbat, as before. Also, the division by 10 is for the example. Taking your first resource as example, it would be something like:

    thing["scv"] = [](pson & in, pson & out)
    {
      if (in.is_empty())
      {
        in = CVbat;
      } else {
        CVbat = in;
      }
      out = float(in) / 1000;
    };

For your text widget (or any other widget) requiring the update, just select the scv as source, and Stream by Device.

Aha! so no thinger.stream() call is required. I was not aware of that.
Thank you for that clue.

And I suppose, if I write it that way, i can get the float to use in my sketch variable “dashboard.CVbat” as well?

    thing["scv"] = [](pson & in, pson & out)
    {
      if (in.is_empty())
      {
        in = CVbat;
      } else {
        CVbat = in;
      }
      dashboard.CVbat = out = float(in) / 1000;
    };

No manual stream is required, as it is currently handled by the thinger.io library (just a few lines below the change we introduced in thinger.h). The library basically knows that the resource is currently being “monitored”, and after an incoming request, it retransmit the input and output states to those listeners. This way, it is possible to monitor the current resource state in several dashboards at the same time (you can open 2 dashboards for the same device and move the slider on the first, and see how automatically moves on the second). If the device is not being monitored (i.e. from dashboards or other websocket requests), and you request a change from REST API, it would not send anything back, saving bandwidth.

Of course, you can update any parameter in your sketch as you did in your last example :wink:

Thank you for these explanations on the clever-made Thinger background processes.
It could be good to publish this knowledge in the coding guide.
I begun with Thinger with streaming everything permanently, thinking it were more efficient than letting the dashboard poll the values. (a bad habit from MQTT :shushing_face:).
Indeed Thinger offers several methods to forward the information, some are just better for both the server load and the device processes.
Thinger does it on a cleverer way: you could advertise with that!

Hi, thanks for your kind words :slight_smile:

Yes, we should add some technical section about Thinger background processes, and how clients and resources behave. I think it will arrive with the release of IOTMP that is currently being tested (not ready for release: https://docs.iotmp.io/). At now, current protocol implementation in Arduino/server is not documented at all, and lacks some optimizations and features we can bring with IOTMP, including the possibility to work as MQTT for subscribing and publishing to topics, listen to server events, listen for properties updates, support different programming languages, etc.

But yes, the paradigm in thinger is different from MQTT. In MQTT devices just publish the information periodically, independently if anyone is looking for it, being used for something, etc. In thinger.io, the paradigm is different in the way that by default, no-one resource is streamed or executed unless the server is listening for it, i.e., a websocket/dashboard is open to listen for devices updates, a bucket is configured for writing from a device resource, etc. In this sense, even if you call thing.stream over a resource, it will not be actually streamed if the server does not have a destination for it.

The server has also some goodies, i.e., if a dashboard/websocket request updates from a device resource at 10 seconds, and a second dashboard requires the same resource, but at 5 seconds interval, it computes the GCD between all requests and configure the device to stream a this interval, in this case, it would be 5 seconds. Then, it delivers the information to each destination at is desired pace.

The problem to advertise with these low level details is that not all people understand it or give it enough importance.

I just did your patch.

If someone else wants to do it as well, the line to replace must in both cases end with an opening curly brace. (b.t.w: I always put my opening curly braces at an extra line, i know, it’s not the recommended programming style, but it just avoids such mistakes).

Please, modify your thinger.h library, at line 573:

Change this:

if(thing_resource->stream_enabled() && thing_resource->get_io_type()==thinger_resource::pson_in){

To this:

if(thing_resource->stream_enabled() && (thing_resource->get_io_type()==thinger_resource::pson_in || thing_resource->get_io_type()==thinger_resource::pson_in_pson_out)){

If you forget the curly brace, you get a bench full of weird compiler errors!

I followed your instructions.
I experience now a lag of ~0,5 to 1 second, but there is more Internet lag between my device and your servers.

Anyhow a big THANK YOU! it is much better now!
:heart::heart:

Hi @rin67630, thanks for report that it worked!

These lags seems to be ok taking into account how is traveling the information:

Your broswer -> Server
Server -> Device (Here your device executes the command)
Device -> Server
Server -> Browser (Here you see the actual response)

Bests