@APL2017 I converted the MySensors 1.5 version to 2.x. It compiles but I can not test it since I don't have a hardware setup.
Can you give it a try?
/****************************************************************
Title: MySensors enabled, gesture controlled lamp.
V1.1 March 2016 by Theo
v2.3 January 2021 by Theo (converted to MS 2.0)
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 ues 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 )
Developed and test with MySensors release 1.5.4
Revision history:
31-02-2021 Version 2.2:
- Sketch converted to MySensors 2.0+ (Not not tested)
20-03-2016 Version 1.1:
- 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
****************************************************************/
// Set the wait for ready to zero if you want the light the be operable even when the Gateway is off.
//#define MY_TRANSPORT_WAIT_READY_MS 0
// Enable and select radio type attached
#define MY_RADIO_NRF24
// Import libraries used by the Sketch.
#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 100 // The maximum number of dim levels. Domoticz supports 0-100 (we'll transalate thim in an array)
#define BRIGHTNESS_INCREMENT 15 // 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
#define SN "Gesture controlled lamp" // Description of this sketch.
#define SV "2.2" // The version of the Sketch
// 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)
/**
Values could be calculated. But the sketch is small and storing in an Array is just faster. Otherwise we have to do calculations that incl Floats.
Floats take up a lot of your arduino memory
*/
int dimlevels[ MAXDIMLEVELS ] = // PWM values used for translating home automation dimmer levels. This gives smoother transations
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 35, 39, 42, 46, 49, 52, 56,
59, 62, 66, 69, 73, 76, 79, 83, 86, 89,
93, 96, 100, 103, 106, 110, 113, 116, 120, 123,
126, 130, 133, 137, 140, 144, 147, 150, 154, 157,
160, 164, 167, 171, 174, 177, 181, 184, 187, 191,
194, 197, 201, 204, 208, 211, 215, 218, 221, 225,
228, 231, 235, 238, 242, 245, 246, 250, 251, 255
};
/**
Variables needed for setting up and communication with MySensors. These variables will handle all of the MySensors magic for you.
*/
MyMessage lightMsg(CHILD_ID_LIGHT, V_LIGHT);
MyMessage dimmerMsg(CHILD_ID_LIGHT, V_DIMMER);
/**
Initializing code. Basicly we'll setup MySensors communication and test if we can communicate with the gesture sensor. See comment in setup method for more details
*/
void setup() {
// // Initialize NFR24L01+ radio for enabling MySensors );
// gw.begin(incomingMessage, AUTO, false);
// declare output pin for PWM control of the MOSFET
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 or more sensitive. 1 does it for me
apds.setGestureGain( 1 );
}
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.
}
}
void presentation( ) {
// Send the Sketch Version Information to the Gateway. Domoticz seems to ignore this. Don't know about the other HA systems.
sendSketchInfo(SN, SV);
delay( 50 ); // It can't hurt to add some delay. It gives the gateway some time to handle other messagess
// Present the dimmable lamp is a child node to the HA system. We'll enable ACK communication.
present(CHILD_ID_LIGHT, S_DIMMER, "floor lamp", true );
delay( 50 ); // It can't hurt to add some delay. It gives the gateway some time to handle other messagess
request( CHILD_ID_LIGHT, V_PERCENTAGE ); // Request current dimvalue from HA. The current value is being handled in the incomming method.
delay( 50 ); // It can't hurt to add some delay. It gives the gateway some time to handle other messagess
request( CHILD_ID_LIGHT, V_STATUS ); // Request current lamp state from HA. The current value is being handled in the incomming method.
delay( 50 ); // It can't hurt to add some delay. It gives the gateway some time to handle other messagess
}
// Main loop. Does twoe 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);
}
}
// 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;
}
// Determine gesture and handle accordingly.We'll ignore FAR and NEAR gestures. Do 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)
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)
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
LastLightState = LIGHT_OFF;
SetCurrentState2Hardware();
break;
case DIR_RIGHT: // Handle right stroke. Turn lamp on
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
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_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;
}
}
//Here we'll set the actual light state/level
SetCurrentState2Hardware();
}
// Send current values to the PWM controlled MOSFET
void SetCurrentState2Hardware() {
if (LastLightState == LIGHT_OFF) {
analogWrite( LED_PIN, dimlevels[0] );
}
else {
analogWrite( LED_PIN, dimlevels[ LastDimValue - 1 ] );
}
//Send current state to the controller
SendCurrentState2Controller();
}
// Report new values to the Gateway.
void SendCurrentState2Controller()
{
if ((LastLightState == LIGHT_OFF) || (LastDimValue == 0)) {
send(dimmerMsg.set(0));
}
else {
send(dimmerMsg.set(LastDimValue));
}
}
Note I didn't made any change to how the sketch functions. Some improvements can surely be done. But let's see if it works.