#include "optoma_rs232.h" #include "esphome/core/log.h" #include "esphome/core/helpers.h" namespace esphome { namespace optoma_rs232 { [[maybe_unused]] static const char *const TAG = "optoma_rs232"; static const char *QUERIES[] = { "~00150 18\r", // Temp "~00108 1\r", // Lamp time "~00351 1\r", // Fan 1 "~00150 1\r", // Info }; template static void publish(C *c, M m) { if (c) c->publish_state(m); } void OptomaRS232Component::dump_config() { ESP_LOGCONFIG(TAG, "Optoma RS232:"); check_uart_settings(9600); } void OptomaRS232Component::loop() { if (!available()) return; // pos = 0 and crlf: none // pos > 0 and crlf: send // pos < end and not crlf: add // pos == end and not crlf: discard while (available()) { uint8_t c; if (!read_byte(&c)) continue; if (!c) continue; if (c == '\r' || c == '\n') { if (cursor_ > 0) { buffer_[cursor_] = 0; process_line_(buffer_); cursor_ = 0; } } else if (cursor_ < sizeof(buffer_) - 1) { buffer_[cursor_++] = toupper(c); } } } void OptomaRS232Component::update() { last_query_ = (last_query_ + 1) % sizeof(QUERIES) / sizeof(QUERIES[0]); write_array(reinterpret_cast(QUERIES[last_query_]), strlen(QUERIES[last_query_])); } void OptomaRS232Component::process_line_(const std::string &str) { // if we are waiting for the projector to respond to a command. // it will respond P (pass) or F (fail) before giving us the actual response to the command. if (str == "P" || str == "F") { ESP_LOGD(TAG, "command response received"); return; } // assuming any commands have been dealt with above, we listen for messages from the projector // the OK-something messages are in response to status queries, sometimes these are in caps, sometimes not // hence the toUpperCase call earlier // the INFO messages come in automatically when the projector changes state if ( // x == "OK1" || // status query returned power on str == "INFO1") { // warming up publish(beamer_power_binary_sensor_, true); return; } if ( // x == "OK0" || // status query returned power off str == "INFO2" || // cooling down str == "INFO0") { // going into standby publish(beamer_power_binary_sensor_, false); return; } if (str_startswith(str, "OK")) { process_query_response_(str); return; } ESP_LOGD("projector", "unhandled message: %s", str.c_str()); } void OptomaRS232Component::process_query_response_(const std::string &str) { if (str.length() >= 3) { switch (last_query_) { case 0: publish(beamer_temp_sensor_, strtol(str.c_str() + 2, 0, 10)); break; case 1: publish(beamer_lamp_time_sensor_, strtol(str.c_str() + 2, 0, 10)); break; case 2: publish(beamer_fan1_sensor_, strtol(str.c_str() + 2, 0, 10)); break; case 3: { char buf[17]{}; strncpy(buf, str.c_str(), sizeof(buf)); publish(beamer_color_mode_sensor_, strtol(buf + 14, 0, 10)); buf[14] = 0; // publish(beamer_firmware_,strtol(buf + 10, 0, 10)); buf[10] = 0; int input = -1; // atol(buf + 8); BUGGY switch (input) { case Inputs::HDMI_1: publish(beamer_input_text_sensor_, "HDMI 1"); break; case Inputs::HDMI_2: publish(beamer_input_text_sensor_, "HDMI 2"); break; case Inputs::VGA: publish(beamer_input_text_sensor_, "VGA"); break; default: case Inputs::UNKNOWN: publish(beamer_input_text_sensor_, "Unknown"); break; } buf[8] = 0; publish(beamer_lamp_time_sensor_, strtol(buf + 3, 0, 10)); buf[3] = 0; publish(beamer_power_binary_sensor_, strtol(buf + 2, 0, 10)); break; } default:; } } } } // namespace optoma_rs232 } // namespace esphome