substitutions:
device_name: benq
ip_address: 192.168.19.54
esphome:
name: ${device_name}
includes:
- uart_read_line_sensor.h
esp8266:
board: nodemcuv2
# Enable logging
logger:
# Enable UART. Please select the pins you're using on your board.
uart:
id: projector
tx_pin: D4 #GPIO2
rx_pin: RX #GPIO3
baud_rate: 115200
# Enable Home Assistant API
api:
ota:
platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
fast_connect: true
use_address: ${ip_address}
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: ${device_name}
password: !secret ap_password
captive_portal:
# This is our hub - it manages our connection to the projector.
text_sensor:
- platform: custom
lambda: |-
auto my_custom_sensor = new UartReadLineSensor(id(projector));
App.register_component(my_custom_sensor);
return {my_custom_sensor};
text_sensors:
id: "uart_readline"
on_value:
then:
- lambda: |-
// Clean up the end of the string
std::string str = x;
str = str.erase(str.size()-1, 1);
// Parse commands and values
std::string command = str.substr(1, str.find("=")-1);
std::string param = str.substr(str.find("=")+1, str.size());
if ((param == "?") || (param == "+") || (param == "-")){
return;
}
if (command == "VOL") {
id(projector_volume).publish_state(atoi(param.c_str()));
} else if (command == "LTIM") {
id(projector_ltim).publish_state(atoi(param.c_str()));
} else if (command == "POW") {
id(projector_power).publish_state(param == "ON");
} else if (command == "SOUR") {
id(projector_source).publish_state(param.c_str());
}
select:
- platform: template
name: ${device_name} Source
id: projector_source
# Change this to the inputs your projector has
options:
- HDMI1
- HDMI2
- USBREADER
set_action:
then:
- lambda: |-
if ((x) != id(projector_source).state) {
std::string c = "\r*SOUR=" + x + "#\r";
id(projector).write_array((const uint8_t*)c.c_str(), c.size());
id(projector_source).publish_state(x);
}
number:
- platform: template
id: projector_volume
step: 1
min_value: 0
max_value: 50
name: ${device_name} Volume
set_action:
then:
- lambda: |-
int target = round(x);
int current = id(projector_volume).state;
int delta = target - current;
for (int i=0; i<abs(delta);i++) {
std::string c = "";
if (delta < 0) {
c = "\r*vol=-#\r";
}
else if (delta > 0){
c = "\r*vol=+#\r";
}
else {
// nothing
}
if (c != "") {
id(projector).write_array((const uint8_t*)c.c_str(), c.size());
}
}
id(projector_volume).publish_state(target);
sensor:
- platform: template
name: ${device_name} Lamp Hours
id: projector_ltim
switch:
- platform: template
name: ${device_name} Power
id: projector_power
turn_on_action:
- uart.write: "\r*pow=on#\r"
turn_off_action:
- uart.write: "\r*pow=off#\r"
interval:
- interval: 10s # not pretty, but works
then:
- uart.write: "\r*pow=?#\r"
- delay: 1s
- if:
condition:
lambda: 'return id(projector_power).state;'
then:
- uart.write: "\r*sour=?#\r"
- delay: 1s
- uart.write: "\r*vol=?#\r"
- delay: 1s
- uart.write: "\r*ltim=?#\r"
else:
- logger.log: "Projector is OFF"
uart_read_line_sensor.h文件
#include "esphome.h"
class UartReadLineSensor : public Component, public UARTDevice, public TextSensor {
public:
UartReadLineSensor(UARTComponent *parent) : UARTDevice(parent) {}
void setup() override {
// nothing to do here
}
int readline(int readch, char *buffer, int len)
{
static int pos = 0;
int rpos;
if (readch > 0) {
switch (readch) {
case '\n': // Ignore new-lines
break;
case '\r': // Return on CR
rpos = pos;
pos = 0; // Reset position index ready for next time
return rpos;
default:
if (pos < len-1) {
buffer[pos++] = readch;
buffer[pos] = 0;
}
}
}
// No end of line has been found, so return -1.
return -1;
}
void loop() override {
const int max_line_length = 80;
static char buffer[max_line_length];
while (available()) {
if(readline(read(), buffer, max_line_length) > 0) {
publish_state(buffer);
}
}
}
};