#pragma once #include #include #include #include #include "esphome/core/component.h" #include "esphome/core/defines.h" #include "esphome/core/log.h" #include "esphome/components/uart/uart.h" #include "helpers.h" #include "decode.h" #include "commands.h" #ifndef PANASONIC_HEATPUMP_VERSION #define PANASONIC_HEATPUMP_VERSION "0.0.9-beta.1" #endif #ifndef KEEP_STATE #define KEEP_STATE 1 #endif namespace esphome { namespace panasonic_heatpump { enum LoopState : uint8_t { READ_RESPONSE, PUBLISH_SENSOR, PUBLISH_BINARY_SENSOR, PUBLISH_TEXT_SENSOR, PUBLISH_NUMBER, PUBLISH_SELECT, PUBLISH_SWITCH, PUBLISH_CLIMATE, PUBLISH_WATER_HEATER, PUBLISH_EXTRA_SENSOR, SEND_REQUEST, RESTART_LOOP, }; enum RequestType : uint8_t { NONE, COMMAND, INITIAL, POLLING, POLLING_EXTRA, }; enum ResponseType : uint8_t { UNKNOWN, STANDARD, EXTRA, }; class PanasonicHeatpumpEntity { public: virtual void set_id(const int id) { id_ = id; } virtual void publish_new_state(const std::vector& data) = 0; protected: int id_{-1}; int keep_state_{0}; }; class PanasonicHeatpumpComponent : public PollingComponent, public uart::UARTDevice { public: PanasonicHeatpumpComponent() = default; // base class functions float get_setup_priority() const override { return setup_priority::DATA; } void dump_config() override; void setup() override; void update() override; void loop() override; // option functions void set_uart_client(uart::UARTComponent* uart) { this->uart_client_ = uart; } void set_uart_client_timeout(uint32_t timeout_ms) { this->uart_client_timeout_ = timeout_ms; } void set_log_uart_msg(bool active) { this->log_uart_msg_ = active; } // functions to use in esphome lambda int get_response_byte(const int index); int get_extra_response_byte(const int index); // command functions void set_command_high_nibble(const uint8_t value, const uint8_t index); void set_command_low_nibble(const uint8_t value, const uint8_t index); void set_command_byte(const uint8_t value, const uint8_t index); void set_command_curve(const uint8_t value, const uint8_t index); // entity functions void add_binary_sensor(PanasonicHeatpumpEntity* binary_sensor) { binary_sensors_.push_back(binary_sensor); } void add_climate(PanasonicHeatpumpEntity* climate) { climates_.push_back(climate); } void add_water_heater(PanasonicHeatpumpEntity* water_heater) { water_heaters_.push_back(water_heater); } void add_number(PanasonicHeatpumpEntity* number) { numbers_.push_back(number); } void add_select(PanasonicHeatpumpEntity* select) { selects_.push_back(select); } void add_sensor(PanasonicHeatpumpEntity* sensor) { sensors_.push_back(sensor); } void add_switch(PanasonicHeatpumpEntity* switch_) { switches_.push_back(switch_); } void add_text_sensor(PanasonicHeatpumpEntity* text_sensor) { text_sensors_.push_back(text_sensor); } void add_extra_sensor(PanasonicHeatpumpEntity* sensor) { extra_sensors_.push_back(sensor); } bool get_uart_client_timeout_exceeded() { return this->uart_client_timeout_exceeded_; } protected: // options variables bool log_uart_msg_{false}; uint32_t last_client_request_time_{0}; uint32_t uart_client_timeout_{10000}; // 10 sec uint32_t request_send_time_{5000}; // 5 sec --> default is 5 sec so first request is not sent too fast after startup static const uint32_t REQUEST_SEND_INTERVAL{250}; // 250 ms static const size_t HEADER_SIZE = 4; // uart message variables, process in main loop TaskHandle_t uart_task_handle_{nullptr}; TaskHandle_t uart_client_task_handle_{nullptr}; QueueHandle_t response_queue_handle_{nullptr}; QueueHandle_t request_queue_handle_{nullptr}; uart::UARTComponent* uart_client_{nullptr}; std::vector heatpump_default_message_; std::vector heatpump_extra_message_; std::vector command_message_; bool uart_client_timeout_exceeded_{false}; LoopState loop_state_{LoopState::RESTART_LOOP}; // entity vectors std::vector binary_sensors_; std::vector climates_; std::vector water_heaters_; std::vector numbers_; std::vector selects_; std::vector sensors_; std::vector switches_; std::vector text_sensors_; std::vector extra_sensors_; // uart message functions static void uart_task(void* pvParameters); static void uart_client_task(void* pvParameters); bool receive_from_uart(uart::UARTComponent* src, std::vector& buffer); void send_request(); void queue_request(const std::vector& message); ResponseType read_response(); static bool check_response_length(const std::vector& message); static bool verify_message_header(const std::vector& message, bool reading_succeeded); static bool verify_message_checksum(const std::vector& message); template static std::vector build_message(const uint8_t (&msg)[N]) { return std::vector(msg, msg + N); } }; } // namespace panasonic_heatpump } // namespace esphome