Creating coordinated Christmas light displays with mesh networking


@peekay123, Thanks for responding, MUCH appreciated. Yes, via web IDE, but I didn’t think to check the DeviceOS. I just looked, it’s set to rc27, and is on the device. I just tried to flash again, looks like that part is fine. I’ll retry the PIR, and a couple others. Having tried this several times last night, I can only say it’s the lack of experience with the devices, and I “panicked” too soon?


@rick.roades, usually going into safe mode means the DeviceOS version and the app you are trying to flash don’t match. More specifically, the app is compiled at a higher version. Which gateway are you using (Argon, Boron, Xenon/Ethernet)?


The code is from a photon post in 2015, and is really simple. But I follow the connection there, so I’ll keep an eye on that. I’m using an Argon gateway. I can ping the xenon from the console, but with the PIR connected, I don’t get any events logged.


@rick.roades, exactly which sensor are you using? If it is a 5v sensor, it may not be usable with the Mesh devices since the pins are not 5V tolerant like the Photon’s.


I honestly don’t know - I bought them 3-4 years ago when I first started playing with Arduino, but they aren’t marked. But trying to find them on Amazon, it comes up as HC-SR501, and says they are 3.3v. the “brand” is 2013Newestseller


@rick.roades, doing a quick search for that model indicates that they do put out 3.3v logic levels but need to be powered with a 5-20V source. So power the unit via the VUSB pin of the Xenon and see if it works. :wink:


That’s IT!! I’m getting events in the console. Now, how do I convince my wife that a 59 year old man acting like a giddy kid is not a danger to myself or others?? :smiley:

Thank you VERY MUCH! I’m off and running to my next obstacle. Whatever it may be!


@rick.roades, your talking to a 58 year old Elite so BE GIDDY!


Should future project questions go to a specific forum? I’m getting away from this topic. But my next challenge is power. First, I’ve moved code to my Boron, which is live and responding. I have the PIR on it, working on USB. In the field, I’ll need to power with battery, charging with solar. But using a Li-Po with on-board JST is 3.7, doesn’t power the PIR. I have 2 different device charger packs (anger, ravpower), which give me 5v USB but I guess the Boron/Xenon/Argon, do not draw enough amps because the chargers sleep after about 15-30 seconds. I’ll also need to add solar to charge anything I do use as power.

Battery Powered Boron and Motion Sensor (PIR)

You could use a 3.3V to 5.0V step-up converter to power the sensor.


Try powering the PIR via the Boron’s LI+ pin, that might help. It’s worth a try.

[Edit] I just tried it and it works on a Boron LTE with a Li-Po.


Thanks @ScruffR - I don’t have the step-up, so will try @Rftop’s suggestion. But even before that, on USB, I have to figure out why the PIR keeps going HIGH non-stop without any activity, or even with the sensor in a small box blocking everything.


It will hold the output high for like 7 seconds after activity, but that’s adjustable.
This code works as expected:

  Pinout :
PIR     Boron
VCC     LI+
OUT     D3
Gnd     Gnd

void setup() {
pinMode(D3, INPUT);
pinMode(D7, OUTPUT);

void loop() {

if (digitalRead(D3) ==1) {
    digitalWrite(D7, HIGH); 
    digitalWrite(D7, LOW);


Thanks for the sample. My issue is that it just never quits triggering.

I borrowed from a couple examples, and for LED, one for PIR and one for functions (Particle.publish()). Maybe I’m getting ahead of myself.

I’ll test your config shortly. As is, here’s the sample code I was combining/testing, I’m sure it needs cleaning up.

int led1 = D0;
int led2 = D7;
// RLR my pin for PIR
int motion = D1;
int n = 0;
// RLR network.
    // Boron, Cellular = 01-01-00 (Network-Section-Zone) (Zone if needed)
        // Other units will be 01-01-01

String monitor_unit = "01-01-00";
// Last time, we only needed to declare pins in the setup function.
// This time, we are also going to register our Particle function

void setup()

   // Here's the pin configuration, same as last time
   pinMode(led1, OUTPUT);
   pinMode(led2, OUTPUT);
  // RLR my addition
   pinMode(motion, INPUT);

   // We are also going to declare a Particle.function so that we can turn the LED on and off from the cloud.
   // This is saying that when we ask the cloud for the function "led", it will employ the function ledToggle() from this app.

   // For good measure, let's also make sure both LEDs are off when we start:
   digitalWrite(led1, LOW);
   digitalWrite(led2, LOW);


// Last time, we wanted to continously blink the LED on and off
// Since we're waiting for input through the cloud this time,
// we don't actually need to put anything in the loop
// RLR - I'm adding Motion detection. So I want to turn the LED on while there is motion
//  or rather as long as the PIR is in the state of detection before resetting.

void loop()
    if (digitalRead(D1) == HIGH) {
        Particle.publish("Motion", monitor_unit);
        while (digitalRead(D1) == HIGH); // hang tight here until motion stops

// We're going to have a super cool function now that gets called when a matching API request is sent
// This is the ledToggle function we registered to the "led" Particle.function earlier.

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.
    In this case, telling the function "on" will turn the LED on and telling it "off" will turn the LED off.
    Then, the function returns a value to us to let us know what happened.
    In this case, it will return 1 for the LEDs turning on, 0 for the LEDs turning off,
    and -1 if we received a totally bogus command that didn't do anything to the LEDs.

    if (command=="on") {
        // RLR added
       n = 0;
        Particle.publish("LED Status = ","Full Power");
        return 1;
    else if (command=="off") {
        n = 0;
        Particle.publish("LED Status = ","Shutting Down");
        return 0;
    else if (command=="blink") {
        // RLR Added the blink section.
        n = 1;
        while (n == 1) {
            // To blink the LED, first we'll turn it on...
            digitalWrite(led1, HIGH);
            digitalWrite(led2, HIGH);
            // We'll leave it on for 1 second...
            Particle.publish("LED Staus = ","1");
            // Then we'll turn it off...
            digitalWrite(led1, LOW);
            digitalWrite(led2, LOW);
            // Wait 1 second...
            Particle.publish("LED Staus = ","0");
        return n;
    else {
        return -1;


@Rftop - THANKS! it does work, but as soon as it fires the first time, it just keeps sending events non-stop. But looking at the pins for the jumper (H or L), there is no jumper. So dug through the other 3 and grabbed one, put it on and now it’s firing just once.

So as before… big smile! :smiley:

Next - power in the field. I think. :thinking:

By the way - This bunch is a phenomenal bunch. Hope some day I can give something back. I actually live in IT, but not on hardware or coding. I’m in the strategy/business/application/project planning & management side. So I’m out of my element, but as I learn, I’ll contribute where I can.


A 6V Solar Panel and a larger Li-Po is the easiest.


That’s my first thought. My head scratching begins with being in the woods without clear view of the sky, wondering if it will get enough light. Digging the finger nails in deeper, in reading your recent post, it might be able to limit power draw to still make it work.

I bought 2000mAH Li-Po’s. How important is it to use Adafruit’s panels with their chargers/batteries?

Next question on the PIR, though, even with the jumper, it started firing continuously with no stopping for 2 hrs until I just pulled power, even under a black cloth. I’m really lost. I put the jumper on for “H” - repeating. Guess I don’t understand the two modes.


You can use any 6V Solar Panel with the Boron. Here’s a couple that I’ve tested:


Try this out:

// Jumper in H position
int PIR = D4;
int motion = 0;
int pirState = LOW; 
int donePIN =D3;

void setup() {
pinMode(PIR, INPUT);  // PIR:  No Motion = High,  Motion = LOW, 
pinMode(D7, OUTPUT);

void loop() {

motion = digitalRead(PIR);

  if (motion == HIGH) {        // PIR OutPut is HIGH = MOTION
    digitalWrite(D7, HIGH); 
     if (pirState == LOW) {
      // we have just turned on
      Serial.println("Motion detected!");
      // We only want to print on the output change, not state
      pirState = HIGH;
} else {
    digitalWrite(D7, LOW);  // turn LED OFF
    if (pirState == HIGH){
      // we have just turned off
      Serial.println("Motion ended!");
      // We only want to print on the output change, not state
      pirState = LOW;



I can’t believe you guys are so helpful on a Sunday morning. Geez…

If I follow the code, and trying to think back through, I should have power on the VUSB, data (PIR OUT) on pin D4.

Adding a Particle.publish() to mimic the Serial.println() but get timestamp, this is what I see and assuming time = UTC (I’m central time) :

event: Motion
data: {“data”:“Detected”,“ttl”:60,“published_at”:“2018-12-23T14:37:19.011Z”,“coreid”:“e00fce68e32c4a9de608b584”}

event: Motion
data: {“data”:“Ended”,“ttl”:60,“published_at”:“2018-12-23T14:37:27.248Z”,“coreid”:“e00fce68e32c4a9de608b584”}

event: Motion
data: {“data”:“Detected”,“ttl”:60,“published_at”:“2018-12-23T14:37:28.449Z”,“coreid”:“e00fce68e32c4a9de608b584”}

event: Motion
data: {“data”:“Ended”,“ttl”:60,“published_at”:“2018-12-23T14:37:36.689Z”,“coreid”:“e00fce68e32c4a9de608b584”}

event: Motion
data: {“data”:“Detected”,“ttl”:60,“published_at”:“2018-12-23T14:37:38.768Z”,“coreid”:“e00fce68e32c4a9de608b584”}

event: Motion
data: {“data”:“Detected”,“ttl”:60,“published_at”:“2018-12-23T14:37:38.849Z”,“coreid”:“e00fce68e32c4a9de608b584”}

event: Motion
data: {“data”:“Ended”,“ttl”:60,“published_at”:“2018-12-23T14:37:41.489Z”,“coreid”:“e00fce68e32c4a9de608b584”}

event: Motion
data: {“data”:“Ended”,“ttl”:60,“published_at”:“2018-12-23T14:37:49.729Z”,“coreid”:“e00fce68e32c4a9de608b584”}

event: Motion
data: {“data”:“Detected”,“ttl”:60,“published_at”:“2018-12-23T14:37:51.489Z”,“coreid”:“e00fce68e32c4a9de608b584”}

event: Motion
data: {“data”:“Detected”,“ttl”:60,“published_at”:“2018-12-23T14:37:51.569Z”,“coreid”:“e00fce68e32c4a9de608b584”}

event: Motion
data: {“data”:“Ended”,“ttl”:60,“published_at”:“2018-12-23T14:37:54.209Z”,“coreid”:“e00fce68e32c4a9de608b584”}

event: Motion
data: {“data”:“Ended”,“ttl”:60,“published_at”:“2018-12-23T14:38:02.529Z”,“coreid”:“e00fce68e32c4a9de608b584”}

event: Motion
data: {“data”:“Detected”,“ttl”:60,“published_at”:“2018-12-23T14:38:04.688Z”,“coreid”:“e00fce68e32c4a9de608b584”}

event: Motion
data: {“data”:“Detected”,“ttl”:60,“published_at”:“2018-12-23T14:38:04.768Z”,“coreid”:“e00fce68e32c4a9de608b584”}


@rick.roades, you’ll have better luck if you start a new thread. That will help others in the future for Searching the same issues also.
You may have an open-collector output. You can try pinMode(PIR, INPUT_PULLUP), but that’s a long shot.

I’d also suggest using serial for testing. You can easily hit the 1-publish per second limitation while de-bugging hardware and code.