From def70dde723b8c978e73ce07390f6645a9743281 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sat, 6 Feb 2021 11:02:20 +1300 Subject: [PATCH 1/6] Fix PN532 SPI communication (#1511) --- esphome/components/pn532/pn532.cpp | 100 ++--------------- esphome/components/pn532/pn532.h | 4 +- .../components/pn532/pn532_mifare_classic.cpp | 6 +- .../pn532/pn532_mifare_ultralight.cpp | 4 +- esphome/components/pn532_i2c/pn532_i2c.cpp | 84 ++++++++++++++ esphome/components/pn532_i2c/pn532_i2c.h | 2 + esphome/components/pn532_spi/pn532_spi.cpp | 105 ++++++++++++++++-- esphome/components/pn532_spi/pn532_spi.h | 1 + 8 files changed, 203 insertions(+), 103 deletions(-) diff --git a/esphome/components/pn532/pn532.cpp b/esphome/components/pn532/pn532.cpp index e2511648b6..1cc2b19c2e 100644 --- a/esphome/components/pn532/pn532.cpp +++ b/esphome/components/pn532/pn532.cpp @@ -22,7 +22,7 @@ void PN532::setup() { } std::vector version_data; - if (!this->read_response_(PN532_COMMAND_VERSION_DATA, version_data)) { + if (!this->read_response(PN532_COMMAND_VERSION_DATA, version_data)) { ESP_LOGE(TAG, "Error getting version"); this->mark_failed(); return; @@ -42,7 +42,7 @@ void PN532::setup() { } std::vector wakeup_result; - if (!this->read_response_(PN532_COMMAND_SAMCONFIGURATION, wakeup_result)) { + if (!this->read_response(PN532_COMMAND_SAMCONFIGURATION, wakeup_result)) { this->error_code_ = WAKEUP_FAILED; this->mark_failed(); return; @@ -62,7 +62,7 @@ void PN532::setup() { } std::vector sam_result; - if (!this->read_response_(PN532_COMMAND_SAMCONFIGURATION, sam_result)) { + if (!this->read_response(PN532_COMMAND_SAMCONFIGURATION, sam_result)) { ESP_LOGV(TAG, "Invalid SAM result: (%u)", sam_result.size()); // NOLINT for (uint8_t dat : sam_result) { ESP_LOGV(TAG, " 0x%02X", dat); @@ -97,7 +97,7 @@ void PN532::loop() { return; std::vector read; - bool success = this->read_response_(PN532_COMMAND_INLISTPASSIVETARGET, read); + bool success = this->read_response(PN532_COMMAND_INLISTPASSIVETARGET, read); this->requested_read_ = false; @@ -230,7 +230,7 @@ bool PN532::write_command_(const std::vector &data) { } bool PN532::read_ack_() { - ESP_LOGVV(TAG, "Reading ACK..."); + ESP_LOGV(TAG, "Reading ACK..."); std::vector data; if (!this->read_data(data, 6)) { @@ -241,96 +241,18 @@ bool PN532::read_ack_() { data[2] == 0x00 && // start of packet data[3] == 0xFF && data[4] == 0x00 && // ACK packet code data[5] == 0xFF && data[6] == 0x00); // postamble - ESP_LOGVV(TAG, "ACK valid: %s", YESNO(matches)); + ESP_LOGV(TAG, "ACK valid: %s", YESNO(matches)); return matches; } -bool PN532::read_response_(uint8_t command, std::vector &data) { - ESP_LOGV(TAG, "Reading response"); - uint8_t len = this->read_response_length_(); - if (len == 0) { - return false; - } - - ESP_LOGV(TAG, "Reading response of length %d", len); - if (!this->read_data(data, 6 + len + 2)) { - ESP_LOGD(TAG, "No response data"); - return false; - } - - if (data[1] != 0x00 && data[2] != 0x00 && data[3] != 0xFF) { - // invalid packet - ESP_LOGV(TAG, "read data invalid preamble!"); - return false; - } - - bool valid_header = (static_cast(data[4] + data[5]) == 0 && // LCS, len + lcs = 0 - data[6] == 0xD5 && // TFI - frame from PN532 to system controller - data[7] == command + 1); // Correct command response - - if (!valid_header) { - ESP_LOGV(TAG, "read data invalid header!"); - return false; - } - - data.erase(data.begin(), data.begin() + 6); // Remove headers - - uint8_t checksum = 0; - for (int i = 0; i < len + 1; i++) { - uint8_t dat = data[i]; - checksum += dat; - } - checksum = ~checksum + 1; - - if (data[len + 1] != checksum) { - ESP_LOGV(TAG, "read data invalid checksum! %02X != %02X", data[len], checksum); - return false; - } - - if (data[len + 2] != 0x00) { - ESP_LOGV(TAG, "read data invalid postamble!"); - return false; - } - - data.erase(data.begin(), data.begin() + 2); // Remove TFI and command code - data.erase(data.end() - 2, data.end()); // Remove checksum and postamble - - return true; -} - -uint8_t PN532::read_response_length_() { - std::vector data; - if (!this->read_data(data, 6)) { - return 0; - } - - if (data[1] != 0x00 && data[2] != 0x00 && data[3] != 0xFF) { - // invalid packet - ESP_LOGV(TAG, "read data invalid preamble!"); - return 0; - } - - bool valid_header = (static_cast(data[4] + data[5]) == 0 && // LCS, len + lcs = 0 - data[6] == 0xD5); // TFI - frame from PN532 to system controller - - if (!valid_header) { - ESP_LOGV(TAG, "read data invalid header!"); - return 0; - } - - this->write_data({0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00}); // NACK - Retransmit last message - - // full length of message, including TFI - uint8_t full_len = data[4]; - // length of data, excluding TFI - uint8_t len = full_len - 1; - if (full_len == 0) - len = 0; - return len; +void PN532::send_nack_() { + ESP_LOGV(TAG, "Sending NACK for retransmit"); + this->write_data({0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00}); + delay(10); } void PN532::turn_off_rf_() { - ESP_LOGVV(TAG, "Turning RF field OFF"); + ESP_LOGV(TAG, "Turning RF field OFF"); this->write_command_({ PN532_COMMAND_RFCONFIGURATION, 0x01, // RF Field diff --git a/esphome/components/pn532/pn532.h b/esphome/components/pn532/pn532.h index 6b3bef2918..95a2e0dd2a 100644 --- a/esphome/components/pn532/pn532.h +++ b/esphome/components/pn532/pn532.h @@ -46,12 +46,12 @@ class PN532 : public PollingComponent { protected: void turn_off_rf_(); bool write_command_(const std::vector &data); - bool read_response_(uint8_t command, std::vector &data); bool read_ack_(); - uint8_t read_response_length_(); + void send_nack_(); virtual bool write_data(const std::vector &data) = 0; virtual bool read_data(std::vector &data, uint8_t len) = 0; + virtual bool read_response(uint8_t command, std::vector &data) = 0; nfc::NfcTag *read_tag_(std::vector &uid); diff --git a/esphome/components/pn532/pn532_mifare_classic.cpp b/esphome/components/pn532/pn532_mifare_classic.cpp index 4e8c255755..93d394330d 100644 --- a/esphome/components/pn532/pn532_mifare_classic.cpp +++ b/esphome/components/pn532/pn532_mifare_classic.cpp @@ -64,7 +64,7 @@ bool PN532::read_mifare_classic_block_(uint8_t block_num, std::vector & return false; } - if (!this->read_response_(PN532_COMMAND_INDATAEXCHANGE, data) || data[0] != 0x00) { + if (!this->read_response(PN532_COMMAND_INDATAEXCHANGE, data) || data[0] != 0x00) { return false; } data.erase(data.begin()); @@ -89,7 +89,7 @@ bool PN532::auth_mifare_classic_block_(std::vector &uid, uint8_t block_ } std::vector response; - if (!this->read_response_(PN532_COMMAND_INDATAEXCHANGE, response) || response[0] != 0x00) { + if (!this->read_response(PN532_COMMAND_INDATAEXCHANGE, response) || response[0] != 0x00) { ESP_LOGE(TAG, "Authentication failed - Block 0x%02x", block_num); return false; } @@ -194,7 +194,7 @@ bool PN532::write_mifare_classic_block_(uint8_t block_num, std::vector } std::vector response; - if (!this->read_response_(PN532_COMMAND_INDATAEXCHANGE, response)) { + if (!this->read_response(PN532_COMMAND_INDATAEXCHANGE, response)) { ESP_LOGE(TAG, "Error writing block %d", block_num); return false; } diff --git a/esphome/components/pn532/pn532_mifare_ultralight.cpp b/esphome/components/pn532/pn532_mifare_ultralight.cpp index 00cb18aacd..bd62806c1e 100644 --- a/esphome/components/pn532/pn532_mifare_ultralight.cpp +++ b/esphome/components/pn532/pn532_mifare_ultralight.cpp @@ -52,7 +52,7 @@ bool PN532::read_mifare_ultralight_page_(uint8_t page_num, std::vector return false; } - if (!this->read_response_(PN532_COMMAND_INDATAEXCHANGE, data) || data[0] != 0x00) { + if (!this->read_response(PN532_COMMAND_INDATAEXCHANGE, data) || data[0] != 0x00) { return false; } data.erase(data.begin()); @@ -168,7 +168,7 @@ bool PN532::write_mifare_ultralight_page_(uint8_t page_num, std::vector } std::vector response; - if (!this->read_response_(PN532_COMMAND_INDATAEXCHANGE, response)) { + if (!this->read_response(PN532_COMMAND_INDATAEXCHANGE, response)) { ESP_LOGE(TAG, "Error writing page %d", page_num); return false; } diff --git a/esphome/components/pn532_i2c/pn532_i2c.cpp b/esphome/components/pn532_i2c/pn532_i2c.cpp index 162487de58..37147c5eb9 100644 --- a/esphome/components/pn532_i2c/pn532_i2c.cpp +++ b/esphome/components/pn532_i2c/pn532_i2c.cpp @@ -36,6 +36,90 @@ bool PN532I2C::read_data(std::vector &data, uint8_t len) { return true; } +bool PN532I2C::read_response(uint8_t command, std::vector &data) { + ESP_LOGV(TAG, "Reading response"); + uint8_t len = this->read_response_length_(); + if (len == 0) { + return false; + } + + ESP_LOGV(TAG, "Reading response of length %d", len); + if (!this->read_data(data, 6 + len + 2)) { + ESP_LOGD(TAG, "No response data"); + return false; + } + + if (data[1] != 0x00 && data[2] != 0x00 && data[3] != 0xFF) { + // invalid packet + ESP_LOGV(TAG, "read data invalid preamble!"); + return false; + } + + bool valid_header = (static_cast(data[4] + data[5]) == 0 && // LCS, len + lcs = 0 + data[6] == 0xD5 && // TFI - frame from PN532 to system controller + data[7] == command + 1); // Correct command response + + if (!valid_header) { + ESP_LOGV(TAG, "read data invalid header!"); + return false; + } + + data.erase(data.begin(), data.begin() + 6); // Remove headers + + uint8_t checksum = 0; + for (int i = 0; i < len + 1; i++) { + uint8_t dat = data[i]; + checksum += dat; + } + checksum = ~checksum + 1; + + if (data[len + 1] != checksum) { + ESP_LOGV(TAG, "read data invalid checksum! %02X != %02X", data[len], checksum); + return false; + } + + if (data[len + 2] != 0x00) { + ESP_LOGV(TAG, "read data invalid postamble!"); + return false; + } + + data.erase(data.begin(), data.begin() + 2); // Remove TFI and command code + data.erase(data.end() - 2, data.end()); // Remove checksum and postamble + + return true; +} + +uint8_t PN532I2C::read_response_length_() { + std::vector data; + if (!this->read_data(data, 6)) { + return 0; + } + + if (data[1] != 0x00 && data[2] != 0x00 && data[3] != 0xFF) { + // invalid packet + ESP_LOGV(TAG, "read data invalid preamble!"); + return 0; + } + + bool valid_header = (static_cast(data[4] + data[5]) == 0 && // LCS, len + lcs = 0 + data[6] == 0xD5); // TFI - frame from PN532 to system controller + + if (!valid_header) { + ESP_LOGV(TAG, "read data invalid header!"); + return 0; + } + + this->send_nack_(); + + // full length of message, including TFI + uint8_t full_len = data[4]; + // length of data, excluding TFI + uint8_t len = full_len - 1; + if (full_len == 0) + len = 0; + return len; +} + void PN532I2C::dump_config() { PN532::dump_config(); LOG_I2C_DEVICE(this); diff --git a/esphome/components/pn532_i2c/pn532_i2c.h b/esphome/components/pn532_i2c/pn532_i2c.h index 23cb00bb10..296d73e042 100644 --- a/esphome/components/pn532_i2c/pn532_i2c.h +++ b/esphome/components/pn532_i2c/pn532_i2c.h @@ -14,6 +14,8 @@ class PN532I2C : public pn532::PN532, public i2c::I2CDevice { protected: bool write_data(const std::vector &data) override; bool read_data(std::vector &data, uint8_t len) override; + bool read_response(uint8_t command, std::vector &data) override; + uint8_t read_response_length_(); }; } // namespace pn532_i2c diff --git a/esphome/components/pn532_spi/pn532_spi.cpp b/esphome/components/pn532_spi/pn532_spi.cpp index 3da799fb24..6f87ad8ca7 100644 --- a/esphome/components/pn532_spi/pn532_spi.cpp +++ b/esphome/components/pn532_spi/pn532_spi.cpp @@ -26,7 +26,7 @@ bool PN532Spi::write_data(const std::vector &data) { delay(2); // First byte, communication mode: Write data this->write_byte(0x01); - + ESP_LOGV(TAG, "Writing data: %s", hexencode(data).c_str()); this->write_array(data.data(), data.size()); this->disable(); @@ -34,31 +34,122 @@ bool PN532Spi::write_data(const std::vector &data) { } bool PN532Spi::read_data(std::vector &data, uint8_t len) { - this->enable(); - // First byte, communication mode: Read state - this->write_byte(0x02); + ESP_LOGV(TAG, "Waiting for ready byte..."); uint32_t start_time = millis(); while (true) { - if (this->read_byte() & 0x01) + this->enable(); + // First byte, communication mode: Read state + this->write_byte(0x02); + bool ready = this->read_byte() == 0x01; + this->disable(); + if (ready) break; + ESP_LOGV(TAG, "Not ready yet..."); if (millis() - start_time > 100) { - this->disable(); ESP_LOGV(TAG, "Timed out waiting for readiness from PN532!"); return false; } + yield(); } // Read data (transmission from the PN532 to the host) + this->enable(); + delay(2); this->write_byte(0x03); + ESP_LOGV(TAG, "Reading data..."); + data.resize(len); this->read_array(data.data(), len); this->disable(); data.insert(data.begin(), 0x01); + ESP_LOGV(TAG, "Read data: %s", hexencode(data).c_str()); return true; -}; +} + +bool PN532Spi::read_response(uint8_t command, std::vector &data) { + ESP_LOGV(TAG, "Reading response"); + + uint32_t start_time = millis(); + while (true) { + this->enable(); + // First byte, communication mode: Read state + this->write_byte(0x02); + bool ready = this->read_byte() == 0x01; + this->disable(); + if (ready) + break; + ESP_LOGV(TAG, "Not ready yet..."); + + if (millis() - start_time > 100) { + ESP_LOGV(TAG, "Timed out waiting for readiness from PN532!"); + return false; + } + yield(); + } + + this->enable(); + delay(2); + this->write_byte(0x03); + + std::vector header(7); + this->read_array(header.data(), 7); + + ESP_LOGV(TAG, "Header data: %s", hexencode(header).c_str()); + + if (header[0] != 0x00 && header[1] != 0x00 && header[2] != 0xFF) { + // invalid packet + ESP_LOGV(TAG, "read data invalid preamble!"); + return false; + } + + bool valid_header = (static_cast(header[3] + header[4]) == 0 && // LCS, len + lcs = 0 + header[5] == 0xD5 && // TFI - frame from PN532 to system controller + header[6] == command + 1); // Correct command response + + if (!valid_header) { + ESP_LOGV(TAG, "read data invalid header!"); + return false; + } + + // full length of message, including command response + uint8_t full_len = header[3]; + // length of data, excluding command response + uint8_t len = full_len - 1; + if (full_len == 0) + len = 0; + + ESP_LOGV(TAG, "Reading response of length %d", len); + + data.resize(len + 1); + this->read_array(data.data(), len + 1); + this->disable(); + + ESP_LOGV(TAG, "Response data: %s", hexencode(data).c_str()); + + uint8_t checksum = header[5] + header[6]; // TFI + Command response code + for (int i = 0; i < len - 1; i++) { + uint8_t dat = data[i]; + checksum += dat; + } + checksum = ~checksum + 1; + + if (data[len - 1] != checksum) { + ESP_LOGV(TAG, "read data invalid checksum! %02X != %02X", data[len - 1], checksum); + return false; + } + + if (data[len] != 0x00) { + ESP_LOGV(TAG, "read data invalid postamble!"); + return false; + } + + data.erase(data.end() - 2, data.end()); // Remove checksum and postamble + + return true; +} void PN532Spi::dump_config() { PN532::dump_config(); diff --git a/esphome/components/pn532_spi/pn532_spi.h b/esphome/components/pn532_spi/pn532_spi.h index 967b8a66cf..d98bd447c8 100644 --- a/esphome/components/pn532_spi/pn532_spi.h +++ b/esphome/components/pn532_spi/pn532_spi.h @@ -18,6 +18,7 @@ class PN532Spi : public pn532::PN532, protected: bool write_data(const std::vector &data) override; bool read_data(std::vector &data, uint8_t len) override; + bool read_response(uint8_t command, std::vector &data) override; }; } // namespace pn532_spi From bc64cf3e4724351b461834e629d200cfddc4f6fb Mon Sep 17 00:00:00 2001 From: Klarstein <62219057+Klarstein@users.noreply.github.com> Date: Fri, 12 Feb 2021 03:26:55 +0100 Subject: [PATCH 2/6] Update Dockerfile health check timings (#1517) --- docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 12b06ec284..bbee4b2434 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -16,7 +16,7 @@ ENV USERNAME="" PASSWORD="" EXPOSE 6052 # Run healthcheck (heartbeat) -HEALTHCHECK --interval=5m --timeout=3s \ +HEALTHCHECK --interval=30s --timeout=30s \ CMD curl --fail http://localhost:6052 || exit 1 # The directory the user should mount their configuration files to From ef89249019d1b8ade991699fcfd9317eb6946586 Mon Sep 17 00:00:00 2001 From: SenexCrenshaw <35600301+SenexCrenshaw@users.noreply.github.com> Date: Sat, 13 Feb 2021 03:34:59 -0500 Subject: [PATCH 3/6] Fixed ST7735 transfer_byte to write_byte without `miso` (#1529) --- esphome/components/st7735/st7735.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/st7735/st7735.cpp b/esphome/components/st7735/st7735.cpp index 2a3d8fc903..5cd79da2cb 100644 --- a/esphome/components/st7735/st7735.cpp +++ b/esphome/components/st7735/st7735.cpp @@ -407,7 +407,7 @@ void HOT ST7735::senddata_(const uint8_t *data_bytes, uint8_t num_data_bytes) { this->cs_->digital_write(false); this->enable(); for (uint8_t i = 0; i < num_data_bytes; i++) { - this->transfer_byte(pgm_read_byte(data_bytes++)); // write byte - SPI library + this->write_byte(pgm_read_byte(data_bytes++)); // write byte - SPI library } this->cs_->digital_write(true); this->disable(); From 57b56010da6d790f56ca5fca3e76bd5f710e272b Mon Sep 17 00:00:00 2001 From: Frank Bakker Date: Sat, 13 Feb 2021 09:57:06 +0100 Subject: [PATCH 4/6] Added energy sensor to hlw8012 (#1198) --- esphome/components/hlw8012/hlw8012.cpp | 6 ++++++ esphome/components/hlw8012/hlw8012.h | 3 +++ esphome/components/hlw8012/sensor.py | 8 ++++++-- tests/test1.yaml | 3 +++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/esphome/components/hlw8012/hlw8012.cpp b/esphome/components/hlw8012/hlw8012.cpp index 2b3b4ec2d9..379dbe578e 100644 --- a/esphome/components/hlw8012/hlw8012.cpp +++ b/esphome/components/hlw8012/hlw8012.cpp @@ -79,6 +79,12 @@ void HLW8012Component::update() { this->power_sensor_->publish_state(power); } + if (this->energy_sensor_ != nullptr) { + cf_total_pulses_ += raw_cf; + float energy = cf_total_pulses_ * power_multiplier_micros / 3600 / 1000000.0f; + this->energy_sensor_->publish_state(energy); + } + if (this->change_mode_at_++ == this->change_mode_every_) { this->current_mode_ = !this->current_mode_; ESP_LOGV(TAG, "Changing mode to %s mode", this->current_mode_ ? "CURRENT" : "VOLTAGE"); diff --git a/esphome/components/hlw8012/hlw8012.h b/esphome/components/hlw8012/hlw8012.h index 4e5dc0f67f..af1f2e9a8c 100644 --- a/esphome/components/hlw8012/hlw8012.h +++ b/esphome/components/hlw8012/hlw8012.h @@ -29,6 +29,7 @@ class HLW8012Component : public PollingComponent { void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; } void set_current_sensor(sensor::Sensor *current_sensor) { current_sensor_ = current_sensor; } void set_power_sensor(sensor::Sensor *power_sensor) { power_sensor_ = power_sensor; } + void set_energy_sensor(sensor::Sensor *energy_sensor) { energy_sensor_ = energy_sensor; } protected: uint32_t nth_value_{0}; @@ -37,6 +38,7 @@ class HLW8012Component : public PollingComponent { uint32_t change_mode_every_{8}; float current_resistor_{0.001}; float voltage_divider_{2351}; + uint64_t cf_total_pulses_{0}; GPIOPin *sel_pin_; GPIOPin *cf_pin_; pulse_counter::PulseCounterStorage cf_store_; @@ -45,6 +47,7 @@ class HLW8012Component : public PollingComponent { sensor::Sensor *voltage_sensor_{nullptr}; sensor::Sensor *current_sensor_{nullptr}; sensor::Sensor *power_sensor_{nullptr}; + sensor::Sensor *energy_sensor_{nullptr}; }; } // namespace hlw8012 diff --git a/esphome/components/hlw8012/sensor.py b/esphome/components/hlw8012/sensor.py index e1f02b8fd2..e1a0ec6f18 100644 --- a/esphome/components/hlw8012/sensor.py +++ b/esphome/components/hlw8012/sensor.py @@ -3,8 +3,8 @@ import esphome.config_validation as cv from esphome import pins from esphome.components import sensor from esphome.const import CONF_CHANGE_MODE_EVERY, CONF_INITIAL_MODE, CONF_CURRENT, \ - CONF_CURRENT_RESISTOR, CONF_ID, CONF_POWER, CONF_SEL_PIN, CONF_VOLTAGE, CONF_VOLTAGE_DIVIDER, \ - ICON_FLASH, UNIT_VOLT, UNIT_AMPERE, UNIT_WATT + CONF_CURRENT_RESISTOR, CONF_ID, CONF_POWER, CONF_ENERGY, CONF_SEL_PIN, CONF_VOLTAGE, \ + CONF_VOLTAGE_DIVIDER, ICON_FLASH, UNIT_VOLT, UNIT_AMPERE, UNIT_WATT, UNIT_WATT_HOURS AUTO_LOAD = ['pulse_counter'] @@ -29,6 +29,7 @@ CONFIG_SCHEMA = cv.Schema({ cv.Optional(CONF_VOLTAGE): sensor.sensor_schema(UNIT_VOLT, ICON_FLASH, 1), cv.Optional(CONF_CURRENT): sensor.sensor_schema(UNIT_AMPERE, ICON_FLASH, 2), cv.Optional(CONF_POWER): sensor.sensor_schema(UNIT_WATT, ICON_FLASH, 1), + cv.Optional(CONF_ENERGY): sensor.sensor_schema(UNIT_WATT_HOURS, ICON_FLASH, 1), cv.Optional(CONF_CURRENT_RESISTOR, default=0.001): cv.resistance, cv.Optional(CONF_VOLTAGE_DIVIDER, default=2351): cv.positive_float, @@ -57,6 +58,9 @@ def to_code(config): if CONF_POWER in config: sens = yield sensor.new_sensor(config[CONF_POWER]) cg.add(var.set_power_sensor(sens)) + if CONF_ENERGY in config: + sens = yield sensor.new_sensor(config[CONF_ENERGY]) + cg.add(var.set_energy_sensor(sens)) cg.add(var.set_current_resistor(config[CONF_CURRENT_RESISTOR])) cg.add(var.set_voltage_divider(config[CONF_VOLTAGE_DIVIDER])) cg.add(var.set_change_mode_every(config[CONF_CHANGE_MODE_EVERY])) diff --git a/tests/test1.yaml b/tests/test1.yaml index 5aed1dac44..fceff00e24 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -434,6 +434,9 @@ sensor: power: name: 'HLW8012 Power' id: hlw8012_power + energy: + name: "HLW8012 Energy" + id: hlw8012_energy update_interval: 15s current_resistor: 0.001 ohm voltage_divider: 2351 From 65c7e27a4364c45903fdeae47c7b570490280c7a Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Sat, 13 Feb 2021 03:07:11 -0600 Subject: [PATCH 5/6] MCP230xx open drain interrupt pins (#1243) --- esphome/components/mcp23008/__init__.py | 4 +++- esphome/components/mcp23008/mcp23008.cpp | 6 ++++-- esphome/components/mcp23008/mcp23008.h | 3 +++ esphome/components/mcp23017/__init__.py | 4 +++- esphome/components/mcp23017/mcp23017.cpp | 8 +++++--- esphome/components/mcp23017/mcp23017.h | 3 +++ esphome/const.py | 1 + tests/test1.yaml | 2 ++ 8 files changed, 24 insertions(+), 7 deletions(-) diff --git a/esphome/components/mcp23008/__init__.py b/esphome/components/mcp23008/__init__.py index 4241b6ba48..858b37b60a 100644 --- a/esphome/components/mcp23008/__init__.py +++ b/esphome/components/mcp23008/__init__.py @@ -2,7 +2,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import pins from esphome.components import i2c -from esphome.const import CONF_ID, CONF_NUMBER, CONF_MODE, CONF_INVERTED +from esphome.const import CONF_ID, CONF_NUMBER, CONF_MODE, CONF_INVERTED, CONF_OPEN_DRAIN_INTERRUPT DEPENDENCIES = ['i2c'] MULTI_CONF = True @@ -20,6 +20,7 @@ MCP23008GPIOPin = mcp23008_ns.class_('MCP23008GPIOPin', cg.GPIOPin) CONFIG_SCHEMA = cv.Schema({ cv.Required(CONF_ID): cv.declare_id(MCP23008), + cv.Optional(CONF_OPEN_DRAIN_INTERRUPT, default=False): cv.boolean, }).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x20)) @@ -27,6 +28,7 @@ def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) yield cg.register_component(var, config) yield i2c.register_i2c_device(var, config) + cg.add(var.set_open_drain_ints(config[CONF_OPEN_DRAIN_INTERRUPT])) CONF_MCP23008 = 'mcp23008' diff --git a/esphome/components/mcp23008/mcp23008.cpp b/esphome/components/mcp23008/mcp23008.cpp index bf5bb55f2e..22c7322458 100644 --- a/esphome/components/mcp23008/mcp23008.cpp +++ b/esphome/components/mcp23008/mcp23008.cpp @@ -14,8 +14,10 @@ void MCP23008::setup() { return; } - // all pins input - this->write_reg_(MCP23008_IODIR, 0xFF); + if (this->open_drain_ints_) { + // enable open-drain interrupt pins, 3.3V-safe + this->write_reg_(MCP23008_IOCON, 0x04); + } } bool MCP23008::digital_read(uint8_t pin) { uint8_t bit = pin % 8; diff --git a/esphome/components/mcp23008/mcp23008.h b/esphome/components/mcp23008/mcp23008.h index b4e5d75fd4..e30a924dde 100644 --- a/esphome/components/mcp23008/mcp23008.h +++ b/esphome/components/mcp23008/mcp23008.h @@ -39,6 +39,8 @@ class MCP23008 : public Component, public i2c::I2CDevice { void digital_write(uint8_t pin, bool value); void pin_mode(uint8_t pin, uint8_t mode); + void set_open_drain_ints(const bool value) { open_drain_ints_ = value; } + float get_setup_priority() const override; protected: @@ -50,6 +52,7 @@ class MCP23008 : public Component, public i2c::I2CDevice { void update_reg_(uint8_t pin, bool pin_value, uint8_t reg_a); uint8_t olat_{0x00}; + bool open_drain_ints_; }; class MCP23008GPIOPin : public GPIOPin { diff --git a/esphome/components/mcp23017/__init__.py b/esphome/components/mcp23017/__init__.py index 4b798bf434..34f94b293a 100644 --- a/esphome/components/mcp23017/__init__.py +++ b/esphome/components/mcp23017/__init__.py @@ -2,7 +2,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome import pins from esphome.components import i2c -from esphome.const import CONF_ID, CONF_NUMBER, CONF_MODE, CONF_INVERTED +from esphome.const import CONF_ID, CONF_NUMBER, CONF_MODE, CONF_INVERTED, CONF_OPEN_DRAIN_INTERRUPT DEPENDENCIES = ['i2c'] MULTI_CONF = True @@ -20,6 +20,7 @@ MCP23017GPIOPin = mcp23017_ns.class_('MCP23017GPIOPin', cg.GPIOPin) CONFIG_SCHEMA = cv.Schema({ cv.Required(CONF_ID): cv.declare_id(MCP23017), + cv.Optional(CONF_OPEN_DRAIN_INTERRUPT, default=False): cv.boolean, }).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x20)) @@ -27,6 +28,7 @@ def to_code(config): var = cg.new_Pvariable(config[CONF_ID]) yield cg.register_component(var, config) yield i2c.register_i2c_device(var, config) + cg.add(var.set_open_drain_ints(config[CONF_OPEN_DRAIN_INTERRUPT])) CONF_MCP23017 = 'mcp23017' diff --git a/esphome/components/mcp23017/mcp23017.cpp b/esphome/components/mcp23017/mcp23017.cpp index 9653aa680d..ec972668ef 100644 --- a/esphome/components/mcp23017/mcp23017.cpp +++ b/esphome/components/mcp23017/mcp23017.cpp @@ -14,9 +14,11 @@ void MCP23017::setup() { return; } - // all pins input - this->write_reg_(MCP23017_IODIRA, 0xFF); - this->write_reg_(MCP23017_IODIRB, 0xFF); + if (this->open_drain_ints_) { + // enable open-drain interrupt pins, 3.3V-safe + this->write_reg_(MCP23017_IOCONA, 0x04); + this->write_reg_(MCP23017_IOCONB, 0x04); + } } bool MCP23017::digital_read(uint8_t pin) { uint8_t bit = pin % 8; diff --git a/esphome/components/mcp23017/mcp23017.h b/esphome/components/mcp23017/mcp23017.h index 4389eeb6ff..5656dcc58d 100644 --- a/esphome/components/mcp23017/mcp23017.h +++ b/esphome/components/mcp23017/mcp23017.h @@ -51,6 +51,8 @@ class MCP23017 : public Component, public i2c::I2CDevice { void digital_write(uint8_t pin, bool value); void pin_mode(uint8_t pin, uint8_t mode); + void set_open_drain_ints(const bool value) { open_drain_ints_ = value; } + float get_setup_priority() const override; protected: @@ -63,6 +65,7 @@ class MCP23017 : public Component, public i2c::I2CDevice { uint8_t olat_a_{0x00}; uint8_t olat_b_{0x00}; + bool open_drain_ints_; }; class MCP23017GPIOPin : public GPIOPin { diff --git a/esphome/const.py b/esphome/const.py index f0edcc71d4..167f4af217 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -357,6 +357,7 @@ CONF_ON_VALUE = 'on_value' CONF_ON_VALUE_RANGE = 'on_value_range' CONF_ONE = 'one' CONF_OPEN_ACTION = 'open_action' +CONF_OPEN_DRAIN_INTERRUPT = 'open_drain_interrupt' CONF_OPEN_DURATION = 'open_duration' CONF_OPEN_ENDSTOP = 'open_endstop' CONF_OPTIMISTIC = 'optimistic' diff --git a/tests/test1.yaml b/tests/test1.yaml index fceff00e24..a4cf1e42dc 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -1895,10 +1895,12 @@ pcf8574: mcp23017: - id: 'mcp23017_hub' + open_drain_interrupt: 'true' mcp23008: - id: 'mcp23008_hub' address: 0x22 + open_drain_interrupt: 'true' mcp23016: - id: 'mcp23016_hub' From 61ecbe4273833c3a644acc820f493523bf2fa883 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sun, 14 Feb 2021 10:01:22 +1300 Subject: [PATCH 6/6] Bump version to v1.16.1 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 167f4af217..b66d3a141a 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -2,7 +2,7 @@ MAJOR_VERSION = 1 MINOR_VERSION = 16 -PATCH_VERSION = '0' +PATCH_VERSION = '1' __short_version__ = f'{MAJOR_VERSION}.{MINOR_VERSION}' __version__ = f'{__short_version__}.{PATCH_VERSION}'