Multiples pins JavaScript

Good evening everyone. I’m working on a project using particle photon. The project consists of turning on and off various devices. I noticed that using the code below as a simulation to connect two devices I get success. However, for one thing it’s not very good. The problem is that when sending a command to turn on one led and then send another command to turn on the second led, the second only turns on after sending another command through the node, that is, to turn on the second led you need two clicks or two commands via node.
I was doing it through HTML using buttons for the clicks when I noticed what happened, that’s when I did it directly through node believing that the fault was in the HTML code and it didn’t matter. Can anyone give a hint if there is any flaw in my code or if it has something to do with the particle API.
I tried it through Jquery using the POST method and it works the same.This is very important to me, as I cannot pass on to my customers an application that requires two clicks to turn on one device and one click to turn on another. Thanks.

int ledPin1 = D1;
int ledPin2 = D2;
int statusPin;

void setup() {
    pinMode(ledPin1, OUTPUT);
    pinMode(ledPin2, OUTPUT);
    Spark.function("IoT", ledSwitch);
}

void loop() {
}

int ledSwitch(String command) {
    if (command.equalsIgnoreCase("D1")) {
        statusPin = !statusPin;                   // toggle the value
        digitalWrite(ledPin1, statusPin);
        return 1;
    }
    if (command.equalsIgnoreCase("D2")) {
        statusPin = !statusPin;                   // toggle the value
        digitalWrite(ledPin2, statusPin);
        return 1;
    }
    return -1;
}

Commands below extracted from particle documents.

var fnPr = particle.callFunction({ deviceId: 'xxxxxx', name: 'IoT', argument: 'D1', auth: token });

fnPr.then(
  function(data) {
    console.log('Function called succesfully:', data);
  }, function(err) {
    console.log('An error occurred:', err);
  });
var fnPr = particle.callFunction({ deviceId: 'xxxxx', name: 'IoT', argument: 'D2', auth: token });

fnPr.then(
  function(data) {
    console.log('Function called succesfully:', data);
  }, function(err) {
    console.log('An error occurred:', err);
  });

You are using the same variable statusPin for both LEDs.
How should one variable hold independent states of two outputs?

Similar to your other question two months ago

And you are still using Spark instead of Particle

Good afternoon everyone. Returning to the topic really the best option was ScruffR. To trigger each pin individually, I created an independent function for each pin that will be called in node or in HTML. If anyone has another suggestion I appreciate it.

int ledPin0 = D0;
int statusPin0;

int ledPin1 = D1;
int statusPin1;

void setup() {
    pinMode(ledPin0, OUTPUT);
    pinMode(ledPin1, OUTPUT);
    
    Particle.function("IoT_D0",ledSwitchD0);
    Particle.function("IoT_D1",ledSwitchD1);
}
void loop() {
}
int ledSwitchD0(String command) {
    if (command.equalsIgnoreCase("D0")){
        statusPin0 = !statusPin0;                   // toggle the value
        digitalWrite(ledPin0, statusPin0);
    return 1;
    }
return -1;
}
int ledSwitchD1(String command) {
    if (command.equalsIgnoreCase("D1")){
        statusPin1 = !statusPin1;                   // toggle the value
        digitalWrite(ledPin1, statusPin1);
    return 1;
    }
return -1;
}

Hi,
IMHO you don’t need two Particle.function() for that you can use just one and then use else if() functionality to achieve the same results :slight_smile:
here some code for tests:

1.ledSwitch .ino

#include "Particle.h"

int ledPin0 = D0;
int ledPin1 = D1;

bool statusPin0 = false;
bool statusPin1 = false;

int ledSwitch(String command){
    if (command.equalsIgnoreCase("D0")){
        statusPin0 = !statusPin0;                   
        digitalWrite(ledPin0, statusPin0);
        return 1;
    }else if(command.equalsIgnoreCase("D1")){
         statusPin1 = !statusPin1;                   
         digitalWrite(ledPin1, statusPin1);  
        return 2;     
        }
return -1;
}

void setup(){
    
    pinMode(ledPin0, OUTPUT);
    pinMode(ledPin1, OUTPUT);
    Particle.function("ledSwitch",ledSwitch);
}

void loop(){
}

  1. toggle_D.html
<!DOCTYPE html>
<html>
 <head>
 <meta name="viewport" content="width=device-width">
 <meta charset="utf-8"/>
 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
</head>

<style>
  html {
    background-color: blue; 
}		
</style>
<body>

<div id='hideme' style="display:block; margin-left: 4px; margin-top: 0px; background: transparent; opacity: 1;  color: aqua; padding:5px 5px;"> Led's Controll 
<p>
    <div style="display: inline-block; margin-left: 7px; margin-top: 0px; background: transparent; opacity: 1; border: 5px solid #c83349; padding:125px; max-width:100%; ">
     
     <button id='Q1' onclick="flipflop('D0');;" style= "background: transparent; color: #39a0ef; " >D0<i class="fa fa-power-off"  style="font-size: 480px;"></i></button>
      
     <button id='Q2' onclick="flipflop('D1');" style= "background: transparent; color: #39a0ef; " >D1<i class="fa fa-power-off"  style="font-size: 480px;"></i></button>
   </div>
 </div>

<script type="text/javascript">

const accessToken = "YOUR_ACCESS_TOKEN_HERE";
const deviceID = "YOUR_DEVICE_ID_HERE";
const url_post = "https://api.particle.io/v1/devices/" + deviceID +"/ledSwitch";

function flipflop(command){
        toggle_led(url_post, {args:command})       
        .then(data => {
          console.log("data",data);
         }).catch(err =>{
           console.log(err);
        });
}
      
async function toggle_led(url, data) { 
     const response = await fetch(url,{
     method: 'POST',  
     mode: 'cors',
     headers: {
      'Content-Type': 'application/json','authorization':'Bearer ' + accessToken 
    }, 
    body: JSON.stringify(data) 
    
  });
 
  return response.json(); 
}    
</script>
</body>
</html>  

Best,
Arek

3 Likes

I’d expand on @dreamER’s suggestion with future extensibility in mind.

struct pinSetup {
  int  pin;
  bool state;
  char command[32];
};

pinSetup pins[] = 
{ { D0, false, "D0" }
, { D1, false, "D1" }
};
const int numPins = sizeof(pins) / sizeof(pins[0]);

void setup() {
  for (int p = 0; p < numPins; p++) {
    pinMode(pins[p].pin, OUTPUT);
    digitalWrite(pins[p].pin, pins[p].state);
  }
  
  Particle.function("ledSwitch", togglePin);
}

int togglePin(const char* command) {
  for(int p = 0; p < numPins; p++) {
    if(!strcmp(command, pins[p].command)) {
      pins[p].state ^= 1;
      digitalWrite(pins[p].pin, pins[p].state);
      return p;
    }
  }
    
  return -1;
}

With this you’d merely need to add another line of

, { Dx, false, "Dx" }

to the pins[] definition and the rest of the code will already know what to do with that - no extra effort required.

This way you can also define the respective pin’s startup state (true/ON or false/OFF).

I’d also always recommend using arrays rather than multiple instances of the “same” stuff. This way your code can be shorter, hence more readable and maintainable, and less prone for copy/paste mistakes and more elegant IMHO.


An alternative to avoid the need for a loop, which would require a slight change on the JS code, could look like this

const int pins[]  = { -99, D0, D1 }; // index 0 used as indicator for a parsing error
const int numPins = sizeof(pins) / sizeof(pins[0]);

void setup() {
  for (int p = 1; p < numPins; p++)
    pinMode(pins[p], OUTPUT);

  Particle.function("togglePin", togglePin);
}

// JS sending the index as '1', '2', ... rather than 'D0', 'D1', ...
// 0 being an invalid index, as would be anything beyond the defined number of pins
int togglePin(const char* command) {
  int p = atoi(command);
  if (0 < p && p < numPins) {
    bool state = !digitalRead(pins[p]);
    digitalWrite(pins[p], state);
    return (state ? p : -p);         // positive index when switched ON and negative when OFF 
  }
  return pins[0];                    // indicate invalid pin selection
}
3 Likes

@ScruffR I love your examples they are always perfect and full of new stuff which I’ll never figured
out !
Will be perfect to have 20 years ago a Teacher as you :grin:

int togglePin(const char* command) {
  for(int p = 0; p < numPins; p++) {
    if(!strcmp(command, pins[p].command)) {
      pins[p].state ^= 1;
      digitalWrite(pins[p].pin, pins[p].state);
      return p;
    }
  }
    
  return -1;
}

Always wanted to see/know how the particle.function() Works with const char*
instead of String and vuala :slight_smile:
just simple strcmp() doing the job !
Thanks

2 Likes

Great. I will apply none of my code and return.

Good evening everyone. First, sorry for the delay in continuing the topic.
Really the first option presented by our colleague ScruffR is without a doubt the best option. Easy to maintain code and also very didactic.
I recommend this algorithm to everyone.
I tested it with a knot and it worked perfectly. Thank you very much ScruffR for your collaboration. I will apply this code to pin toggle.
I will also try to increment for reading the logical level of the pins.

struct pinSetup {
  int  pin;
  bool state;
  char command[32];
};

pinSetup pins[] = 
{ { D0, false, "D0" }
, { D1, false, "D1" }
};
const int numPins = sizeof(pins) / sizeof(pins[0]);

void setup() {
  for (int p = 0; p < numPins; p++) {
    pinMode(pins[p].pin, OUTPUT);
    digitalWrite(pins[p].pin, pins[p].state);
  }
  
  Particle.function("ledSwitch", togglePin);
}

int togglePin(const char* command) {
  for(int p = 0; p < numPins; p++) {
    if(!strcmp(command, pins[p].command)) {
      pins[p].state ^= 1;
      digitalWrite(pins[p].pin, pins[p].state);
      return p;
    }
  }
    
  return -1;
}

var fnPr = particle.callFunction({ deviceId: ‘xxxxxxxxxxxx’, name: ‘ledSwitch’, argument: ‘D0’, auth: token });

fnPr.then(
function(data) {
console.log(‘Function called succesfully:’, data);
}, function(err) {
console.log(‘An error occurred:’, err);
});

1 Like