esphome-tw7100/tw7100.cpp
2024-09-15 20:25:34 +02:00

234 lines
6.1 KiB
C++

#include "tw7100.h"
#include "esphome/core/log.h"
#include "esphome/core/defines.h"
#include "esphome/core/helpers.h"
#include "esphome/components/uart/uart.h"
namespace esphome {
namespace tw7100 {
bool waiting_for_answer = false;
std::vector<std::string> cmd_queue;
std::vector<std::string> pwr_off_query_cmds{ "PWR?", "LAMP?" };
std::vector<std::string> pwr_on_query_cmds{
// Projection screen adjustment settings
/*
"VKEYSTONE?",
"HKEYSTONE?",
"QC?",
"CORRECTMET?",
"ASPECT?",
"LUMINANCE?",
"OVSCAN?",
*/
//
// Source/Input/Resolution settings
// "SOURCE?", // TODO: implement parser
// Image settings
/*
"BRIGHT?",
"CONTRAST?",
"DENSITY?",
"TINT?",
"CTEMP?",
"FCOLOR?",
"CMODE?",
"NRS?",
"MPEGNRS?",
"OFFSETR?",
"OFFSETG?",
"OFFSETB?",
"GAINR?",
"GAING?",
"GAINB?",
"GAMMA?",
"CSEL?",
"4KENHANCE?",
"IMGPRESET?",
"SHRF?",
"SHRS?",
"DERANGE?",
"MCFI?",
"CLRSPACE?",
"DYNRANGE?",
"HDRPQ?",
"HDRHLG?",
"IMGPROC?",
*/
//
// Sound settings
/*
"VOL?",
"AUDIOOUT?",
*/
//
// "MUTE?", // TODO: implement parser
// Environment settings
/*
"HREVERSE?",
"VREVERSE?",
"MSEL?",
"SPEED?",
"ILLUM?",
"STANDBYCONF?",
"PRODUCT?",
*/
//
// Home Screen settings
// "AUTOHOME?", // TODO: implement parser
// Network settings
// "WLPWR?", // TODO: implement parser
// Bluetooth
// "BTAUDIO?", // TODO: implement parser
// Information
"SIGNAL?",
"SOURCELIST?"
// "SOURCELISTA?", // same as SOURCELIST
// "LOGTO?", // TODO: implement parser
// "SNO?" // Pushed on demand if sensor value is empty (e.g. after boot-up)
};
void tw7100Component::setup() {
static const char *const TAG = "setup()";
ESP_LOGV(TAG, "SETUP");
};
void tw7100Component::update() {
static const char *const TAG = "update()";
if (cmd_queue.size() == 0) {
for (auto &cmd : pwr_off_query_cmds) {
cmd_queue.push_back(cmd);
}
if ((powered_->state)) {
if (this->serial_->state.length() < 1) {
cmd_queue.push_back("SNO?");
}
for (auto &cmd : pwr_on_query_cmds) {
cmd_queue.push_back(cmd);
}
}
}
};
void tw7100Component::loop() {
static const char *const TAG = "loop()";
unsigned long _startMillis; // used for timeout measurement
_startMillis = millis();
do {
std::string response = readStringUntil(':');
if (response == "") { // no response on bus, we can use our time to do something else
if (cmd_queue.size() > 0 && !waiting_for_answer) {
waiting_for_answer = true;
std::string cmd = cmd_queue[0];
cmd_queue.erase(cmd_queue.begin());
ESP_LOGV(TAG, "sending out command: %s", cmd.c_str());
write_str((cmd + "\r\n").c_str());
flush();
}
} else { // response found, handle eventual errors
ESP_LOGV(TAG, "buffer content: %s", response.c_str());
std::pair<std::string, std::string> parsed_response = parse_response(response);
if (parsed_response.first == "ERR" && parsed_response.second == "ERR") {
if (powered_->state) {;
cmd_queue.push_back("ERR?"); // TODO: produces a ERR? loop on bootup if projector is turned off
} else {
ESP_LOGE(TAG, "got ERR while projector is off, check if PWR+LAMP is too much?");
}
} else if (parsed_response.first == "ERR") {
// TODO: Handle error
} else {
update_sensor(parsed_response);
}
waiting_for_answer = false;
}
//ESP_LOGV(TAG, "read processing finished");
} while (millis() - _startMillis < _max_loop_time);
//ESP_LOGV(TAG, "inner timed loop done");
};
void tw7100Component::dump_config() {
static const char *const TAG = "dump_config()";
ESP_LOGCONFIG(TAG, "TW7100:");
this->check_uart_settings(9600);
};
void tw7100Component::update_sensor(std::pair<std::string, std::string> data) {
static const char *const TAG = "update_sensor()";
std::string cmd = data.first;
std::string value_string = data.second;
if (cmd == "PWR") {
ESP_LOGV(TAG, "updating power sensors");
int value = std::stoi(value_string);
powered_->publish_state(value > 0);
power_status_->publish_state(value);
} else if (cmd == "LAMP") {
ESP_LOGV(TAG, "updating lamp sensors");
int value = std::stoi(value_string);
lamp_hours_->publish_state(value);
} else if (cmd == "SIGNAL") {
ESP_LOGV(TAG, "updating signal sensors");
int value = std::stoi(value_string);
has_signal_->publish_state(value > 0);
signal_status_->publish_state(value);
} else if (cmd == "LUMINANCE") {
ESP_LOGV(TAG, "updating luminance sensors");
int value = std::stoi(value_string);
luminance_level_->publish_state(value);
} else if (cmd == "SOURCELIST") {
//for(char& c : value_string) {
// ESP_LOGV(TAG, "%c (%02x)", c, c);
//}
} else if (cmd == "SNO") {
serial_->publish_state(value_string);
} else {
ESP_LOGW(TAG, "Command %s unknown, skipping updating sensor with value", cmd.c_str());
}
}
std::pair<std::string, std::string> tw7100Component::parse_response(std::string data) {
static const char *const TAG = "parse_response()";
std::string key = "";
std::string value = "";
data.erase(std::remove(data.begin(), data.end(), '\r'), data.cend());
data.erase(std::remove(data.begin(), data.end(), '\n'), data.cend());
if (data != "") {
key = data.substr(0, data.find("="));
value = data.substr(data.find("=") + 1, data.length());
}
ESP_LOGV(TAG, "parsed response into (key: %s, value: %s)", key.c_str(), value.c_str());
return std::make_pair(key, value);
}
int tw7100Component::timedRead() {
unsigned long _startMillis; // used for timeout measurement
int c;
_startMillis = millis();
do {
if (this->available() > 0) {
c = this->read();
//ESP_LOGV("timedRead()", "timed read byte: %c (%x)", c, c);
if (c >= 0) {
return c;
}
}
} while (millis() - _startMillis < _readStringUntil_timeout);
return -1; // -1 indicates timeout
}
std::string tw7100Component::readStringUntil(char terminator) {
std::string line="";
int c = timedRead();
while (c >= 0 && (char)c != terminator) {
line += (char)c;
c = timedRead();
}
return line;
};
} // namespace tw7100
} // namespace esphome