Ok, got it working. Probably could use some code cleanup but it works so I don't care. lol
Code is set up so you can tap on/off, tap and hold to dim with dim value at release getting saved to eeprom and you can double tap to 100% brightness.
This can be added to any led dimmer by adding a 1M ohm resistor and a touch wire. aka, on the cheap. The Arduino capSense library is needed as well as a good ground.
http://playground.arduino.cc/Main/CapacitiveSensor?from=Main.CapSense
@hek you are more than welcome to add this code to the led dimmer build page, I recommend cleaning it up first though. Touch sense could be broken into functions, noted better, and I am pretty sure there is at least one variable declared but not used. lol
/**
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2015 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
* Support Forum: http://forum.mysensors.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
*******************************
*
* REVISION HISTORY
* Version 1.0 - Developed by Bruce Lacey and GizMoCuz (Domoticz)
* Version 1.1 - Modified by hek to incorporate a rotary encode to adjust
* light level locally at node
* Version 1.2 - Modified FreakOfNature to replace rotary encode with touch dim
* DESCRIPTION
*
* Default MOSFET pin is 3
*
*/
#include <SPI.h>
#include <Encoder.h>
#include <MySensor.h>
#include <Bounce2.h>
#include <CapacitiveSensor.h>
// touch sensor smoothing
const int numReadings = 10;
int readings[numReadings]; // the readings from the analog input
int readIndex = 0; // the index of the current reading
int total = 0; // the running total
int average = 0; // the average
CapacitiveSensor cs_4_2 = CapacitiveSensor(4,2); // 1M resistor between pins 4 & 2, pin 2 is sensor pin
// value returned by cap sensor that is a touch if exceeded
#define TOUCH_THRESHOLD 500
// lenght in time before touch is hold, 200 ~1.5 seconds on 16mhz pro mini
#define TOUCH_HOLD_THRESHOLD 200
#define LED_PIN 3 // Arduino pin attached to MOSFET Gate pin
#define FADE_DELAY 10 // Delay in ms for each percentage fade up/down (10ms = 1s full-range dim)
#define TOUCH_FADE_DELAY 40 // Delay() value in dim while touched loop
#define SEND_THROTTLE_DELAY 4000 // Number of milliseconds before sending after user stops turning knob
#define DOUBLE_TAP_DELAY 500
#define SN "DimmableLED /w touch"
#define SV "1.2"
#define CHILD_ID_LIGHT 1
#define EEPROM_DIM_LEVEL_LAST 1
#define EEPROM_DIM_LEVEL_SAVE 2
#define LIGHT_OFF 0
#define LIGHT_ON 1
int tapCount = 0;
int touchHoldCount = 0;
int isTouched;
int totalraw = 0;
int dimValue;
int fadeTo;
int fadeDelta;
int oldTotal1;
int total1;
bool dimIncrease=true;
bool sendDimValue=false;
bool changedByTouch=false;
unsigned long lastFadeStep;
unsigned long sendDimTimeout;
char convBuffer[10];
MySensor gw;
MyMessage dimmerMsg(CHILD_ID_LIGHT, V_DIMMER);
Bounce debouncer = Bounce();
void setup()
{
// turn off autocalibrate on channel 1
// cs_4_2.set_CS_AutocaL_Millis(0xFFFFFFFF);
// oldTotal1 = cs_4_2.capacitiveSensor(30);
// initialize smoothing readings to 0
for (int thisReading = 0; thisReading < numReadings; thisReading++)
readings[thisReading] = 0;
// Set analog led pin to off
analogWrite( LED_PIN, 0);
// Init mysensors library
gw.begin(incomingMessage, AUTO, false);
// Send the Sketch Version Information to the Gateway
gw.present(CHILD_ID_LIGHT, S_DIMMER);
gw.sendSketchInfo(SN, SV);
Serial.begin(9600);
// Retreive our last dim levels from the eprom
fadeTo = dimValue = 0;
byte oldLevel = loadLevelState(EEPROM_DIM_LEVEL_LAST);
Serial.print("Sending in last known light level to controller: ");
Serial.println(oldLevel);
gw.send(dimmerMsg.set(oldLevel), true);
Serial.println("Ready to receive messages...");
}
void loop()
{
// Process incoming messages (like config and light state from controller)
gw.process();
// Check if someone turned the rotary encode
checkTouchSensor();
// Fade light to new dim value
fadeStep();
}
void incomingMessage(const MyMessage &message)
{
if (message.type == V_LIGHT) {
// Incoming on/off command sent from controller ("1" or "0")
int lightState = message.getString()[0] == '1';
int newLevel = 0;
if (lightState==LIGHT_ON) {
// Pick up last saved dimmer level from the eeprom
newLevel = loadLevelState(EEPROM_DIM_LEVEL_SAVE);
}
// Send dimmer level back to controller with ack enabled
gw.send(dimmerMsg.set(newLevel), true);
// We do not change any levels here until ack comes back from gateway
return;
} else if (message.type == V_DIMMER) {
// Incoming dim-level command sent from controller (or ack message)
fadeTo = atoi(message.getString(convBuffer));
// Save received dim value to eeprom (unless turned off). Will be
// retreived when a on command comes in
if (fadeTo != 0)
saveLevelState(EEPROM_DIM_LEVEL_SAVE, fadeTo);
}
saveLevelState(EEPROM_DIM_LEVEL_LAST, fadeTo);
Serial.print("New light level received: ");
Serial.println(fadeTo);
// Stard fading to new light level
startFade();
}
void checkTouchSensor() {
byte newLevel = 0;
// cs_4_2.set_CS_AutocaL_Millis(0xFFFFFFFF);
int totalraw = cs_4_2.capacitiveSensor(30);
// prevent touch from rolling to negative
if (totalraw > 3200) {
totalraw = 3200;
}
// average last numReadings to stabalize touch
// subtract the last reading:
total = total - readings[readIndex];
// read from the sensor:
readings[readIndex] = totalraw;
// add the reading to the total:
total = total + readings[readIndex];
// advance to the next position in the array:
readIndex = readIndex + 1;
// if we're at the end of the array...
if (readIndex >= numReadings)
// ...wrap around to the beginning:
readIndex = 0;
// calculate the average:
total1 = total / numReadings;
unsigned long currentTime = millis();
//fadeTo = loadLevelState(EEPROM_DIM_LEVEL_SAVE);
if (total1 > TOUCH_THRESHOLD) {
if (touchHoldCount > TOUCH_HOLD_THRESHOLD) {
if (fadeTo >= 100) {
dimIncrease = false;
}
if (fadeTo <= 0) {
dimIncrease = true;
}
if (dimIncrease == true) {
fadeTo = fadeTo +1;
}
if (dimIncrease == false) {
fadeTo = fadeTo -1;
}
Serial.print(fadeTo);
Serial.print('\n');
sendDimValue = true;
sendDimTimeout = currentTime;
saveLevelState(EEPROM_DIM_LEVEL_SAVE, fadeTo);
analogWrite( LED_PIN, (int)(fadeTo / 100. * 255) );
delay(TOUCH_FADE_DELAY);
dimValue = fadeTo;
}else if (touchHoldCount < (TOUCH_HOLD_THRESHOLD + 5)) {
touchHoldCount = touchHoldCount +1;
}
}else if (total1 < TOUCH_THRESHOLD && tapCount >= 2) {
newLevel = 100;
touchHoldCount = 0;
tapCount = 0;
sendDimValue = true;
sendDimTimeout = currentTime;
fadeTo = newLevel;
startFade();
}else if (total1 < TOUCH_THRESHOLD && dimValue==0 && touchHoldCount != 0 && touchHoldCount < TOUCH_HOLD_THRESHOLD) {
Serial.print("set old dim");
Serial.print('\n');
// Turn on light. Set the level to last saved dim value
int saved = loadLevelState(EEPROM_DIM_LEVEL_SAVE);
newLevel = saved > 0 ? saved : 100;
if (newLevel > 100) {
newLevel = 100;
} else if (newLevel < 0) {
newLevel = 0;
}
tapCount = tapCount + 1;
touchHoldCount = 0;
sendDimValue = true;
sendDimTimeout = currentTime;
fadeTo = newLevel;
startFade();
}else if (total1 < TOUCH_THRESHOLD && dimValue>0 && touchHoldCount != 0 && touchHoldCount < TOUCH_HOLD_THRESHOLD) {
Serial.print("set dim zero");
Serial.print('\n');
// Turn off
tapCount = tapCount + 1;
newLevel = 0;
touchHoldCount = 0;
sendDimValue = true;
sendDimTimeout = currentTime;
fadeTo = newLevel;
startFade();
}
//oldTotal1 = total1;
if (total1 < TOUCH_THRESHOLD && touchHoldCount >= 1) {
// gw.send(dimmerMsg.set(newLevel),true);
touchHoldCount = 0;
dimIncrease = !dimIncrease;
}
if (tapCount > 0 && currentTime > sendDimTimeout + DOUBLE_TAP_DELAY) {
tapCount = 0;
Serial.print("tap count zero");
Serial.print('\n');
}
if (sendDimValue && currentTime > sendDimTimeout + SEND_THROTTLE_DELAY) {
// We're done fading.. send in new dim-value to controller.
// Send in new dim value with ack (will be picked up in incomingMessage)
gw.send(dimmerMsg.set(dimValue), true); // Send new dimmer value and request ack back
sendDimValue = false;
}
}
void startFade() {
fadeDelta = ( fadeTo - dimValue ) < 0 ? -1 : 1;
lastFadeStep = millis();
}
// This method provides a graceful none-blocking fade up/down effect
void fadeStep() {
unsigned long currentTime = millis();
if ( dimValue != fadeTo && currentTime > lastFadeStep + FADE_DELAY) {
dimValue += fadeDelta;
analogWrite( LED_PIN, (int)(dimValue / 100. * 255) );
lastFadeStep = currentTime;
Serial.print("Fading level: ");
Serial.println(dimValue);
if (fadeTo == dimValue && changedByTouch) {
sendDimValue = true;
sendDimTimeout = currentTime;
}
}
// Wait a few millisecs before sending in new value (if user still turns the knob)
if (sendDimValue && currentTime > sendDimTimeout + SEND_THROTTLE_DELAY) {
// We're done fading.. send in new dim-value to controller.
// Send in new dim value with ack (will be picked up in incomingMessage)
gw.send(dimmerMsg.set(dimValue), true); // Send new dimmer value and request ack back
sendDimValue = false;
}
}
// Make sure only to store/fetch values in the range 0-100 from eeprom
int loadLevelState(byte pos) {
return min(max(gw.loadState(pos),0),100);
}
void saveLevelState(byte pos, byte data) {
gw.saveState(pos,min(max(data,0),100));
}