diff --git a/example.yaml b/example.yaml index f880918..b357a56 100644 --- a/example.yaml +++ b/example.yaml @@ -36,3 +36,10 @@ text_sensor: - platform: tw7100 serial: name: "Serial number" + +switch: + - platform: tw7100 + PWR: + name: "Power" + BTAUDIO: + name: "Bluetooth Audio" diff --git a/switch/__init__.py b/switch/__init__.py index fa02f28..5b035c5 100644 --- a/switch/__init__.py +++ b/switch/__init__.py @@ -16,6 +16,9 @@ CONFIG_SCHEMA = cv.Schema( cv.Optional("PWR"): switch.switch_schema( tw7100Switch ), + cv.Optional("BTAUDIO"): switch.switch_schema( + tw7100Switch + ), } ) @@ -27,3 +30,10 @@ async def to_code(config): switch_ = await switch.new_switch(config["PWR"]) cg.add(switch_.set_cmd("PWR")) cg.add(switch_.set_tw7100_parent(parent)) + cg.add(parent.set_set_power(switch_)) + + if "BTAUDIO" in config: + switch_ = await switch.new_switch(config["BTAUDIO"]) + cg.add(switch_.set_cmd("BTAUDIO")) + cg.add(switch_.set_tw7100_parent(parent)) + cg.add(parent.set_set_btaudio(switch_)) diff --git a/switch/tw7100_switch.cpp b/switch/tw7100_switch.cpp index 1202a1c..88a4162 100644 --- a/switch/tw7100_switch.cpp +++ b/switch/tw7100_switch.cpp @@ -15,11 +15,17 @@ void tw7100Switch::dump_config() { void tw7100Switch::write_state(bool state) { static const char *const TAG = "write_state()"; - ESP_LOGV(TAG, "write switch state for cmd: %s", this->cmd_.c_str()); - parent_->push_cmd("PWR?"); - // TODO: actually send something! - // TODO: check response before publishing state - publish_state(state); + ESP_LOGV(TAG, "write switch state for cmd: %s, new state: %i", this->cmd_.c_str(), state); + if (cmd_ == "PWR") { + std::string param = state ? "ON" : "OFF"; + ESP_LOGV(TAG, "pushing back cmd %s with param %s", cmd_.c_str(), param.c_str()); + parent_->push_cmd(cmd_, param); + } else if (cmd_ == "BTAUDIO") { + char param [3]; + sprintf(param, "%02d", state); + ESP_LOGV(TAG, "pushing back cmd %s with param %s", cmd_.c_str(), param); + parent_->push_cmd(cmd_, param); + } } } // namespace tw7100 diff --git a/tw7100.cpp b/tw7100.cpp index abfe89f..b1f84bf 100644 --- a/tw7100.cpp +++ b/tw7100.cpp @@ -9,6 +9,7 @@ namespace tw7100 { bool waiting_for_answer = false; std::deque cmd_queue; +unsigned long last_set_cmd_timestamp; std::map sourcelist; std::vector pwr_off_query_cmds{ "PWR?", "LAMP?" }; @@ -73,15 +74,15 @@ std::vector pwr_on_query_cmds{ "SPEED?", "ILLUM?", "STANDBYCONF?", - "PRODUCT?", */ +// "PRODUCT?", // // Home Screen settings // "AUTOHOME?", // TODO: implement parser // Network settings // "WLPWR?", // TODO: implement parser // Bluetooth -// "BTAUDIO?", // TODO: implement parser + "BTAUDIO?", // TODO: implement parser // Information "SIGNAL?", // "SOURCELIST?" // Pushed on demand if sensor value is empty (e.g. after boot-up) @@ -124,13 +125,17 @@ void tw7100Component::loop() { std::string response = readStringUntil(':'); if (response == "") { // no response on bus, we can use our time to do something else - if (!cmd_queue.empty() && !waiting_for_answer) { - waiting_for_answer = true; + if (!cmd_queue.empty() && !waiting_for_answer && (millis() - last_set_cmd_timestamp > _timeout_after_cmd)) { std::string cmd = cmd_queue.front(); cmd_queue.pop_front(); ESP_LOGV(TAG, "sending out command: %s", cmd.c_str()); write_str((cmd + "\r\n").c_str()); flush(); + if (cmd.find("?") != std::string::npos) { // only wait for response on CMD? requests + waiting_for_answer = true; + } else { + last_set_cmd_timestamp = millis(); + } } } else { // response found, handle eventual errors ESP_LOGV(TAG, "buffer content: %s", response.c_str()); @@ -159,10 +164,13 @@ void tw7100Component::dump_config() { this->check_uart_settings(9600); }; -void tw7100Component::push_cmd(std::string cmd) { +void tw7100Component::push_cmd(std::string cmd, std::string param) { static const char *const TAG = "push_cmd()"; - cmd_queue.push_front(cmd); - ESP_LOGV(TAG, "pushing priority cmd (%s) from external component", cmd.c_str()); + if (powered_->state) { + ESP_LOGV(TAG, "pushing priority cmd (%s) from external component", cmd.c_str()); + cmd_queue.push_front(cmd + "?"); + cmd_queue.push_front(cmd + " " + param); + } } void tw7100Component::update_sensor(std::pair data) { @@ -173,6 +181,7 @@ void tw7100Component::update_sensor(std::pair data) { ESP_LOGV(TAG, "updating power sensors"); int value = std::stoi(value_string); powered_->publish_state(value > 0); + power_switch_->publish_state(value > 0); // ack previous cmd or update switch power_status_->publish_state(value); } else if (cmd == "LAMP") { ESP_LOGV(TAG, "updating lamp sensors"); @@ -212,6 +221,10 @@ void tw7100Component::update_sensor(std::pair data) { // TODO: if we exceed parse_rounds we most likely encountered a critical issue, inform user somehow } else if (cmd == "SNO") { serial_->publish_state(value_string); + } else if (cmd == "BTAUDIO") { + ESP_LOGV(TAG, "updating btaudio switch"); + int value = std::stoi(value_string); + btaudio_switch_->publish_state(value > 0); } else { ESP_LOGW(TAG, "Command %s unknown, skipping updating sensor with value", cmd.c_str()); } diff --git a/tw7100.h b/tw7100.h index 00a8912..fa62f6d 100644 --- a/tw7100.h +++ b/tw7100.h @@ -5,6 +5,7 @@ #include "esphome/components/sensor/sensor.h" #include "esphome/components/binary_sensor/binary_sensor.h" #include "esphome/components/text_sensor/text_sensor.h" +#include "esphome/components/switch/switch.h" #include "esphome/components/uart/uart.h" namespace esphome { @@ -14,12 +15,13 @@ class tw7100Component : public PollingComponent, public uart::UARTDevice { private: unsigned long _max_loop_time = 30; unsigned long _readStringUntil_timeout = _max_loop_time/5; // number of milliseconds to wait for the next char before aborting timed read + unsigned long _timeout_after_cmd = 1000; public: tw7100Component() = default; std::string readStringUntil(char terminator); - void push_cmd(std::string cmd); + void push_cmd(std::string cmd, std::string param); void update_sensor(std::pair data); std::pair parse_response(std::string data); int timedRead(void); @@ -35,7 +37,8 @@ class tw7100Component : public PollingComponent, public uart::UARTDevice { void set_signal_status(sensor::Sensor *signal_status) { this->signal_status_ = signal_status; } void set_luminance_level(sensor::Sensor *luminance_level) { this->luminance_level_ = luminance_level; } void set_serial(text_sensor::TextSensor *serial) { this->serial_ = serial; } - //void set_set_power(tw7100::tw7100Switch *switch_) { this->power_switch_ = switch_; } + void set_set_power(switch_::Switch *switch_) { this->power_switch_ = switch_; } + void set_set_btaudio(switch_::Switch *switch_) { this->btaudio_switch_ = switch_; } protected: binary_sensor::BinarySensor *powered_{nullptr}; @@ -45,7 +48,8 @@ class tw7100Component : public PollingComponent, public uart::UARTDevice { sensor::Sensor *signal_status_{nullptr}; sensor::Sensor *luminance_level_{nullptr}; text_sensor::TextSensor *serial_{nullptr}; - //tw7100::tw7100Switch *power_switch_{nullptr}; + switch_::Switch *power_switch_{nullptr}; + switch_::Switch *btaudio_switch_{nullptr}; }; } // namespace tw7100