Indeed, I would never thought that loop() would impact the response of the cloud function. I was expecting there was 2 threads: one for the loop() and another one for cloud functions.
See below the complete code for the main file. Please note that it works well when I use the gesture sensor. LedManager is my code and comes after. RGBConverter is a utility class for converting RGB to HSV and back. SparkFun_APDS9960 is a library I found from the Particle IDE.
Thank you in advance.
#include "RGBConverter.h"
#include "LedManager.h"
#include "SparkFun_APDS9960.h"
/*
Soft SPI wires (LED strip)
--------------------------
SCK => D4 green wire
MOSI => D5 white wire
GND => GND blue wire
+5V => VIN red wire
I2C wires (APDS - Gesture sensor)
--------------------------
SDA => D0 orange wire
SCL => D1 yellow wire
INT => D3 white wire
GND => GND blue wire
+3.3V => 3V3 red wire
*/
// APDS interrupt pin
#define APDS9960_INT D3
// Create APDS
SparkFun_APDS9960 apds = SparkFun_APDS9960();
// Flag set to true when interrupt trigger
bool interrupt = false;
// Led manager configuration
#define DATAPIN D4
#define CLOCKPIN D5
#define NUMPIXELS 36
// Create LedManager
LedManager ledManager = LedManager();
// Cloud function
int remoteCtrl(String command);
// Command set by the cloud function
String remoteCommand = NULL;
void setup() {
// Print system version
Serial.printlnf("System version: %s", System.version().c_str());
// Set APDS interrupt pin as input
pinMode(APDS9960_INT, INPUT);
// Initialize interrupt service routine
attachInterrupt(APDS9960_INT, interruptRoutine, FALLING);
// Initialize APDS
if (apds.init()) {
Serial.println("Gesture Sensor initialized.");
} else {
Serial.println("Gesture Sensor failed.");
}
// Start running the APDS-9960 gesture sensor (interrupts)
if (apds.enableGestureSensor(true)) {
Serial.println("Gesture sensor is now running");
} else {
Serial.println("Something went wrong during gesture sensor init!");
}
// Initialize LedManager
ledManager.init(NUMPIXELS, DATAPIN, CLOCKPIN);
// Register the cloud function
Particle.function("remoteCtrl", remoteCtrl);
}
void loop() {
if (interrupt) {
detachInterrupt(APDS9960_INT);
if (apds.isGestureAvailable()) {
handleGesture();
}
interrupt = false;
attachInterrupt(APDS9960_INT, interruptRoutine, FALLING);
}
if (remoteCommand != NULL) {
handleRemoteCommand();
remoteCommand = NULL;
}
}
void interruptRoutine() {
interrupt = true;
}
void handleGesture() {
String eventName = NULL;
switch (apds.readGesture()) {
case DIR_UP:
eventName = "UP";
handleUp();
break;
case DIR_DOWN:
eventName = "DOWN";
handleDown();
break;
case DIR_LEFT:
eventName = "LEFT";
handleLeft();
break;
case DIR_RIGHT:
eventName = "RIGHT";
handleRight();
break;
case DIR_NEAR:
eventName = "NEAR";
handleNear();
break;
case DIR_FAR:
eventName = "FAR";
handleFar();
break;
}
if (eventName != NULL) {
Serial.println(eventName);
Particle.publish("GESTURE-EVENT", eventName, 60, PRIVATE);
}
}
void handleRemoteCommand() {
if (remoteCommand == "up") {
handleUp();
} else if (remoteCommand == "down") {
handleDown();
} else if (remoteCommand == "left") {
handleLeft();
} else if (remoteCommand == "right") {
handleRight();
}
}
void handleUp() {
ledManager.increaseBrightness();
}
void handleDown() {
ledManager.decreaseBrightness();
}
void handleLeft() {
ledManager.previousColor();
}
void handleRight() {
ledManager.nextColor();
}
void handleNear() {
// TODO get color from the cloud. Use a CloudManager class if needed
}
void handleFar() {
// TODO send color to the cloud. Use a CloudManager class if needed
}
int remoteCtrl(String command) {
if ((command == "up") || (command == "down") || (command == "left") || (command == "right")) {
remoteCommand = command;
return 1;
} else {
return -1;
}
}
Here is the LedManager cpp code:
#include "LedManager.h"
// Possible brightness values
double LedManager::BRIGHTNESSES[] = {1, 0.8, 0.6, 0.4, 0.2, 0};
// Possible color values
// white, red, orange, yellow, light green, green, light blue, cyan, navy blue, blue, purple, pink, fushia
byte LedManager::COLORS[][3] = { {255, 255, 255}, {255, 0, 0}, {255, 127, 0}, {255, 255, 0}, {127, 255, 0},
{0, 255, 0}, {0, 255, 127}, {0, 255, 255}, {0, 127, 255}, {0, 0, 255},
{127, 0, 255}, {255, 0, 255}, {255, 0, 127} };
LedManager::LedManager() {
}
LedManager::~LedManager() {
}
void LedManager::init(int NUMPIXELS, int DATAPIN, int CLOCKPIN) {
// Create Adafruit DotStar strip
strip = Adafruit_DotStar(NUMPIXELS, DATAPIN, CLOCKPIN);
// Initialize pins for output
strip.begin();
// Turn all LEDs off ASAP
strip.show();
// Create RGBConverter
rgbConverter = RGBConverter();
// Set brightnessIndex and nbBrightnesses
brightnessIndex = 0;
nbBrightnesses = sizeof(BRIGHTNESSES)/sizeof(double);
// Set colorIndex and nbColors
colorIndex = 0;
nbColors = sizeof(COLORS)/(3*sizeof(byte));
// TODO fade up brightness to max (switch on the light to black to max white)
setStripBrightness(0, BRIGHTNESSES[brightnessIndex], 40, 50);
}
void LedManager::increaseBrightness() {
// Keep current brightness
double currentBrightness = BRIGHTNESSES[brightnessIndex];
if (brightnessIndex > 0) {
brightnessIndex --;
} else {
brightnessIndex = nbBrightnesses - 1;
}
setStripBrightness(currentBrightness, BRIGHTNESSES[brightnessIndex], 10, 10);
}
void LedManager::decreaseBrightness() {
// Keep current brightness
double currentBrightness = BRIGHTNESSES[brightnessIndex];
if (brightnessIndex < nbBrightnesses - 1) {
brightnessIndex ++;
} else {
brightnessIndex = 0;
}
setStripBrightness(currentBrightness, BRIGHTNESSES[brightnessIndex], 10, 10);
}
void LedManager::nextColor() {
if (colorIndex < nbColors - 1) {
colorIndex ++;
} else {
colorIndex = 0;
}
setStripColor(COLORS[colorIndex]);
}
void LedManager::previousColor() {
if (colorIndex > 0) {
colorIndex --;
} else {
colorIndex = nbColors - 1;
}
setStripColor(COLORS[colorIndex]);
}
void LedManager::setStripColor(byte color[3]) {
// TODO Fade brightness down
// Take into account the current brightness
// Convert rgb to hsv and set the brightness
double hsv[] = {0, 0, 0};
rgbConverter.rgbToHsv(color[0], color[1], color[2], hsv);
hsv[2] = BRIGHTNESSES[brightnessIndex];
showStrip(hsv[0], hsv[1], hsv[2]);
// TODO fade brightness up
}
void LedManager::setStripBrightness(double sourceBrightness, double targetBrightness, int nbStep, int sleep) {
// Convert rgb to hsv and set the brightness
double hsv[] = {0, 0, 0};
rgbConverter.rgbToHsv(COLORS[colorIndex][0], COLORS[colorIndex][1], COLORS[colorIndex][2], hsv);
double vIncrement = (targetBrightness - sourceBrightness) / nbStep;
double tmpV = sourceBrightness;
for (int i = 0; i < nbStep; i ++) {
tmpV = tmpV + vIncrement;
if (tmpV >= 0 && tmpV <= 1) {
// Show led strip and wait
showStrip(hsv[0], hsv[1], tmpV);
delay(sleep);
}
}
// Set target brightness because previous v is double and previous calculation may not have reach the exact v value
// Show led strip and wait
showStrip(hsv[0], hsv[1], targetBrightness);
delay(sleep);
}
void LedManager::showStrip(double h, double s, double v) {
// Convert hsv to rgb
byte color[] = {0, 0, 0};
rgbConverter.hsvToRgb(h, s, v, color);
// Set pixels color
for (int i = 0; i < strip.numPixels(); i ++) {
strip.setPixelColor(i, color[0], color[2], color[1]); // this method accepts r, b and g
}
strip.show();
}