This is an alternative configuration for the ESP32 that looks to handle touch events better. It appears the touch hardware’s range of reported values will change for multiple reasons. This makes selecting a threshold that continues to work over time hard to do. This new code just looks for a significate change in the reported touch value from event to event in order to determine that the lamp is being touched. By significant I simply mean a change in value larger than might happen from random sampling of the hardware. Here’s the updated sensor code. While you need to set a threshold value, it’s not used for any thing.
esphome:
name: "fr-lamp-touch-bs"
friendly_name: fr brian side lamp
esp32:
board: esp32dev
# 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: "FR-Lamp-Touch"
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( cur_val < (prev_val - 30)){
ESP_LOGI("custom", "initial touch, value decreased from %d to %d", prev_val, cur_val);
touch_cnt = 1;
}
else if( touch_cnt > 0 ){
if( cur_val > (prev_val + 30)){
ESP_LOGI("custom", "done touch %d, value increased 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(cycle_brightness).press();
}
else
{
ESP_LOGI("custom", "push power button");
id(power).toggle();
}
touch_cnt = 0;
}
else
{
if( touch_cnt < 100){
touch_cnt += 1;
}
ESP_LOGD("custom", "multi touch %d, value %d to %d", touch_cnt, prev_val, cur_val);
}
}
prev_val = cur_val;
return ((uint32_t) id(touch_sensor)->get_value());
esp32_touch:
setup_mode: False
iir_filter: 15ms
# 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: GPIO27
threshold: 710
filters:
# Small filter, to debounce the spurious events.
- delayed_on: 10ms
- delayed_off: 10ms
switch:
- platform: gpio
name: "low_level_filament"
pin: 17
id: low_level
internal: True
- platform: gpio
name: "high_level_filament"
pin: 16
id: high_level
internal: True
- platform: template
name: power
id: power
restore_mode: RESTORE_DEFAULT_OFF
lambda: |-
if (id(low_level).state || id(high_level).state) {
return true;
} else {
return false;
}
turn_on_action:
- select.set:
id: modus_mode
option: "low"
#- switch.turn_on:
turn_off_action:
- select.set:
id: modus_mode
option: "off"
select:
- platform: template
name: "brightness"
id: modus_mode
optimistic: true
options:
- "off"
- "low"
- "medium"
- "high"
initial_option: "off"
on_value:
then:
- lambda: |-
if (id(modus_mode).active_index() == 0) {
id(low_level).turn_off();
id(high_level).turn_off();
} else if (id(modus_mode).active_index() == 1) {
id(low_level).turn_on();
id(high_level).turn_off();
} else if (id(modus_mode).active_index() == 2) {
id(low_level).turn_off();
id(high_level).turn_on();
} else if (id(modus_mode).active_index() == 3) {
id(low_level).turn_on();
id(high_level).turn_on();
}
button:
# button to cycle brightness
- platform: template
name: cycle brightness
id: cycle_brightness
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
- select.set:
id: modus_mode
option: "low"
else:
if:
condition:
and:
# if at low bright
- switch.is_on: low_level
- switch.is_off: high_level
then:
# go to medium bright
- select.set:
id: modus_mode
option: "medium"
else:
if:
condition:
and:
# if at medium bright
- switch.is_off: low_level
- switch.is_on: high_level
then:
# go to high bright
- select.set:
id: modus_mode
option: "high"
else:
# finally if at high bright go to low bright
- select.set:
id: modus_mode
option: "low"
# restart-button
- platform: restart
name: "restart-esp32-dim-touch"
One thing with this code is if you put the logging in DEBUG mode you will get a log entry every 333ms as the handle_touch method runs. I couldn’t figure out how to have the ESPHOME code stop reporting the value with each iteration. If anyone knows how to suppress those messages, please let me know. As these message do provide the touch value that can be useful for seeing all the touch values the code is handling.
I received a suggestion to presented the lamp as a monochromatic light. This gives an on/off button with a slider and is a standard light type handled via HA. The result is easier integration to HA with a standard control. Below is the ESP code to make that happen:
esphome:
name: "fr-lamp-touch-bs"
friendly_name: fr brian side lamp
esp32:
board: esp32dev
# 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: "FR-Lamp-Touch"
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
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( cur_val < (prev_val - 30)){
ESP_LOGI("custom", "initial touch, value decreased from %d to %d", prev_val, cur_val);
touch_cnt = 1;
}
else if( touch_cnt > 0 ){
if( cur_val > (prev_val + 30)){
ESP_LOGI("custom", "done touch %d, value increased 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;
}
else
{
if( touch_cnt < 100){
touch_cnt += 1;
}
ESP_LOGD("custom", "multi touch %d, value %d to %d", touch_cnt, prev_val, cur_val);
}
}
prev_val = cur_val;
return ((uint32_t) id(touch_sensor)->get_value());
esp32_touch:
setup_mode: False
iir_filter: 15ms
# low_voltage_reference: 0.5V
high_voltage_reference: 2.4V
voltage_attenuation: 1V
binary_sensor:
# touch actions handled above
- platform: esp32_touch
id: touch_sensor
pin: GPIO27
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: 17
id: low_level
internal: True
- platform: gpio
#name: "high_level_filament"
pin: 16
id: high_level
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