@TheoL Please see attached stripped version of @pjjarzembowski code. I see that gesture is being detected, attempted to reduce number of light levels to 5. Having trouble with detecting UP and DOWN gestures - not always happening. Trying to understand how dimmer works.
/****************************************************************
Title: MySensors enabled, gesture controlled lamp.
This lamp can be turned on/off, and dimmed by gestures. And it can be controlled by any Home Automation
system, that can talk with MySensors.
Supported gesture:
1. Left to right stroke: turns lamp on
2. Right to left stroke: turns lamp off
3. Down to up stroke: increases brightness (When brightness is already at max, the lamp will blink - duration and blink count can be changed in the sketch)
4. Up to down stroke: decreases brgihtness (When brightness level is at 0 the lamp is off)
The gesture sensor used in this Sketch is an APDS-9960 RGB and Gesture Sensor, sold by SparkFun. They can be found on eBay and Aliexpress as well.
See Sparkfuns hookup guide for pin lay-out ( https://learn.sparkfun.com/tutorials/apds-9960-rgb-and-gesture-sensor-hookup-guide )
IMPORTANT: The APDS-9960 can only accept 3.3V! Use bi direction level converter when using another Arduino than a Pro Mini 3.3V
This Sketch is based upon the GestureTest exampl developped by,
Shawn Hymel @ SparkFun Electronics on May 30, 2014. See https://github.com/sparkfun/APDS-9960_RGB_and_Gesture_Sensor
The lamp itself is a white LED strip, controlled by an N channel MOSFET.
Fore more details on the used hardware and libraries (see https://www.openhardware.io/view/50/Gesture-controlled-MySensors-Floor-lamp )
Revision history:
25-1-2021 Version 2.1 Stripped from everything except gesture and light control.
3-07-2017 Version 2 by pjjarzembowski
- Changed for tests on Mysensors 2.0
20-03-2016 Version 1.1 by Theo:
- set the brightness level to defined BRIGHTNESS_INCREMENT, when lamp is being turned on be a gesture and the current brightness level is 0.
This was a little bug in previous version. It sometimes seemed that the APDS didn't work, but in some cases I had to increase brightness after
I turned the lamp on.
- cleaned up the code a bit
19-03-2016 Version 1.0 by Theo
- Developed and test with MySensors release 1.5.4
****************************************************************/
// Import libraries used by the Sketch.
// added some of my radio definitions (must be before #includes)
#define MY_DEBUG
#define MY_RADIO_RF24
#define MY_NODE_ID 27
//#include <SPI.h>
#include <MySensors.h>
#include <Wire.h>
#include <SparkFun_APDS9960.h>
// Constants declaration(s)
#define APDS9960_INT 2 // Needs to be an interrupt pin. We should be able to use the Arduino's pin 3 as well.
#define LED_PIN 3 // The led PWM pin, that drives the LED strip. This is the pin thats attached to the mosfet.
#define MAXDIMLEVELS 6 // The maximum number of dim levels. Domoticz supports 0-100 (we'll transalate thim in an array)
#define BRIGHTNESS_INCREMENT 20 // Dimmer increment for gesture(s). Play with this value yourself. The amount of gesture controlled
// dim levels is MAXDIMLEVELS / BRIGHTNESS_INCREMENT having 8 to 5 levels feels more natural to me.
#define MAX_LEVEL_REACHED_DELAY 150 // Short blinking delay when increasing the dimmer while the dimmer is already at max
// Had some troubles in the past with tha acurateness of the gw.wait on pro mini's. But that'll probably
// not be noticeable with this short delay. Delay is in milliseconds
#define MAX_LEVEL_REACHED_SIGNAL_COUNT 2 // The amount of blinks, when the max dim level already has been reached. It's just a way to let the user know
// that the lamp can not be more brighter than the current brightness
#define CHILD_ID_LIGHT 1 // The child id of the Node. Only one Node on this sensor though. See MySensors documentation
#define LIGHT_OFF 0 // Constant indicating the lamp on state
#define LIGHT_ON 1 // Constant indicationg light off state
// Global Variables
SparkFun_APDS9960 apds = SparkFun_APDS9960(); // Initialize a SparkFun_APDS9960 object. This does all the magic incl. i2c communication with the sensor.
int isr_flag = 0; // interrupt flag, triggered when a gesture has been dectected. Used to detect gesture detection in the interrupt handler
// the actual handling is done in the main loop. This allows is the keep the interrupt handler is lightweight is possible
// which is a good practice. Otherwise you'll get some behaviour you don't expect.
int LastLightState=LIGHT_OFF; // The current lamp state. Wel'll turn it off for first time useage. The Sketch will query your Home Automation System for
// the last value when it's being reboot.
int LastDimValue=MAXDIMLEVELS; // last known dim value (Only initial value. Value is retrieved from your HA system)
int dimlevels[ MAXDIMLEVELS ] = // PWM values used for translating home automation dimmer levels. This gives smoother transations
{ 0, 50, 100, 150, 200, 255};
MyMessage lightMsg(CHILD_ID_LIGHT, V_LIGHT);
MyMessage dimmerMsg(CHILD_ID_LIGHT, V_DIMMER);
// interrupt handler. Is being triggered by the gesture sensor whenever a gesture has been detected. We've setup this up in the setup.
void interruptRoutine() {
isr_flag = 1;
}
void presentation()
{
sendSketchInfo("Led with Gesture", "2.0");
present(CHILD_ID_LIGHT, S_DIMMER);
}
void setup() {
pinMode( LED_PIN, OUTPUT );
// APDS Initialization code
pinMode(APDS9960_INT, INPUT); // Set interrupt pin as input. @@Note: this should be handled my the library. But it isn't
attachInterrupt(0, interruptRoutine, FALLING); // Initialize interrupt service routine. Basicly it'll call our interrupt routine
if ( apds.init() ) { // Initialize APDS-9960 (configure I2C and initial values)
// @@NOTE: original value is two. But it looks like the modern gesture sensor more sensitive. 1 does it for me
apds.setGestureGain( 2 );
}
if ( apds.enableGestureSensor(true) ) { // Start running the APDS-9960 gesture sensor engine. Sensor support more functions than gesture detection only.
analogWrite( LED_PIN, 0 ); // Turn the lamp off.
// Request current dimvalue. The current value is being handled in the incomming method.
request( CHILD_ID_LIGHT, V_PERCENTAGE ); // Request current dimvalue from HA. The current value is being handled in the incomming method.
// Request current lamp state. The current value is being handled in the incomming method.
request( CHILD_ID_LIGHT, V_STATUS ); // Request current lamp state from HA. The current value is being handled in the incomming method.
}
}
// Main loop. Does two things. Handle gestures if detected by the interrupt routine. And give the MySensors lib the oppurtunity to handle incomming messages.
void loop()
{
if( isr_flag == 1 ) {
detachInterrupt(0);
handleGesture();
isr_flag = 0;
attachInterrupt(0, interruptRoutine, FALLING);
}
}
// Determine gesture and handle accordingly.We'll ignore FAR and NEAR gestures. Didn't feel natural to me anyway.
void handleGesture() {
if ( apds.isGestureAvailable() ) { // Check if there's a gesture available. Which should be, because the interrupt handler told us so.
switch ( apds.readGesture() ) { // Get the gesture type.
case DIR_UP: // Handle up stroke (Brightness increasing)
Serial.println ("DIR_UP");
if ( LastDimValue + BRIGHTNESS_INCREMENT > ( MAXDIMLEVELS - 1 ) ) {
for ( int i = 0; i < MAX_LEVEL_REACHED_SIGNAL_COUNT; i++ ) {
analogWrite( LED_PIN, dimlevels[ 0 ] );
wait( MAX_LEVEL_REACHED_DELAY );
analogWrite( LED_PIN, dimlevels[ MAXDIMLEVELS - 1 ] );
wait(MAX_LEVEL_REACHED_DELAY );
}
LastDimValue = ( MAXDIMLEVELS - 1 );
}
else {
LastDimValue += BRIGHTNESS_INCREMENT;
}
LastLightState = LIGHT_ON;
SetCurrentState2Hardware();
break;
case DIR_DOWN: // Handle down stroke (Brightness decreasing)
Serial.println ("DIR_DOWN");
if ( LastDimValue - BRIGHTNESS_INCREMENT <= 0 ) {
LastDimValue = 0;
}
else {
LastDimValue -= BRIGHTNESS_INCREMENT;
}
if ( LastDimValue == 0 ) {
LastLightState = LIGHT_OFF;
}
else {
LastLightState = LIGHT_ON;
}
SetCurrentState2Hardware();
break;
case DIR_LEFT: // Handle left stroke. Turn lamp off
Serial.println ("DIR_LEFT");
LastLightState = LIGHT_OFF;
SetCurrentState2Hardware();
break;
case DIR_RIGHT: // Handle right stroke. Turn lamp on
Serial.println ("DIR_RIGHT");
LastLightState = LIGHT_ON;
if ( LastDimValue == 0 ) { // @@Version 1.1 addition Slight modification. When the dimValue was 0, the light stayed off when turned on.
LastDimValue = BRIGHTNESS_INCREMENT; // Just used the first Gesture dimming stage (2 times would be better for my taste though. Might change that in the future)
}
SetCurrentState2Hardware();
break;
}
}
}
/**
* Handler for message send by the MySensor gateway.
*/
void receive(const MyMessage &message) {
//if ( message.type == V_LIGHT ) { // Gateway reports a new Light state
if ( message.type == V_STATUS ) { // Gateway reports a new Light state
int lstate= atoi( message.data );
if ( ( lstate < 0 ) || ( lstate > 1 ) ) {
return;
}
LastLightState=lstate;
if ( ( LastLightState == LIGHT_ON ) &&( LastDimValue == 0 ) ) {
//In the case that the Light State = On, but the dimmer value is zero, then something (probably the controller) did something wrong,
//for the Dim value to 100%
LastDimValue = 100;
}
//When receiving a V_LIGHT command we switch the light between OFF and the last received dimmer value
//This means if you previously set the lights dimmer value to 50%, and turn the light ON
//it will do so at 50%
}
//else if (message.type == V_PERCENTAGE) { // Gateway reports new dimmer level. We'l adjust it to the new value
else if (message.type == V_DIMMER) { // Gateway reports new dimmer level. We'l adjust it to the new value
int dimvalue= atoi( message.data );
if ( ( dimvalue < 0 ) || ( dimvalue > 100 ) ) {
return;
}
if ( dimvalue == 0 ) {
LastLightState = LIGHT_OFF;
}
else {
LastLightState = LIGHT_ON;
LastDimValue = dimvalue;
}
}
SetCurrentState2Hardware(); //Here we'll set the actual light state/level
}
void SetCurrentState2Hardware() { // Send current values to the PWM controlled MOSFET
if (LastLightState==LIGHT_OFF) {
analogWrite( LED_PIN, dimlevels[0] );
Serial.print ("DIMELEVELS ");
Serial.println (dimlevels[LastDimValue] );
}
else {
analogWrite( LED_PIN, dimlevels[ LastDimValue - 1 ] );
}
SendCurrentState2Controller(); //Send current state to the controller
}
void SendCurrentState2Controller() // Report new values to the Gateway
{
if ((LastLightState==LIGHT_OFF)||(LastDimValue==0)) {
send(dimmerMsg.set(0));
}
else {
send(dimmerMsg.set(LastDimValue));
}
}