Cannot fathom why just one LED won't work with a particular library but will with another library

I’ve just started using @harrisonhjones’s “LEDEffect” library as I wanted to be able to easily set LEDs to blink or breathe without dealing with a lot of millis timers etc in my loop.

Now I’ve got the absolute darndest problem that I CANNOT figure out. It’s nearly midnight here and that might have something to do with it.

One of my LEDs just WILL not function - AT ALL - with this code. I’ve tried moving the pin assignment about, the problem follows this particular LED (i.e. it doesn’t light).

However, if I either
a) leave wiring wholly intact BUT roll back to previous code before I involved this library, the LED functions as before (so it can’t be a problematic I/O pin?
b) if I connect the LED directly to the Photon’s gnd and 3.3v it lights.

I’m guessing I’ve made an error somewhere in the code, but I removed everything from my loop except “OfficeLED.on();” and STILL it didn’t work. I had a brainwave and wondered if it was because I’d come up against a programmed in limit for number of LEDs the library is default configured to deal with but can find no evidence for this in the library files. And I moved the declaration of the problematic pin from last to first. Nothing changed. HELP!!
Thanks
P.S. I am SURE this will turn out to be something (in my code? it must be!) rather than a @harrisonhjones bug by the way…

#include "Alert.h"
#include "JC_Button.h" 
#include <LEDEffect.h>

using namespace Alert;

SYSTEM_THREAD(ENABLED);

// PUB-SUB constants
constexpr char * DEVICE_NAME = "ALERT";
constexpr char * WINDOWSHUT_MSSG = "Office window shut.";
constexpr char * WINDOWOPEN_MSSG = "Office window open.";
constexpr char * BWINDOWSHUT_MSSG = "Bathroom window shut.";
constexpr char * BWINDOWOPEN_MSSG = "Bathroom window open.";
constexpr char * BDSHUT_MSSG = "Bathroom door shut.";
constexpr char * BDOPEN_MSSG = "Bathroom door open.";
constexpr char * SDCLOSED_MSSG = "Sliding door closed.";
constexpr char * SDOPEN_MSSG = "Sliding door open.";
constexpr char * KEEPBOLT_MSSG = "Stores door locked.";
constexpr char * KEEPOPEN_MSSG = "Stores door unlocked.";
constexpr char * MDKEEPBOLT_MSSG = "Main door locked.";
constexpr char * MDKEEPOPEN_MSSG = "Main door unlocked.";
constexpr char * RSATUS_MSSG = "Requesting Status";
constexpr char * SHOPL_MSSG = "SHOPLIFTER";
constexpr char * RESCUE_MSSG = "RESCUE";
constexpr char * RAIN_MSSG = "RAIN";

int slidingstate = 3;
int Storeskeepstate = 3;
int officewindowlocked = 3;
int bathroomwindowlocked = 3;
int maindoorlocked = 3;

LEDEffect BathroomLED(D3);	//should be D3
LEDEffect OfficeLED(D4);	//should be D4
LEDEffect SlidingLED(D0);	//Should be D0
LEDEffect StoresLED(D1);	//should be D1
LEDEffect MainLED(D2);	//should be D2






// function declarations
void eventHandler(const char * event,
        const char * data);

#include "DFRobotDFPlayerMini.h"
#include "TimeAlarms/TimeAlarms.h"
DFRobotDFPlayerMini myDFPlayer;
void printDetail(uint8_t type, int value);

boolean alreadyRun = false;

void setup() {

        Particle.subscribe(DEVICE_NAME, eventHandler, MY_DEVICES);
        setZone();
        Serial.begin(9600);
        
        Particle.function("slstate", setSlidingState);
        Particle.function("cvstate", setStoresState);
        Particle.function("mnstate", setMainState);
        Particle.function("ofstate", setOfficeState);
        Particle.function("btstate", setBathState);
        

        Alarm.alarmRepeat(8, 1, 00, setZone);

        Serial1.begin(9600);

        if (!myDFPlayer.begin(Serial1)) { // use Serial1 to communicate with mp3.
                Serial.println(F("Unable to begin:"));
                Serial.println(F("1.Please recheck the connection!"));
                Serial.println(F("2.Please insert the SD card!"));
                while (true);
        }
        Serial.println(F("DFPlayer Mini online."));

        myDFPlayer.setTimeOut(500); //Set serial communictaion time out 500ms

        //----Set volume----
        myDFPlayer.volume(30); //Set volume value (0~30).
        myDFPlayer.volumeUp(); //Volume Up
        myDFPlayer.volumeDown(); //Volume Down

        //----Set different EQ----
        myDFPlayer.EQ(DFPLAYER_EQ_NORMAL);

        //----Set device we use SD as default----
        //  myDFPlayer.outputDevice(DFPLAYER_DEVICE_U_DISK);
        myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);

        //----Read imformation----
        Serial.println(myDFPlayer.readState()); //read mp3 state
        Serial.println(myDFPlayer.readVolume()); //read current volume
        Serial.println(myDFPlayer.readEQ()); //read EQ setting
        Serial.println(myDFPlayer.readFileCounts()); //read all file counts in SD card
        Serial.println(myDFPlayer.readCurrentFileNumber()); //read current play file number
        Serial.println(myDFPlayer.readFileCountsInFolder(3)); //read fill counts in folder SD:/03

}

void loop() {
        if (alreadyRun == false) {
                InitialPub();
        }
        SlidingLED.update();
        StoresLED.update();
        BathroomLED.update();
        OfficeLED.update();
        MainLED.update();
        ToggleSwitchAction::update();
        //digitalClockDisplay();
        MillisTimer::processTimers();

        Alarm.delay(0); // wait one second between clock display

        static unsigned long timer = millis();

        if (millis() - timer > 3000) {
                timer = millis();

        }

        if (myDFPlayer.available()) {
                printDetail(myDFPlayer.readType(), myDFPlayer.read());
        }

        if (Time.hour() >= 8 || Time.hour() < 16) //time between 0800 and 1500 
        {
                if (Storeskeepstate == 0) {
                        StoresLED.blink(125);
                } else {
                        StoresLED.off();
                }
                if (slidingstate == 0) {
                        SlidingLED.blink(125);
                } else {
                        SlidingLED.off();
                }
        }
        if (Time.hour() >= 17 || Time.hour() <= 23) {
                if (bathroomwindowlocked == 0) {
                        BathroomLED.breath(30);
                } else {
                        BathroomLED.blink(125);
                }
                if (Storeskeepstate == 0) {
                        StoresLED.breath(30);
                } else {
                        StoresLED.blink(125);
                }
                if (slidingstate == 0) {
                        SlidingLED.breath(30);
                } else {
                        SlidingLED.blink(125);
                }
                if (maindoorlocked == 0) {
                        MainLED.breath(30);
                } else {
                        MainLED.blink(125);
                }
                if (officewindowlocked == 0) {
                        OfficeLED.breath(30);
                } else {
                        OfficeLED.blink(125);
                }
        }

}

// functions to be called when an alarm triggers:

void Repeats() {
        Serial.println("15 second timer");
}

void printDetail(uint8_t type, int value) {
        switch (type) {
        case TimeOut:
                Serial.println(F("Time Out!"));
                break;
        case WrongStack:
                Serial.println(F("Stack Wrong!"));
                break;
        case DFPlayerCardInserted:
                Serial.println(F("Card Inserted!"));
                break;
        case DFPlayerCardRemoved:
                Serial.println(F("Card Removed!"));
                break;
        case DFPlayerCardOnline:
                Serial.println(F("Card Online!"));
                break;
        case DFPlayerPlayFinished:
                Serial.print(F("Number:"));
                Serial.print(value);
                Serial.println(F(" Play Finished!"));
                break;
        case DFPlayerError:
                Serial.print(F("DFPlayerError:"));
                switch (value) {
                case Busy:
                        Serial.println(F("Card not found"));
                        break;
                case Sleeping:
                        Serial.println(F("Sleeping"));
                        break;
                case SerialWrongStack:
                        Serial.println(F("Get Wrong Stack"));
                        break;
                case CheckSumNotMatch:
                        Serial.println(F("Check Sum Not Match"));
                        break;
                case FileIndexOut:
                        Serial.println(F("File Index Out of Bound"));
                        break;
                case FileMismatch:
                        Serial.println(F("Cannot Find File"));
                        break;
                case Advertise:
                        Serial.println(F("In Advertise"));
                        break;
                default:
                        break;
                }
                break;
        default:
                break;
        }
}

void digitalClockDisplay() {
        // digital clock display of the time
        Serial.print(Time.hour());
        printDigits(Time.minute());
        printDigits(Time.second());
        Serial.println();
}

void printDigits(int digits) {
        Serial.print(":");
        if (digits < 10)
                Serial.print('0');
        Serial.print(digits);
}

void eventHandler(const char * event,
        const char * data) {
        if (strcmp(data, SHOPL_MSSG) == 0) {
                myDFPlayer.playMp3Folder(1);
        } else if (strcmp(data, RESCUE_MSSG) == 0) {
                myDFPlayer.playMp3Folder(4);
        } else if (strcmp(data, RAIN_MSSG) == 0) {
                myDFPlayer.playMp3Folder(20);
        } else if (strcmp(data, MDKEEPOPEN_MSSG) == 0) {
                maindoorlocked = 1;
        } else if (strcmp(data, MDKEEPBOLT_MSSG) == 0) {
                maindoorlocked = 0;
        } else if (strcmp(data, SDOPEN_MSSG) == 0) {
                slidingstate = 1;
        } else if (strcmp(data, SDCLOSED_MSSG) == 0) {
                slidingstate = 0;
        } else if (strcmp(data, KEEPOPEN_MSSG) == 0) {
                Storeskeepstate = 1;
        } else if (strcmp(data, KEEPBOLT_MSSG) == 0) {
                Storeskeepstate = 0;
        } else if (strcmp(data, BWINDOWOPEN_MSSG) == 0) {
                bathroomwindowlocked = 1;
        } else if (strcmp(data, BWINDOWSHUT_MSSG) == 0) {
                bathroomwindowlocked = 0;
        } else if (strcmp(data, WINDOWOPEN_MSSG) == 0) {
                officewindowlocked = 1;
        } else if (strcmp(data, WINDOWSHUT_MSSG) == 0) {
                officewindowlocked = 0;
        }
        sscanf(data, "K%d, S%d", & slidingstate, & Storeskeepstate);
        sscanf(data, "O%d, B%d", & officewindowlocked, & bathroomwindowlocked);

}

void setZone() {
        Particle.syncTime();
        int month = Time.month();
        int day = Time.day();
        int weekday = Time.weekday();
        int previousSunday = day - weekday + 1;

        if (month < 3 || month > 11) {
                Time.zone(0);
        } else if (month > 3 && month < 11) {
                Time.zone(1);
        } else if (month == 3) {
                int offset = (previousSunday >= 8) ? 1 : 0;
                Time.zone(offset);
        } else {
                int offset = (previousSunday <= 0) ? 1 : 0;
                Time.zone(offset);
        }
}

void InitialPub() {
        Particle.publish(DEVICE_NAME, RSATUS_MSSG, 60, PRIVATE);
        alreadyRun = true;
}

int setSlidingState(String s) {
        slidingstate = atoi(s);
        return slidingstate;
}
int setBathState(String s) {
        bathroomwindowlocked = atoi(s);
        return bathroomwindowlocked;
}
int setOfficeState(String s) {
        officewindowlocked = atoi(s);
        return officewindowlocked;
}
int setMainState(String s) {
        maindoorlocked = atoi(s);
        return maindoorlocked;
}
int setStoresState(String s) {
        Storeskeepstate = atoi(s);
        return Storeskeepstate;
}

Really sorry about the big dump of code. I figured if it was a small segment of my code I’d be told to post the whole lot and I figure I might be criticised now for either not including the library files OR for posting irrelevant chunks of my ino file. Sorry either way!

Thanks

Not addressing your actual problem, but one hint I usually and hope at one point people will pick up on:

Instead of having tons of individual variables like here

// PUB-SUB constants
constexpr char * DEVICE_NAME = "ALERT";
constexpr char * WINDOWSHUT_MSSG = "Office window shut.";
constexpr char * WINDOWOPEN_MSSG = "Office window open.";
constexpr char * BWINDOWSHUT_MSSG = "Bathroom window shut.";
constexpr char * BWINDOWOPEN_MSSG = "Bathroom window open.";
constexpr char * BDSHUT_MSSG = "Bathroom door shut.";
constexpr char * BDOPEN_MSSG = "Bathroom door open.";
constexpr char * SDCLOSED_MSSG = "Sliding door closed.";
constexpr char * SDOPEN_MSSG = "Sliding door open.";
constexpr char * KEEPBOLT_MSSG = "Stores door locked.";
constexpr char * KEEPOPEN_MSSG = "Stores door unlocked.";
constexpr char * MDKEEPBOLT_MSSG = "Main door locked.";
constexpr char * MDKEEPOPEN_MSSG = "Main door unlocked.";
constexpr char * RSATUS_MSSG = "Requesting Status";
constexpr char * SHOPL_MSSG = "SHOPLIFTER";
constexpr char * RESCUE_MSSG = "RESCUE";
constexpr char * RAIN_MSSG = "RAIN";

and a rats nest of check logic like this

        if (strcmp(data, SHOPL_MSSG) == 0) {
                myDFPlayer.playMp3Folder(1);
        } else if (strcmp(data, RESCUE_MSSG) == 0) {
                myDFPlayer.playMp3Folder(4);
        } else if (strcmp(data, RAIN_MSSG) == 0) {
                myDFPlayer.playMp3Folder(20);
        } else if (strcmp(data, MDKEEPOPEN_MSSG) == 0) {
                maindoorlocked = 1;
        } else if (strcmp(data, MDKEEPBOLT_MSSG) == 0) {
                maindoorlocked = 0;
        } else if (strcmp(data, SDOPEN_MSSG) == 0) {
                slidingstate = 1;
        } else if (strcmp(data, SDCLOSED_MSSG) == 0) {
                slidingstate = 0;
        } else if (strcmp(data, KEEPOPEN_MSSG) == 0) {
                Storeskeepstate = 1;
        } else if (strcmp(data, KEEPBOLT_MSSG) == 0) {
                Storeskeepstate = 0;
        } else if (strcmp(data, BWINDOWOPEN_MSSG) == 0) {
                bathroomwindowlocked = 1;
        } else if (strcmp(data, BWINDOWSHUT_MSSG) == 0) {
                bathroomwindowlocked = 0;
        } else if (strcmp(data, WINDOWOPEN_MSSG) == 0) {
                officewindowlocked = 1;
        } else if (strcmp(data, WINDOWSHUT_MSSG) == 0) {
                officewindowlocked = 0;
        }

I’d rather go with an array of strings (const char[][64]) and optionally some enum and have the check performed in a for() loop.

1 Like

Maybe one day I’ll get there Mr @ScruffR! It’s a bit beyond me at present with the time constraints (and let’s not forget brain constraints!) I have.

This part is puzzling

You are trying to scan the same string for two contradicting formats. Is this intentional?

Granted, if the string doesn't start with K or O the respective scan will be terminated and not alter the target variables, but it still seems odd.

Additionally since you are also checking data against all your other strings, I'd assume the sscanf() calls would be better held in an else branch, as both these scans will definetly fail if any of the previous conditions was met.

BTW, where is this LEDEffect library? I can't find it in Web IDE.

If the library uses analogWrite() your OfficeLED on D4 won't work since - as the docs do state - D4 is not PWM enabled.

2 Likes

I think you've probably cracked it, Mr Scruff, as the library does appear to use analogWrite.

Many many thanks. This is probably the answer! Also probably why when I tried D5 that didn't work either as also not PWM enabled! How funny. Sort of! :slight_smile: :slight_smile:

On that note if you or anyone else can recall a state machine on GitHub for Particle devices? It was divided up into servo state machine, LED state machine, button state machine etc etc etc. I seem to recall it was written by a well known member here on these forums but I CANNOT for the life of me find it now.

As for scanning the string for two contradicting formats - it seems to work - basically I have five "slave" Photons and one "master" Photon collecting sensor readings and holding those readings for informing a SCADA display panel.

So on one slave Photon I have a function that does this

void SendStatus()
{
	char data[64];
  snprintf(data, sizeof(data), "K%d, S%d", slidingstate, Storeskeepstate);
  Particle.publish(DEVICE_NAME, data, PRIVATE);
}

and on another

void SendStatus()
{
	char data[64];
  snprintf(data, sizeof(data), "O%d, B%d", officewindowlocked, bathroomwindowlocked);
  Particle.publish(DEVICE_NAME, data, PRIVATE);
}

As I said, your "contradicting" scans will work due to the fact that they are mutually exclusively valid, but aren't you making things a bit too complicated for yourself?

You seem to have multiple code bases for (as I assume) rather similar use-cases.
But why not have the same code for both devices, you have the DEVICE_NAME to distinguish what's meant on the receiving end.

void SendStatus()
{
  char data[64];
  snprintf(data, sizeof(data), "A%d, B%d", state[A], state[B]);
  Particle.publish(DEVICE_NAME, data, PRIVATE);
}

On the receiving side

void handler(const char* event, const char* data) {
  int device = -1;

  if      (strcmp(event, "DeviceX") == 0) device = 0;
  else if (strcmp(event, "DeviceY") == 0) device = 1;
  
  if (device >= 0)
    sscanf(data, "A%d, B%d", &deviceStateA[device], &deviceStateB[device]);
}

Regarding the task to match the incoming device name against a list of possible options you can have a look at this post where another member asked me to elaborate a bit more about my proposal to use arrays and loops instead of individual variables