mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	Support high update rates and fix several bugs in the cse7766 component. (#3675)
This commit is contained in:
		| @@ -13,8 +13,9 @@ void CSE7766Component::loop() { | |||||||
|     this->raw_data_index_ = 0; |     this->raw_data_index_ = 0; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (this->available() == 0) |   if (this->available() == 0) { | ||||||
|     return; |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   this->last_transmission_ = now; |   this->last_transmission_ = now; | ||||||
|   while (this->available() != 0) { |   while (this->available() != 0) { | ||||||
| @@ -22,6 +23,7 @@ void CSE7766Component::loop() { | |||||||
|     if (!this->check_byte_()) { |     if (!this->check_byte_()) { | ||||||
|       this->raw_data_index_ = 0; |       this->raw_data_index_ = 0; | ||||||
|       this->status_set_warning(); |       this->status_set_warning(); | ||||||
|  |       continue; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (this->raw_data_index_ == 23) { |     if (this->raw_data_index_ == 23) { | ||||||
| @@ -51,8 +53,9 @@ bool CSE7766Component::check_byte_() { | |||||||
|  |  | ||||||
|   if (index == 23) { |   if (index == 23) { | ||||||
|     uint8_t checksum = 0; |     uint8_t checksum = 0; | ||||||
|     for (uint8_t i = 2; i < 23; i++) |     for (uint8_t i = 2; i < 23; i++) { | ||||||
|       checksum += this->raw_data_[i]; |       checksum += this->raw_data_[i]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if (checksum != this->raw_data_[23]) { |     if (checksum != this->raw_data_[23]) { | ||||||
|       ESP_LOGW(TAG, "Invalid checksum from CSE7766: 0x%02X != 0x%02X", checksum, this->raw_data_[23]); |       ESP_LOGW(TAG, "Invalid checksum from CSE7766: 0x%02X != 0x%02X", checksum, this->raw_data_[23]); | ||||||
| @@ -66,22 +69,36 @@ bool CSE7766Component::check_byte_() { | |||||||
| void CSE7766Component::parse_data_() { | void CSE7766Component::parse_data_() { | ||||||
|   ESP_LOGVV(TAG, "CSE7766 Data: "); |   ESP_LOGVV(TAG, "CSE7766 Data: "); | ||||||
|   for (uint8_t i = 0; i < 23; i++) { |   for (uint8_t i = 0; i < 23; i++) { | ||||||
|     ESP_LOGVV(TAG, "  i=%u: 0b" BYTE_TO_BINARY_PATTERN " (0x%02X)", i, BYTE_TO_BINARY(this->raw_data_[i]), |     ESP_LOGVV(TAG, "  %u: 0b" BYTE_TO_BINARY_PATTERN " (0x%02X)", i + 1, BYTE_TO_BINARY(this->raw_data_[i]), | ||||||
|               this->raw_data_[i]); |               this->raw_data_[i]); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   uint8_t header1 = this->raw_data_[0]; |   uint8_t header1 = this->raw_data_[0]; | ||||||
|   if (header1 == 0xAA) { |   if (header1 == 0xAA) { | ||||||
|     ESP_LOGW(TAG, "CSE7766 not calibrated!"); |     ESP_LOGE(TAG, "CSE7766 not calibrated!"); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if ((header1 & 0xF0) == 0xF0 && ((header1 >> 0) & 1) == 1) { |   bool power_cycle_exceeds_range = false; | ||||||
|     ESP_LOGW(TAG, "CSE7766 reports abnormal hardware: (0x%02X)", header1); |  | ||||||
|     ESP_LOGW(TAG, "  Coefficient storage area is abnormal."); |   if ((header1 & 0xF0) == 0xF0) { | ||||||
|  |     if (header1 & 0xD) { | ||||||
|  |       ESP_LOGE(TAG, "CSE7766 reports abnormal external circuit or chip damage: (0x%02X)", header1); | ||||||
|  |       if (header1 & (1 << 3)) { | ||||||
|  |         ESP_LOGE(TAG, "  Voltage cycle exceeds range."); | ||||||
|  |       } | ||||||
|  |       if (header1 & (1 << 2)) { | ||||||
|  |         ESP_LOGE(TAG, "  Current cycle exceeds range."); | ||||||
|  |       } | ||||||
|  |       if (header1 & (1 << 0)) { | ||||||
|  |         ESP_LOGE(TAG, "  Coefficient storage area is abnormal."); | ||||||
|  |       } | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     power_cycle_exceeds_range = header1 & (1 << 1); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   uint32_t voltage_calib = this->get_24_bit_uint_(2); |   uint32_t voltage_calib = this->get_24_bit_uint_(2); | ||||||
|   uint32_t voltage_cycle = this->get_24_bit_uint_(5); |   uint32_t voltage_cycle = this->get_24_bit_uint_(5); | ||||||
|   uint32_t current_calib = this->get_24_bit_uint_(8); |   uint32_t current_calib = this->get_24_bit_uint_(8); | ||||||
| @@ -92,46 +109,29 @@ void CSE7766Component::parse_data_() { | |||||||
|   uint8_t adj = this->raw_data_[20]; |   uint8_t adj = this->raw_data_[20]; | ||||||
|   uint32_t cf_pulses = (this->raw_data_[21] << 8) + this->raw_data_[22]; |   uint32_t cf_pulses = (this->raw_data_[21] << 8) + this->raw_data_[22]; | ||||||
|  |  | ||||||
|   bool power_ok = true; |   bool have_voltage = adj & 0x40; | ||||||
|   bool voltage_ok = true; |   if (have_voltage) { | ||||||
|   bool current_ok = true; |  | ||||||
|  |  | ||||||
|   if (header1 > 0xF0) { |  | ||||||
|     // ESP_LOGV(TAG, "CSE7766 reports abnormal hardware: (0x%02X)", byte); |  | ||||||
|     if ((header1 >> 3) & 1) { |  | ||||||
|       ESP_LOGV(TAG, "  Voltage cycle exceeds range."); |  | ||||||
|       voltage_ok = false; |  | ||||||
|     } |  | ||||||
|     if ((header1 >> 2) & 1) { |  | ||||||
|       ESP_LOGV(TAG, "  Current cycle exceeds range."); |  | ||||||
|       current_ok = false; |  | ||||||
|     } |  | ||||||
|     if ((header1 >> 1) & 1) { |  | ||||||
|       ESP_LOGV(TAG, "  Power cycle exceeds range."); |  | ||||||
|       power_ok = false; |  | ||||||
|     } |  | ||||||
|     if ((header1 >> 0) & 1) { |  | ||||||
|       ESP_LOGV(TAG, "  Coefficient storage area is abnormal."); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if ((adj & 0x40) == 0x40 && voltage_ok && current_ok) { |  | ||||||
|     // voltage cycle of serial port outputted is a complete cycle; |     // voltage cycle of serial port outputted is a complete cycle; | ||||||
|     this->voltage_acc_ += voltage_calib / float(voltage_cycle); |     this->voltage_acc_ += voltage_calib / float(voltage_cycle); | ||||||
|     this->voltage_counts_ += 1; |     this->voltage_counts_ += 1; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   float power = 0; |   bool have_power = adj & 0x10; | ||||||
|   if ((adj & 0x10) == 0x10 && voltage_ok && current_ok && power_ok) { |   float power = 0.0f; | ||||||
|  |  | ||||||
|  |   if (have_power) { | ||||||
|     // power cycle of serial port outputted is a complete cycle; |     // power cycle of serial port outputted is a complete cycle; | ||||||
|  |     // According to the user manual, power cycle exceeding range means the measured power is 0 | ||||||
|  |     if (!power_cycle_exceeds_range) { | ||||||
|       power = power_calib / float(power_cycle); |       power = power_calib / float(power_cycle); | ||||||
|  |     } | ||||||
|     this->power_acc_ += power; |     this->power_acc_ += power; | ||||||
|     this->power_counts_ += 1; |     this->power_counts_ += 1; | ||||||
|  |  | ||||||
|     uint32_t difference; |     uint32_t difference; | ||||||
|     if (this->cf_pulses_last_ == 0) |     if (this->cf_pulses_last_ == 0) { | ||||||
|       this->cf_pulses_last_ = cf_pulses; |       this->cf_pulses_last_ = cf_pulses; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if (cf_pulses < this->cf_pulses_last_) { |     if (cf_pulses < this->cf_pulses_last_) { | ||||||
|       difference = cf_pulses + (0x10000 - this->cf_pulses_last_); |       difference = cf_pulses + (0x10000 - this->cf_pulses_last_); | ||||||
| @@ -139,41 +139,52 @@ void CSE7766Component::parse_data_() { | |||||||
|       difference = cf_pulses - this->cf_pulses_last_; |       difference = cf_pulses - this->cf_pulses_last_; | ||||||
|     } |     } | ||||||
|     this->cf_pulses_last_ = cf_pulses; |     this->cf_pulses_last_ = cf_pulses; | ||||||
|     this->energy_total_ += difference * float(power_calib) / 1000000.0 / 3600.0; |     this->energy_total_ += difference * float(power_calib) / 1000000.0f / 3600.0f; | ||||||
|  |     this->energy_total_counts_ += 1; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if ((adj & 0x20) == 0x20 && current_ok && voltage_ok && power != 0.0) { |   if (adj & 0x20) { | ||||||
|     // indicates current cycle of serial port outputted is a complete cycle; |     // indicates current cycle of serial port outputted is a complete cycle; | ||||||
|     this->current_acc_ += current_calib / float(current_cycle); |     float current = 0.0f; | ||||||
|  |     if (have_voltage && !have_power) { | ||||||
|  |       // Testing has shown that when we have voltage and current but not power, that means the power is 0. | ||||||
|  |       // We report a power of 0, which in turn means we should report a current of 0. | ||||||
|  |       this->power_counts_ += 1; | ||||||
|  |     } else if (power != 0.0f) { | ||||||
|  |       current = current_calib / float(current_cycle); | ||||||
|  |     } | ||||||
|  |     this->current_acc_ += current; | ||||||
|     this->current_counts_ += 1; |     this->current_counts_ += 1; | ||||||
|   } |   } | ||||||
| } | } | ||||||
| void CSE7766Component::update() { | void CSE7766Component::update() { | ||||||
|   float voltage = this->voltage_counts_ > 0 ? this->voltage_acc_ / this->voltage_counts_ : 0.0f; |   const auto publish_state = [](const char *name, sensor::Sensor *sensor, float &acc, uint32_t &counts) { | ||||||
|   float current = this->current_counts_ > 0 ? this->current_acc_ / this->current_counts_ : 0.0f; |     if (counts != 0) { | ||||||
|   float power = this->power_counts_ > 0 ? this->power_acc_ / this->power_counts_ : 0.0f; |       const auto avg = acc / counts; | ||||||
|  |  | ||||||
|   ESP_LOGV(TAG, "Got voltage_acc=%.2f current_acc=%.2f power_acc=%.2f", this->voltage_acc_, this->current_acc_, |       ESP_LOGV(TAG, "Got %s_acc=%.2f %s_counts=%d %s=%.1f", name, acc, name, counts, name, avg); | ||||||
|            this->power_acc_); |  | ||||||
|   ESP_LOGV(TAG, "Got voltage_counts=%d current_counts=%d power_counts=%d", this->voltage_counts_, this->current_counts_, |  | ||||||
|            this->power_counts_); |  | ||||||
|   ESP_LOGD(TAG, "Got voltage=%.1fV current=%.1fA power=%.1fW", voltage, current, power); |  | ||||||
|  |  | ||||||
|   if (this->voltage_sensor_ != nullptr) |       if (sensor != nullptr) { | ||||||
|     this->voltage_sensor_->publish_state(voltage); |         sensor->publish_state(avg); | ||||||
|   if (this->current_sensor_ != nullptr) |       } | ||||||
|     this->current_sensor_->publish_state(current); |  | ||||||
|   if (this->power_sensor_ != nullptr) |       acc = 0.0f; | ||||||
|     this->power_sensor_->publish_state(power); |       counts = 0; | ||||||
|   if (this->energy_sensor_ != nullptr) |     } | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   publish_state("voltage", this->voltage_sensor_, this->voltage_acc_, this->voltage_counts_); | ||||||
|  |   publish_state("current", this->current_sensor_, this->current_acc_, this->current_counts_); | ||||||
|  |   publish_state("power", this->power_sensor_, this->power_acc_, this->power_counts_); | ||||||
|  |  | ||||||
|  |   if (this->energy_total_counts_ != 0) { | ||||||
|  |     ESP_LOGV(TAG, "Got energy_total=%.2f energy_total_counts=%d", this->energy_total_, this->energy_total_counts_); | ||||||
|  |  | ||||||
|  |     if (this->energy_sensor_ != nullptr) { | ||||||
|       this->energy_sensor_->publish_state(this->energy_total_); |       this->energy_sensor_->publish_state(this->energy_total_); | ||||||
|  |     } | ||||||
|   this->voltage_acc_ = 0.0f; |     this->energy_total_counts_ = 0; | ||||||
|   this->current_acc_ = 0.0f; |   } | ||||||
|   this->power_acc_ = 0.0f; |  | ||||||
|   this->voltage_counts_ = 0; |  | ||||||
|   this->power_counts_ = 0; |  | ||||||
|   this->current_counts_ = 0; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| uint32_t CSE7766Component::get_24_bit_uint_(uint8_t start_index) { | uint32_t CSE7766Component::get_24_bit_uint_(uint8_t start_index) { | ||||||
|   | |||||||
| @@ -39,6 +39,8 @@ class CSE7766Component : public PollingComponent, public uart::UARTDevice { | |||||||
|   uint32_t voltage_counts_{0}; |   uint32_t voltage_counts_{0}; | ||||||
|   uint32_t current_counts_{0}; |   uint32_t current_counts_{0}; | ||||||
|   uint32_t power_counts_{0}; |   uint32_t power_counts_{0}; | ||||||
|  |   // Setting this to 1 means it will always publish 0 once at startup | ||||||
|  |   uint32_t energy_total_counts_{1}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| }  // namespace cse7766 | }  // namespace cse7766 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user