Adding bed controller to shared esphome devices

This commit is contained in:
John Dillenburg
2025-03-03 14:19:27 -06:00
parent 871f4a2c65
commit 8bdfb26203
2 changed files with 346 additions and 0 deletions

1
.gitignore vendored
View File

@@ -11,6 +11,7 @@
# List of files to consider for check in
!garage-door-controller.yaml
!bed-controller2.yaml
!TFmini.h
!/packages/
!/packages/wifi.yaml

345
bed-controller2.yaml Normal file
View File

@@ -0,0 +1,345 @@
#
# EspHome device that controls the inclination of a bed. Assumes the Esp32
# is connected to a 12V motor via a motor controller with GPIO4 and 5
# connected to the forward and reverse PWM inputs. Also requires an
# ADXL345 accelerometer that is mounted under the bed frame in such a way
# that its tilt angle can be determined based on it becoming "off_vertical".
# This is used to stop the bed motor once the ADXL345 tells this Esp32 the
# bed is inclined as desired. I also have an LCD readout but that is optional.
#
esphome:
name: bed-controller2
friendly_name: Bed Controller2
on_boot:
# network not up yet when at 600 priority
- priority: 600
then:
- light.turn_on:
id: onboard_led
red: 100%
green: 0%
blue: 0%
# network and mqtt are up, turn light green off and enable motor
- priority: 200
then:
- output.turn_on: motor_ren
- output.turn_on: motor_len
- delay: 10s
- light.turn_off:
id: onboard_led
- lambda: |-
id(lcd).no_backlight();
comment: esp32-c3-devkitm-1
libraries:
- "Wire"
- "SPI"
- "Adafruit BusIO"
- "Adafruit Unified Sensor"
- "Adafruit ADXL345"
external_components:
- source:
type: git
url: https://github.com/jdillenburg/esphome
ref: main
components: [ adxl345 ]
packages:
wifi: !include { file: "packages/wifi.yaml", vars: { ssid: "bed-controller" }}
esp32:
board: esp32-c3-devkitm-1
framework:
type: arduino
# Enable logging
logger:
level: WARN
# Enable Home Assistant API
api:
encryption:
key: !secret bed_controller2_api_key
ota:
- platform: esphome
password: "630cb512ba32dcd66c55220b3921a0b0"
# Sync time with Home Assistant.
time:
- platform: homeassistant
id: homeassistant_time
# Text sensors with general information.
text_sensor:
# Expose ESPHome version as sensor.
- platform: version
name: ESPHome Version
# Expose WiFi information as sensors.
- platform: wifi_info
ip_address:
name: IP
ssid:
name: SSID
bssid:
name: BSSID
switch:
- platform: restart
name: "Restart"
globals:
- id: motor_speed
type: float
restore_value: False
initial_value: '10'
- id: num_speeds
type: int
restore_value: False
initial_value: '2'
- id: motor_dir_char
type: std::string
initial_value: '"+"'
output:
- platform: ledc
pin: GPIO4
id: motor_forward_pin
- platform: ledc
pin: GPIO5
id: motor_reverse_pin
- platform: gpio
pin: GPIO6
id: motor_ren
- platform: gpio
pin: GPIO7
id: motor_len
fan:
- platform: hbridge
id: bed_motor
name: "Bed Motor"
pin_a: motor_forward_pin
pin_b: motor_reverse_pin
decay_mode: slow
number:
- platform: template
name: Lower limit
id: bed_lower_limit
icon: "mdi:cogs"
optimistic: true
restore_value: true
initial_value: "0.0"
min_value: -90.0
max_value: 90.0
step: 1.0
unit_of_measurement: degrees
on_value:
then:
- script.execute: start_motor_if_needed
- platform: template
name: Upper limit
id: bed_upper_limit
icon: "mdi:cogs"
optimistic: true
restore_value: true
initial_value: "45.0"
min_value: -90.0
max_value: 90.0
step: 1.0
unit_of_measurement: degrees
on_value:
then:
- script.execute: start_motor_if_needed
- platform: template
name: Accuracy
id: accuracy
icon: "mdi:cogs"
optimistic: true
restore_value: true # If you don't want to store the setting at ESP, set it to false.
initial_value: "2.0" # Default accuracy Setting 2%
min_value: 0.0
max_value: 100.0
step: 1.0
on_value:
then:
- script.execute: start_motor_if_needed
- platform: template
name: Desired percentage
id: bed_desired_position
icon: "mdi:cogs"
optimistic: true
restore_value: true # If you don't want to store the setting at ESP, set it to false.
initial_value: "0.0" # Default desired position Setting
min_value: 0.0
max_value: 100.0
step: 1.0
unit_of_measurement: percentage
on_value:
then:
- script.execute: start_motor_if_needed
- platform: template
name: Max motor speed
id: max_speed
icon: "mdi:cogs"
optimistic: true
restore_value: true # If you don't want to store the setting at ESP, set it to false.
initial_value: "90.0" # Default desired max_speed setting
min_value: 0.0
max_value: 100.0
step: 5.0
unit_of_measurement: percentage
on_value:
then:
- script.execute: start_motor_if_needed
light:
- platform: neopixelbus
variant: WS2812
pin: GPIO8
num_leds: 1
type: GRB
restore_mode: RESTORE_DEFAULT_ON
id: onboard_led
name: "Status light"
# turn LCD backlight on and off along with status LED
on_turn_off:
then:
- lambda: |-
id(lcd).no_backlight();
on_turn_on:
then:
- lambda: |-
id(lcd).backlight();
i2c:
sda: GPIO0
scl: GPIO1
frequency: 400kHz
adxl345:
id: adxl345_sensor
address: 0x53
update_interval: 100ms
off_vertical:
id: bed_angle
name: "Bed Angle"
unit_of_measurement: degrees
filters:
- sliding_window_moving_average:
window_size: 5
send_every: 5
- throttle_average: 10s
on_value:
then:
- lambda: |-
id(bed_position).publish_state(100 * (id(bed_angle).state - id(bed_lower_limit).state) / (id(bed_upper_limit).state - id(bed_lower_limit).state));
- script.execute: start_motor_if_needed
jitter:
id: jitter_raw
internal: True
unit_of_measurement: "m/s²"
accuracy_decimals: 3
sensor:
- platform: template
id: bed_position
accuracy_decimals: 0
name: "Bed Position"
update_interval: never
lambda: return 100 * (id(bed_angle).state - id(bed_lower_limit).state) / (id(bed_upper_limit).state - id(bed_lower_limit).state);
script:
- id: calc_motor_speed
then:
- lambda: |-
float diff = abs(id(bed_desired_position).state - id(bed_position).state);
float speed_size = id(max_speed).state / id(num_speeds);
if (diff > 20) {
id(motor_speed) = id(max_speed).state;
}
else if (diff > 10 && id(num_speeds) > 1) {
id(motor_speed) = speed_size * 2;
}
else {
id(motor_speed) = speed_size;
}
- id: start_motor_if_needed
then:
- script.execute: calc_motor_speed
- if:
condition:
lambda: 'return id(bed_position).state < -id(accuracy).state;'
then:
- logger.log: 'bed lower then lower limit!'
- fan.turn_on:
id: bed_motor
direction: FORWARD
speed:
!lambda |-
id(motor_dir_char) = "+";
return id(motor_speed);
else:
- if:
condition:
lambda: 'return id(bed_position).state > 100.0 + id(accuracy).state;'
then:
- logger.log: 'bed higher than high limit!'
- fan.turn_on:
id: bed_motor
direction: REVERSE
speed:
!lambda |-
id(motor_dir_char) = "-";
return id(motor_speed);
else:
- if:
condition:
- lambda: 'return id(bed_position).state < id(bed_desired_position).state - id(accuracy).state;'
then:
- logger.log: 'bed lower than desired, moving up'
- fan.turn_on:
id: bed_motor
direction: FORWARD
speed:
!lambda |-
id(motor_dir_char) = "+";
return id(motor_speed);
else:
- if:
condition:
- lambda: 'return id(bed_position).state > id(bed_desired_position).state + id(accuracy).state;'
then:
- logger.log: 'bed higher than desired, moving down'
- fan.turn_on:
id: bed_motor
direction: REVERSE
speed:
!lambda |-
id(motor_dir_char) = "-";
return id(motor_speed);
else:
- fan.turn_off: bed_motor
- lambda: |-
id(motor_dir_char) = " ";
id(motor_speed) = 0.0;
display:
- platform: lcd_pcf8574
id: lcd
dimensions: 16x2
address: 0x27
update_interval: 30s
lambda: |-
static bool toggle = false;
toggle = !toggle;
if (toggle) {
it.printf(0, 0, "I:%.0f%% ", id(bed_desired_position).state);
} else {
it.printf(0, 1, "D:%.0f%% ", id(bed_position).state);
}