Visual feedback (leds) @ error


  • Hardware Contributor

    Hi!

    I'm not sure how widely this can be used, or if its a lot of work with a small area of use.

    I have an idea of implementing garden lights, and when I start/reboot these or during operation when something goes wrong (Init fail, no reply, error signing and so on...) I want to be able to create a light pattern to visually indicate the error. The LEDs will already be attached since I'm going to use an RGB strip and I will probably have some sort of on/off switch. So during deployment, reboot or operation, I have this idea of getting a visual feedback depending on the error.

    This could be used as a MysX shield as well on regular nodes (build a MysX board and attach to any MysX board)

    I'm of course going to debug with serial the first time I upload, but it would be nice to be able to get the visual feedback if the node goes into an error state or loses its connection.

    A possible problem might be the controller going down and with 10+ lights, you suddenly have a Christmas lights arrangement... fun for the neighbours.

    Any thoughts on this?? Would this be hard to implement?


  • Hardware Contributor

    Hi,

    there is already an indication management in MySensors (thx to @Yveaux ).
    It's maybe not complete for what you're asking for, but you can easily expand it.

    https://forum.mysensors.org/topic/9286/radio-traffic-leds-lights-up-on-heart-beat/12
    https://forum.mysensors.org/topic/7181/what-do-the-error-led-flashes-mean/11


  • Contest Winner


  • Hardware Contributor

    @anticimex @scalz - thanks I have seen those, but currently, I don't understand how to implement it in my idea. I will have to dig some deeper into this to get more understanding. Is it that easy that you get a true if the variable in MyIndication.h is present and you can blink the led that way?


  • Mod

    @sundberg84 I can guide you through the use of indication() and I also have a led pattern blinking library that seems to suit your application.
    I'll come back on this, hopefully this evening.


  • Mod

    @sundberg84 the indication system in MySensors allows a user's sketch to receive events each time the MySensors stack does something 'meaningful' or detects an error condition.
    The core/MyIndication.h file contains an enum indication_t that defines all events that will be generated by the stack; e.g. INDICATION_TX indicates a message is about to be sent over the air to a node and INDICATION_ERR_TRANSPORT_FAILURE indicates a problem with the transport layer (radio defect).

    The stack itself implements a setIndication() handler for these events (I removed the #ifdefs for readability):

    void setIndication( const indication_t ind )
    {
        if ((INDICATION_TX == ind) || (INDICATION_GW_TX == ind)) {
            ledsBlinkTx(1);
        } else
        if ((INDICATION_RX == ind) || (INDICATION_GW_RX == ind)) {
            ledsBlinkRx(1);
        } else
        if (ind > INDICATION_ERR_START) {
            // Number of blinks indicates which error occurred.
            ledsBlinkErr(ind-INDICATION_ERR_START);
        }
    }
    

    As you can see it blinks the Tx led one time when an INDICATION_TX or INDICATION_GW_TX event is received, it blinks the Rx led one time when an INDICATION_RX or INDICATION_GW_RX event is received, and it blinks the error led a number of times, depending on the actual error event code.

    The error events are defined in a separate range of the indication_t enum, starting from INDICATION_ERR_START which is defined as 100.
    As you see in the code above, in case of errors the INDICATION_ERR_START value will be substracted from the actual event value.
    The first actual error in indication_t is defined as INDICATION_ERR_HW_INIT (its value is 101), and will therefore cause the error led to blink 1 time.
    The next error in indication_t is defined as INDICATION_ERR_TX(its value is 102), and will therefore cause the error led to blink 2 times, etc.

    The fun thing is, you can define your own handler which receives exactly the same events as this piece of LED blink code from the stack does!

    To enable it, define MY_INDICATION_HANDLER before the MySensors-include in your sketch:

    #define MY_INDICATION_HANDLER
    #include <MySensors.h>
    

    Now, anywhere in your sketch add the following function:

    void indication( const indication_t ind )
    {
        // .. act on events you're interested in ..
        // Not a very useful example, but I hope you get the point
        if (INDICATION_TX == ind) {
            // turn my garden lights on
            digitalWrite(GARDEN_LIGHTS_PIN, HIGH);
        }
        if (INDICATION_RX == ind)
            // turn my garden lights off
            digitalWrite(GARDEN_LIGHTS_PIN, LOW);
        }
    }
    

    Make sure to not stay long in this function, as it will block the MySensors stack from running! Do the bare minimum of what you need to do and exit. Don't use delay() and the like, and don't call any MySensors functions from it!

    The gateway from @Japio uses the indication() function. (Note that he doesn't define MY_INDICATION_HANDLER as it was written for an older version of the library).

    My dollhouse sketches also use the indication() handler, but I wrapped it into a library as the implementation is shared for all sketches.

    This dollhouse library also uses my Arduino LedPattern library what was the other thing suitable for your application.
    Instead of having to code all kinds of different LED blinking patterns, you can simply define them as (repeating) sequences in your code and call an update function at regular intervals. The library automagically blinks and/or fades the LEDs in the defined pattern without having to worry about a thing.

    Definition of a basic sequence to fade a LED looks like:

    // A repeating sequence of fading the LED to on
    // in 50 cycles, then fading back to off in 100 cycles.
    const uint8_t myPattern[] = {
        LedPattern::CMD_SET, OFF,
        LedPattern::CMD_REPEAT, LedPattern::repeatForever, 
            LedPattern::CMD_FADETO,  50, LED_ON,
            LedPattern::CMD_FADETO, 100, LED_OFF,
        LedPattern::CMD_ENDREPEAT
    };
    

    To start the fading pattern, just call

    pattern.start(myPattern);
    

    And in your loop() you call update regularly:

    void loop()
    {
      // Update pattern state. LED gets updated and the pattern gets parsed.
      pattern.update();
      
      // Wait 1 time (10ms) cycle before updating again.
      delay(10);
    }
    

    Another option is to call update() from e.g. a timer interrupt.
    The library supports regular LEDs (or garden lights 😉 ), RGB LEDs, NeoPixels and FastLED library. See the readme and examples that come with it.

    Now, if you look again at the dollhouse sketch library, you see I defined a number of different blinking patterns for different states of the stack:

    const uint8_t ledPatternJoin[] = {
      LedPattern::CMD_REPEAT, LedPattern::repeatForever,
      LedPattern::CMD_SET, LED_ON,
      LedPattern::CMD_WAIT, 10,
      LedPattern::CMD_SET, LED_OFF,
      LedPattern::CMD_WAIT, 50,
      LedPattern::CMD_ENDREPEAT
    };
    
    // ...
    
    const uint8_t ledPatternTxRx[] = {
      LedPattern::CMD_SET, LED_ON,
      LedPattern::CMD_WAIT, 1,
      LedPattern::CMD_SET, LED_OFF,
      LedPattern::CMD_FINISHED
    };
    

    These patterns are started from the indication() handler I explained above (simplified):

    void indication( const indication_t ind )
    {
      if (     INDICATION_TX == ind)
           || (INDICATION_GW_TX == ind)
           || (INDICATION_RX == ind)
           || (INDICATION_GW_RX == ind) )
        {
           ledPattern.start(ledPatternTxRx);
        }
      } else if (INDICATION_FIND_PARENT == ind)
      {
        ledPattern.start(ledPatternJoin);
      } // ... else ... 
    }
    

    So any TX/RX event from the stack will play the ledPatternTxRx sequence, and when the node starts searching for a parent the ledPatternJoin sequence is played!
    You might want to block starting new patterns once a pattern is playing to prevent getting a blinking mess when events come in rapidly. The ledPattern.finished() function tells you if a pattern is currently playing or not.

    Note that these sketches use MsTimer2 to time the LedPattern update() calls.

    Combining these two techniques in your gardenlights will certainly drive your neighbours crazy 😜


  • Hardware Contributor

    @yveaux thanks for taking your time to explain. I really appreciate it. Now I understand how to implement this and all above is a great guide for other as well. Really pedagogical and easy to understand for a coding newbie. I will report this back when I got my project ongoing. Have a great weekend and i will buy you a beer if we anytime meet!!

    This could btw be used in a tutorial on the website for others... just my thoughts.


  • Contest Winner

    @yveaux excellent writeup. Perhaps parts of it can be included in a doxygen segment for the MyIndication "module"? I can assist with doxygen support if needed.


  • Mod

    @sundberg84 said in Visual feedback (leds) @ error:

    This could btw be used in a tutorial on the website for others... just my thoughts.

    @sundberg84 @Anticimex Yeah, I know I should, but this alone already burned my spare time for tonight 😅

    Anyway, now I have an extra excuse to meet you guys for a 🍻 !


 

332
Online

7.4k
Users

8.3k
Topics

89.6k
Posts