Proximity LED Strip Dimming

Hello, I want to be able to dim an LED strip using a touch capacitive sheet. I have a sketch that currently switches the strip on and off when I wave my hand across the sheet. The built in LED dims at the same time, however I cant seem to be able to get the Strip to do the same. I will attach the sketch I currently have below. It is using the Bare conductive Touch board.

// compiler error handling
#include "Compiler_Errors.h"

// touch includes
#include <MPR121.h>
#include <MPR121_Datastream.h>
#include <Wire.h>

// neopixel includes
#include <Adafruit_NeoPixel.h>

// touch constants
const uint32_t BAUD_RATE = 115200;
const uint8_t MPR121_ADDR = 0x5C;
const uint8_t MPR121_INT = 4;

// serial monitor behaviour constants
const bool WAIT_FOR_SERIAL = false;

// MPR121 datastream behaviour constants
const bool MPR121_DATASTREAM_ENABLE = false;

// led switch behaviour constants
//Input is set to touch electrode 1
const uint8_t PROX_ELECTRODE = 11;

// led switch variable
bool PIXELS_ON = false;

// neopixle behaviour constants
// output pin is set to pin 1 for LED data cable to be connected to
#define OUTPUT_PIN 11
#define NUMPIXELS 40  // define how many LEDs are in the strip
Adafruit_NeoPixel pixels2(NUMPIXELS, OUTPUT_PIN, NEO_GRB + NEO_KHZ800);

// mapping and filter definitions
#define LOW_DIFF 0
#define HIGH_DIFF 50
#define filterWeight 0.3f // 0.0f to 1.0f - higher value = more smoothing
float lastProx = 0;

void setup() {
  Serial.begin(BAUD_RATE);
  pinMode(LED_BUILTIN, OUTPUT);

  if (WAIT_FOR_SERIAL) {
    while (!Serial);
  }

  if (!MPR121.begin(MPR121_ADDR)) {
    Serial.println("error setting up MPR121");
    switch (MPR121.getError()) {
      case NO_ERROR:
        Serial.println("no error");
        break;
      case ADDRESS_UNKNOWN:
        Serial.println("incorrect address");
        break;
      case READBACK_FAIL:
        Serial.println("readback failure");
        break;
      case OVERCURRENT_FLAG:
        Serial.println("overcurrent on REXT pin");
        break;
      case OUT_OF_RANGE:
        Serial.println("electrode out of range");
        break;
      case NOT_INITED:
        Serial.println("not initialised");
        break;
      default:
        Serial.println("unknown error");
        break;
    }
    while (1);
  }

  MPR121.setInterruptPin(MPR121_INT);

  if (MPR121_DATASTREAM_ENABLE) {
    MPR121.restoreSavedThresholds();
    MPR121_Datastream.begin(&Serial);
  } else {
    MPR121.setTouchThreshold(40);
    MPR121.setReleaseThreshold(20);
  }

  MPR121.setFFI(FFI_10);
  MPR121.setSFI(SFI_10);
  MPR121.setGlobalCDT(CDT_4US);

  analogWrite(LED_BUILTIN, HIGH);
  delay(1000);
  MPR121.autoSetElectrodes();
  analogWrite(LED_BUILTIN, LOW);

  pinMode(OUTPUT_PIN, OUTPUT);
  analogWrite(OUTPUT_PIN, LOW);

  pixels2.begin();
  pixels2.clear();
  pixels2.show();

  // slow down some of the MPR121 baseline filtering to avoid 
  // filtering out slow hand movements
  MPR121.setRegister(MPR121_NHDF, 0x01); //noise half delta (falling)
  MPR121.setRegister(MPR121_FDLF, 0x3F); //filter delay limit (falling)

}

void loop() {
  MPR121.updateAll();

  if (MPR121.isNewTouch(PROX_ELECTRODE)) {
    if (PIXELS_ON) {  // if the LED strip is on
      PIXELS_ON = false;
      pixels2.clear();
      pixels2.show();
    } else {  // if the LED strip is off
      PIXELS_ON = true;

      for (int i = 0; i < NUMPIXELS; i++) {  // for each LED within the strip
        pixels2.setPixelColor(i, pixels2.Color(255, 255, 255));
        pixels2.show();
        delay(5);
      }
    }
  }

  if (MPR121_DATASTREAM_ENABLE) {
    MPR121_Datastream.update();
  }

  // update all of the data from the MPR121
  MPR121.updateAll();

  // read the difference between the measured baseline and the measured continuous data
  int reading = MPR121.getBaselineData(PROX_ELECTRODE)-MPR121.getFilteredData(PROX_ELECTRODE);

  // print out the reading value for debug
  Serial.println(reading); 

  // constrain the reading between our low and high mapping values
  unsigned int prox = constrain(reading, LOW_DIFF, HIGH_DIFF);
  
  // implement a simple (IIR lowpass) smoothing filter
  lastProx = (filterWeight*lastProx) + ((1-filterWeight)*(float)prox);

  // map the LOW_DIFF..HIGH_DIFF range to 0..255 (8-bit resolution for analogWrite)
  uint8_t thisOutput = (uint8_t)map(lastProx,LOW_DIFF,HIGH_DIFF,0,255);

  // output the mapped value to the LED
  analogWrite(LED_BUILTIN, thisOutput);

}

If anybody can provide advice as to how the strip can be dimmable using the capacitive sheet that would be appreciated.

this code

  // map the LOW_DIFF..HIGH_DIFF range to 0..255 (8-bit resolution for analogWrite)
  uint8_t thisOutput = (uint8_t)map(lastProx,LOW_DIFF,HIGH_DIFF,0,255);

  // output the mapped value to the LED
  analogWrite(LED_BUILTIN, thisOutput);

is what would dim your led based on proximity. It calculates in thisOutput a value between 0 (OFF) and 255 (full brightness) for your LED.

you would need to use that value so set the brightness of the pixels. At the moment your code just detect the touch and does on and off.

so change this

 MPR121.updateAll();

  if (MPR121.isNewTouch(PROX_ELECTRODE)) {
    if (PIXELS_ON) {  // if the LED strip is on
      PIXELS_ON = false;
      pixels2.clear();
      pixels2.show();
    } else {  // if the LED strip is off
      PIXELS_ON = true;

      for (int i = 0; i < NUMPIXELS; i++) {  // for each LED within the strip
        pixels2.setPixelColor(i, pixels2.Color(255, 255, 255));
        pixels2.show();
        delay(5);
      }
    }
  }

  if (MPR121_DATASTREAM_ENABLE) {
    MPR121_Datastream.update();
  }

  // update all of the data from the MPR121
  MPR121.updateAll();

to be after the calculation of the thisOutput (what a stupid variable name :innocent: ) and use it to decide how you paint the pixels.

Changing that part of the sketch to occur after the "thisOutput" doesn't have any effect on the LED strip. That still only turns on or off when I move my hand across the capacitive sheet.

I have also tried inputting the "thisOutput" into the pixels2.color values, but this again only has the LED strip coming on as a white light, switching only on or off, not dimming as I require.

This code would read as,

void loop() {
  MPR121.updateAll();

// read the difference between the measured baseline and the measured continuous data
  int reading = MPR121.getBaselineData(PROX_ELECTRODE)-MPR121.getFilteredData(PROX_ELECTRODE);

  // print out the reading value for debug
  Serial.println(reading); 

  // constrain the reading between our low and high mapping values
  unsigned int prox = constrain(reading, LOW_DIFF, HIGH_DIFF);
  
  // implement a simple (IIR lowpass) smoothing filter
  lastProx = (filterWeight*lastProx) + ((1-filterWeight)*(float)prox);

  // map the LOW_DIFF..HIGH_DIFF range to 0..255 (8-bit resolution for analogWrite)
  uint8_t thisOutput = (uint8_t)map(lastProx,LOW_DIFF,HIGH_DIFF,0,255);

  // output the mapped value to the LED
  analogWrite(LED_BUILTIN, thisOutput);

  if (MPR121.isNewTouch(PROX_ELECTRODE)) {
    if (PIXELS_ON) {  // if the LED strip is on
      PIXELS_ON = false;
      //analogWrite(pixels2, thisOutput);
      pixels2.clear();
      pixels2.show();
    } else {  // if the LED strip is off
      PIXELS_ON = true;

      for (int i = 0; i < NUMPIXELS; i++) {  // for each LED within the strip
        pixels2.setPixelColor(i, pixels2.Color(thisOutput, thisOutput, thisOutput));
        pixels2.show();
        delay(5);
      }
    }
  }

I have tried inputting the pixels2 in a line that read "analogWrite(pixels2, thisOutput);" however this doesn't work as I get an error reading,

cannot convert adafruit_neopixel to uint8_t.

Any further suggestions would be great.

Keep things simple. try this - typed here from your code, so no clue if it compiles or does anything - but should get you started.

#include <Wire.h>
#include <MPR121.h>

#include <Adafruit_NeoPixel.h>
#define OUTPUT_PIN 11
#define NUMPIXELS 40  // define how many LEDs are in the strip
Adafruit_NeoPixel pixelStrip(NUMPIXELS, OUTPUT_PIN, NEO_GRB + NEO_KHZ800);

const uint8_t MPR121_ADDR = 0x5C;
const uint8_t MPR121_INT = 4;

const uint8_t PROX_ELECTRODE = 11;

// mapping and filter definitions
const uint8_t LOW_DIFF = 0;
const uint8_t HIGH_DIFF = 50;
const double filterWeight = 0.3f; // 0.0f to 1.0f - higher value = more smoothing

double lastProx = 0;

void setup() {
  pinMode(OUTPUT_PIN, OUTPUT);
  analogWrite(OUTPUT_PIN, LOW);

  Serial.begin(115200);

  Serial.print("\nSetting up MPR121...");

  if (!MPR121.begin(MPR121_ADDR)) {
    Serial.println("error.Stop.");
    while (true) yield();
  }

  MPR121.setInterruptPin(MPR121_INT);
  MPR121.setTouchThreshold(40);     // this is the touch threshold - setting it low makes it more like a proximity trigger, default value is 40 for touch
  MPR121.setReleaseThreshold(20);   // this is the release threshold - must ALWAYS be smaller than the touch threshold, default value is 20 for touch

  MPR121.setFFI(FFI_10);
  MPR121.setSFI(SFI_10);
  MPR121.setGlobalCDT(CDT_4US);  // reasonable for larger capacitances

  MPR121.autoSetElectrodes();
  // slow down some of the MPR121 baseline filtering to avoid
  // filtering out slow hand movements
  MPR121.setRegister(MPR121_NHDF, 0x01); //noise half delta (falling)
  MPR121.setRegister(MPR121_FDLF, 0x3F); //filter delay limit (falling)
  Serial.println("OK");

  pixelStrip.begin();
  pixelStrip.clear();
  pixelStrip.show();

  Serial.println("Ready");
}

void loop() {
  MPR121.updateAll();
  if (MPR121.isNewTouch(PROX_ELECTRODE)) {
    int reading = MPR121.getBaselineData(PROX_ELECTRODE) - MPR121.getFilteredData(PROX_ELECTRODE);

    // constrain the reading between our low and high mapping values
    unsigned int prox = constrain(reading, LOW_DIFF, HIGH_DIFF);

    // implement a simple (IIR lowpass) smoothing filter
    lastProx = (filterWeight * lastProx) + ((1.0 - filterWeight) * prox);

    // map the LOW_DIFF..HIGH_DIFF range to 0..255 (8-bit resolution for analogWrite)
    uint8_t brightness = constrain(map(lastProx, LOW_DIFF, HIGH_DIFF, 0, 255), 0, 255);

    if (brightness < 10) { // turn off
      pixelStrip.clear();
    } else {
      pixelStrip.setBrightness(brightness);
      pixelStrip.fill(pixelStrip.Color(255, 255, 255));
    }
    pixelStrip.show();
  }
}

Or you leave the brightness alone and just adjust the RGB values you are writing.
[just the loop() part]

void loop() {

  if (MPR121_DATASTREAM_ENABLE) {
    MPR121_Datastream.update();
  }

  // update all of the data from the MPR121
  MPR121.updateAll();

  // read the difference between the measured baseline and the measured continuous data
  int reading = MPR121.getBaselineData(PROX_ELECTRODE) - MPR121.getFilteredData(PROX_ELECTRODE);

  // print out the reading value for debug
  Serial.println(reading);

  // constrain the reading between our low and high mapping values
  unsigned int prox = constrain(reading, LOW_DIFF, HIGH_DIFF);

  // implement a simple (IIR lowpass) smoothing filter
  lastProx = (filterWeight * lastProx) + ((1 - filterWeight) * (float)prox);

  // map the LOW_DIFF..HIGH_DIFF range to 0..255 (8-bit resolution for analogWrite)
  uint8_t thisOutput = (uint8_t)map(lastProx, LOW_DIFF, HIGH_DIFF, 0, 255);

  // output the mapped value to the LED
  analogWrite(LED_BUILTIN, thisOutput);

  // fill LEDs
  //for (int i = 0; i < NUMPIXELS; i++) {  // for each LED within the strip
  //  pixels2.setPixelColor(i, pixels2.Color(255, 255, 255));
  //  pixels2.show();
  //  delay(5);
  //}
  fill_solid(pixels2, NUMPIXELS, CRGB(thisOutput, thisOutput, thisOutput));
  pixels2.show();
}

Using J-M-L suggestion, that does control the brightness of the LED, however it does not switch them off when my hand is moved away, but remains at the brightness it last was set to, and only gets brighter.

And using blh64 suggestion, it causes errors and states that "CRGB" is unknown and then "fill_solid" has not been declared. When I have changed it so that it no longer errors it just makes the LEDS function as I have previously had. Just turning both on and off.

this part of the code

    if (brightness < 10) { // turn off
      pixelStrip.clear();
    }

is where I turn off the leds. If they never turn off it means the threshold is not high enough probably. Worth printing brightness and see what are the variations when your hand is there or not.

Sorry, that is from the FastLED library and you are using the NoePixel library. Just go back to the for loop...

  // fill LEDs
  for (int i = 0; i < NUMPIXELS; i++) {  // for each LED within the strip
    pixels2.setPixelColor(i, pixels2.Color(thisOutput, thisOutput, thisOutput));
  }
  //fill_solid(pixels2, NUMPIXELS, CRGB(thisOutput, thisOutput, thisOutput));
  pixels2.show();