Files
Home-Assistant-Dev/YAML Examples/WREN C5/wren-c5-esphome.yaml
T
Dave Williams | DitroniX | G8PUO b5b3999fe4 WREN C5 1.00.03
Added more substitutions and travel time in preperation for the next phase.

Trying to keep the controls generic as the WREN is more than a recliner controller and is being used in other area such as solar panel and vent controls.
2026-06-22 12:03:26 +01:00

753 lines
18 KiB
YAML

# Dave Williams, DitroniX 2019-2026 (ditronix.net)
# WREN | ESP32-C5 Recliner Linear Motor Controller | IoT Home Automation
# Example Code, to demonstrate and test the WREN C5
# Remember!
# - Set the BOARD to Use ESP32C5 Dev Module (or similar).
# - You can also set the BAUD rate up to 921600 to speed up flashing.
# - The SDK does NOT need external power to flash. It will take Power from the USB 5V.
# - The Serial Monitor is configured for BAUD 115200
# The purpose of this test code is to cycle through the various main functions of the board as part of bring up testing.
# This test code is OPEN SOURCE and formatted for easier viewing. Although is is not intended for real world use, it may be freely used, or modified as needed.
# It is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# For board configuration, see:
# * github.com/DitroniX/WREN-Recliner-Linear-Motor-Controller-IoT-Home-Automation/wiki/Arduino-IDE
# * github.com/DitroniX/WREN-Recliner-Linear-Motor-Controller-IoT-Home-Automation/wiki/PlatformIO-ESP32%E2%80%90C5
# * github.com/DitroniX/WREN-Recliner-Linear-Motor-Controller-IoT-Home-Automation/wiki/Home-Assistant-and-ESPHome
# * github.com/DitroniX/Home-Assistant-Dev
# Further information, details and examples can be found on our website or github.com/DitroniX
# * ditronix.net
# * github.com/DitroniX
# * github.com/DitroniX/WREN-Recliner-Linear-Motor-Controller-IoT-Home-Automation
# * github.com/DitroniX/WREN-Recliner-Linear-Motor-Controller-IoT-Home-Automation/wiki
# * github.com/DitroniX/WREN-Recliner-Linear-Motor-Controller-IoT-Home-Automation/wiki/FAQ
# * hackster.io/DitroniX/
# * hackster.io/DitroniX/wren-esp32-c5-recliner-linear-motor-controller-iot-rs485-e2b397
# This YAML code has been created to show the features and functionality of WREN C5.
# This code has expanded to become an all encompassing ESPHome applicaition and is a fully working baseline.
esphome:
name: wren-c5
friendly_name: WREN C5
on_boot:
priority: 800
then:
- lambda: |-
uint8_t cfg[2] = {0x03,0x00};
id(bus_a).write(0x21,cfg,2);
uint8_t pol[2] = {0x02,0x00};
id(bus_a).write(0x21,pol,2);
uint8_t out[2] = {0x01,0x00};
id(bus_a).write(0x21,out,2);
ESP_LOGI(
"tca",
"TCA6408A initialized"
);
- delay: 500ms
- if:
condition:
binary_sensor.is_on: sflag
then:
- logger.log: "SFLAG ACTIVE AFTER BOOT"
- script.execute: fault_handler
esp32:
board: esp32-c5-devkitc-1
variant: esp32c5
framework:
type: esp-idf
################################## ESPHOME ##################################
# ======================== ESPHome - Enter Below your Key/Pasawords ===========================
api:
encryption:
key: !secret wren_c5__encryption_key
ota:
- platform: esphome
password: !secret wren_c5__ota_password
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
ap:
ssid: WREN C5 Fallback Hotspot
password: !secret wren_c5__ap_password
captive_portal:
logger:
################################## SUBSTITUTIONS ##################################
substitutions:
# ======================== About ===========================
author: "DitroniX - Dave Williams"
firmware_version: "1.00.03"
release_date: "2026-06-22"
board_name: "WREN C5"
board_mcu: "ESP32-C5"
board_rev: "1.2606.104"
# ======================== Config ===========================
board_Initial_location: "Lounge"
voltage_low: 3.00
voltage_high: 48.0
travel_time_min: "1"
travel_time_max: "60"
travel_time_step: "1"
open_travel_time_default: "12"
preset_position_time_default: "6"
close_travel_time_default: "11"
################################## SETUP ##################################
# ========================== GPIO =============================
i2c:
id: bus_a
sda: GPIO2
scl: GPIO3
scan: true
globals:
- id: fault_active
type: bool
restore_value: no
initial_value: "false"
- id: tca_state
type: uint8_t
restore_value: no
initial_value: "0"
################################## SWITCH ##################################
switch:
- platform: gpio
id: rs485_enable
pin: GPIO23
restore_mode: ALWAYS_ON
output:
- platform: gpio
pin: GPIO27
id: blue_led
################################## LIGHT ######################################
light:
- platform: binary
id: heartbeat
output: blue_led
################################## NUMBER ######################################
number:
- platform: template
id: open_travel_time
name: "Open Travel Time"
entity_category: config
icon: mdi:arrow-expand-horizontal
optimistic: true
restore_value: true
min_value: ${travel_time_min}
max_value: ${travel_time_max}
step: ${travel_time_step}
unit_of_measurement: "s"
initial_value: ${open_travel_time_default}
- platform: template
id: preset_position_time
name: "Preset Position Time"
entity_category: config
icon: mdi:seat-recline-extra
optimistic: true
restore_value: true
min_value: ${travel_time_min}
max_value: ${travel_time_max}
step: ${travel_time_step}
unit_of_measurement: "s"
initial_value: ${preset_position_time_default}
set_action:
- lambda: |-
id(preset_position_time).publish_state(x);
id(preset_position_time_diag).publish_state(x);
- platform: template
id: close_travel_time
name: "Close Travel Time"
entity_category: config
icon: mdi:arrow-collapse-horizontal
optimistic: true
restore_value: true
min_value: ${travel_time_min}
max_value: ${travel_time_max}
step: ${travel_time_step}
unit_of_measurement: "s"
initial_value: ${close_travel_time_default}
################################## BUTTON ######################################
button:
- platform: template
name: "Reset Travel Times"
id: reset_travel_times
entity_category: config
icon: mdi:restore
on_press:
- lambda: |-
id(open_travel_time).publish_state(${open_travel_time_default});
id(preset_position_time).publish_state(${preset_position_time_default});
id(close_travel_time).publish_state(${close_travel_time_default});
ESP_LOGI(
"CONFIG",
"Travel times restored to defaults."
);
################################## TEXT ######################################
text:
- platform: template
id: board_location
name: "Board Location"
mode: TEXT
max_length: 32
restore_value: true
optimistic: true
entity_category: config
icon: mdi:map-marker
initial_value: "${board_Initial_location}"
set_action:
- lambda: |-
id(board_location).publish_state(x);
################################## TEXT SENSOR ##################################
text_sensor:
- platform: template
id: board_location_diagnostic
name: "Board Location"
entity_category: diagnostic
icon: mdi:map-marker
- platform: version
id: esphome_version
name: "ESPHome Version"
entity_category: diagnostic
icon: mdi:tag
hide_timestamp: true
hide_hash: true
- platform: template
name: "Author"
entity_category: diagnostic
icon: mdi:account
lambda: |-
return {"${author}"};
- platform: template
name: "Firmware Version"
entity_category: diagnostic
icon: mdi:application-cog
lambda: |-
return {"${firmware_version}"};
- platform: template
name: "Release Date"
entity_category: diagnostic
icon: mdi:calendar
lambda: |-
return {"${release_date}"};
- platform: template
name: "Board Name"
entity_category: diagnostic
icon: mdi:developer-board
lambda: |-
return {"${board_name}"};
- platform: template
name: "Board MCU"
entity_category: diagnostic
icon: mdi:cpu-64-bit
lambda: |-
return {"${board_mcu}"};
- platform: template
name: "Board Revision"
entity_category: diagnostic
icon: mdi:memory
lambda: |-
return {"${board_rev}"};
- platform: template
name: "Product"
entity_category: diagnostic
icon: mdi:package-variant-closed
lambda: |-
return {"Professional Energy Monitor"};
- platform: template
name: "Hardware"
entity_category: diagnostic
icon: mdi:chip
lambda: |-
return {"ESP32-C5 Dual ATM90E32"};
- platform: template
id: wifi_signal_quality
name: "WiFi Signal Quality"
entity_category: diagnostic
icon: mdi:wifi
update_interval: 30s
lambda: |-
if (!id(wifi_signal_db).has_state()) {
return {"No Signal"};
}
int rssi = abs((int) id(wifi_signal_db).state);
if (rssi <= 30) {
return {"Very Strong"};
} else if (rssi <= 50) {
return {"Excellent"};
} else if (rssi <= 60) {
return {"Healthy"};
} else if (rssi <= 70) {
return {"Very Good"};
} else if (rssi <= 80) {
return {"Good"};
} else if (rssi <= 90) {
return {"Poor - Reposition AP"};
} else if (rssi <= 100) {
return {"Very Low - Move AP"};
}
return {"No Signal"};
- platform: template
name: "Travel Configuration"
entity_category: diagnostic
icon: mdi:clipboard-check
lambda: |-
float open = id(open_travel_time).state;
float preset = id(preset_position_time).state;
float close = id(close_travel_time).state;
if (preset > open)
return {"Invalid - Preset exceeds Open"};
if (preset < close)
return {"Invalid - Preset below Close"};
return {"Valid"};
# =====================================================
# VOLTAGE STATUS AND LOG
# =====================================================
- platform: template
name: "Supply Status"
id: supply_status
icon: mdi:power-plug
entity_category: diagnostic
update_interval: 1s
lambda: |-
float v = id(supply_voltage).state;
constexpr float VOLTAGE_LOW = ${voltage_low};
constexpr float VOLTAGE_HIGH = ${voltage_high};
// Developer. Only enable for PCB 1.2606.104 and above, as this value is now taken from +VBUS rather than P24V_DVR
// if (v >= VOLTAGE_LOW && v <= 5.5f) {
// ESP_LOGI(
// "POWER",
// "USB Power Detected - Supply Voltage %.2fV",
// v
// );
// return {"USB Powered"};
// }
if (v >= 5.5f && v <= 10.0f) {
ESP_LOGI(
"POWER",
"Voltage Too Low %.2fV",
v
);
return {"Power Fail"};
}
if (v >= 10.0f && v <= 20.0f) {
return {"Low Voltage"};
}
if (v >= 20.0f && v <= 30.0f) {
return {"Recliner"};
}
if (v >= 30.0f && v <= VOLTAGE_HIGH) {
char buffer[20];
snprintf(buffer, sizeof(buffer), "%.1fV", v);
return {buffer};
}
if (v > 48.0f) {
ESP_LOGI(
"POWER",
"Over Voltage %.2fV",
v
);
return {"Over Voltage"};
}
return {"Unknown"};
############################## BINARY SENSOR ###############################
binary_sensor:
- platform: gpio
id: in_1a
name: "Motor 1 Extend"
pin:
number: GPIO8
mode:
input: true
pulldown: true
- platform: gpio
id: in_1b
name: "Motor 1 Retract"
pin:
number: GPIO9
mode:
input: true
pulldown: true
- platform: gpio
id: in_2a
name: "Motor 2 Extend"
pin:
number: GPIO14
mode:
input: true
pulldown: true
- platform: gpio
id: in_2b
name: "Motor 2 Retract"
pin:
number: GPIO13
mode:
input: true
pulldown: true
- platform: gpio
id: sflag
name: "Motor Driver Fault"
pin:
number: GPIO10
mode:
input: true
pulldown: true
on_press:
then:
- logger.log: "SFLAG INTERRUPT"
- script.execute: fault_handler
- platform: gpio
id: en1
name: "EN1 Feedback"
pin:
number: GPIO5
mode:
input: true
- platform: gpio
id: en2
name: "EN2 Feedback"
pin:
number: GPIO6
mode:
input: true
################################## SENSOR ##################################
sensor:
- platform: template
id: open_travel_time_diag
name: " Open Time"
entity_category: diagnostic
icon: mdi:arrow-expand-horizontal
unit_of_measurement: "s"
accuracy_decimals: 0
lambda: |-
return id(open_travel_time).state;
- platform: template
id: preset_position_time_diag
name: "Travel Preset Time"
entity_category: diagnostic
icon: mdi:seat-recline-extra
unit_of_measurement: "s"
accuracy_decimals: 0
lambda: |-
return id(preset_position_time).state;
- platform: template
id: close_travel_time_diag
name: "Travel Close Time"
entity_category: diagnostic
icon: mdi:arrow-collapse-horizontal
unit_of_measurement: "s"
accuracy_decimals: 0
lambda: |-
return id(close_travel_time).state;
- platform: adc
id: supply_voltage
pin: GPIO4
name: "Supply Voltage"
attenuation: auto
update_interval: 30s
entity_category: diagnostic
filters:
- multiply: 44.4444
- platform: tmp102
name: "Board Temperature"
address: 0x4A
entity_category: diagnostic
update_interval: 30s
- platform: wifi_signal
name: "WiFi RSSI"
update_interval: 60s
- platform: uptime
name: "Uptime"
# =====================================================
# OTHER SENSORS
# =====================================================
- platform: wifi_signal
name: "WiFi Signal"
id: wifi_signal_db
unit_of_measurement: "dBm"
device_class: signal_strength
state_class: measurement
entity_category: diagnostic
update_interval: 30s
################################## SCRIPT ##################################
script:
- id: fault_handler
mode: single
then:
- lambda: |-
if(id(fault_active))
return;
id(fault_active)=true;
ESP_LOGE(
"FAULT - IMMEDIATE FAULT SHUTDOWN",
"MOTOR STOP - TCA OUTPUT LOW. POWER CYCLE TO RE-ENABLE WREN"
"HAVE A GREAT DAY!"
);
uint8_t off[2];
off[0]=0x01;
off[1]=0x00;
id(bus_a).write(0x21, off, 2);
id(bus_a).write(0x21, off, 2);
id(bus_a).write(0x21, off, 2);
- repeat:
count: 20
then:
- lambda: |-
uint8_t led[2];
led[0]=0x01;
// TCA BIT7 ON
led[1]=0x80;
id(bus_a).write(
0x21,
led,
2
);
- delay: 1000ms
- lambda: |-
uint8_t led[2];
led[0]=0x01;
// ALL OFF
led[1]=0x00;
id(bus_a).write(
0x21,
led,
2
);
- delay: 100ms
# - lambda: |-
# ESP_LOGE(
# "FAULT",
# "RESTARTING"
# );
# esp_restart();
################################## INTERVAL ##################################
interval:
# heartbeat
- interval: 1s
then:
- light.turn_on: heartbeat
- delay: 750ms
- light.turn_off: heartbeat
# motor supervisor
- interval: 10ms
then:
- lambda: |-
//
// HARD SFLAG CHECK
//
if(id(sflag).state)
{
ESP_LOGE(
"FAULT",
"SFLAG HIGH"
);
id(fault_handler).execute();
return;
}
if(id(sflag).state)
{
id(fault_handler).execute();
return;
}
//
// LATCHED FAULT
//
if(id(fault_active))
{
uint8_t off[2]={0x01,0x00};
id(bus_a).write(
0x21,
off,
2
);
return;
}
//
// VOLTAGE CHECK
//
constexpr float VOLTAGE_LOW = ${voltage_low};
constexpr float VOLTAGE_HIGH = ${voltage_high};
float v = id(supply_voltage).state;
if (v < VOLTAGE_LOW || v > VOLTAGE_HIGH)
{
ESP_LOGE("FAULT", "Voltage %.2fV out of range", v);
id(fault_handler).execute();
return;
}
uint8_t output=0;
bool m1a=id(in_1a).state;
bool m1b=id(in_1b).state;
bool m2a=id(in_2a).state;
bool m2b=id(in_2b).state;
bool active =
m1a ||
m1b ||
m2a ||
m2b;
//
// BOTH ENABLES TOGETHER
//
if(active)
{
output |= (1<<0); // EN1
output |= (1<<3); // EN2
}
// MOTOR 1
if(m1a)
output |= (1<<1);
if(m1b)
output |= (1<<2);
// MOTOR 2
if(m2a)
output |= (1<<4);
if(m2b)
output |= (1<<5);
uint8_t buf[2];
buf[0]=0x01;
buf[1]=output;
id(bus_a).write(
0x21,
buf,
2
);
// ESP_LOGI(
// "motor",
// "OUT=0x%02X",
// output
// );