Navigation

    • Register
    • Login
    • OpenHardware.io
    • Categories
    • Recent
    • Tags
    • Popular
    1. Home
    2. FreakOfNature
    • Profile
    • Following
    • Followers
    • Topics
    • Posts
    • Best
    • Groups

    FreakOfNature

    @FreakOfNature

    3
    Reputation
    7
    Posts
    491
    Profile views
    0
    Followers
    0
    Following
    Joined Last Online

    FreakOfNature Follow

    Best posts made by FreakOfNature

    • RE: Led dimmer with touch sensor

      I thought about it a little bit and realized that the reliability issue arose when I was not connected to a really good ground. Referred to the docs and it appears that this is a known issue with capacitive sensing and that a good ground is needed.
      http://playground.arduino.cc/Main/CapacitiveSensor?from=Main.CapSense

      Apparently another work around is a large grounding plate under the touch sensor separated by an insulator. I may just hang some rebar in the middle of my lamp to act as a grounding plate.

      I think the code above can be considered an alpha or rough beta of adding touch. My gateway died so I have not tested that part of the code to make sure I did not break it.

      Basically, the code should take the normal dimmable led and add touch dimming to it. Touching for less than TOUCH_HOLD_THRESHOLD will toggle on/off, longer than that will start a dim up to max, then down to zero and repeat till you let go. What you release at is saved so that if you tap off then back on it returns to the dim level you selected.

      Once I iron out the code I'll post a final version with some instructions. With this you can add touch dimming with a resistor and wire if you have good grounding.

      posted in Development
      FreakOfNature
      FreakOfNature
    • RE: Led dimmer with touch sensor

      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));
      }
      
      
      
      posted in Development
      FreakOfNature
      FreakOfNature
    • RE: Led dimmer with touch sensor

      Before I forget, I should add a few notes for anyone else that wants to try this.

      1. grounding is required unless you want to do trial and error on a ground plane. I just bought a 3 wire extension cord and modified it. Please do not do this unless you know how to mess with things connected to mains without killing yourself.

      2. any capacitance added to the system will skew results, aka you may get good results via serial, but remember even a laptop on batteries adds capacitance, and if you touch it you add more. So, while it looks to work connected to a computer or laptop, do not expect it to work when connected to a lamp the first time.

      3. the larger the metal mass connected to the sensor pin, the less likely it is to work. a small wire, works great. A small lamp, probably works fine I did not test. A six foot tall metal lamp when you live near high voltage lines.... will not work. I had to go with a wire running to a touch pad rather than the entire lamp being the touch surface.

      4. if touch is not working in final install location, get the smallest battery powered computer you have and keep an eye on serial output. print out total1 as this is the value measured against TOUCH_THRESHOLD.

      posted in Development
      FreakOfNature
      FreakOfNature

    Latest posts made by FreakOfNature

    • RE: Led dimmer with touch sensor

      Before I forget, I should add a few notes for anyone else that wants to try this.

      1. grounding is required unless you want to do trial and error on a ground plane. I just bought a 3 wire extension cord and modified it. Please do not do this unless you know how to mess with things connected to mains without killing yourself.

      2. any capacitance added to the system will skew results, aka you may get good results via serial, but remember even a laptop on batteries adds capacitance, and if you touch it you add more. So, while it looks to work connected to a computer or laptop, do not expect it to work when connected to a lamp the first time.

      3. the larger the metal mass connected to the sensor pin, the less likely it is to work. a small wire, works great. A small lamp, probably works fine I did not test. A six foot tall metal lamp when you live near high voltage lines.... will not work. I had to go with a wire running to a touch pad rather than the entire lamp being the touch surface.

      4. if touch is not working in final install location, get the smallest battery powered computer you have and keep an eye on serial output. print out total1 as this is the value measured against TOUCH_THRESHOLD.

      posted in Development
      FreakOfNature
      FreakOfNature
    • RE: Led dimmer with touch sensor

      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));
      }
      
      
      
      posted in Development
      FreakOfNature
      FreakOfNature
    • RE: Led dimmer with touch sensor

      I thought about it a little bit and realized that the reliability issue arose when I was not connected to a really good ground. Referred to the docs and it appears that this is a known issue with capacitive sensing and that a good ground is needed.
      http://playground.arduino.cc/Main/CapacitiveSensor?from=Main.CapSense

      Apparently another work around is a large grounding plate under the touch sensor separated by an insulator. I may just hang some rebar in the middle of my lamp to act as a grounding plate.

      I think the code above can be considered an alpha or rough beta of adding touch. My gateway died so I have not tested that part of the code to make sure I did not break it.

      Basically, the code should take the normal dimmable led and add touch dimming to it. Touching for less than TOUCH_HOLD_THRESHOLD will toggle on/off, longer than that will start a dim up to max, then down to zero and repeat till you let go. What you release at is saved so that if you tap off then back on it returns to the dim level you selected.

      Once I iron out the code I'll post a final version with some instructions. With this you can add touch dimming with a resistor and wire if you have good grounding.

      posted in Development
      FreakOfNature
      FreakOfNature
    • Led dimmer with touch sensor

      I'm working on modifying the led dimmer with rotary input to use a touch pad but have ran into issues. It works exactly the way I want it to when the arduino is still plugged into my pc, but it I use my laptop or just the power brick the capsense values fluctuate wildly and even smoothing is not helping.

      I'm thinking it is hardware, I have the default led dimmer setup with a 1M ohm resistor between pins 2 & 4 and a wire coming off 2 for the cap sensing. I am using the capsense library from arduino.

      Here is my wall of code. It is still a bit messy due to troubleshooting.

      /**
       * 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
       * 
       * 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);        // 11M resistor between pins 4 & 2, pin 2 is sensor pin
      
      // value returned by cap sensor that is a touch if exceeded
      #define TOUCH_THRESHOLD 3000
      #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 SEND_THROTTLE_DELAY 2000 // Number of milliseconds before sending after user stops turning knob
      #define SN "DimmableLED /w touch"
      #define SV "0.1"
      
      #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 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);
        if (totalraw > 3200) {
          totalraw = 3200;
        }
        // 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;
        Serial.print(total1);
        Serial.print('\n');
        unsigned long currentTime  = millis();
        //fadeTo = loadLevelState(EEPROM_DIM_LEVEL_SAVE);
        if (total1 > TOUCH_THRESHOLD) {
      //    Serial.print(touchHoldCount);
      //    Serial.print('\n');
          Serial.print(total1);
          Serial.print('\n');
          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;
            }
      
            //changedByTouch = true;
            sendDimValue = true;
            sendDimTimeout = currentTime;
            saveLevelState(EEPROM_DIM_LEVEL_SAVE, fadeTo);
            analogWrite( LED_PIN, (int)(fadeTo / 100. * 255) );
            delay(20);
            dimValue = fadeTo;
            //startFade();
          }else if (touchHoldCount < (TOUCH_HOLD_THRESHOLD + 5)) {
            touchHoldCount = touchHoldCount +1;
          }    
        }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;
          }
          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
          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;
        }
        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));
      }
      
      posted in Development
      FreakOfNature
      FreakOfNature
    • RE: Presence detection

      I think what ericvdb said with the IR sensors is probably close to the best solution. If you figure out a way to count people at each doorway you could do a sudo presence detection.

      So, if you count people as they enter, and at each threshold remove a person from the room they are leaving and add to the one they are going to you should have something that is rather accurate.

      This could have issues if you carry someone from one room to another, but you could add pir to rooms to correct exceptions. Something along the lines of, you carry someone into the living room, it counts one person there, you go to kitchen, it reduces to 0 and turns off lights, but you have an exception that if there is motion and zero people it changes to one person in the room. Would just have to be sure your hvac does not set of the pir.

      posted in Hardware
      FreakOfNature
      FreakOfNature
    • RE: Presence detection

      https://xethru.com/ When this comes down in price it seems like it would be a good solution. Right now it is still a bit pricey.

      posted in Hardware
      FreakOfNature
      FreakOfNature
    • RE: Parking Sensor

      My brother just bought a house and I am going to sucker him into taking up this project by building this for him. I want to add some gas sensors and would like advice on best ones to add. I want to monitor CO, LPG, Butane, and fumes you would get off regular old automotive gas.

      posted in My Project
      FreakOfNature
      FreakOfNature