Particle project is posting is randomly posting to Twitter ( through IFTTT)

I’m extremely new to this so bear with me if I don’t make a lot of sense.

I picked up a Photon after reviewing someone else’s project online. The project is a door sensor that updates a NeoPixel display to reflect whether the status of the door is open or close. I tweaked the existing code and learned quite a bit while toying with it just to get everything working. The basic function is working fine and I can now reflect the door status using a reed switch and neopixel display.

I wanted to extend the functionality so that the IFTTT can check the status of the sensor and post a tweet when the status changes. The IFTTT recipe is fine and the sensor data can be read and tweeted about as the sensor status changes.

However, it will randomly tweet erroneous status or repeat the current status at random intervals. This happens several times a minute and usually back to back when the status changes. I believe this is an issue with exceeding the limit on posts per second and/or the particle publish limit.

Is there a way to run the loop code only when there is a status change? I don’t want to insert a wait/delay into the loops as I’d like to keep the neopixel display to reflect the current status. I also read that introducing a delay command can cause issues with other critical Photon functions. I checked the documentation but nothing stood out to me on how to do this.

I’m also open to suggestion or corrections to the code I’m using, if there are any glaring issues.

Thanks in advance!


include "neopixel/neopixel.h"

define PIXEL_PIN D2
define PIXEL_COUNT 64
define PIXEL_TYPE WS2812B
define sensorPin D1
int sensorData = 0;
int doorStatus = 0;


Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);

void setup() {
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
  Particle.variable("doorStatus", &doorStatus, INT);
  pinMode(D1, INPUT);
}

void loop() {
    


  sensorData = digitalRead(sensorPin);
  
  if (sensorData == HIGH)
  {
    doorStatus = 1;
    doorClosed();
    Particle.publish("Door_IFTTT","Closed!");
  }
  else
  {
    doorStatus = 0;
    doorOpen();
    Particle.publish("Door_IFTTT","Open!");
  }
}

void doorOpen() {
    strip.setPixelColor(0, 0, 0, 0);
    strip.setPixelColor(1, 0, 0, 0);
    strip.setPixelColor(2, 0, 0, 0);
    strip.setPixelColor(3, 0, 0, 0);
    strip.setPixelColor(4, 0, 0, 0);
    strip.setPixelColor(5, 0, 0, 0);
    strip.setPixelColor(6, 0, 0, 0);
    strip.setPixelColor(7, 0, 0, 0);
    strip.setPixelColor(8, 0, 0, 0);
    strip.setPixelColor(9, 0, 0, 0);
    strip.setPixelColor(10, 0, 0, 0);
    strip.setPixelColor(11, 0, 0, 0);
    strip.setPixelColor(12, 0, 0, 0);
    strip.setPixelColor(13, 0, 0, 0);
    strip.setPixelColor(14, 0, 0, 0);
    strip.setPixelColor(15, 0, 0, 0);
    strip.setPixelColor(16, 0, 0, 0);
    strip.setPixelColor(17, 0, 0, 0);
    strip.setPixelColor(18, 0, 0, 0);
    strip.setPixelColor(19, 0, 0, 0);
    strip.setPixelColor(20, 0, 0, 0);
    strip.setPixelColor(21, 0, 0, 0);
    strip.setPixelColor(22, 27, 167, 46);
    strip.setPixelColor(23, 0, 0, 0);
    strip.setPixelColor(24, 0, 0, 0);
    strip.setPixelColor(25, 0, 0, 0);
    strip.setPixelColor(26, 0, 0, 0);
    strip.setPixelColor(27, 0, 0, 0);
    strip.setPixelColor(28, 0, 0, 0);
    strip.setPixelColor(29, 27, 167, 46);
    strip.setPixelColor(30, 0, 0, 0);
    strip.setPixelColor(31, 0, 0, 0);
    strip.setPixelColor(32, 0, 0, 0);
    strip.setPixelColor(33, 0, 0, 0);
    strip.setPixelColor(34, 0, 0, 0);
    strip.setPixelColor(35, 0, 0, 0);
    strip.setPixelColor(36, 27, 167, 46);
    strip.setPixelColor(37, 0, 0, 0);
    strip.setPixelColor(38, 0, 0, 0);
    strip.setPixelColor(39, 0, 0, 0);
    strip.setPixelColor(40, 0, 0, 0);
    strip.setPixelColor(41, 27, 167, 46);
    strip.setPixelColor(42, 0, 0, 0);
    strip.setPixelColor(43, 27, 167, 46);
    strip.setPixelColor(44, 0, 0, 0);
    strip.setPixelColor(45, 0, 0, 0);
    strip.setPixelColor(46, 0, 0, 0);
    strip.setPixelColor(47, 0, 0, 0);
    strip.setPixelColor(48, 0, 0, 0);
    strip.setPixelColor(49, 0, 0, 0);
    strip.setPixelColor(50, 27, 167, 46);
    strip.setPixelColor(51, 0, 0, 0);
    strip.setPixelColor(52, 0, 0, 0);
    strip.setPixelColor(53, 0, 0, 0);
    strip.setPixelColor(54, 0, 0, 0);
    strip.setPixelColor(55, 0, 0, 0);
    strip.setPixelColor(56, 0, 0, 0);
    strip.setPixelColor(57, 0, 0, 0);
    strip.setPixelColor(58, 0, 0, 0);
    strip.setPixelColor(59, 0, 0, 0);
    strip.setPixelColor(60, 0, 0, 0);
    strip.setPixelColor(61, 0, 0, 0);
    strip.setPixelColor(62, 0, 0, 0);
    strip.setPixelColor(63, 0, 0, 0);
    strip.setBrightness(30);
    strip.show();
}

void doorClosed() {
    strip.setPixelColor(0, 0, 0, 0);
    strip.setPixelColor(1, 0, 0, 0);
    strip.setPixelColor(2, 0, 0, 0);
    strip.setPixelColor(3, 0, 0, 0);
    strip.setPixelColor(4, 0, 0, 0);
    strip.setPixelColor(5, 0, 0, 0);
    strip.setPixelColor(6, 0, 0, 0);
    strip.setPixelColor(7, 0, 0, 0);
    strip.setPixelColor(8, 0, 0, 0);
    strip.setPixelColor(9, 185, 30, 0);
    strip.setPixelColor(10, 0, 0, 0);
    strip.setPixelColor(11, 0, 0, 0);
    strip.setPixelColor(12, 0, 0, 0);
    strip.setPixelColor(13, 0, 0, 0);
    strip.setPixelColor(14, 185, 30, 0);
    strip.setPixelColor(15, 0, 0, 0);
    strip.setPixelColor(16, 0, 0, 0);
    strip.setPixelColor(17, 0, 0, 0);
    strip.setPixelColor(18, 185, 30, 0);
    strip.setPixelColor(19, 0, 0, 0);
    strip.setPixelColor(20, 0, 0, 0);
    strip.setPixelColor(21, 185, 30, 0);
    strip.setPixelColor(22, 0, 0, 0);
    strip.setPixelColor(23, 0, 0, 0);
    strip.setPixelColor(24, 0, 0, 0);
    strip.setPixelColor(25, 0, 0, 0);
    strip.setPixelColor(26, 0, 0, 0);
    strip.setPixelColor(27, 185, 30, 0);
    strip.setPixelColor(28, 185, 30, 0);
    strip.setPixelColor(29, 0, 0, 0);
    strip.setPixelColor(30, 0, 0, 0);
    strip.setPixelColor(31, 0, 0, 0);
    strip.setPixelColor(32, 0, 0, 0);
    strip.setPixelColor(33, 0, 0, 0);
    strip.setPixelColor(34, 0, 0, 0);
    strip.setPixelColor(35, 185, 30, 0);
    strip.setPixelColor(36, 185, 30, 0);
    strip.setPixelColor(37, 0, 0, 0);
    strip.setPixelColor(38, 0, 0, 0);
    strip.setPixelColor(39, 0, 0, 0);
    strip.setPixelColor(40, 0, 0, 0);
    strip.setPixelColor(41, 0, 0, 0);
    strip.setPixelColor(42, 185, 30, 0);
    strip.setPixelColor(43, 0, 0, 0);
    strip.setPixelColor(44, 0, 0, 0);
    strip.setPixelColor(45, 185, 30, 0);
    strip.setPixelColor(46, 0, 0, 0);
    strip.setPixelColor(47, 0, 0, 0);
    strip.setPixelColor(48, 0, 0, 0);
    strip.setPixelColor(49, 185, 30, 0);
    strip.setPixelColor(50, 0, 0, 0);
    strip.setPixelColor(51, 0, 0, 0);
    strip.setPixelColor(52, 0, 0, 0);
    strip.setPixelColor(53, 0, 0, 0);
    strip.setPixelColor(54, 185, 30, 0);
    strip.setPixelColor(55, 0, 0, 0);
    strip.setPixelColor(56, 0, 0, 0);
    strip.setPixelColor(57, 0, 0, 0);
    strip.setPixelColor(58, 0, 0, 0);
    strip.setPixelColor(59, 0, 0, 0);
    strip.setPixelColor(60, 0, 0, 0);
    strip.setPixelColor(61, 0, 0, 0);
    strip.setPixelColor(62, 0, 0, 0);
    strip.setPixelColor(63, 0, 0, 0);
    strip.setBrightness(30);
    strip.show();
}

With that loop you’ll instantly blow through the publish limit, since you’ll be publishing as quickly as the loop runs.
Try creating a “last state” variable in which you store the last state. Only if the new state is different from the last, you’ll do some action. I also don’t think you need to reset the neopixels every loop, since they’ll keep their values once they’re set.
You could also look into using interrupts based on a changed state, though you should implement some debouncing (shouldn’t be too hard)

1 Like

Thanks for the quick reply. I’ll look around for some example code using those terms to see if I can find anything involving “last state” variables. Do you think implementing something like that would replace or work in conjunction with the loop I have setup?

That's not a 'thing'. It's a way of saying that you should take a measurement and store it in a variable. The next time you take a measurement see if it's different. If so, do the thing you'd like it to to, if not, then don't do anything, since nothing changed.
You'd only have to change your look slightly I think. An interrupt based setup would require a bigger change, but would probably be neater.

Thanks. I’ve done some research and will try to figure out how to code what you are describing.

I have also reached out to another community member after reviewing his project, to possibly get some insight on his code and how he may have achieved similar results.

@tg512 What @Moors7 suggested is correct. You should only publish when you detect state change. Keep last state and in loop compare with current state to detect change. e.g.

    String lastDoorState;
    String currentDoorState;
    
    void setup(){
        lastDoorState = "closed";
        currentDoorState = "closed";
    }
    void loop() {
        sensorData = digitalRead(sensorPin);
        currentDoorState = (sensorData == HIGH) ? "closed" : "open";
    
        if(!currentDoorState.equals(lastDoorState)){
            // Door status change detected...
            if(currentDoorState.equals("open")){
                doorOpen();
                Particle.publish("Door_IFTTT","Open!");
            }
            else {
                doorClose();
                Particle.publish("Door_IFTTT","Closed!");
            }
        }
    
        // DO NOT forget this!
        lastDoorState = currentDoorState;
    }
2 Likes

Awesome! I’ll give it a shot. I was struggling with the logic but I think the last part under “DO NOT forget this!” was the part I was missing.

I have a simple set of classes for digital I/O that detects state changes quite well.

Here is an example. Note that the IntervalTimer class is just a simple wrapper around millis(). Just implement a 10mS delay around the sensor scan to allow for debounce.

DigitalInput        door_sensor(D0, INPUT_PULLUP, false);
IntervalTimer       scan_timer(100);

void setup() 
{
    scan_timer.Start();
}

void loop() 
{

    // Delay I/O scanning for debounce.
    
    if (scan_timer.Expired())
    {
        scan_timer.Reset();
        
        door_sensor.Scan();
        
        if (true == door_sensor.FallingEdge())        // Door Closed
        {
           // do something
        }
    }
}

Thanks for everyone who helped. I got the suggested code running but it looks like I have some more work ahead of me.

I was able to push the firmware and get everything operational on my workbench. Even added in the 20ft wire runs for the reed switch and neopixel; everything tested fine. Soldered the wires to the switches and neopixels after getting comfortable with the setup. It continued testing fine.

Went to deploy it, and after running the reed and neopixels wires through the ceiling, it isn’t working. This issue is something different than before. Now it is acting like the switch is going from open state to a closed state in a constant back and forth matter. It’s going so fast that the neopixel is displaying open and close on top of each other. Almost as if then reed switch isn’t fully open or close, and the magnet isn’t changing that.

Back to the drawing board. Not sure what went wrong. I used the same 20ft wires that I coiled on my work bench during my extensive testing. I’m guessing either interference, wire runs are too long, or the 3.3 voltage isn’t enough at that distance.

My neopixels get funky colors after about .-m of strip (4.5-6feet) due to voltage drop from 5v. When starting from 3.3 it's even more likely to encounter issues on long runs,