ChipChop Support Forum
Log in
Log out
Join the forum
My Details
REPLIES: 6
VIEWS: 276
BACK
REPLY TO THIS POST
Gizmo
08 Feb 2024
Trigger Events sync discussion
This is a continuation of the discussion (https://forum.chipchop.io/post/349/) with Mr @Hossrod and issues encountered when attempting to trigger notifications using triggerEvents


Hi Hoss,

I have done a ton of tests and here's some explanations. In your example (the one with the warning/error messages) I think the potential cause of the problem is enclosing both the triggerEvent and updateStatus one after another in the
    if ((millis() - loopCycle) > 10000) {

You are potentially getting the loopCycle to be in a close sync as the library's "sending of the status cycle" (within 501ms), which is ok, but if at the same time you hit the triggerEvent the library will try to postpone the triggerEvent to happen around 600ms later to keep the events spaced at least 500ms apart.

Now, the library will do it's best to keep that spacing but one factor it can not control and that's the exact speed the requests travel through the wires, satellites, swamps and whatnot. At the other end your API server (the ChipChop engine) doesn't know what is happening inside your device, it only knows when it gets slammed with your device requests.

If we are cutting those spacings tight depending on the latency, your ISP etc you can get two requests hitting the engine closer together than 500ms (when the first one travels a tad longer)
ChipChop does give some grace space for that reason (around +-80ms ish) but it may simply not be enough.

So, there are few solutions that can be implemented to give that extra breathing space. As I said, the library will do what it can but adding your own checks will give you a more fine grained control that you can always tweak in the future to match the specifics of what you are building.

I will just list these suggestions as a general ideas but I will put at the end a proper example, if it doesn't fit on this page I'll add another post.

1. encapsulate the triggerEvents in their own cycle check timer - downside of that is that you may miss an important alert like a motion sensor alarm if that cycle is too long (too short, back to the same story)

2. use something like a "debounce" method you would use on a push button. On the first event start a timer and send it, then if the same event happens again closer than let's say 600ms ignore it.
For exact these reasons many motion sensors will have an automatic cooling-off period (some up to 30sec) to avoid fast repetitive triggering.

3. in your case you want the alert on both state changes, in that case you can combine the two methods. It's pretty much what the library does but this would add an extra guarantee that the event will be delivered and not missed.

In the next post I will include an example code that I have used to push the limits and I have also done some tweaks to the library timings so it's a bit more strict but would actually increase the chance of successful delivery. The small sacrifice I had to make is if a timing collision is detected the eventTrigger will take precedence and push the heartbeat if needed for 1000ms.
This seems to work ok and only on a rare occasion I had a ChipChop warning "error: 408" and mostly with the delivery of the heartbeat not with the triggerEvent.

I have also uploaded a test version of the library for everyone to try (link in the next post)
Gizmo
08 Feb 2024

Read the first post before this one :-)

Ok, so here is something to try:

1. Download the test library here and just replace the "ChipChopManager.h &.cpp" files: http://chipchop.io/downloads/public/ChipChop-1.38.zip

Here is the test code roughly based on your examples. I have used a random generator to keep triggering the events and put set the timers quite low. You can play with those values.
Also, there is an option you can tweak by using ChipChop.hearBeatInterval(int seconds); the default is 10 sec but can be increased to 11,12...

You will have in the serial monitor a pretty good illustration of the flow of events,



//unsigned long loopCycle = 0;
String display_line1,display_line3,display_line4,display_line5;
unsigned long displayLoopCycle = 0;
bool light_state = 0;

int light_sensor_value = 0;
String Notification = "STOP";
unsigned long last_event_time = 0;


void loop(){

        ChipChop.run();

    bool can_send_immediately = 0;

        if(millis() - last_event_time > 600){ //we are ok to send

            if(Notification != "STOP"){ //we have something buffered/remembered from before, send it now

                ChipChop.triggerEvent("Notification","Office light turned on.");
        Notification = "STOP";

                last_event_time = millis(); //block the next sending for 600ms

            }else{
                bool can_send_immediately = 1; //allow an immediate send below
            }
        }    
    



if(millis() - displayLoopCycle > 200){ // we are acting on sensor states every 200ms, adjust this to what you want but keep it a lot less that 10000


    ///your display bits of code
    if((millis() - displayLoopCycle) > 200) {
    display_line1 = "Light Sensor";
    display_line3 = "BlueLED";
    display_line4 = "WhiteLED" ;
    display_line5 = "Temperature";
    displayUpdate();
         displayLoopCycle = millis();
     }


         bool can_send_immediately = 0;

        if(millis() - last_event_time > 600){ //we are ok to send

            if(Notification != "STOP"){ //we have something buffered/remembered from before, send it now

                ChipChop.triggerEvent("Notification","Office light turned on.");
Notification = "STOP";

                last_event_time = millis(); //block the next sending for 600ms

            }else{
                bool can_send_immediately = 1; //allow an immediate send below
            }
        }    

//we will fake the sensor reading by using a random number
light_sensor_value = random(100); //<<< dirty little random generator

    bool prev_light_state = light_state;

    if (light_sensor_value > 50) { //<<using the random generated number
        light_state = true;
     }else {
        light_state = false;
    }

    if(millis() - debounce_timer > 200){ // we are checking some sensor state every 200ms, adjust this to what you want but keep it a lot less that 10000
if (prev_light_state != light_state) {

    if (light_state) {
        Notification = "Office light turned on.";
    }else {
        Notification = "Office light turned off.";
    }
    if(can_send_immediately == 1){
         ChipChop.triggerEvent("Notification", Notification);
        last_event_time = millis();
        }
    //we are debouncing/preventing any checks in case it was just a fast flicker or fluctuation in the sensor reading
    debounce_timer = millis();
    }else{

    Notification = "STOP";
    }    
}

    // if((millis() - loopCycle) > 10000) {

     ChipChop.updateStatus("BlueLED", blue_led_status);
    ChipChop.updateStatus("WhiteLED", white_led_status);
    ChipChop.updateStatus("LightSensor", light_sensor_value);
     ChipChop.updateStatus("Temperature", temperature_sensor.getTempFByIndex(0));
    ChipChop.updateStatus("Notification", "STOP"); // <<< we are not using the Notification variable here but explicitly sending STOP as a status otherwise we could get multiple notifications


     // }

}


Thezzi Mfkr
08 Feb 2024

is this library something customised for @Hossrod and you want someone else to test it or it's a general update?
Hossrod
08 Feb 2024

@Gizmo

Sorry for the delay. Life happens, job hunting, etc. :)

I'll give this a go, hopefully tonight or tomorrow.

Just FYI, I've switched to a ESP32-WROOM-32 model as it has a display I'm testing. I've also reverted the Espressif library to latest stable version 2.0.11 from the 3.0.0-alpha I was using with the C6 (still on Arduino IDE, still plan on switching to platform.IO). This is the configuration I was using when when getting this most recent issue with timing this thread is about.



Attached images
Gizmo
09 Feb 2024

uuu..that's a sexy looking little board!

Didn't know you were job hunting!? maybe I should make a ChipChop "job board" page and be the cyber-pimp, I'll sell ya right n' good (maybe not what you want to do...but... :-)

No seriously man, if you want to expand your resume into the IoT automation/integration side I'm happy to set you up a private ChipChop node and work together to bash it to its limits...I don't mean like becoming a "certified" ChipChop engineer...lol...more so that you can experiment really quickly with hardware>software>cloud>client>whatnot concepts.

Heck, I run this joint and will do anything to help good people, we seem to have a lot in common so mi casa es su casa amigo.
Hossrod
09 Feb 2024

I only do sexy. :)

Thanks, I might take you up on that offer depending how things go (I'm in no rush to find a job, so looking for the "right" job).

I'm going to email you my code. I had to make changes from your sample code a bit to make it integrate with my existing code. I got it working, but I am getting some odd results. Here is a sample of what I'm talking about from my log...


12:50:30.949 -> ChipChop => {"api_call":"heartbeat","command":"heartbeat","uuid":"xxx","device_id":"000001","status":{"Notification":{"value":"Office light turned on."},"BlueLED":{"value":"OFF"},"WhiteLED":{"value":"OFF"},"LightSensor":{"value":102},"Temperature":{"value":76.44}}}
12:50:32.242 -> ChipChop => {"status":"ok","timestamp":1707483032716}
12:50:37.388 -> ChipChop => {"api_call":"heartbeat","command":"triggerevent","uuid":"xxx","device_id":"000001","status":{"Notification":{"value":"Office light turned off."}}}
12:50:38.662 -> ChipChop => {"status":"ok","timestamp":1707483038723}
12:50:41.186 -> ChipChop => {"api_call":"heartbeat","command":"heartbeat","uuid":"xxx","device_id":"000001","status":{"Notification":{"value":"Office light turned off."},"BlueLED":{"value":"OFF"},"WhiteLED":{"value":"OFF"},"LightSensor":{"value":2362},"Temperature":{"value":76.44}}}
12:50:42.499 -> ChipChop => {"status":"ok","timestamp":1707483042725}
12:50:51.427 -> ChipChop => {"api_call":"heartbeat","command":"heartbeat","uuid":"xxx","device_id":"000001","status":{"Notification":{"value":"Stop"},"BlueLED":{"value":"OFF"},"WhiteLED":{"value":"OFF"},"LightSensor":{"value":0},"Temperature":{"value":76.44}}}
12:50:51.472 -> event delay for 1 sec
12:50:52.483 -> ChipChop => Event will not be sent. Max requests speed of 500 milliseconds between events has been exceeded.
12:50:53.713 -> ChipChop => {"status":"ok","timestamp":1707483052734}
12:51:02.667 -> ChipChop => {"api_call":"heartbeat","command":"heartbeat","uuid":"xxx","device_id":"000001","status":{"Notification":{"value":"Stop"},"BlueLED":{"value":"OFF"},"WhiteLED":{"value":"OFF"},"LightSensor":{"value":2379},"Temperature":{"value":76.44}}}
12:51:03.970 -> ChipChop => {"status":"ok","timestamp":1707483063743}
12:51:12.918 -> ChipChop => {"api_call":"heartbeat","command":"heartbeat","uuid":"xxx","device_id":"000001","status":{"Notification":{"value":"Stop"},"BlueLED":{"value":"OFF"},"WhiteLED":{"value":"OFF"},"LightSensor":{"value":2373},"Temperature":{"value":76.32}}}
12:51:14.198 -> ChipChop => {"status":"ok","timestamp":1707483074753}


It says Event will not be fired as 500ms has been exceeded.

Also, when office light was turned off in the above log, I see both a triggerevent and a heartbeat event both with {"Notification":{"value":"Office light turned off."}. Should this even be possible with my code? The only call I have in my code to ChipChop.updateStatus() for "Notification" is hard coded to "Stop".

FYI, this is with your v1.38 cpp and h files.
Gizmo
09 Feb 2024

no worries, I'll have a look. I can see what you mean, that does look wrong!