Web interface with Electron Help

Hello!

I am new to using an Electron, and it is really great learning new stuff.

I have a lot of experience using and programming arduinos, but not with interfacing with the web.

I have successfully got my Electron communicating with the WS2801 LED’s over SPI using the library. So there are 25 LEDs working well.

I would like to create a web interface to turn these LED’s on and off using radio buttons and check boxes. Ideally I would have one page where you check certain boxes and mark radio buttons, then press a “submit” button on the bottom and the LED statuses are updated, and the webpage stays on the same page (doesn’t go to a different page), showing the current configuration.

I have experimented a bunch with some of the tutorials, I will post the code below, but I can’t get it to do exactly what I want yet.

I really appreciate all help!

Electron Code:

    /* ========================== Application.cpp =========================== */

    #include "application.h"
    #include "WS2801.h"

    /*****************************************************************************
    Example sketch for driving Adafruit WS2801 pixels on the Spark Core!
      Designed specifically to work with the Adafruit RGB Pixels!
      12mm Bullet shape ----> https://www.adafruit.com/products/322
      12mm Flat shape   ----> https://www.adafruit.com/products/738
      36mm Square shape ----> https://www.adafruit.com/products/683
      These pixels use SPI to transmit the color data, and have built in
      high speed PWM drivers for 24 bit color per pixel
      2 pins are required to interface
      Adafruit invests time and resources providing this open source code,
      please support Adafruit and open-source hardware by purchasing
      products from Adafruit!
      Written by Limor Fried/Ladyada for Adafruit Industries.
      BSD license, all text above must be included in any redistribution
    *****************************************************************************/

    // The colors of the wires may be totally different so
    // BE SURE TO CHECK YOUR PIXELS TO SEE WHICH WIRES TO USE!

    // SPARK CORE SPI PINOUTS
    // http://docs.spark.io/#/firmware/communication-spi
    // A5 (MOSI) Yellow wire on Adafruit Pixels
    // A3 (SCK) Green wire on Adafruit Pixels

    // Don't forget to connect the ground wire to Arduino ground,
    // and the +5V wire to a +5V supply$

    const int numPixel = 25;
    //const int numPixelX = 10;
    //const int numPixelY = 10;

    uint8_t dataPin  = A5;    // Yellow wire on Adafruit Pixels
    uint8_t clockPin = A3;    // Green wire on Adafruit Pixels

    // Set the argument to the NUMBER of pixels.
    Adafruit_WS2801 strip = Adafruit_WS2801(numPixel);
    //Adafruit_WS2801 strip = Adafruit_WS2801(numPixelX, numPixelY);

    // For 36mm LED pixels: these pixels internally represent color in a
    // different format.  Either of the above constructors can accept an
    // optional extra parameter: WS2801_RGB is 'conventional' RGB order
    // WS2801_GRB is the GRB order required by the 36mm pixels.  Other
    // than this parameter, your code does not need to do anything different;
    // the library will handle the format change.  Example:
    //Adafruit_WS2801 strip = Adafruit_WS2801(25, WS2801_GRB);

    //Setup LED constants. This will be the index for which LED is which. Note first LED is 0, not 1
    const int LED0 = 0;
    const int LED1 = 1;
    const int LED2 = 2;
    const int LED3 = 3;

    

    void setup() {
        //Spark.function("color", color);
        strip.begin();
        colorWipe(Color(0, 0, 0), 0);
        
        // We are also going to declare a Particle.function so that we can turn the LED on and off from the cloud.
       Particle.function("led",ledToggle);
       // This is saying that when we ask the cloud for the function "led", it will employ the function ledToggle() from this app.
    }

    void loop() {
      /*Since we're waiting for input through the cloud this time,
        we don't actually need to put anything in the loop */
      
      // Some example procedures showing how to display to the pixels
      
      //colorWipe(Color(255, 0, 0), 50);
      //colorWipe(Color(0, 255, 0), 50);
      //colorWipe(Color(0, 0, 255), 50);
      //rainbow(20);
      //rainbowCycle(20);
      //strip.setPixelColor(0,Color(255,255,255));
      //strip.show();
    }


    int ledToggle(String command) {
        /* Particle.functions always take a string as an argument and return an integer.
        Since we can pass a string, it means that we can give the program commands on how the function should be used.*/
        
        if (command=="LED0"){
            strip.setPixelColor(LED0,Color(0,255,0));
            strip.setPixelColor(LED1,Color(0,0,0));
            strip.show();
            //return 1;
        }
        else if (command=="LED1"){
            strip.setPixelColor(LED0,Color(0,0,0));
            strip.setPixelColor(LED1,Color(255,0,0));
            strip.show();
            //return 0;
        }
        if (command=="LED2"){
            strip.setPixelColor(LED2,Color(255,120,0));
            strip.show();
            //return 2;
        }
        if (command=="LED3"){
            strip.setPixelColor(LED3,Color(0,0,255));
            strip.show();
            //return 3;
        }
        if (command=="AllOff"){
            colorWipe(Color(0, 0, 0), 0);
            //return 3;
        }
        else{
            return -1;
        }
    }

        
        
        
    void rainbow(uint8_t wait) {
      int i, j;
       
      for (j=0; j < 256; j++) {     // 3 cycles of all 256 colors in the wheel
        for (i=0; i < strip.numPixels(); i++) {
          strip.setPixelColor(i, Wheel( (i + j) % 255));
        }  
        strip.show();   // write all the pixels out
        delay(wait);
      }
    }

    // Slightly different, this one makes the rainbow wheel equally distributed 
    // along the chain
    void rainbowCycle(uint8_t wait) {
      int i, j;
      
      for (j=0; j < 256 * 5; j++) {     // 5 cycles of all 25 colors in the wheel
        for (i=0; i < strip.numPixels(); i++) {
          // tricky math! we use each pixel as a fraction of the full 96-color wheel
          // (thats the i / strip.numPixels() part)
          // Then add in j which makes the colors go around per pixel
          // the % 96 is to make the wheel cycle around
          strip.setPixelColor(i, Wheel( ((i * 256 / strip.numPixels()) + j) % 256) );
        }  
        strip.show();   // write all the pixels out
        delay(wait);
      }
    }

    // fill the dots one after the other with said color
    // good for testing purposes
    void colorWipe(uint32_t c, uint8_t wait) {
      int i;
      
      for (i=0; i < strip.numPixels(); i++) {
          strip.setPixelColor(i, c);
          strip.show();
          delay(wait);
      }
    }

    /* Helper functions */

    // Create a 24 bit color value from R,G,B
    uint32_t Color(byte r, byte g, byte b)
    {
      uint32_t c;
      c = r;
      c <<= 8;
      c |= g;
      c <<= 8;
      c |= b;
      return c;
    }

    //Input a value 0 to 255 to get a color value.
    //The colours are a transition r - g -b - back to r
    uint32_t Wheel(byte WheelPos)
    {
      if (WheelPos < 85) {
       return Color(WheelPos * 3, 255 - WheelPos * 3, 0);
      } else if (WheelPos < 170) {
       WheelPos -= 85;
       return Color(255 - WheelPos * 3, 0, WheelPos * 3);
      } else {
       WheelPos -= 170; 
       return Color(0, WheelPos * 3, 255 - WheelPos * 3);
      }
    }

And here is the HTML code:

    <!-- Replace your-device-ID-goes-here with your actual device ID
    and replace your-access-token-goes-here with your actual access token-->
    <!DOCTYPE>
    <html>
      <body>
      <Left>
      <br>
      <br>
      <br>
      <form action="https://api.particle.io/v1/devices/******/led?access_token=*****" method="POST">
        <font size="6"><strong>LED Application</font><br>
        <br>
       Category 1</strong><br>
        <input type="radio" name="arg" value="LED0">Item1
        <input type="radio" name="arg" value="LED1">Item2
        <br>
        <input type="checkbox" name="arg1" value="LED2">Item3
        <br>
        <input type="checkbox" name="arg2" value="LED3">Item4
        <br>
        <br>
        
        <br>
        <strong>Clear All</strong><br>
        <input type="checkbox" name="arg3" value="AllOff">Turn Off All Lights
        <br>
        <br>
        
        <input type="submit"  value="Update LEDs" >
        
        
        
      </form>
      </Left>
      </body>
    </html>

One option for doing that is using Ubidots.com

There is a Ubidots library you can check out.

Thanks, RWB - I appreciate your reply!

I will check out Ubidots. When you say library, do you mean a library for ws2801 or just a standard form/checkbox interface?

I was hoping to use the Electron without going through another interface - seems like I should be able to, just with the right HTML or other code.

Edit: ahh, i see now, an electron library.

I would host the website on a server, not on the Electron itself. You will consume too much data $$$.

There is a Javascript API that you can refer to that can help you:

  1. retrieve state data from particle variables
  2. set states with particle functions.

All-time favorite example:

I don't own any shares of Ubidots, so I couldn't comment on that. :stuck_out_tongue_winking_eye:

1 Like

Thanks Bulldog.

I wouldn’t think it would consume too much data – I only need to send updates to the LED states once in a while - and wouldn’t that be tiny?

I’ll take a look at your tutorial and try to get it working!

Ahh, I have read that example and that seems that is more suited for constantly reading/sending signals. My application is more about just sending an update to variables once in a while, when a “set” button is pressed. No feedback to worry about.

I see.

If you are good with the HTTP coding “which I am NOT :wink:” then you probably do not need a third party service in the mix.

I only mention Ubidots because they made it easy to setup a dashboard and 2-way communication with zero cost to me.

Look into IFTTT. With native Particle integration, it may be the easiest way to accomplish just that.

To explain further and include some code:

I want it to look like this:

and have it update the electron when the “Update LEDs” button is pushed, but not go to a new page. Also radio buttons/check boxes would maintain their status to reflect what is actually set.

Here is the Electron code I have so far:

/* ========================== Application.cpp =========================== */

#include "application.h"
#include "WS2801.h"

/*****************************************************************************
Example sketch for driving Adafruit WS2801 pixels on the Spark Core!
  Designed specifically to work with the Adafruit RGB Pixels!
  12mm Bullet shape ----> https://www.adafruit.com/products/322
  12mm Flat shape   ----> https://www.adafruit.com/products/738
  36mm Square shape ----> https://www.adafruit.com/products/683
  These pixels use SPI to transmit the color data, and have built in
  high speed PWM drivers for 24 bit color per pixel
  2 pins are required to interface
  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!
  Written by Limor Fried/Ladyada for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
*****************************************************************************/

// The colors of the wires may be totally different so
// BE SURE TO CHECK YOUR PIXELS TO SEE WHICH WIRES TO USE!

// SPARK CORE SPI PINOUTS
// http://docs.spark.io/#/firmware/communication-spi
// A5 (MOSI) Yellow wire on Adafruit Pixels
// A3 (SCK) Green wire on Adafruit Pixels

// Don't forget to connect the ground wire to Arduino ground,
// and the +5V wire to a +5V supply$

const int numPixel = 25;
//const int numPixelX = 10;
//const int numPixelY = 10;

uint8_t dataPin  = A5;    // Yellow wire on Adafruit Pixels
uint8_t clockPin = A3;    // Green wire on Adafruit Pixels

// Set the argument to the NUMBER of pixels.
Adafruit_WS2801 strip = Adafruit_WS2801(numPixel);
//Adafruit_WS2801 strip = Adafruit_WS2801(numPixelX, numPixelY);

// For 36mm LED pixels: these pixels internally represent color in a
// different format.  Either of the above constructors can accept an
// optional extra parameter: WS2801_RGB is 'conventional' RGB order
// WS2801_GRB is the GRB order required by the 36mm pixels.  Other
// than this parameter, your code does not need to do anything different;
// the library will handle the format change.  Example:
//Adafruit_WS2801 strip = Adafruit_WS2801(25, WS2801_GRB);

//Setup LED constants. This will be the index for which LED is which. Note first LED is 0, not 1
const int LED0 = 0;
const int LED1 = 1;
const int LED2 = 2;
const int LED3 = 3;



void setup() {
    //Spark.function("color", color);
    strip.begin();
    colorWipe(Color(0, 0, 0), 0);
    
    // We are also going to declare a Particle.function so that we can turn the LED on and off from the cloud.
   Particle.function("led",ledToggle);
   // This is saying that when we ask the cloud for the function "led", it will employ the function ledToggle() from this app.
}

void loop() {
  /*Since we're waiting for input through the cloud this time,
    we don't actually need to put anything in the loop */
  
  // Some example procedures showing how to display to the pixels
  
  //colorWipe(Color(255, 0, 0), 50);
  //colorWipe(Color(0, 255, 0), 50);
  //colorWipe(Color(0, 0, 255), 50);
  //rainbow(20);
  //rainbowCycle(20);
  //strip.setPixelColor(0,Color(255,255,255));
  //strip.show();
}


int ledToggle(String command) {
    /* Particle.functions always take a string as an argument and return an integer.
    Since we can pass a string, it means that we can give the program commands on how the function should be used.*/
    
    if (command=="LED0"){
        strip.setPixelColor(LED0,Color(0,255,0));
        strip.setPixelColor(LED1,Color(0,0,0));
        strip.show();
        //return 1;
    }
    else if (command=="LED1"){
        strip.setPixelColor(LED0,Color(0,0,0));
        strip.setPixelColor(LED1,Color(255,0,0));
        strip.show();
        //return 0;
    }
    if (command=="LED2"){
        strip.setPixelColor(LED2,Color(255,120,0));
        strip.show();
        //return 2;
    }
    if (command=="LED3"){
        strip.setPixelColor(LED3,Color(0,0,255));
        strip.show();
        //return 3;
    }
    if (command=="AllOff"){
        colorWipe(Color(0, 0, 0), 0);
        //return 3;
    }
    else{
        return -1;
    }
}

    
    
    
void rainbow(uint8_t wait) {
  int i, j;
   
  for (j=0; j < 256; j++) {     // 3 cycles of all 256 colors in the wheel
    for (i=0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel( (i + j) % 255));
    }  
    strip.show();   // write all the pixels out
    delay(wait);
  }
}

// Slightly different, this one makes the rainbow wheel equally distributed 
// along the chain
void rainbowCycle(uint8_t wait) {
  int i, j;
  
  for (j=0; j < 256 * 5; j++) {     // 5 cycles of all 25 colors in the wheel
    for (i=0; i < strip.numPixels(); i++) {
      // tricky math! we use each pixel as a fraction of the full 96-color wheel
      // (thats the i / strip.numPixels() part)
      // Then add in j which makes the colors go around per pixel
      // the % 96 is to make the wheel cycle around
      strip.setPixelColor(i, Wheel( ((i * 256 / strip.numPixels()) + j) % 256) );
    }  
    strip.show();   // write all the pixels out
    delay(wait);
  }
}

// fill the dots one after the other with said color
// good for testing purposes
void colorWipe(uint32_t c, uint8_t wait) {
  int i;
  
  for (i=0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, c);
      strip.show();
      delay(wait);
  }
}

/* Helper functions */

// Create a 24 bit color value from R,G,B
uint32_t Color(byte r, byte g, byte b)
{
  uint32_t c;
  c = r;
  c <<= 8;
  c |= g;
  c <<= 8;
  c |= b;
  return c;
}

//Input a value 0 to 255 to get a color value.
//The colours are a transition r - g -b - back to r
uint32_t Wheel(byte WheelPos)
{
  if (WheelPos < 85) {
   return Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if (WheelPos < 170) {
   WheelPos -= 85;
   return Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
   WheelPos -= 170; 
   return Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}

no matter how minimal, you need to design your website and develop the javascript. It may be good to complete that first, on your PC.

That’s what I am trying to do. Here is the HTML code so far. Looking for some guidance.

<!-- Replace your-device-ID-goes-here with your actual device ID
and replace your-access-token-goes-here with your actual access token-->
<!DOCTYPE>
<html>
  <body>
  <Left>
  <br>
  <br>
  <br>
  <form action="https://api.particle.io/v1/devices/******/led?access_token=*****" method="POST">
    <font size="6"><strong>LED Application</font><br>
    <br>
   Category 1</strong><br>
    <input type="radio" name="arg" value="LED0">Item1
    <input type="radio" name="arg" value="LED1">Item2
    <br>
    <input type="checkbox" name="arg1" value="LED2">Item3
    <br>
    <input type="checkbox" name="arg2" value="LED3">Item4
    <br>
    <br>
    
    <br>
    <strong>Clear All</strong><br>
    <input type="checkbox" name="arg3" value="AllOff">Turn Off All Lights
    <br>
    <br>
    
    <input type="submit"  value="Update LEDs" >
    
    
    
  </form>
  </Left>
  </body>
</html>

the tutorial I linked will show you how how to integrate the Particle functions/variables.

If you need help getting through that, you may want to start with an online course on HTML/JavaScript first.

1 Like

Thanks Bulldog - I really appreciate your help and I understand what you are saying.
I do get your example, but I feel I am trying to do something different and I wish there were more tutorials/examples for this side of the photon/electron.
Could you help me with how I would change your example from a constantly polling/refreshing page to a “submit” type system?
Thanks.

it is @bko’s code… props to him.

You would want to only get the variables from the Electron when the page loads. there are several ways to do that but it can be as simple as:

<body onload="getElectronStatus()">

then, you could use a callback to verify the changes after you set any changes, something like this:

<button onclick="doSomethingWithElectron();">Do It</button>

<script>
function doSomethingWithElectron(){
    runElectronFunction();
	setTimeout(verifyChanges, 3000);
}
function verifyChanges() {
    alert('Updating');
    getElectronStatus();
}
function getElectronStatus(){
...
</script>

all pseudo code, of course! :wink:

1 Like

"that" side is Web Development, and cleanly separated from the Particle ecosystem thanks to the REST API. Particle makes sure that you're able to interact with your devices. How you choose to do so is entirely up to you :wink: That's not to say there shouldn't be examples, but rather that every Web Dev tutorial is potentially applicable. @bko's example is exactly what you're looking for though, since it demonstrates how to POST to functions and how to GET variables, which is all you really need. Everything after that is just to make it pretty.

1 Like

Understood completely, Moors, and I appreciate your comment completely.

Coming from a strong electronics and microcontroller background, the main draw of the Photon and Electron is the connectivity side - otherwise I could keep going with the environment I know well and love! Therefore the biggest help to me with the Particle ecosystem would be with its biggest draw, the web development side, and how it interacts with the hardware and software.

Thanks again for your help and I really appreciate your responses.

Ok, I appreciate everyone’s help so far - I am making progress using bko’s example, and now I have some specific questions.

I am trying to send the value of a radio button when I press the “submit” button, but I can’t seem to get that value to transfer. I am able to get a specific function running on the electron when I press the submit button, but I have verified with a serial monitor that the value of the variable is not changing.

Here is the HTML code:

<!DOCTYPE HTML>
<html>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript" charset="utf-8"></script>
<body>
    <P><strong><font size="6"> Test Board 1</font><br><br>
    <P>Area 1</strong>&nbsp
    <input type="radio" name="Set1" id="Set1Id" value="1">Open 
    <input type="radio" name="Set1" value="0">Closed   &nbsp
    <input type="checkbox" name="Set2" value="1">Status1 &nbsp 
    <input type="checkbox" name="Set3" value="1">Status2<br>
    <br>
    <br>
    <input type="button" name="submit" value="submit" onclick="setValue(this)"> <br><br>
    
    
    
    <br><br>
    

    <script type="text/javascript">
      var deviceID    = "***";
      var accessToken = "***";
      var setFunc = "setpos";
      

      function setValue(obj) {
        
                   
        var newValue = document.getElementById('Set1Id').value;
             
        sparkSetPos(newValue);   
        
      }
      
     
      function sparkSetPos(newValue) {
	      var requestURL = "https://api.spark.io/v1/devices/" +deviceID + "/" + setFunc + "/";
        $.post( requestURL, { params: "newValue", access_token: accessToken });
      }

    </script>
</body>
</html>

On the particle side, I am using code very similar to the servo example as well – this is the function that gets called.

int setPosition(String posValue) {
    pos = posValue.toInt();
    Serial.println(pos);
    
    digitalWrite(Led2,HIGH);
    delay(500);
    digitalWrite(Led2,LOW);
    
    if(pos == 1){
        colorWipe(Color(255, 0, 0), 50);
        colorWipe(Color(0, 0, 0), 0);
        
    }
    
    
    return 0;
}

I do see the LED flash, but in the serial monitor the variable pos stays at 0 (and the other functions don’t get called).

  function sparkSetPos(newValue) {
	      var requestURL = "https://api.spark.io/v1/devices/" +deviceID + "/" + setFunc + "/";
    $.post( requestURL, { params: "newValue", access_token: accessToken });
  }

Take another very close look at this part (and compare it to BKO’s tutorial. “Find the difference” :wink:

2 Likes

Ahh yes! Thank you! I had put those quotes in when I was playing with trying to pass different strings and forgot to take them out!

Sends the 1 clearly now. Thanks again!

On to the next challenge!

2 Likes

that is the beauty of using EM6 Template Literals:

var requestURL = 'https://api.spark.io/v1/devices/${deviceID}/${setFunc}/';

So much nicer. :slight_smile:

2 Likes