1
0
mirror of https://github.com/esphome/esphome.git synced 2025-10-09 13:23:47 +01:00
Files
esphome/esphome/components/opentherm/hub.h

180 lines
6.1 KiB
C++

#pragma once
#include <vector>
#include "esphome/core/component.h"
#include "esphome/core/defines.h"
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
#include "opentherm.h"
#ifdef OPENTHERM_USE_SENSOR
#include "esphome/components/sensor/sensor.h"
#endif
#ifdef OPENTHERM_USE_BINARY_SENSOR
#include "esphome/components/binary_sensor/binary_sensor.h"
#endif
#ifdef OPENTHERM_USE_SWITCH
#include "esphome/components/opentherm/switch/opentherm_switch.h"
#endif
#ifdef OPENTHERM_USE_OUTPUT
#include "esphome/components/opentherm/output/opentherm_output.h"
#endif
#ifdef OPENTHERM_USE_NUMBER
#include "esphome/components/opentherm/number/opentherm_number.h"
#endif
#include <functional>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include "opentherm_macros.h"
namespace esphome {
namespace opentherm {
static const uint8_t REPEATING_MESSAGE_ORDER = 255;
static const uint8_t INITIAL_UNORDERED_MESSAGE_ORDER = 254;
// OpenTherm component for ESPHome
class OpenthermHub : public Component {
protected:
// Communication pins for the OpenTherm interface
InternalGPIOPin *in_pin_, *out_pin_;
// The OpenTherm interface
std::unique_ptr<OpenTherm> opentherm_;
OPENTHERM_SENSOR_LIST(OPENTHERM_DECLARE_SENSOR, )
OPENTHERM_BINARY_SENSOR_LIST(OPENTHERM_DECLARE_BINARY_SENSOR, )
OPENTHERM_SWITCH_LIST(OPENTHERM_DECLARE_SWITCH, )
OPENTHERM_NUMBER_LIST(OPENTHERM_DECLARE_NUMBER, )
OPENTHERM_OUTPUT_LIST(OPENTHERM_DECLARE_OUTPUT, )
OPENTHERM_INPUT_SENSOR_LIST(OPENTHERM_DECLARE_INPUT_SENSOR, )
OPENTHERM_SETTING_LIST(OPENTHERM_DECLARE_SETTING, )
bool sending_initial_ = true;
std::unordered_map<MessageId, uint8_t> configured_messages_;
std::vector<MessageId> messages_;
std::vector<MessageId>::const_iterator message_iterator_;
uint32_t last_conversation_start_ = 0;
uint32_t last_conversation_end_ = 0;
OperationMode last_mode_ = IDLE;
OpenthermData last_request_;
// Synchronous communication mode prevents other components from disabling interrupts while
// we are talking to the boiler. Enable if you experience random intermittent invalid response errors.
// Very likely to happen while using Dallas temperature sensors.
bool sync_mode_ = false;
CallbackManager<void(OpenthermData &)> before_send_callback_;
CallbackManager<void(OpenthermData &)> before_process_response_callback_;
// Create OpenTherm messages based on the message id
OpenthermData build_request_(MessageId request_id) const;
bool handle_error_(OperationMode mode);
void handle_protocol_error_();
void handle_timeout_error_();
void handle_timer_error_();
void stop_opentherm_();
void start_conversation_();
void read_response_();
void check_timings_(uint32_t cur_time);
bool should_skip_loop_(uint32_t cur_time) const;
void sync_loop_();
void write_initial_messages_(std::vector<MessageId> &target);
void write_repeating_messages_(std::vector<MessageId> &target);
template<typename F> bool spin_wait_(uint32_t timeout, F func) {
auto start_time = millis();
while (func()) {
yield();
auto cur_time = millis();
if (cur_time - start_time >= timeout) {
return false;
}
}
return true;
}
public:
// Constructor with references to the global interrupt handlers
OpenthermHub();
// Handle responses from the OpenTherm interface
void process_response(OpenthermData &data);
// Setters for the input and output OpenTherm interface pins
void set_in_pin(InternalGPIOPin *in_pin) { this->in_pin_ = in_pin; }
void set_out_pin(InternalGPIOPin *out_pin) { this->out_pin_ = out_pin; }
OPENTHERM_SENSOR_LIST(OPENTHERM_SET_SENSOR, )
OPENTHERM_BINARY_SENSOR_LIST(OPENTHERM_SET_BINARY_SENSOR, )
OPENTHERM_SWITCH_LIST(OPENTHERM_SET_SWITCH, )
OPENTHERM_NUMBER_LIST(OPENTHERM_SET_NUMBER, )
OPENTHERM_OUTPUT_LIST(OPENTHERM_SET_OUTPUT, )
OPENTHERM_INPUT_SENSOR_LIST(OPENTHERM_SET_INPUT_SENSOR, )
OPENTHERM_SETTING_LIST(OPENTHERM_SET_SETTING, )
// Add a request to the vector of initial requests
void add_initial_message(MessageId message_id) {
this->configured_messages_[message_id] = INITIAL_UNORDERED_MESSAGE_ORDER;
}
void add_initial_message(MessageId message_id, uint8_t order) { this->configured_messages_[message_id] = order; }
// Add a request to the set of repeating requests. Note that a large number of repeating
// requests will slow down communication with the boiler. Each request may take up to 1 second,
// so with all sensors enabled, it may take about half a minute before a change in setpoint
// will be processed.
void add_repeating_message(MessageId message_id) { this->configured_messages_[message_id] = REPEATING_MESSAGE_ORDER; }
// There are seven status variables, which can either be set as a simple variable,
// or using a switch. ch_enable and dhw_enable default to true, the others to false.
bool ch_enable = true, dhw_enable = true, cooling_enable = false, otc_active = false, ch2_active = false,
summer_mode_active = false, dhw_block = false;
// Setters for the status variables
void set_ch_enable(bool value) { this->ch_enable = value; }
void set_dhw_enable(bool value) { this->dhw_enable = value; }
void set_cooling_enable(bool value) { this->cooling_enable = value; }
void set_otc_active(bool value) { this->otc_active = value; }
void set_ch2_active(bool value) { this->ch2_active = value; }
void set_summer_mode_active(bool value) { this->summer_mode_active = value; }
void set_dhw_block(bool value) { this->dhw_block = value; }
void set_sync_mode(bool sync_mode) { this->sync_mode_ = sync_mode; }
void add_on_before_send_callback(std::function<void(OpenthermData &)> &&callback) {
this->before_send_callback_.add(std::move(callback));
}
void add_on_before_process_response_callback(std::function<void(OpenthermData &)> &&callback) {
this->before_process_response_callback_.add(std::move(callback));
}
float get_setup_priority() const override { return setup_priority::HARDWARE; }
void setup() override;
void on_shutdown() override;
void loop() override;
void dump_config() override;
};
} // namespace opentherm
} // namespace esphome