How can I use the same particle.function to control 2 independent LEDs?

Hello,
I want to control (turn on or OFF) independent LEDs between themselves. So, I can create 2 particle.functions if I want to control only 2 LEDs, but if I want to control more LEDs I think it’s not a good option. So I want to use one particle.function to control all the LEDs independently.
Will this work?

int led1 = D1;
int led2 = D2;

void setup() {
    
    pinMode(led1,OUTPUT);
    pinMode(led2,OUTPUT);

    Particle.function("LED",ledToggle);
}

void loop() {
}

int ledToggle(String command) { //In this solution we need to send as argument ON or OFF and the LED we want control (e.g. "ON,led1")
    String ONorOff = "none";
    String led = "none";
    sscanf(command, "%[^,],%[^,]", ONorOFF, led);

    if (ONorOFF=="on") {
        digitalWrite(led,HIGH);
        return 1;
    }
    else if (ONorOFF=="off") {
        digitalWrite(led,LOW);
        return 0;
    }
    else {
        return -1;
    }

}

Is that correct?
So, or I do as many particle.functions as LEDs I want to control or can I do that or what can I do?

Hi @fcabana

Yes, the idea you have will work fine. Unless you need it for something else, I would avoid the sscanf() stuff and just encode the String in a slightly less readable way such as “01” for LED 0 on and “10” for LED 1 off, etc. That way you can just look at the first character to know which LED and the second character to do on/off.

2 Likes

Apart from my feeling that String won’t work well with sscanf() :wink:

I’d go for char[] and strcmp() instead of String and == compare in any case.

1 Like

To separate the 2 arguments (instruction and led to control). You'd go with the same sscanf but declaring the variables char instead of String, do I understand well?

char [] ONorOff = "none";
char led [] = "none";
sscanf(command, "%[^,],%[^,]", ONorOFF, led);

and then compare the instruction with ON and OFF using strcmp() and then do the same for the LED, is that right?
Thank you!

You understood right, but the code would look more like this

int ledToggle(String command) { //In this solution we need to send as argument ON or OFF and the LED we want control (e.g. "ON,led1")
  char ONorOff[8] = "none";
  char led[8] = "none";
  int nLED = -1;

  sscanf(command, "%7[^,],%7[^,]", ONorOFF, led); // limit the string to 7 char

  // depending on how you provide the LED pin, you need to convert the string
  // to some numeric value 

  if (strcmp(ONorOFF, "on") == 0) {
    digitalWrite(nLED, HIGH);
    return 1;
  }
  else if (strcmp(ONorOFF, "off") == 0) {
    digitalWrite(nLED, LOW);
    return 0;
  }
  return -1;
}

But @bko’s suggestion to go for a more machine than human oriented solution might still be worth a thought - depending on how you plan to communicate with your device.


BTW, if you made a mistake in a post you don’t need to delete the post and post anew, you can just use the :pencil2: icon at the bottom of your post and edit.

2 Likes

Sounds interesting!
So, you'd go with something similar to this?

int ledToggle(String command) {

char [] led = "led" + command[0]
                            
if (command[1]=="1") {
    digitalWrite(led,HIGH);
    return 1;
}
else if (command[1]=="0") {
    digitalWrite(led,LOW);
    return 0;
}
else {
    return -1;
}

}

Is it correct? Is this part: char [] led = "led" + command[0] correctly done?
Thank you!

I don’t see where do you use char led[8] in the code, maybe the if instruction could be: digitalWrite(led, HIGH). And then I can delete de nLED variable. I provide the LED pin as “D0”/“D1”/“D2”…
Could be like this?


I deleted the comment because I reply you with a normal reply on the topic not replying your comment directly and I haven’t known how to change it.

Not quite.

First you want the [] after the variable name to actually create an array.
Next digitalWrite(led, XXXX) would still not work since the first parameter has to be numeric (range 0..7, 10..19) but you are not providing a value in that range.

In order to implement Brians suggestion you'd rather go along this line

int ledToggle(String command) {
  // expected command format pp:v 
  // e.g 10:0 to turn A0 (pin 10) off
  //     07:1 to turn D7 (pin 7)  on
  int nPin = command.substring(0,2).toInt(); 
  int value = command.substring(3).toInt();

  // add some sanity check for the provided values

  digitalWrite(nPin, value);

  return nPin*100 + value;
}

I'm not since I didn't know how your LED number would come in, hence this section in the snippet

This is where led[] would be used to translate the string into the numeric value nLED.

Just to clear up some misconception:
In pinMode(D0, HIGH) the D0 is not a string (like "D0") but is a compiler macro that gets substituted at compile time with the numeric value 0. That's why you cannot use a string as pin parameter directly.

I'm providing it because at the beginning of the code I defined int led1 = D1


Thank you so much! I really appreciate these explanations.


Thank you for your time, I'll try it!!!

2 Likes

No, you are not really, since int led1 = D1 is not a string, but you could send the command as "1" or "D1" or "Led1" or "first LED" or .... So to assume D1 will be sent as "D1" might be obvious but is still an assumption and as professional programmer I've learnt not to assume but to ask :wink:

Computers need unambiguity and so programmers should be explicit about their intent and hence need (and should demand) explicit statements from their client.

@fcabana, here is some code I use to control a Particle relay board with a set of command including “reset”, “prog” and “power=on/off”. Simple command parser that you can adapt.

int control(String command) {
    char copyStr[30];
    command.toCharArray(copyStr,30);
    char *p = strtok(copyStr, "=");

	if (strcmp(p, "power") == 0) {			// power command
		p = strtok(NULL, "=");
		if (strcmp(p, "on") == 0) {			// ON selected
			fsm_state = IDLE;
			relayBoard.on(POWER_RELAY);
		}
		else if (strcmp(p, "off") == 0) {	// OFF selected
			fsm_state = POWER_OFF;
			led1.off();
			relayBoard.allOff();		}
	}
	else if (strcmp(p, "reset") == 0) {
	if (fsm_state == IDLE)
        fsm_state = START_RESET;
	}
	else if (strcmp(p, "prog") == 0) {
	if (fsm_state == IDLE)
        fsm_state = START_PROG;
	}
    return 1;
}
1 Like