I am now able to serially control my video projector using the following config in ESPhome and thought I’d share it in case it helps someone in future:
This is an ESP32 board so I am using a second hardware UART
uart:
tx_pin: GPIO12
rx_pin: GPIO32
baud_rate: 9600
id: projector
And a custom Home Assistant service to send the serial data:
api:
password: !secret api_password
services:
- service: write
variables:
command: string
then:
- uart.write:
id: projector
data: !lambda |-
std::string str = command;
std::vector<uint8_t> vec(str.begin(), str.end());
return vec;
This is how it is used in a couple of scripts in Home Assistant:
projector_on:
- service: esphome.projector_uart_write
data:
command: "PWR ON\r\n"
projector_menu:
sequence:
- service: esphome.projector_uart_write
data:
command: "KEY 03\r\n"
The scripts can be called by button tap actions or used in automations.
At the moment I have not implemented a receive function to check if the command was successfully executed. Though I do check the trigger output port (usually used to lower automatic screens) to check if the projector is on or off:
binary_sensor:
- platform: gpio
name: Projector Power
pin: GPIO18
This is fed via a resistor voltage divider to drop the 12V out when the projector is on to 3V.
I probably wont check for valid command responses as there’s nothing I can do if the command does not execute anyway (hasn’t happened yet). But the Epson projector API document does list the minimum times between successive commands. I’ve found this to be way too conservative and have lowered the recommended 3 second gap to 1 second using a guard input_boolean in my Home Assistant scripts like so:
projector_menu:
sequence:
- condition: state
entity_id: input_boolean.uart_busy
state: 'off'
- service: input_boolean.turn_on
entity_id: input_boolean.uart_busy
- service: esphome.projector_uart_write
data:
command: "KEY 03\r\n"
- delay: 1
- service: input_boolean.turn_off
entity_id: input_boolean.uart_busy
All the command scripts have this so if one command is being executed another will be ignored until a second later (40 seconds for power on!). The default “single” mode for scripts ensures this is not interrupted either.
There are a few other niceties like a wifi connected LED, a TX in progress LED, wifi signal strength sensor etc… in the full ESP config:
esphome:
name: projector_uart
platform: ESP32
board: mhetesp32minikit
wifi:
ssid: 'WAPRU'
password: !secret wifi_pwd
manual_ip:
static_ip: 10.1.1.194
gateway: 10.1.1.1
subnet: 255.255.255.0
api:
password: !secret api_password
services:
- service: uart_write
variables:
command: string
then:
- output.turn_on: tx_led
- uart.write:
id: projector
data: !lambda |-
std::string str = command;
std::vector<uint8_t> vec(str.begin(), str.end());
return vec;
- delay: 0.25sec
- output.turn_off: tx_led
ota:
password: !secret esp_pwd
logger:
# level: VERY_VERBOSE
binary_sensor:
- platform: status
name: "Projector UART Status"
- platform: gpio
name: Projector Power
pin: GPIO18
interval:
- interval: 10s
then:
if:
condition:
wifi.connected:
then:
- output.turn_on: wifi_led
else:
- output.turn_off: wifi_led
output:
- id: wifi_led
platform: gpio
pin: GPIO16
- id: tx_led
platform: gpio
pin: GPIO17
sensor:
- platform: wifi_signal
name: "Projector UART WiFi Signal"
update_interval: 15s
filters:
- sliding_window_moving_average:
window_size: 15
send_every: 15
send_first_at: 1
icon: mdi:wifi
switch:
- platform: restart
name: "Projector UART Restart"
uart:
tx_pin: GPIO12
rx_pin: GPIO32
baud_rate: 9600
id: projector
### TW9200 / TW8200 ###
# COMMANDS:
# "PWR ON\r\n" # power_on
# "PWR OFF\r\n" # power_off
# "KEY 20\r\n" # aspect_ratio
# "KEY 3F\r\n" # colour_mode
# "KEY 16\r\n" # enter / OK
# "KEY 05\r\n" # exit
# "KEY A5\r\n" # iris
# "KEY 8D\r\n" # interlace
# "KEY 03\r\n" # menu
# "KEY 36\r\n" # navigate_down
# "KEY 37\r\n" # navigate_left
# "KEY 38\r\n" # navigate_right
# "KEY 35\r\n" # navigte_up
# "KEY 4B\r\n" # pattern
One thing to note is that most (if not all) projectors will use real RS232 levels (+/- 12V) not the 0 to 3.3V TTL output from the ESP. Fortunately converter boards are cheap and easily available on ebay or aliexpress.
e.g. RS232 To TTL Converter Module Serial Module DB9 Connector 3.3V-5.5V Arduino、SEAU | eBay
EDIT: Wiring diagram:
EDIT 2: ESPHome now requires that services be enabled in Home Assistant.
https://esphome.io/components/api.html#configuration-variables