How to make a dumb 3 way bulb lamp smart

I’ve been working on getting things smaller for you. Here are the items I put into this lamp.

  • M5Stamp ESP32S3 Module - I used this one but would suggest using this alternative with pins. The one I used does not come with pins and if you’re not an experts with the soldering iron it’s near impossible to get things connected.
  • SunFounder 2 Channel DC 5V Relay - This is the smallest I could find. If anyone has seen something smaller, please let me know.
  • A small box. Wish I had a 3D printer to make something just right. I had to cut out some plastic that reduced the space in the box. As you can see below this is a tight fit.
  • 18 Guage 3 conductor wire - After ordering this I found 25ft at Lowes for $11.

Two wire connectors. I couldn’t get two of the new ones I listed in the first post inside the box with everything. Fortunately I had an alternative that was slightly narrower to make everything fit.

Here’s the open box loaded:

Here’s everything buttoned up:

And here it sits in it’s normal place:

There was sensitivity with the touch sensor with this lamp. I’m wondering if the issue is my shoddy connections, because there are no pins on the esp32. I order a few of the second M5Stamp with the pins to see if it works better, like it did in the standard bulb lamp I built. To deal with the sensitivity I had to use the code I worked out earlier. Here is the code I used in lamp:

esphome:
  name: "master-bed-touch-lamp"
  friendly_name: "master-bed-touch-lamp"

esp32:
  board: esp32-s3-devkitc-1
  framework:
    type: arduino

# Enable logging
logger:
  level: INFO
#  level: DEBUG

# Enable Home Assistant API
api:
  encryption:
    key: !secret api_key

ota:
  password: !secret ota_password

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Master-Touch-Lamp"
    password: !secret wifi_password

# Enable Web server.
web_server:
  port: 80
  
captive_portal:

sensor:
  # hack so the touch sensor doesn't kick off at power on
  - platform: uptime
    name: Uptime Sensor
    id: time_since_boot
    update_interval: 30s

  #Readings calculated from espTouch sensors
  - platform: template
#    name: "Handle Touch"
    id: "handle_touch"
    internal: True
    update_interval: 333ms # a third of a second between check of touch 
    accuracy_decimals: 0
    lambda: |-
      static uint32_t touch_cnt; 
      static uint32_t prev_val;
      static uint16_t first_time = 1;
      static uint16_t start_up_delay = 30; // about 10 seconds - 30*333ms
      uint32_t cur_val;

      cur_val = ((uint32_t) id(touch_sensor)->get_value());

      if( first_time ){
        start_up_delay -= 1;
        if( start_up_delay <= 0){
          ESP_LOGI("custom", "Initial touch value, cur is: %d", cur_val);
          first_time = 0;
          touch_cnt = 0;
        }
        else
        {
          ESP_LOGI("custom", "Establishing initial touch sensor value, cur is: %d", cur_val);
        }
      }
      else if( !touch_cnt && (cur_val > (prev_val + 25000))){
        ESP_LOGI("custom", "initial touch, value increased from %d to %d", prev_val, cur_val);
        touch_cnt = 1;
      }
      else if( touch_cnt > 0 ){
        if( cur_val < (prev_val - 25000)){
          ESP_LOGI("custom", "done touch %d, value decreased from %d to %d", touch_cnt, prev_val, cur_val);
          if( touch_cnt > 10)
          {
            ESP_LOGI("custom", "ignore touch");
          }
          else if (touch_cnt > 2)
          {
            ESP_LOGI("custom", "change brightness");
            id(brightness_step).press();
          }
          else 
          {
            ESP_LOGI("custom", "push power button");
            id(power).toggle();
          }
          touch_cnt = 0;
          // force skipping a couple after we handle a touch
          start_up_delay = 2;
          first_time = 1;
        }
        else
        {
          if( touch_cnt < 30){
            touch_cnt += 1;
            ESP_LOGD("custom", "multi touch %d, value %d to %d", touch_cnt, prev_val, cur_val);
          }
          else {
            ESP_LOGD("custom", "Reset touch because count too high %d, value %d to %d", touch_cnt, prev_val, cur_val);
            touch_cnt = 0;
            // force skipping a couple after we handle a touch
            start_up_delay = 2;
            first_time = 1;
          }
        }
      }

      prev_val = cur_val;
      return ((uint32_t) id(touch_sensor)->get_value());

esp32_touch:
  setup_mode: False
  measurement_duration: 0.25ms
#  low_voltage_reference: 0.5V
#  high_voltage_reference: 2.4V
#  voltage_attenuation: 1V

binary_sensor:
  - platform: esp32_touch
#    name: "esp32 touch sensor"
    id: touch_sensor
    #pin: GPIO32
    pin: GPIO5
    threshold: 10
    filters:
      # Small filter, to debounce the spurious events.
      - delayed_on: 10ms
      - delayed_off: 10ms
       

button:
  # button to cycle brightness
  - platform: template
    name: brightness step
    id: brightness_step
    on_press:
      then:
        if:
          condition:
            and:
              # if light is off 
              - switch.is_off: low_level
              - switch.is_off: high_level
          then:
            # set to lowest level
            - light.turn_on:
                id: lamp_ctrl
                brightness: 33%          
          else:
            if:
              condition:
                and:
                  # if at low bright
                  - switch.is_on: low_level
                  - switch.is_off: high_level
              then:
                # go to medium bright
                - light.turn_on:
                    id: lamp_ctrl
                    brightness: 66%
              else:
                if:
                  condition:
                    and:
                      # if at medium bright
                      - switch.is_off: low_level
                      - switch.is_on: high_level
                  then:
                    # go to high bright
                    - light.turn_on:
                        id: lamp_ctrl
                        brightness: 100%
                  else:
                    # finally if at high bright go to low bright
                    - light.turn_on:
                        id: lamp_ctrl
                        brightness: 33%

  # restart-button
  - platform: restart
    name: "restart-esp32-dim-touch"

switch:
  - platform: gpio
    #name: "low_level_filament"
    pin: GPIO7
    id: low_level
    inverted: true
    internal: True

  - platform: gpio
    #name: "high_level_filament"
    pin: GPIO9
    id: high_level
    inverted: true
    internal: True

  - platform: template
    #name: power
    id: power
    internal: True
    restore_mode: RESTORE_DEFAULT_OFF
    lambda: |-
      if (id(low_level).state || id(high_level).state) {
        return true;
      } else {
        return false;
      }
    turn_on_action:
      - light.turn_on:
          id: lamp_ctrl
          brightness: 33%    
      #- switch.turn_on: 
    turn_off_action:
      - light.turn_off:
          id: lamp_ctrl

output:
  - platform: template
    type: float
    id: output_comp
    write_action:
#      - lambda: |-
#          ESP_LOGI("custom", "Write action state = %f", state);
      - if:
          condition:
            lambda: return ((state > 0) && (state < .34));
          then:
            - switch.turn_on: low_level
            - switch.turn_off: high_level
          else:
            - if: 
                condition:
                  lambda: return ((state >= .34) && (state < .67));
                then:
#                  - lambda: |-
#                      ESP_LOGI("custom", "Low level state = %f", state);
                  - switch.turn_off: low_level
                  - switch.turn_on: high_level
                else:
                  - if: 
                      condition:
                        lambda: return ((state >= .67) && (state <= 1));
                      then:
#                        - lambda: |-
#                            ESP_LOGI("custom", "Low level state = %f", state);
                        - switch.turn_on: low_level
                        - switch.turn_on: high_level
                      else:
                        - if: 
                            condition:
                              lambda: return ((state == 0) );
                            then:
#                              - lambda: |-
#                                  ESP_LOGI("custom", "Turn light off = %f", state);
                              - switch.turn_off: low_level
                              - switch.turn_off: high_level

            
light:
  - platform: monochromatic
    name: "Lamp Control"
    id: lamp_ctrl
    output: output_comp
    gamma_correct: 1
    default_transition_length: 10ms
    restore_mode: RESTORE_DEFAULT_OFF

Hopefully this packaging will address the WAF. This is my third post in a row on this thread so I will not be able to post again unless someone else response on the thread. Once I get the other M5SampS3 controllers I’ll provide an update.

1 Like