esphome_elektromer_han/components/xt211/xt211.h

206 lines
5.3 KiB
C++

#pragma once
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/uart/uart.h"
#include "esphome/core/component.h"
#ifdef USE_BINARY_SENSOR
#include "esphome/components/binary_sensor/binary_sensor.h"
#endif
#include <cstdint>
#include <list>
#include <map>
#include <memory>
#include <string>
#include "xt211_sensor.h"
#include "xt211_uart.h"
#include "object_locker.h"
#include "client.h"
#include "converters.h"
#include "cosem.h"
#include "dlmssettings.h"
namespace esphome {
namespace xt211 {
static const size_t DEFAULT_IN_BUF_SIZE_PUSH = 2048;
using SensorMap = std::multimap<std::string, XT211SensorBase *>;
using FrameStopFunction = std::function<
bool(uint8_t
*buf,
size_t size
)>;
class AxdrStreamParser;
class XT211Component : public PollingComponent, public uart::UARTDevice {
public:
XT211Component() : tag_(generateTag()) {};
void setup() override;
void dump_config() override;
void loop() override;
void update() override; // Kept for PollingComponent, but will be empty
float get_setup_priority() const override { return setup_priority::DATA; };
void set_baud_rate(uint32_t baud_rate) { this->baud_rate_ = baud_rate; };
void set_receive_timeout_ms(uint32_t timeout) { this->receive_timeout_ms_ = timeout; };
void register_sensor(XT211SensorBase *sensor);
void set_reboot_after_failure(uint16_t number_of_failures) { this->failures_before_reboot_ = number_of_failures; }
// PUSH mode is now default, these are for configuring it
void set_push_show_log(bool show_log) { this->push_show_log_ = show_log; }
void set_push_custom_pattern_dsl(const std::string &dsl) { this->push_custom_pattern_dsl_ = dsl; }
bool has_error{true};
#ifdef USE_BINARY_SENSOR
SUB_BINARY_SENSOR(transmission)
SUB_BINARY_SENSOR(session)
SUB_BINARY_SENSOR(connection)
#endif
#ifdef USE_TEXT_SENSOR
SUB_TEXT_SENSOR(last_scan)
#endif
protected:
bool push_show_log_{false};
std::string push_custom_pattern_dsl_{""};
uint32_t receive_timeout_ms_{2000};
std::unique_ptr <XT211Uart> iuart_;
SensorMap sensors_;
sensor::Sensor *crc_errors_per_session_sensor_{};
enum class State : uint8_t {
NOT_INITIALIZED,
IDLE,
WAIT,
COMMS_RX,
MISSION_FAILED,
PUSH_DATA_PROCESS, // Process received push data
PUBLISH,
} state_{State::NOT_INITIALIZED};
State last_reported_state_{State::NOT_INITIALIZED};
struct {
uint32_t start_time{0};
uint32_t delay_ms{0};
State next_state{State::IDLE};
} wait_;
bool is_idling() const { return this->state_ == State::WAIT || this->state_ == State::IDLE; };
void set_next_state_(State next_state) { state_ = next_state; };
void set_next_state_delayed_(uint32_t ms, State next_state);
void process_push_data();
// State handler methods extracted from loop()
void handle_comms_rx_();
void handle_push_data_process_();
void handle_publish_();
int set_sensor_value(uint16_t class_id, const uint8_t *obis_code, DLMS_DATA_TYPE value_type,
const uint8_t *value_buffer_ptr, uint8_t value_length, const int8_t *scaler,
const uint8_t *unit);
void indicate_transmission(bool transmission_on);
void indicate_session(bool session_on);
void indicate_connection(bool connection_on);
AxdrStreamParser *axdr_parser_{nullptr};
size_t received_frame_size_{0};
uint32_t baud_rate_{9600};
uint32_t last_rx_time_{0};
struct LoopState {
uint32_t session_started_ms{0}; // start of session
SensorMap::iterator sensor_iter{nullptr}; // publishing sensor values
} loop_state_;
struct PushBuffers {
gxByteBuffer in;
void init(size_t default_in_buf_size);
void reset();
void check_and_grow_input(uint16_t more_data);
} buffers_;
protected:
void clear_rx_buffers_();
void set_baud_rate_(uint32_t baud_rate);
size_t receive_frame_(FrameStopFunction stop_fn);
size_t receive_frame_raw_();
inline void update_last_rx_time_() { this->last_rx_time_ = millis(); }
bool check_wait_timeout_() { return millis() - wait_.start_time >= wait_.delay_ms; }
bool check_rx_timeout_() { return millis() - this->last_rx_time_ >= receive_timeout_ms_; }
void report_failure(bool failure);
void abort_mission_();
const char *state_to_string(State state);
void log_state_(State *next_state = nullptr);
struct Stats {
uint32_t connections_tried_{0};
uint32_t crc_errors_{0};
uint32_t crc_errors_recovered_{0};
uint32_t invalid_frames_{0};
uint8_t failures_{0};
float crc_errors_per_session() const { return (float) crc_errors_ / connections_tried_; }
} stats_;
void stats_dump();
uint8_t failures_before_reboot_{0};
bool try_lock_uart_session_();
// unlock_uart_session_() has been removed
public:
private:
static uint8_t next_obj_id_;
std::string tag_;
static std::string generateTag();
};
} // namespace xt211
} // namespace esphome