2024-09-15 16:43:29 +02:00
|
|
|
#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
|
2024-09-15 20:08:51 +02:00
|
|
|
// "SOURCE?", // TODO: implement parser
|
2024-09-15 16:43:29 +02:00
|
|
|
// 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?",
|
|
|
|
*/
|
|
|
|
//
|
2024-09-15 20:08:51 +02:00
|
|
|
// "MUTE?", // TODO: implement parser
|
2024-09-15 16:43:29 +02:00
|
|
|
// Environment settings
|
|
|
|
/*
|
|
|
|
"HREVERSE?",
|
|
|
|
"VREVERSE?",
|
|
|
|
"MSEL?",
|
|
|
|
"SPEED?",
|
|
|
|
"ILLUM?",
|
|
|
|
"STANDBYCONF?",
|
|
|
|
"PRODUCT?",
|
|
|
|
*/
|
|
|
|
//
|
|
|
|
// Home Screen settings
|
2024-09-15 20:08:51 +02:00
|
|
|
// "AUTOHOME?", // TODO: implement parser
|
2024-09-15 16:43:29 +02:00
|
|
|
// Network settings
|
2024-09-15 20:08:51 +02:00
|
|
|
// "WLPWR?", // TODO: implement parser
|
2024-09-15 16:43:29 +02:00
|
|
|
// Bluetooth
|
2024-09-15 20:08:51 +02:00
|
|
|
// "BTAUDIO?", // TODO: implement parser
|
2024-09-15 16:43:29 +02:00
|
|
|
// Information
|
|
|
|
"SIGNAL?",
|
2024-09-15 20:08:51 +02:00
|
|
|
"SOURCELIST?"
|
2024-09-15 16:43:29 +02:00
|
|
|
// "SOURCELISTA?", // same as SOURCELIST
|
2024-09-15 20:08:51 +02:00
|
|
|
// "LOGTO?", // TODO: implement parser
|
|
|
|
// "SNO?" // Pushed on demand if sensor value is empty (e.g. after boot-up)
|
2024-09-15 16:43:29 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2024-09-15 20:08:51 +02:00
|
|
|
if ((powered_->state)) {
|
2024-09-15 20:25:06 +02:00
|
|
|
if (this->serial_->state.length() < 1) {
|
|
|
|
cmd_queue.push_back("SNO?");
|
|
|
|
}
|
2024-09-15 16:43:29 +02:00
|
|
|
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") {
|
2024-09-15 20:25:06 +02:00
|
|
|
//for(char& c : value_string) {
|
|
|
|
// ESP_LOGV(TAG, "%c (%02x)", c, c);
|
|
|
|
//}
|
|
|
|
} else if (cmd == "SNO") {
|
|
|
|
serial_->publish_state(value_string);
|
2024-09-15 16:43:29 +02:00
|
|
|
} 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
|