mirror of
https://github.com/esphome/esphome.git
synced 2025-09-28 08:02:23 +01:00
Add PZEM004T/PZEMAC/PZEMDC Support (#587)
* Add PZEM004T Support * Don't flush as much * Update pzem004t.cpp * Add generalized modbus * Add PZEMAC * Add PZEMDC * Fix file modes * Lint * Fix * Fix * Add check_uart_settings
This commit is contained in:
@@ -29,11 +29,13 @@ def validate_rx_pin(value):
|
||||
return value
|
||||
|
||||
|
||||
CONF_STOP_BITS = 'stop_bits'
|
||||
CONFIG_SCHEMA = cv.All(cv.Schema({
|
||||
cv.GenerateID(): cv.declare_id(UARTComponent),
|
||||
cv.Required(CONF_BAUD_RATE): cv.int_range(min=1),
|
||||
cv.Optional(CONF_TX_PIN): pins.output_pin,
|
||||
cv.Optional(CONF_RX_PIN): validate_rx_pin,
|
||||
cv.Optional(CONF_STOP_BITS, default=1): cv.one_of(1, 2, int=True),
|
||||
}).extend(cv.COMPONENT_SCHEMA), cv.has_at_least_one_key(CONF_TX_PIN, CONF_RX_PIN))
|
||||
|
||||
|
||||
@@ -48,6 +50,7 @@ def to_code(config):
|
||||
cg.add(var.set_tx_pin(config[CONF_TX_PIN]))
|
||||
if CONF_RX_PIN in config:
|
||||
cg.add(var.set_rx_pin(config[CONF_RX_PIN]))
|
||||
cg.add(var.set_stop_bits(config[CONF_STOP_BITS]))
|
||||
|
||||
|
||||
# A schema to use for all UART devices, all UART integrations must extend this!
|
||||
|
@@ -25,7 +25,10 @@ void UARTComponent::setup() {
|
||||
}
|
||||
int8_t tx = this->tx_pin_.has_value() ? *this->tx_pin_ : -1;
|
||||
int8_t rx = this->rx_pin_.has_value() ? *this->rx_pin_ : -1;
|
||||
this->hw_serial_->begin(this->baud_rate_, SERIAL_8N1, rx, tx);
|
||||
uint32_t config = SERIAL_8N1;
|
||||
if (this->stop_bits_ == 2)
|
||||
config = SERIAL_8N2;
|
||||
this->hw_serial_->begin(this->baud_rate_, config, rx, tx);
|
||||
}
|
||||
|
||||
void UARTComponent::dump_config() {
|
||||
@@ -37,6 +40,7 @@ void UARTComponent::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, " RX Pin: GPIO%d", *this->rx_pin_);
|
||||
}
|
||||
ESP_LOGCONFIG(TAG, " Baud Rate: %u baud", this->baud_rate_);
|
||||
ESP_LOGCONFIG(TAG, " Stop bits: %u", this->stop_bits_);
|
||||
}
|
||||
|
||||
void UARTComponent::write_byte(uint8_t data) {
|
||||
@@ -102,21 +106,27 @@ void UARTComponent::setup() {
|
||||
// Use Arduino HardwareSerial UARTs if all used pins match the ones
|
||||
// preconfigured by the platform. For example if RX disabled but TX pin
|
||||
// is 1 we still want to use Serial.
|
||||
uint32_t mode = UART_NB_BIT_8 | UART_PARITY_NONE;
|
||||
if (this->stop_bits_ == 1)
|
||||
mode |= UART_NB_STOP_BIT_1;
|
||||
else
|
||||
mode |= UART_NB_STOP_BIT_2;
|
||||
SerialConfig config = static_cast<SerialConfig>(mode);
|
||||
if (this->tx_pin_.value_or(1) == 1 && this->rx_pin_.value_or(3) == 3) {
|
||||
this->hw_serial_ = &Serial;
|
||||
this->hw_serial_->begin(this->baud_rate_);
|
||||
this->hw_serial_->begin(this->baud_rate_, config);
|
||||
} else if (this->tx_pin_.value_or(15) == 15 && this->rx_pin_.value_or(13) == 13) {
|
||||
this->hw_serial_ = &Serial;
|
||||
this->hw_serial_->begin(this->baud_rate_);
|
||||
this->hw_serial_->begin(this->baud_rate_, config);
|
||||
this->hw_serial_->swap();
|
||||
} else if (this->tx_pin_.value_or(2) == 2 && this->rx_pin_.value_or(8) == 8) {
|
||||
this->hw_serial_ = &Serial1;
|
||||
this->hw_serial_->begin(this->baud_rate_);
|
||||
this->hw_serial_->begin(this->baud_rate_, config);
|
||||
} else {
|
||||
this->sw_serial_ = new ESP8266SoftwareSerial();
|
||||
int8_t tx = this->tx_pin_.has_value() ? *this->tx_pin_ : -1;
|
||||
int8_t rx = this->rx_pin_.has_value() ? *this->rx_pin_ : -1;
|
||||
this->sw_serial_->setup(tx, rx, this->baud_rate_);
|
||||
this->sw_serial_->setup(tx, rx, this->baud_rate_, this->stop_bits_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,6 +139,7 @@ void UARTComponent::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, " RX Pin: GPIO%d", *this->rx_pin_);
|
||||
}
|
||||
ESP_LOGCONFIG(TAG, " Baud Rate: %u baud", this->baud_rate_);
|
||||
ESP_LOGCONFIG(TAG, " Stop bits: %u", this->stop_bits_);
|
||||
if (this->hw_serial_ != nullptr) {
|
||||
ESP_LOGCONFIG(TAG, " Using hardware serial interface.");
|
||||
} else {
|
||||
@@ -231,7 +242,7 @@ void UARTComponent::flush() {
|
||||
}
|
||||
}
|
||||
|
||||
void ESP8266SoftwareSerial::setup(int8_t tx_pin, int8_t rx_pin, uint32_t baud_rate) {
|
||||
void ESP8266SoftwareSerial::setup(int8_t tx_pin, int8_t rx_pin, uint32_t baud_rate, uint8_t stop_bits) {
|
||||
this->bit_time_ = F_CPU / baud_rate;
|
||||
if (tx_pin != -1) {
|
||||
auto pin = GPIOPin(tx_pin, OUTPUT);
|
||||
@@ -246,6 +257,7 @@ void ESP8266SoftwareSerial::setup(int8_t tx_pin, int8_t rx_pin, uint32_t baud_ra
|
||||
this->rx_buffer_ = new uint8_t[this->rx_buffer_size_];
|
||||
pin.attach_interrupt(ESP8266SoftwareSerial::gpio_intr, this, FALLING);
|
||||
}
|
||||
this->stop_bits_ = stop_bits;
|
||||
}
|
||||
void ICACHE_RAM_ATTR ESP8266SoftwareSerial::gpio_intr(ESP8266SoftwareSerial *arg) {
|
||||
uint32_t wait = arg->bit_time_ + arg->bit_time_ / 3 - 500;
|
||||
@@ -262,6 +274,8 @@ void ICACHE_RAM_ATTR ESP8266SoftwareSerial::gpio_intr(ESP8266SoftwareSerial *arg
|
||||
rec |= arg->read_bit_(&wait, start) << 7;
|
||||
// Stop bit
|
||||
arg->wait_(&wait, start);
|
||||
if (arg->stop_bits_ == 2)
|
||||
arg->wait_(&wait, start);
|
||||
|
||||
arg->rx_buffer_[arg->rx_in_pos_] = rec;
|
||||
arg->rx_in_pos_ = (arg->rx_in_pos_ + 1) % arg->rx_buffer_size_;
|
||||
@@ -289,6 +303,8 @@ void ICACHE_RAM_ATTR HOT ESP8266SoftwareSerial::write_byte(uint8_t data) {
|
||||
this->write_bit_(data & (1 << 7), &wait, start);
|
||||
// Stop bit
|
||||
this->write_bit_(true, &wait, start);
|
||||
if (this->stop_bits_ == 2)
|
||||
this->wait_(&wait, start);
|
||||
enable_interrupts();
|
||||
}
|
||||
void ICACHE_RAM_ATTR ESP8266SoftwareSerial::wait_(uint32_t *wait, const uint32_t &start) {
|
||||
@@ -344,5 +360,16 @@ int UARTComponent::peek() {
|
||||
return data;
|
||||
}
|
||||
|
||||
void UARTDevice::check_uart_settings(uint32_t baud_rate, uint8_t stop_bits) {
|
||||
if (this->parent_->baud_rate_ != baud_rate) {
|
||||
ESP_LOGE(TAG, " Invalid baud_rate: Integration requested baud_rate %u but you have %u!", baud_rate,
|
||||
this->parent_->baud_rate_);
|
||||
}
|
||||
if (this->parent_->stop_bits_ != stop_bits) {
|
||||
ESP_LOGE(TAG, " Invalid stop bits: Integration requested stop_bits %u but you have %u!", stop_bits,
|
||||
this->parent_->stop_bits_);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace uart
|
||||
} // namespace esphome
|
||||
|
@@ -10,7 +10,7 @@ namespace uart {
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
class ESP8266SoftwareSerial {
|
||||
public:
|
||||
void setup(int8_t tx_pin, int8_t rx_pin, uint32_t baud_rate);
|
||||
void setup(int8_t tx_pin, int8_t rx_pin, uint32_t baud_rate, uint8_t stop_bits);
|
||||
|
||||
uint8_t read_byte();
|
||||
uint8_t peek_byte();
|
||||
@@ -33,6 +33,7 @@ class ESP8266SoftwareSerial {
|
||||
size_t rx_buffer_size_{512};
|
||||
volatile size_t rx_in_pos_{0};
|
||||
size_t rx_out_pos_{0};
|
||||
uint8_t stop_bits_;
|
||||
ISRInternalGPIOPin *tx_pin_{nullptr};
|
||||
ISRInternalGPIOPin *rx_pin_{nullptr};
|
||||
};
|
||||
@@ -72,9 +73,11 @@ class UARTComponent : public Component, public Stream {
|
||||
|
||||
void set_tx_pin(uint8_t tx_pin) { this->tx_pin_ = tx_pin; }
|
||||
void set_rx_pin(uint8_t rx_pin) { this->rx_pin_ = rx_pin; }
|
||||
void set_stop_bits(uint8_t stop_bits) { this->stop_bits_ = stop_bits; }
|
||||
|
||||
protected:
|
||||
bool check_read_timeout_(size_t len = 1);
|
||||
friend class UARTDevice;
|
||||
|
||||
HardwareSerial *hw_serial_{nullptr};
|
||||
#ifdef ARDUINO_ARCH_ESP8266
|
||||
@@ -83,6 +86,7 @@ class UARTComponent : public Component, public Stream {
|
||||
optional<uint8_t> tx_pin_;
|
||||
optional<uint8_t> rx_pin_;
|
||||
uint32_t baud_rate_;
|
||||
uint8_t stop_bits_;
|
||||
};
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
@@ -100,6 +104,9 @@ class UARTDevice : public Stream {
|
||||
|
||||
void write_array(const uint8_t *data, size_t len) { this->parent_->write_array(data, len); }
|
||||
void write_array(const std::vector<uint8_t> &data) { this->parent_->write_array(data); }
|
||||
template<size_t N> void write_array(const std::array<uint8_t, N> &data) {
|
||||
this->parent_->write_array(data.data(), data.size());
|
||||
}
|
||||
|
||||
void write_str(const char *str) { this->parent_->write_str(str); }
|
||||
|
||||
@@ -107,6 +114,13 @@ class UARTDevice : public Stream {
|
||||
bool peek_byte(uint8_t *data) { return this->parent_->peek_byte(data); }
|
||||
|
||||
bool read_array(uint8_t *data, size_t len) { return this->parent_->read_array(data, len); }
|
||||
template<size_t N> optional<std::array<uint8_t, N>> read_array() { // NOLINT
|
||||
std::array<uint8_t, N> res;
|
||||
if (!this->read_array(res.data(), N)) {
|
||||
return {};
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int available() override { return this->parent_->available(); }
|
||||
|
||||
@@ -116,6 +130,9 @@ class UARTDevice : public Stream {
|
||||
int read() override { return this->parent_->read(); }
|
||||
int peek() override { return this->parent_->peek(); }
|
||||
|
||||
/// Check that the configuration of the UART bus matches the provided values and otherwise print a warning
|
||||
void check_uart_settings(uint32_t baud_rate, uint8_t stop_bits = 1);
|
||||
|
||||
protected:
|
||||
UARTComponent *parent_{nullptr};
|
||||
};
|
||||
|
Reference in New Issue
Block a user