NeoPixels - Changing patterns based on input from pressure sensor?

Hi everyone! I’m trying to set up a program that will time how long someone is putting pressure on a pressure sensor and then give them an alert after a certain amount of time has elapsed. It also needs to display how long they’ve been off the sensor and then either run the alert again if they sit down too early, or go back to the original countdown if they’ve completed the correct amount of time.

The code below is as close as I’ve gotten to getting it to work correctly. It’ll run to the end of the five colorWipes and theaterChase countdown pattern. However, if I move my hand off the sensor, it just pauses where it is and doesn’t go to the next pattern at all. It also doesn’t react if I put pressure on it again. I think the issue is that it gets stuck on that countDownPattern that’s within the colorWipe and theaterChase functions? It does print “user moved!” to the Serial Monitor.

#include <Adafruit_NeoPixel.h>

const int analogInPin = A9;
Adafruit_NeoPixel strip = Adafruit_NeoPixel(12, 6, NEO_GRB + NEO_KHZ800);
int sensorValue = 0;
int sensorValueInAlert = 0;

unsigned long currentMillis;
unsigned long previousMillis;

bool sensorUnPressed = false;

void setup() {
  // put your setup code here, to run once:

  Serial.begin(9600);
  pinMode(9, INPUT_PULLUP);
  strip.begin();
  strip.setBrightness(10);
  //colorWipe(strip.Color(255, 255, 255),0);
  strip.show();
  previousMillis = millis();

}

void loop() {
  // put your main code here, to run repeatedly:
  // the analog in value
  sensorValue = analogRead(analogInPin);
  //print the results to the serial monitor
  Serial.print("sensor = " );
  Serial.println(sensorValue);

if (sensorValue < 800){

  if (sensorValue > 800){
    bool sensorUnPressed = true;
  };

  if (!sensorUnPressed){
    Serial.println("10 min countdown");
    colorWipe(strip.Color(0, 0, 255), 1000); //Dark Blue
    colorWipe(strip.Color(66, 206, 244), 1000);  // Light Blue
    colorWipe(strip.Color(249, 249, 17), 1000);  //Yellow
    colorWipe(strip.Color(255, 110, 0), 1000);  // Orange
    colorWipe(strip.Color(255, 0, 0), 1000);  // Red
    theaterChase(strip.Color(127, 127, 127), 50); // White

    sensorValueInAlert = analogRead(analogInPin);
    if (sensorValueInAlert < 800){
      Serial.println("user still on sensor");
      theaterChase(strip.Color(255, 0, 0), 50);
    }

    if (sensorValueInAlert > 800){
      Serial.println("user got off the sensor!");
      theaterChase(strip.Color(0, 0, 255), 50);
    }
  }


if (sensorValue > 800){
  Serial.println("waiting to start");
}
}
}

void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<strip.numPixels() && !sensorUnPressed; i++) { {
    strip.setPixelColor(i, c);
    strip.show();
    unsigned long start = millis();
    while(millis() - start <= 2 * 50)
        { 
          int sensorValueInWipe = analogRead(analogInPin);
          if (sensorValueInWipe > 800) {
            //person is off sensor (doing pushup early)
            //go to countDownPattern
            sensorUnPressed = true;
            Serial.println("user moved early!");
            countDownPattern(strip.Color(0, 255, 0), 100);
          }
        }
      }    
   }
}

void theaterChase(uint32_t c, uint8_t wait) {
  for (int j=0; j<10 && !sensorUnPressed; j++) {  //do 10 cycles of chasing
    for (int q=0; q < 3 && !sensorUnPressed; q++) {
      for (int i=0; i < strip.numPixels() && !sensorUnPressed; i=i+3) {
        strip.setPixelColor(i+q, c);    //turn every third pixel on
      }
      strip.show();

      //delay(wait);

      unsigned long start = millis();
      while(millis() - start <= 100)
          {
   // read the switch
      int sensorValueInChase = analogRead(analogInPin);
          if (sensorValueInChase > 800) {
            //person is off sensor (doing pushup early)
            //go to countDownPattern
            sensorUnPressed = true;
            Serial.println("user moved on time!");
            countDownPattern(strip.Color(0, 255, 0), 100);
            
          }

      for (int i=0; i < strip.numPixels() && !sensorUnPressed; i=i+3) {
        strip.setPixelColor(i+q, 0);        //turn every third pixel off
      }
    }
  }
}
}

void countDownPattern(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<strip.numPixels() && !sensorUnPressed; i++) { {
    strip.setPixelColor(i, c);
    strip.show();
    unsigned long start = millis();
    while(millis() - start <= 2 * 50)
        {
          if (sensorValue < 800) {
            //person is on sensor
            //check whether the proper amount of time has elapsed
            theaterChase(strip.Color(255, 0, 0), 50); // White
                      //if yes: go to colorWipe countdown
                      //if no: theaterChase alert continues
          }
        }
      }    
   }
}

uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

I’ve tried a couple of different ways to re-write it but haven’t gotten much closer.

I’ve looked at the code for Adafruit’s Firewalker shoes and they seem to have their LED pattern written within the loop() function, which I think might be part of the fix for this. I haven’t been able to move the colorWipe function so that’s it’s inside the loop() without breaking everything, though. The Firewalker code also has the STEP_HYSTERESIS bit that seems to help control responsiveness beyond the initial trigger, but I can’t quite parse what the rest of their code is doing & I haven’t been able to pull that out.

Does anyone have any thoughts on how to make this work in an efficient way? I’m still super new to this, so apologies if this is a dumb question!

First, you claim it outputs “user moved!” but that string does not exist in your code. Is it “user got off the sensor!”, "user moved on time! or “user moved early!”?

Also, this nested if statement will never occur:

if (sensorValue < 800) {

    if (sensorValue > 800) {
      bool sensorUnPressed = true;
    };

If it is known to be under 800 it cannot also be above 800. I also dont see sensorUnPressed being cleared back to false anywhere other than the initialization. Not sure if that’s a problem, just more of a pain to hit the reset button every time.

Yes, sorry, it prints "user moved on time!" or "user moved early!" depending on whether I release during the colorWipes or during theaterChase.

Thanks for pointing out the if statements you quoted - in retrospect they are bonkers, haha. As you can see I've tried just about every ham-handed approach I could think up to get it to respond the way I want it to.

In many of your if statements these could be removed && !sensorUnPressed; because you never change the value of sensorUnPressed in the loop so there is no reason to check every time through the loop, especially the nested ones. If you don’t want to enter the loop if it is unpressed, just check once before entering the loop.

Instead of the plain ole “if”, try the if…else so you can easily handle both cases when sensorValue < 800 and >= 800.