mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	New component: ADE7880 voltage/current/power/energy sensor (#5242)
This commit is contained in:
		| @@ -18,6 +18,7 @@ esphome/components/ac_dimmer/* @glmnet | |||||||
| esphome/components/adc/* @esphome/core | esphome/components/adc/* @esphome/core | ||||||
| esphome/components/adc128s102/* @DeerMaximum | esphome/components/adc128s102/* @DeerMaximum | ||||||
| esphome/components/addressable_light/* @justfalter | esphome/components/addressable_light/* @justfalter | ||||||
|  | esphome/components/ade7880/* @kpfleming | ||||||
| esphome/components/ade7953/* @angelnu | esphome/components/ade7953/* @angelnu | ||||||
| esphome/components/ade7953_i2c/* @angelnu | esphome/components/ade7953_i2c/* @angelnu | ||||||
| esphome/components/ade7953_spi/* @angelnu | esphome/components/ade7953_spi/* @angelnu | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								esphome/components/ade7880/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								esphome/components/ade7880/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | CODEOWNERS = ["@kpfleming"] | ||||||
							
								
								
									
										302
									
								
								esphome/components/ade7880/ade7880.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										302
									
								
								esphome/components/ade7880/ade7880.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,302 @@ | |||||||
|  | // This component was developed using knowledge gathered by a number | ||||||
|  | // of people who reverse-engineered the Shelly 3EM: | ||||||
|  | // | ||||||
|  | // @AndreKR on GitHub | ||||||
|  | // Axel (@Axel830 on GitHub) | ||||||
|  | // Marko (@goodkiller on GitHub) | ||||||
|  | // Michaël Piron (@michaelpiron on GitHub) | ||||||
|  | // Theo Arends (@arendst on GitHub) | ||||||
|  |  | ||||||
|  | #include "ade7880.h" | ||||||
|  | #include "ade7880_registers.h" | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace ade7880 { | ||||||
|  |  | ||||||
|  | static const char *const TAG = "ade7880"; | ||||||
|  |  | ||||||
|  | void IRAM_ATTR ADE7880Store::gpio_intr(ADE7880Store *arg) { arg->reset_done = true; } | ||||||
|  |  | ||||||
|  | void ADE7880::setup() { | ||||||
|  |   if (this->irq0_pin_ != nullptr) { | ||||||
|  |     this->irq0_pin_->setup(); | ||||||
|  |   } | ||||||
|  |   this->irq1_pin_->setup(); | ||||||
|  |   if (this->reset_pin_ != nullptr) { | ||||||
|  |     this->reset_pin_->setup(); | ||||||
|  |   } | ||||||
|  |   this->store_.irq1_pin = this->irq1_pin_->to_isr(); | ||||||
|  |   this->irq1_pin_->attach_interrupt(ADE7880Store::gpio_intr, &this->store_, gpio::INTERRUPT_FALLING_EDGE); | ||||||
|  |  | ||||||
|  |   // if IRQ1 is already asserted, the cause must be determined | ||||||
|  |   if (this->irq1_pin_->digital_read() == 0) { | ||||||
|  |     ESP_LOGD(TAG, "IRQ1 found asserted during setup()"); | ||||||
|  |     auto status1 = read_u32_register16_(STATUS1); | ||||||
|  |     if ((status1 & ~STATUS1_RSTDONE) != 0) { | ||||||
|  |       // not safe to proceed, must initiate reset | ||||||
|  |       ESP_LOGD(TAG, "IRQ1 asserted for !RSTDONE, resetting device"); | ||||||
|  |       this->reset_device_(); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     if ((status1 & STATUS1_RSTDONE) == STATUS1_RSTDONE) { | ||||||
|  |       // safe to proceed, device has just completed reset cycle | ||||||
|  |       ESP_LOGD(TAG, "Acknowledging RSTDONE"); | ||||||
|  |       this->write_u32_register16_(STATUS0, 0xFFFF); | ||||||
|  |       this->write_u32_register16_(STATUS1, 0xFFFF); | ||||||
|  |       this->init_device_(); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   this->reset_device_(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ADE7880::loop() { | ||||||
|  |   // check for completion of a reset cycle | ||||||
|  |   if (!this->store_.reset_done) { | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ESP_LOGD(TAG, "Acknowledging RSTDONE"); | ||||||
|  |   this->write_u32_register16_(STATUS0, 0xFFFF); | ||||||
|  |   this->write_u32_register16_(STATUS1, 0xFFFF); | ||||||
|  |   this->init_device_(); | ||||||
|  |   this->store_.reset_done = false; | ||||||
|  |   this->store_.reset_pending = false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<typename F> | ||||||
|  | void ADE7880::update_sensor_from_s24zp_register16_(sensor::Sensor *sensor, uint16_t a_register, F &&f) { | ||||||
|  |   if (sensor == nullptr) { | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   float val = this->read_s24zp_register16_(a_register); | ||||||
|  |   sensor->publish_state(f(val)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<typename F> | ||||||
|  | void ADE7880::update_sensor_from_s16_register16_(sensor::Sensor *sensor, uint16_t a_register, F &&f) { | ||||||
|  |   if (sensor == nullptr) { | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   float val = this->read_s16_register16_(a_register); | ||||||
|  |   sensor->publish_state(f(val)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<typename F> | ||||||
|  | void ADE7880::update_sensor_from_s32_register16_(sensor::Sensor *sensor, uint16_t a_register, F &&f) { | ||||||
|  |   if (sensor == nullptr) { | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   float val = this->read_s32_register16_(a_register); | ||||||
|  |   sensor->publish_state(f(val)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ADE7880::update() { | ||||||
|  |   if (this->store_.reset_pending) { | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   auto start = millis(); | ||||||
|  |  | ||||||
|  |   if (this->channel_n_ != nullptr) { | ||||||
|  |     auto *chan = this->channel_n_; | ||||||
|  |     this->update_sensor_from_s24zp_register16_(chan->current, NIRMS, [](float val) { return val / 100000.0f; }); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (this->channel_a_ != nullptr) { | ||||||
|  |     auto *chan = this->channel_a_; | ||||||
|  |     this->update_sensor_from_s24zp_register16_(chan->current, AIRMS, [](float val) { return val / 100000.0f; }); | ||||||
|  |     this->update_sensor_from_s24zp_register16_(chan->voltage, BVRMS, [](float val) { return val / 10000.0f; }); | ||||||
|  |     this->update_sensor_from_s24zp_register16_(chan->active_power, AWATT, [](float val) { return val / 100.0f; }); | ||||||
|  |     this->update_sensor_from_s24zp_register16_(chan->apparent_power, AVA, [](float val) { return val / 100.0f; }); | ||||||
|  |     this->update_sensor_from_s16_register16_(chan->power_factor, APF, | ||||||
|  |                                              [](float val) { return std::abs(val / -327.68f); }); | ||||||
|  |     this->update_sensor_from_s32_register16_(chan->forward_active_energy, AFWATTHR, [&chan](float val) { | ||||||
|  |       return chan->forward_active_energy_total += val / 14400.0f; | ||||||
|  |     }); | ||||||
|  |     this->update_sensor_from_s32_register16_(chan->reverse_active_energy, AFWATTHR, [&chan](float val) { | ||||||
|  |       return chan->reverse_active_energy_total += val / 14400.0f; | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (this->channel_b_ != nullptr) { | ||||||
|  |     auto *chan = this->channel_b_; | ||||||
|  |     this->update_sensor_from_s24zp_register16_(chan->current, BIRMS, [](float val) { return val / 100000.0f; }); | ||||||
|  |     this->update_sensor_from_s24zp_register16_(chan->voltage, BVRMS, [](float val) { return val / 10000.0f; }); | ||||||
|  |     this->update_sensor_from_s24zp_register16_(chan->active_power, BWATT, [](float val) { return val / 100.0f; }); | ||||||
|  |     this->update_sensor_from_s24zp_register16_(chan->apparent_power, BVA, [](float val) { return val / 100.0f; }); | ||||||
|  |     this->update_sensor_from_s16_register16_(chan->power_factor, BPF, | ||||||
|  |                                              [](float val) { return std::abs(val / -327.68f); }); | ||||||
|  |     this->update_sensor_from_s32_register16_(chan->forward_active_energy, BFWATTHR, [&chan](float val) { | ||||||
|  |       return chan->forward_active_energy_total += val / 14400.0f; | ||||||
|  |     }); | ||||||
|  |     this->update_sensor_from_s32_register16_(chan->reverse_active_energy, BFWATTHR, [&chan](float val) { | ||||||
|  |       return chan->reverse_active_energy_total += val / 14400.0f; | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (this->channel_c_ != nullptr) { | ||||||
|  |     auto *chan = this->channel_c_; | ||||||
|  |     this->update_sensor_from_s24zp_register16_(chan->current, CIRMS, [](float val) { return val / 100000.0f; }); | ||||||
|  |     this->update_sensor_from_s24zp_register16_(chan->voltage, CVRMS, [](float val) { return val / 10000.0f; }); | ||||||
|  |     this->update_sensor_from_s24zp_register16_(chan->active_power, CWATT, [](float val) { return val / 100.0f; }); | ||||||
|  |     this->update_sensor_from_s24zp_register16_(chan->apparent_power, CVA, [](float val) { return val / 100.0f; }); | ||||||
|  |     this->update_sensor_from_s16_register16_(chan->power_factor, CPF, | ||||||
|  |                                              [](float val) { return std::abs(val / -327.68f); }); | ||||||
|  |     this->update_sensor_from_s32_register16_(chan->forward_active_energy, CFWATTHR, [&chan](float val) { | ||||||
|  |       return chan->forward_active_energy_total += val / 14400.0f; | ||||||
|  |     }); | ||||||
|  |     this->update_sensor_from_s32_register16_(chan->reverse_active_energy, CFWATTHR, [&chan](float val) { | ||||||
|  |       return chan->reverse_active_energy_total += val / 14400.0f; | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ESP_LOGD(TAG, "update took %u ms", millis() - start); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ADE7880::dump_config() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "ADE7880:"); | ||||||
|  |   LOG_PIN("  IRQ0  Pin: ", this->irq0_pin_); | ||||||
|  |   LOG_PIN("  IRQ1  Pin: ", this->irq1_pin_); | ||||||
|  |   LOG_PIN("  RESET Pin: ", this->reset_pin_); | ||||||
|  |   ESP_LOGCONFIG(TAG, "  Frequency: %.0f Hz", this->frequency_); | ||||||
|  |  | ||||||
|  |   if (this->channel_a_ != nullptr) { | ||||||
|  |     ESP_LOGCONFIG(TAG, "  Phase A:"); | ||||||
|  |     LOG_SENSOR("    ", "Current", this->channel_a_->current); | ||||||
|  |     LOG_SENSOR("    ", "Voltage", this->channel_a_->voltage); | ||||||
|  |     LOG_SENSOR("    ", "Active Power", this->channel_a_->active_power); | ||||||
|  |     LOG_SENSOR("    ", "Apparent Power", this->channel_a_->apparent_power); | ||||||
|  |     LOG_SENSOR("    ", "Power Factor", this->channel_a_->power_factor); | ||||||
|  |     LOG_SENSOR("    ", "Forward Active Energy", this->channel_a_->forward_active_energy); | ||||||
|  |     LOG_SENSOR("    ", "Reverse Active Energy", this->channel_a_->reverse_active_energy); | ||||||
|  |     ESP_LOGCONFIG(TAG, "    Calibration:"); | ||||||
|  |     ESP_LOGCONFIG(TAG, "     Current: %u", this->channel_a_->current_gain_calibration); | ||||||
|  |     ESP_LOGCONFIG(TAG, "     Voltage: %d", this->channel_a_->voltage_gain_calibration); | ||||||
|  |     ESP_LOGCONFIG(TAG, "     Power: %d", this->channel_a_->power_gain_calibration); | ||||||
|  |     ESP_LOGCONFIG(TAG, "     Phase Angle: %u", this->channel_a_->phase_angle_calibration); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (this->channel_b_ != nullptr) { | ||||||
|  |     ESP_LOGCONFIG(TAG, "  Phase B:"); | ||||||
|  |     LOG_SENSOR("    ", "Current", this->channel_b_->current); | ||||||
|  |     LOG_SENSOR("    ", "Voltage", this->channel_b_->voltage); | ||||||
|  |     LOG_SENSOR("    ", "Active Power", this->channel_b_->active_power); | ||||||
|  |     LOG_SENSOR("    ", "Apparent Power", this->channel_b_->apparent_power); | ||||||
|  |     LOG_SENSOR("    ", "Power Factor", this->channel_b_->power_factor); | ||||||
|  |     LOG_SENSOR("    ", "Forward Active Energy", this->channel_b_->forward_active_energy); | ||||||
|  |     LOG_SENSOR("    ", "Reverse Active Energy", this->channel_b_->reverse_active_energy); | ||||||
|  |     ESP_LOGCONFIG(TAG, "    Calibration:"); | ||||||
|  |     ESP_LOGCONFIG(TAG, "     Current: %u", this->channel_b_->current_gain_calibration); | ||||||
|  |     ESP_LOGCONFIG(TAG, "     Voltage: %d", this->channel_b_->voltage_gain_calibration); | ||||||
|  |     ESP_LOGCONFIG(TAG, "     Power: %d", this->channel_b_->power_gain_calibration); | ||||||
|  |     ESP_LOGCONFIG(TAG, "     Phase Angle: %u", this->channel_b_->phase_angle_calibration); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (this->channel_c_ != nullptr) { | ||||||
|  |     ESP_LOGCONFIG(TAG, "  Phase C:"); | ||||||
|  |     LOG_SENSOR("    ", "Current", this->channel_c_->current); | ||||||
|  |     LOG_SENSOR("    ", "Voltage", this->channel_c_->voltage); | ||||||
|  |     LOG_SENSOR("    ", "Active Power", this->channel_c_->active_power); | ||||||
|  |     LOG_SENSOR("    ", "Apparent Power", this->channel_c_->apparent_power); | ||||||
|  |     LOG_SENSOR("    ", "Power Factor", this->channel_c_->power_factor); | ||||||
|  |     LOG_SENSOR("    ", "Forward Active Energy", this->channel_c_->forward_active_energy); | ||||||
|  |     LOG_SENSOR("    ", "Reverse Active Energy", this->channel_c_->reverse_active_energy); | ||||||
|  |     ESP_LOGCONFIG(TAG, "    Calibration:"); | ||||||
|  |     ESP_LOGCONFIG(TAG, "     Current: %u", this->channel_c_->current_gain_calibration); | ||||||
|  |     ESP_LOGCONFIG(TAG, "     Voltage: %d", this->channel_c_->voltage_gain_calibration); | ||||||
|  |     ESP_LOGCONFIG(TAG, "     Power: %d", this->channel_c_->power_gain_calibration); | ||||||
|  |     ESP_LOGCONFIG(TAG, "     Phase Angle: %u", this->channel_c_->phase_angle_calibration); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (this->channel_n_ != nullptr) { | ||||||
|  |     ESP_LOGCONFIG(TAG, "  Neutral:"); | ||||||
|  |     LOG_SENSOR("    ", "Current", this->channel_n_->current); | ||||||
|  |     ESP_LOGCONFIG(TAG, "    Calibration:"); | ||||||
|  |     ESP_LOGCONFIG(TAG, "     Current: %u", this->channel_n_->current_gain_calibration); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   LOG_I2C_DEVICE(this); | ||||||
|  |   LOG_UPDATE_INTERVAL(this); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ADE7880::calibrate_s10zp_reading_(uint16_t a_register, int16_t calibration) { | ||||||
|  |   if (calibration == 0) { | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   this->write_s10zp_register16_(a_register, calibration); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ADE7880::calibrate_s24zpse_reading_(uint16_t a_register, int32_t calibration) { | ||||||
|  |   if (calibration == 0) { | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   this->write_s24zpse_register16_(a_register, calibration); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ADE7880::init_device_() { | ||||||
|  |   this->write_u8_register16_(CONFIG2, CONFIG2_I2C_LOCK); | ||||||
|  |  | ||||||
|  |   this->write_u16_register16_(GAIN, 0); | ||||||
|  |  | ||||||
|  |   if (this->frequency_ > 55) { | ||||||
|  |     this->write_u16_register16_(COMPMODE, COMPMODE_DEFAULT | COMPMODE_SELFREQ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (this->channel_n_ != nullptr) { | ||||||
|  |     this->calibrate_s24zpse_reading_(NIGAIN, this->channel_n_->current_gain_calibration); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (this->channel_a_ != nullptr) { | ||||||
|  |     this->calibrate_s24zpse_reading_(AIGAIN, this->channel_a_->current_gain_calibration); | ||||||
|  |     this->calibrate_s24zpse_reading_(AVGAIN, this->channel_a_->voltage_gain_calibration); | ||||||
|  |     this->calibrate_s24zpse_reading_(APGAIN, this->channel_a_->power_gain_calibration); | ||||||
|  |     this->calibrate_s10zp_reading_(APHCAL, this->channel_a_->phase_angle_calibration); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (this->channel_b_ != nullptr) { | ||||||
|  |     this->calibrate_s24zpse_reading_(BIGAIN, this->channel_b_->current_gain_calibration); | ||||||
|  |     this->calibrate_s24zpse_reading_(BVGAIN, this->channel_b_->voltage_gain_calibration); | ||||||
|  |     this->calibrate_s24zpse_reading_(BPGAIN, this->channel_b_->power_gain_calibration); | ||||||
|  |     this->calibrate_s10zp_reading_(BPHCAL, this->channel_b_->phase_angle_calibration); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (this->channel_c_ != nullptr) { | ||||||
|  |     this->calibrate_s24zpse_reading_(CIGAIN, this->channel_c_->current_gain_calibration); | ||||||
|  |     this->calibrate_s24zpse_reading_(CVGAIN, this->channel_c_->voltage_gain_calibration); | ||||||
|  |     this->calibrate_s24zpse_reading_(CPGAIN, this->channel_c_->power_gain_calibration); | ||||||
|  |     this->calibrate_s10zp_reading_(CPHCAL, this->channel_c_->phase_angle_calibration); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // write three default values to data memory RAM to flush the I2C write queue | ||||||
|  |   this->write_s32_register16_(VLEVEL, 0); | ||||||
|  |   this->write_s32_register16_(VLEVEL, 0); | ||||||
|  |   this->write_s32_register16_(VLEVEL, 0); | ||||||
|  |  | ||||||
|  |   this->write_u8_register16_(DSPWP_SEL, DSPWP_SEL_SET); | ||||||
|  |   this->write_u8_register16_(DSPWP_SET, DSPWP_SET_RO); | ||||||
|  |   this->write_u16_register16_(RUN, RUN_ENABLE); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ADE7880::reset_device_() { | ||||||
|  |   if (this->reset_pin_ != nullptr) { | ||||||
|  |     ESP_LOGD(TAG, "Reset device using RESET pin"); | ||||||
|  |     this->reset_pin_->digital_write(false); | ||||||
|  |     delay(1); | ||||||
|  |     this->reset_pin_->digital_write(true); | ||||||
|  |   } else { | ||||||
|  |     ESP_LOGD(TAG, "Reset device using SWRST command"); | ||||||
|  |     this->write_u16_register16_(CONFIG, CONFIG_SWRST); | ||||||
|  |   } | ||||||
|  |   this->store_.reset_pending = true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace ade7880 | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										131
									
								
								esphome/components/ade7880/ade7880.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								esphome/components/ade7880/ade7880.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,131 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | // This component was developed using knowledge gathered by a number | ||||||
|  | // of people who reverse-engineered the Shelly 3EM: | ||||||
|  | // | ||||||
|  | // @AndreKR on GitHub | ||||||
|  | // Axel (@Axel830 on GitHub) | ||||||
|  | // Marko (@goodkiller on GitHub) | ||||||
|  | // Michaël Piron (@michaelpiron on GitHub) | ||||||
|  | // Theo Arends (@arendst on GitHub) | ||||||
|  |  | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/core/hal.h" | ||||||
|  | #include "esphome/components/i2c/i2c.h" | ||||||
|  | #include "esphome/components/sensor/sensor.h" | ||||||
|  |  | ||||||
|  | #include "ade7880_registers.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace ade7880 { | ||||||
|  |  | ||||||
|  | struct NeutralChannel { | ||||||
|  |   void set_current(sensor::Sensor *sens) { this->current = sens; } | ||||||
|  |  | ||||||
|  |   void set_current_gain_calibration(int32_t val) { this->current_gain_calibration = val; } | ||||||
|  |  | ||||||
|  |   sensor::Sensor *current{nullptr}; | ||||||
|  |   int32_t current_gain_calibration{0}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct PowerChannel { | ||||||
|  |   void set_current(sensor::Sensor *sens) { this->current = sens; } | ||||||
|  |   void set_voltage(sensor::Sensor *sens) { this->voltage = sens; } | ||||||
|  |   void set_active_power(sensor::Sensor *sens) { this->active_power = sens; } | ||||||
|  |   void set_apparent_power(sensor::Sensor *sens) { this->apparent_power = sens; } | ||||||
|  |   void set_power_factor(sensor::Sensor *sens) { this->power_factor = sens; } | ||||||
|  |   void set_forward_active_energy(sensor::Sensor *sens) { this->forward_active_energy = sens; } | ||||||
|  |   void set_reverse_active_energy(sensor::Sensor *sens) { this->reverse_active_energy = sens; } | ||||||
|  |  | ||||||
|  |   void set_current_gain_calibration(int32_t val) { this->current_gain_calibration = val; } | ||||||
|  |   void set_voltage_gain_calibration(int32_t val) { this->voltage_gain_calibration = val; } | ||||||
|  |   void set_power_gain_calibration(int32_t val) { this->power_gain_calibration = val; } | ||||||
|  |   void set_phase_angle_calibration(int32_t val) { this->phase_angle_calibration = val; } | ||||||
|  |  | ||||||
|  |   sensor::Sensor *current{nullptr}; | ||||||
|  |   sensor::Sensor *voltage{nullptr}; | ||||||
|  |   sensor::Sensor *active_power{nullptr}; | ||||||
|  |   sensor::Sensor *apparent_power{nullptr}; | ||||||
|  |   sensor::Sensor *power_factor{nullptr}; | ||||||
|  |   sensor::Sensor *forward_active_energy{nullptr}; | ||||||
|  |   sensor::Sensor *reverse_active_energy{nullptr}; | ||||||
|  |   int32_t current_gain_calibration{0}; | ||||||
|  |   int32_t voltage_gain_calibration{0}; | ||||||
|  |   int32_t power_gain_calibration{0}; | ||||||
|  |   uint16_t phase_angle_calibration{0}; | ||||||
|  |   float forward_active_energy_total{0}; | ||||||
|  |   float reverse_active_energy_total{0}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // Store data in a class that doesn't use multiple-inheritance (no vtables in flash!) | ||||||
|  | struct ADE7880Store { | ||||||
|  |   volatile bool reset_done{false}; | ||||||
|  |   bool reset_pending{false}; | ||||||
|  |   ISRInternalGPIOPin irq1_pin; | ||||||
|  |  | ||||||
|  |   static void gpio_intr(ADE7880Store *arg); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class ADE7880 : public i2c::I2CDevice, public PollingComponent { | ||||||
|  |  public: | ||||||
|  |   void set_irq0_pin(InternalGPIOPin *pin) { this->irq0_pin_ = pin; } | ||||||
|  |   void set_irq1_pin(InternalGPIOPin *pin) { this->irq1_pin_ = pin; } | ||||||
|  |   void set_reset_pin(InternalGPIOPin *pin) { this->reset_pin_ = pin; } | ||||||
|  |   void set_frequency(float frequency) { this->frequency_ = frequency; } | ||||||
|  |   void set_channel_n(NeutralChannel *channel) { this->channel_n_ = channel; } | ||||||
|  |   void set_channel_a(PowerChannel *channel) { this->channel_a_ = channel; } | ||||||
|  |   void set_channel_b(PowerChannel *channel) { this->channel_b_ = channel; } | ||||||
|  |   void set_channel_c(PowerChannel *channel) { this->channel_c_ = channel; } | ||||||
|  |  | ||||||
|  |   void setup() override; | ||||||
|  |  | ||||||
|  |   void loop() override; | ||||||
|  |  | ||||||
|  |   void update() override; | ||||||
|  |  | ||||||
|  |   void dump_config() override; | ||||||
|  |  | ||||||
|  |   float get_setup_priority() const override { return setup_priority::DATA; } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   ADE7880Store store_{}; | ||||||
|  |   InternalGPIOPin *irq0_pin_{nullptr}; | ||||||
|  |   InternalGPIOPin *irq1_pin_{nullptr}; | ||||||
|  |   InternalGPIOPin *reset_pin_{nullptr}; | ||||||
|  |   float frequency_; | ||||||
|  |   NeutralChannel *channel_n_{nullptr}; | ||||||
|  |   PowerChannel *channel_a_{nullptr}; | ||||||
|  |   PowerChannel *channel_b_{nullptr}; | ||||||
|  |   PowerChannel *channel_c_{nullptr}; | ||||||
|  |  | ||||||
|  |   void calibrate_s10zp_reading_(uint16_t a_register, int16_t calibration); | ||||||
|  |   void calibrate_s24zpse_reading_(uint16_t a_register, int32_t calibration); | ||||||
|  |  | ||||||
|  |   void init_device_(); | ||||||
|  |  | ||||||
|  |   // each of these functions allow the caller to pass in a lambda (or any other callable) | ||||||
|  |   // which modifies the value read from the register before it is passed to the sensor | ||||||
|  |   // the callable will be passed a 'float' value and is expected to return a 'float' | ||||||
|  |   template<typename F> void update_sensor_from_s24zp_register16_(sensor::Sensor *sensor, uint16_t a_register, F &&f); | ||||||
|  |   template<typename F> void update_sensor_from_s16_register16_(sensor::Sensor *sensor, uint16_t a_register, F &&f); | ||||||
|  |   template<typename F> void update_sensor_from_s32_register16_(sensor::Sensor *sensor, uint16_t a_register, F &&f); | ||||||
|  |  | ||||||
|  |   void reset_device_(); | ||||||
|  |  | ||||||
|  |   uint8_t read_u8_register16_(uint16_t a_register); | ||||||
|  |   int16_t read_s16_register16_(uint16_t a_register); | ||||||
|  |   uint16_t read_u16_register16_(uint16_t a_register); | ||||||
|  |   int32_t read_s24zp_register16_(uint16_t a_register); | ||||||
|  |   int32_t read_s32_register16_(uint16_t a_register); | ||||||
|  |   uint32_t read_u32_register16_(uint16_t a_register); | ||||||
|  |  | ||||||
|  |   void write_u8_register16_(uint16_t a_register, uint8_t value); | ||||||
|  |   void write_s10zp_register16_(uint16_t a_register, int16_t value); | ||||||
|  |   void write_u16_register16_(uint16_t a_register, uint16_t value); | ||||||
|  |   void write_s24zpse_register16_(uint16_t a_register, int32_t value); | ||||||
|  |   void write_s32_register16_(uint16_t a_register, int32_t value); | ||||||
|  |   void write_u32_register16_(uint16_t a_register, uint32_t value); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace ade7880 | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										101
									
								
								esphome/components/ade7880/ade7880_i2c.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								esphome/components/ade7880/ade7880_i2c.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | |||||||
|  | // This component was developed using knowledge gathered by a number | ||||||
|  | // of people who reverse-engineered the Shelly 3EM: | ||||||
|  | // | ||||||
|  | // @AndreKR on GitHub | ||||||
|  | // Axel (@Axel830 on GitHub) | ||||||
|  | // Marko (@goodkiller on GitHub) | ||||||
|  | // Michaël Piron (@michaelpiron on GitHub) | ||||||
|  | // Theo Arends (@arendst on GitHub) | ||||||
|  |  | ||||||
|  | #include "ade7880.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace ade7880 { | ||||||
|  |  | ||||||
|  | // adapted from https://stackoverflow.com/a/55912127/1886371 | ||||||
|  | template<size_t Bits, typename T> inline T sign_extend(const T &v) noexcept { | ||||||
|  |   using S = struct { signed Val : Bits; }; | ||||||
|  |   return reinterpret_cast<const S *>(&v)->Val; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Register types | ||||||
|  | // unsigned 8-bit (uint8_t) | ||||||
|  | // signed 10-bit - 16-bit ZP on wire (int16_t, needs sign extension) | ||||||
|  | // unsigned 16-bit (uint16_t) | ||||||
|  | // unsigned 20-bit - 32-bit ZP on wire (uint32_t) | ||||||
|  | // signed 24-bit - 32-bit ZPSE on wire (int32_t, needs sign extension) | ||||||
|  | // signed 24-bit - 32-bit ZP on wire (int32_t, needs sign extension) | ||||||
|  | // signed 24-bit - 32-bit SE on wire (int32_t) | ||||||
|  | // signed 28-bit - 32-bit ZP on wire (int32_t, needs sign extension) | ||||||
|  | // unsigned 32-bit (uint32_t) | ||||||
|  | // signed 32-bit (int32_t) | ||||||
|  |  | ||||||
|  | uint8_t ADE7880::read_u8_register16_(uint16_t a_register) { | ||||||
|  |   uint8_t in; | ||||||
|  |   this->read_register16(a_register, &in, sizeof(in)); | ||||||
|  |   return in; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int16_t ADE7880::read_s16_register16_(uint16_t a_register) { | ||||||
|  |   int16_t in; | ||||||
|  |   this->read_register16(a_register, reinterpret_cast<uint8_t *>(&in), sizeof(in)); | ||||||
|  |   return convert_big_endian(in); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint16_t ADE7880::read_u16_register16_(uint16_t a_register) { | ||||||
|  |   uint16_t in; | ||||||
|  |   this->read_register16(a_register, reinterpret_cast<uint8_t *>(&in), sizeof(in)); | ||||||
|  |   return convert_big_endian(in); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int32_t ADE7880::read_s24zp_register16_(uint16_t a_register) { | ||||||
|  |   // s24zp means 24 bit signed value in the lower 24 bits of a 32-bit register | ||||||
|  |   int32_t in; | ||||||
|  |   this->read_register16(a_register, reinterpret_cast<uint8_t *>(&in), sizeof(in)); | ||||||
|  |   return sign_extend<24>(convert_big_endian(in)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int32_t ADE7880::read_s32_register16_(uint16_t a_register) { | ||||||
|  |   int32_t in; | ||||||
|  |   this->read_register16(a_register, reinterpret_cast<uint8_t *>(&in), sizeof(in)); | ||||||
|  |   return convert_big_endian(in); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint32_t ADE7880::read_u32_register16_(uint16_t a_register) { | ||||||
|  |   uint32_t in; | ||||||
|  |   this->read_register16(a_register, reinterpret_cast<uint8_t *>(&in), sizeof(in)); | ||||||
|  |   return convert_big_endian(in); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ADE7880::write_u8_register16_(uint16_t a_register, uint8_t value) { | ||||||
|  |   this->write_register16(a_register, &value, sizeof(value)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ADE7880::write_s10zp_register16_(uint16_t a_register, int16_t value) { | ||||||
|  |   int16_t out = convert_big_endian(value & 0x03FF); | ||||||
|  |   this->write_register16(a_register, reinterpret_cast<uint8_t *>(&out), sizeof(out)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ADE7880::write_u16_register16_(uint16_t a_register, uint16_t value) { | ||||||
|  |   uint16_t out = convert_big_endian(value); | ||||||
|  |   this->write_register16(a_register, reinterpret_cast<uint8_t *>(&out), sizeof(out)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ADE7880::write_s24zpse_register16_(uint16_t a_register, int32_t value) { | ||||||
|  |   // s24zpse means a 24-bit signed value, sign-extended to 28 bits, in the lower 28 bits of a 32-bit register | ||||||
|  |   int32_t out = convert_big_endian(value & 0x0FFFFFFF); | ||||||
|  |   this->write_register16(a_register, reinterpret_cast<uint8_t *>(&out), sizeof(out)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ADE7880::write_s32_register16_(uint16_t a_register, int32_t value) { | ||||||
|  |   int32_t out = convert_big_endian(value); | ||||||
|  |   this->write_register16(a_register, reinterpret_cast<uint8_t *>(&out), sizeof(out)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ADE7880::write_u32_register16_(uint16_t a_register, uint32_t value) { | ||||||
|  |   uint32_t out = convert_big_endian(value); | ||||||
|  |   this->write_register16(a_register, reinterpret_cast<uint8_t *>(&out), sizeof(out)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace ade7880 | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										243
									
								
								esphome/components/ade7880/ade7880_registers.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										243
									
								
								esphome/components/ade7880/ade7880_registers.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,243 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | // This file is a modified version of the one created by Michaël Piron (@michaelpiron on GitHub) | ||||||
|  |  | ||||||
|  | // Source: https://www.analog.com/media/en/technical-documentation/application-notes/AN-1127.pdf | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace ade7880 { | ||||||
|  |  | ||||||
|  | // DSP Data Memory RAM registers | ||||||
|  | constexpr uint16_t AIGAIN = 0x4380; | ||||||
|  | constexpr uint16_t AVGAIN = 0x4381; | ||||||
|  | constexpr uint16_t BIGAIN = 0x4382; | ||||||
|  | constexpr uint16_t BVGAIN = 0x4383; | ||||||
|  | constexpr uint16_t CIGAIN = 0x4384; | ||||||
|  | constexpr uint16_t CVGAIN = 0x4385; | ||||||
|  | constexpr uint16_t NIGAIN = 0x4386; | ||||||
|  |  | ||||||
|  | constexpr uint16_t DICOEFF = 0x4388; | ||||||
|  |  | ||||||
|  | constexpr uint16_t APGAIN = 0x4389; | ||||||
|  | constexpr uint16_t AWATTOS = 0x438A; | ||||||
|  | constexpr uint16_t BPGAIN = 0x438B; | ||||||
|  | constexpr uint16_t BWATTOS = 0x438C; | ||||||
|  | constexpr uint16_t CPGAIN = 0x438D; | ||||||
|  | constexpr uint16_t CWATTOS = 0x438E; | ||||||
|  | constexpr uint16_t AIRMSOS = 0x438F; | ||||||
|  | constexpr uint16_t AVRMSOS = 0x4390; | ||||||
|  | constexpr uint16_t BIRMSOS = 0x4391; | ||||||
|  | constexpr uint16_t BVRMSOS = 0x4392; | ||||||
|  | constexpr uint16_t CIRMSOS = 0x4393; | ||||||
|  | constexpr uint16_t CVRMSOS = 0x4394; | ||||||
|  | constexpr uint16_t NIRMSOS = 0x4395; | ||||||
|  | constexpr uint16_t HPGAIN = 0x4398; | ||||||
|  | constexpr uint16_t ISUMLVL = 0x4399; | ||||||
|  |  | ||||||
|  | constexpr uint16_t VLEVEL = 0x439F; | ||||||
|  |  | ||||||
|  | constexpr uint16_t AFWATTOS = 0x43A2; | ||||||
|  | constexpr uint16_t BFWATTOS = 0x43A3; | ||||||
|  | constexpr uint16_t CFWATTOS = 0x43A4; | ||||||
|  |  | ||||||
|  | constexpr uint16_t AFVAROS = 0x43A5; | ||||||
|  | constexpr uint16_t BFVAROS = 0x43A6; | ||||||
|  | constexpr uint16_t CFVAROS = 0x43A7; | ||||||
|  |  | ||||||
|  | constexpr uint16_t AFIRMSOS = 0x43A8; | ||||||
|  | constexpr uint16_t BFIRMSOS = 0x43A9; | ||||||
|  | constexpr uint16_t CFIRMSOS = 0x43AA; | ||||||
|  |  | ||||||
|  | constexpr uint16_t AFVRMSOS = 0x43AB; | ||||||
|  | constexpr uint16_t BFVRMSOS = 0x43AC; | ||||||
|  | constexpr uint16_t CFVRMSOS = 0x43AD; | ||||||
|  |  | ||||||
|  | constexpr uint16_t HXWATTOS = 0x43AE; | ||||||
|  | constexpr uint16_t HYWATTOS = 0x43AF; | ||||||
|  | constexpr uint16_t HZWATTOS = 0x43B0; | ||||||
|  | constexpr uint16_t HXVAROS = 0x43B1; | ||||||
|  | constexpr uint16_t HYVAROS = 0x43B2; | ||||||
|  | constexpr uint16_t HZVAROS = 0x43B3; | ||||||
|  |  | ||||||
|  | constexpr uint16_t HXIRMSOS = 0x43B4; | ||||||
|  | constexpr uint16_t HYIRMSOS = 0x43B5; | ||||||
|  | constexpr uint16_t HZIRMSOS = 0x43B6; | ||||||
|  | constexpr uint16_t HXVRMSOS = 0x43B7; | ||||||
|  | constexpr uint16_t HYVRMSOS = 0x43B8; | ||||||
|  | constexpr uint16_t HZVRMSOS = 0x43B9; | ||||||
|  |  | ||||||
|  | constexpr uint16_t AIRMS = 0x43C0; | ||||||
|  | constexpr uint16_t AVRMS = 0x43C1; | ||||||
|  | constexpr uint16_t BIRMS = 0x43C2; | ||||||
|  | constexpr uint16_t BVRMS = 0x43C3; | ||||||
|  | constexpr uint16_t CIRMS = 0x43C4; | ||||||
|  | constexpr uint16_t CVRMS = 0x43C5; | ||||||
|  | constexpr uint16_t NIRMS = 0x43C6; | ||||||
|  |  | ||||||
|  | constexpr uint16_t ISUM = 0x43C7; | ||||||
|  |  | ||||||
|  | // Internal DSP Memory RAM registers | ||||||
|  | constexpr uint16_t RUN = 0xE228; | ||||||
|  |  | ||||||
|  | constexpr uint16_t AWATTHR = 0xE400; | ||||||
|  | constexpr uint16_t BWATTHR = 0xE401; | ||||||
|  | constexpr uint16_t CWATTHR = 0xE402; | ||||||
|  | constexpr uint16_t AFWATTHR = 0xE403; | ||||||
|  | constexpr uint16_t BFWATTHR = 0xE404; | ||||||
|  | constexpr uint16_t CFWATTHR = 0xE405; | ||||||
|  | constexpr uint16_t AFVARHR = 0xE409; | ||||||
|  | constexpr uint16_t BFVARHR = 0xE40A; | ||||||
|  | constexpr uint16_t CFVARHR = 0xE40B; | ||||||
|  |  | ||||||
|  | constexpr uint16_t AVAHR = 0xE40C; | ||||||
|  | constexpr uint16_t BVAHR = 0xE40D; | ||||||
|  | constexpr uint16_t CVAHR = 0xE40E; | ||||||
|  |  | ||||||
|  | constexpr uint16_t IPEAK = 0xE500; | ||||||
|  | constexpr uint16_t VPEAK = 0xE501; | ||||||
|  |  | ||||||
|  | constexpr uint16_t STATUS0 = 0xE502; | ||||||
|  | constexpr uint16_t STATUS1 = 0xE503; | ||||||
|  |  | ||||||
|  | constexpr uint16_t AIMAV = 0xE504; | ||||||
|  | constexpr uint16_t BIMAV = 0xE505; | ||||||
|  | constexpr uint16_t CIMAV = 0xE506; | ||||||
|  |  | ||||||
|  | constexpr uint16_t OILVL = 0xE507; | ||||||
|  | constexpr uint16_t OVLVL = 0xE508; | ||||||
|  | constexpr uint16_t SAGLVL = 0xE509; | ||||||
|  | constexpr uint16_t MASK0 = 0xE50A; | ||||||
|  | constexpr uint16_t MASK1 = 0xE50B; | ||||||
|  |  | ||||||
|  | constexpr uint16_t IAWV = 0xE50C; | ||||||
|  | constexpr uint16_t IBWV = 0xE50D; | ||||||
|  | constexpr uint16_t ICWV = 0xE50E; | ||||||
|  | constexpr uint16_t INWV = 0xE50F; | ||||||
|  | constexpr uint16_t VAWV = 0xE510; | ||||||
|  | constexpr uint16_t VBWV = 0xE511; | ||||||
|  | constexpr uint16_t VCWV = 0xE512; | ||||||
|  |  | ||||||
|  | constexpr uint16_t AWATT = 0xE513; | ||||||
|  | constexpr uint16_t BWATT = 0xE514; | ||||||
|  | constexpr uint16_t CWATT = 0xE515; | ||||||
|  |  | ||||||
|  | constexpr uint16_t AFVAR = 0xE516; | ||||||
|  | constexpr uint16_t BFVAR = 0xE517; | ||||||
|  | constexpr uint16_t CFVAR = 0xE518; | ||||||
|  |  | ||||||
|  | constexpr uint16_t AVA = 0xE519; | ||||||
|  | constexpr uint16_t BVA = 0xE51A; | ||||||
|  | constexpr uint16_t CVA = 0xE51B; | ||||||
|  |  | ||||||
|  | constexpr uint16_t CHECKSUM = 0xE51F; | ||||||
|  | constexpr uint16_t VNOM = 0xE520; | ||||||
|  | constexpr uint16_t LAST_RWDATA_24BIT = 0xE5FF; | ||||||
|  | constexpr uint16_t PHSTATUS = 0xE600; | ||||||
|  | constexpr uint16_t ANGLE0 = 0xE601; | ||||||
|  | constexpr uint16_t ANGLE1 = 0xE602; | ||||||
|  | constexpr uint16_t ANGLE2 = 0xE603; | ||||||
|  | constexpr uint16_t PHNOLOAD = 0xE608; | ||||||
|  | constexpr uint16_t LINECYC = 0xE60C; | ||||||
|  | constexpr uint16_t ZXTOUT = 0xE60D; | ||||||
|  | constexpr uint16_t COMPMODE = 0xE60E; | ||||||
|  | constexpr uint16_t GAIN = 0xE60F; | ||||||
|  | constexpr uint16_t CFMODE = 0xE610; | ||||||
|  | constexpr uint16_t CF1DEN = 0xE611; | ||||||
|  | constexpr uint16_t CF2DEN = 0xE612; | ||||||
|  | constexpr uint16_t CF3DEN = 0xE613; | ||||||
|  | constexpr uint16_t APHCAL = 0xE614; | ||||||
|  | constexpr uint16_t BPHCAL = 0xE615; | ||||||
|  | constexpr uint16_t CPHCAL = 0xE616; | ||||||
|  | constexpr uint16_t PHSIGN = 0xE617; | ||||||
|  | constexpr uint16_t CONFIG = 0xE618; | ||||||
|  | constexpr uint16_t MMODE = 0xE700; | ||||||
|  | constexpr uint16_t ACCMODE = 0xE701; | ||||||
|  | constexpr uint16_t LCYCMODE = 0xE702; | ||||||
|  | constexpr uint16_t PEAKCYC = 0xE703; | ||||||
|  | constexpr uint16_t SAGCYC = 0xE704; | ||||||
|  | constexpr uint16_t CFCYC = 0xE705; | ||||||
|  | constexpr uint16_t HSDC_CFG = 0xE706; | ||||||
|  | constexpr uint16_t VERSION = 0xE707; | ||||||
|  | constexpr uint16_t DSPWP_SET = 0xE7E3; | ||||||
|  | constexpr uint16_t LAST_RWDATA_8BIT = 0xE7FD; | ||||||
|  | constexpr uint16_t DSPWP_SEL = 0xE7FE; | ||||||
|  | constexpr uint16_t FVRMS = 0xE880; | ||||||
|  | constexpr uint16_t FIRMS = 0xE881; | ||||||
|  | constexpr uint16_t FWATT = 0xE882; | ||||||
|  | constexpr uint16_t FVAR = 0xE883; | ||||||
|  | constexpr uint16_t FVA = 0xE884; | ||||||
|  | constexpr uint16_t FPF = 0xE885; | ||||||
|  | constexpr uint16_t VTHDN = 0xE886; | ||||||
|  | constexpr uint16_t ITHDN = 0xE887; | ||||||
|  | constexpr uint16_t HXVRMS = 0xE888; | ||||||
|  | constexpr uint16_t HXIRMS = 0xE889; | ||||||
|  | constexpr uint16_t HXWATT = 0xE88A; | ||||||
|  | constexpr uint16_t HXVAR = 0xE88B; | ||||||
|  | constexpr uint16_t HXVA = 0xE88C; | ||||||
|  | constexpr uint16_t HXPF = 0xE88D; | ||||||
|  | constexpr uint16_t HXVHD = 0xE88E; | ||||||
|  | constexpr uint16_t HXIHD = 0xE88F; | ||||||
|  | constexpr uint16_t HYVRMS = 0xE890; | ||||||
|  | constexpr uint16_t HYIRMS = 0xE891; | ||||||
|  | constexpr uint16_t HYWATT = 0xE892; | ||||||
|  | constexpr uint16_t HYVAR = 0xE893; | ||||||
|  | constexpr uint16_t HYVA = 0xE894; | ||||||
|  | constexpr uint16_t HYPF = 0xE895; | ||||||
|  | constexpr uint16_t HYVHD = 0xE896; | ||||||
|  | constexpr uint16_t HYIHD = 0xE897; | ||||||
|  | constexpr uint16_t HZVRMS = 0xE898; | ||||||
|  | constexpr uint16_t HZIRMS = 0xE899; | ||||||
|  | constexpr uint16_t HZWATT = 0xE89A; | ||||||
|  | constexpr uint16_t HZVAR = 0xE89B; | ||||||
|  | constexpr uint16_t HZVA = 0xE89C; | ||||||
|  | constexpr uint16_t HZPF = 0xE89D; | ||||||
|  | constexpr uint16_t HZVHD = 0xE89E; | ||||||
|  | constexpr uint16_t HZIHD = 0xE89F; | ||||||
|  | constexpr uint16_t HCONFIG = 0xE900; | ||||||
|  | constexpr uint16_t APF = 0xE902; | ||||||
|  | constexpr uint16_t BPF = 0xE903; | ||||||
|  | constexpr uint16_t CPF = 0xE904; | ||||||
|  | constexpr uint16_t APERIOD = 0xE905; | ||||||
|  | constexpr uint16_t BPERIOD = 0xE906; | ||||||
|  | constexpr uint16_t CPERIOD = 0xE907; | ||||||
|  | constexpr uint16_t APNOLOAD = 0xE908; | ||||||
|  | constexpr uint16_t VARNOLOAD = 0xE909; | ||||||
|  | constexpr uint16_t VANOLOAD = 0xE90A; | ||||||
|  | constexpr uint16_t LAST_ADD = 0xE9FE; | ||||||
|  | constexpr uint16_t LAST_RWDATA_16BIT = 0xE9FF; | ||||||
|  | constexpr uint16_t CONFIG3 = 0xEA00; | ||||||
|  | constexpr uint16_t LAST_OP = 0xEA01; | ||||||
|  | constexpr uint16_t WTHR = 0xEA02; | ||||||
|  | constexpr uint16_t VARTHR = 0xEA03; | ||||||
|  | constexpr uint16_t VATHR = 0xEA04; | ||||||
|  |  | ||||||
|  | constexpr uint16_t HX_REG = 0xEA08; | ||||||
|  | constexpr uint16_t HY_REG = 0xEA09; | ||||||
|  | constexpr uint16_t HZ_REG = 0xEA0A; | ||||||
|  | constexpr uint16_t LPOILVL = 0xEC00; | ||||||
|  | constexpr uint16_t CONFIG2 = 0xEC01; | ||||||
|  |  | ||||||
|  | // STATUS1 Register Bits | ||||||
|  | constexpr uint32_t STATUS1_RSTDONE = (1 << 15); | ||||||
|  |  | ||||||
|  | // CONFIG Register Bits | ||||||
|  | constexpr uint16_t CONFIG_SWRST = (1 << 7); | ||||||
|  |  | ||||||
|  | // CONFIG2 Register Bits | ||||||
|  | constexpr uint8_t CONFIG2_I2C_LOCK = (1 << 1); | ||||||
|  |  | ||||||
|  | // COMPMODE Register Bits | ||||||
|  | constexpr uint16_t COMPMODE_DEFAULT = 0x01FF; | ||||||
|  | constexpr uint16_t COMPMODE_SELFREQ = (1 << 14); | ||||||
|  |  | ||||||
|  | // RUN Register Bits | ||||||
|  | constexpr uint16_t RUN_ENABLE = (1 << 0); | ||||||
|  |  | ||||||
|  | // DSPWP_SET Register Bits | ||||||
|  | constexpr uint8_t DSPWP_SET_RO = (1 << 7); | ||||||
|  |  | ||||||
|  | // DSPWP_SEL Register Bits | ||||||
|  | constexpr uint8_t DSPWP_SEL_SET = 0xAD; | ||||||
|  |  | ||||||
|  | }  // namespace ade7880 | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										290
									
								
								esphome/components/ade7880/sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										290
									
								
								esphome/components/ade7880/sensor.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,290 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.components import sensor, i2c | ||||||
|  | from esphome import pins | ||||||
|  | from esphome.const import ( | ||||||
|  |     CONF_ACTIVE_POWER, | ||||||
|  |     CONF_APPARENT_POWER, | ||||||
|  |     CONF_CALIBRATION, | ||||||
|  |     CONF_CURRENT, | ||||||
|  |     CONF_FORWARD_ACTIVE_ENERGY, | ||||||
|  |     CONF_FREQUENCY, | ||||||
|  |     CONF_ID, | ||||||
|  |     CONF_NAME, | ||||||
|  |     CONF_PHASE_A, | ||||||
|  |     CONF_PHASE_ANGLE, | ||||||
|  |     CONF_PHASE_B, | ||||||
|  |     CONF_PHASE_C, | ||||||
|  |     CONF_POWER_FACTOR, | ||||||
|  |     CONF_RESET_PIN, | ||||||
|  |     CONF_REVERSE_ACTIVE_ENERGY, | ||||||
|  |     CONF_VOLTAGE, | ||||||
|  |     DEVICE_CLASS_APPARENT_POWER, | ||||||
|  |     DEVICE_CLASS_CURRENT, | ||||||
|  |     DEVICE_CLASS_ENERGY, | ||||||
|  |     DEVICE_CLASS_POWER, | ||||||
|  |     DEVICE_CLASS_POWER_FACTOR, | ||||||
|  |     DEVICE_CLASS_VOLTAGE, | ||||||
|  |     STATE_CLASS_MEASUREMENT, | ||||||
|  |     STATE_CLASS_TOTAL_INCREASING, | ||||||
|  |     UNIT_AMPERE, | ||||||
|  |     UNIT_PERCENT, | ||||||
|  |     UNIT_VOLT, | ||||||
|  |     UNIT_VOLT_AMPS, | ||||||
|  |     UNIT_VOLT_AMPS_REACTIVE_HOURS, | ||||||
|  |     UNIT_WATT, | ||||||
|  |     UNIT_WATT_HOURS, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | DEPENDENCIES = ["i2c"] | ||||||
|  |  | ||||||
|  | ade7880_ns = cg.esphome_ns.namespace("ade7880") | ||||||
|  | ADE7880 = ade7880_ns.class_("ADE7880", cg.PollingComponent, i2c.I2CDevice) | ||||||
|  | NeutralChannel = ade7880_ns.struct("NeutralChannel") | ||||||
|  | PowerChannel = ade7880_ns.struct("PowerChannel") | ||||||
|  |  | ||||||
|  | CONF_CURRENT_GAIN = "current_gain" | ||||||
|  | CONF_IRQ0_PIN = "irq0_pin" | ||||||
|  | CONF_IRQ1_PIN = "irq1_pin" | ||||||
|  | CONF_POWER_GAIN = "power_gain" | ||||||
|  | CONF_VOLTAGE_GAIN = "voltage_gain" | ||||||
|  |  | ||||||
|  | CONF_NEUTRAL = "neutral" | ||||||
|  |  | ||||||
|  | NEUTRAL_CHANNEL_SCHEMA = cv.Schema( | ||||||
|  |     { | ||||||
|  |         cv.GenerateID(): cv.declare_id(NeutralChannel), | ||||||
|  |         cv.Optional(CONF_NAME): cv.string_strict, | ||||||
|  |         cv.Required(CONF_CURRENT): cv.maybe_simple_value( | ||||||
|  |             sensor.sensor_schema( | ||||||
|  |                 unit_of_measurement=UNIT_AMPERE, | ||||||
|  |                 accuracy_decimals=2, | ||||||
|  |                 device_class=DEVICE_CLASS_CURRENT, | ||||||
|  |                 state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             ), | ||||||
|  |             key=CONF_NAME, | ||||||
|  |         ), | ||||||
|  |         cv.Required(CONF_CALIBRATION): cv.Schema( | ||||||
|  |             { | ||||||
|  |                 cv.Required(CONF_CURRENT_GAIN): cv.int_, | ||||||
|  |             }, | ||||||
|  |         ), | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | POWER_CHANNEL_SCHEMA = cv.Schema( | ||||||
|  |     { | ||||||
|  |         cv.GenerateID(): cv.declare_id(PowerChannel), | ||||||
|  |         cv.Optional(CONF_NAME): cv.string_strict, | ||||||
|  |         cv.Optional(CONF_VOLTAGE): cv.maybe_simple_value( | ||||||
|  |             sensor.sensor_schema( | ||||||
|  |                 unit_of_measurement=UNIT_VOLT, | ||||||
|  |                 accuracy_decimals=1, | ||||||
|  |                 device_class=DEVICE_CLASS_VOLTAGE, | ||||||
|  |                 state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             ), | ||||||
|  |             key=CONF_NAME, | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_CURRENT): cv.maybe_simple_value( | ||||||
|  |             sensor.sensor_schema( | ||||||
|  |                 unit_of_measurement=UNIT_AMPERE, | ||||||
|  |                 accuracy_decimals=2, | ||||||
|  |                 device_class=DEVICE_CLASS_CURRENT, | ||||||
|  |                 state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             ), | ||||||
|  |             key=CONF_NAME, | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_ACTIVE_POWER): cv.maybe_simple_value( | ||||||
|  |             sensor.sensor_schema( | ||||||
|  |                 unit_of_measurement=UNIT_WATT, | ||||||
|  |                 accuracy_decimals=1, | ||||||
|  |                 device_class=DEVICE_CLASS_POWER, | ||||||
|  |                 state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             ), | ||||||
|  |             key=CONF_NAME, | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_APPARENT_POWER): cv.maybe_simple_value( | ||||||
|  |             sensor.sensor_schema( | ||||||
|  |                 unit_of_measurement=UNIT_VOLT_AMPS, | ||||||
|  |                 accuracy_decimals=1, | ||||||
|  |                 device_class=DEVICE_CLASS_APPARENT_POWER, | ||||||
|  |                 state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             ), | ||||||
|  |             key=CONF_NAME, | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_POWER_FACTOR): cv.maybe_simple_value( | ||||||
|  |             sensor.sensor_schema( | ||||||
|  |                 unit_of_measurement=UNIT_PERCENT, | ||||||
|  |                 accuracy_decimals=0, | ||||||
|  |                 device_class=DEVICE_CLASS_POWER_FACTOR, | ||||||
|  |                 state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             ), | ||||||
|  |             key=CONF_NAME, | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_FORWARD_ACTIVE_ENERGY): cv.maybe_simple_value( | ||||||
|  |             sensor.sensor_schema( | ||||||
|  |                 unit_of_measurement=UNIT_WATT_HOURS, | ||||||
|  |                 accuracy_decimals=2, | ||||||
|  |                 device_class=DEVICE_CLASS_ENERGY, | ||||||
|  |                 state_class=STATE_CLASS_TOTAL_INCREASING, | ||||||
|  |             ), | ||||||
|  |             key=CONF_NAME, | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_REVERSE_ACTIVE_ENERGY): cv.maybe_simple_value( | ||||||
|  |             sensor.sensor_schema( | ||||||
|  |                 unit_of_measurement=UNIT_VOLT_AMPS_REACTIVE_HOURS, | ||||||
|  |                 accuracy_decimals=2, | ||||||
|  |                 device_class=DEVICE_CLASS_ENERGY, | ||||||
|  |                 state_class=STATE_CLASS_TOTAL_INCREASING, | ||||||
|  |             ), | ||||||
|  |             key=CONF_NAME, | ||||||
|  |         ), | ||||||
|  |         cv.Required(CONF_CALIBRATION): cv.Schema( | ||||||
|  |             { | ||||||
|  |                 cv.Required(CONF_CURRENT_GAIN): cv.int_, | ||||||
|  |                 cv.Required(CONF_VOLTAGE_GAIN): cv.int_, | ||||||
|  |                 cv.Required(CONF_POWER_GAIN): cv.int_, | ||||||
|  |                 cv.Required(CONF_PHASE_ANGLE): cv.int_, | ||||||
|  |             }, | ||||||
|  |         ), | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = ( | ||||||
|  |     cv.Schema( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(): cv.declare_id(ADE7880), | ||||||
|  |             cv.Optional(CONF_FREQUENCY, default="50Hz"): cv.All( | ||||||
|  |                 cv.frequency, cv.Range(min=45.0, max=66.0) | ||||||
|  |             ), | ||||||
|  |             cv.Optional(CONF_IRQ0_PIN): pins.internal_gpio_input_pin_schema, | ||||||
|  |             cv.Required(CONF_IRQ1_PIN): pins.internal_gpio_input_pin_schema, | ||||||
|  |             cv.Optional(CONF_RESET_PIN): pins.internal_gpio_output_pin_schema, | ||||||
|  |             cv.Optional(CONF_PHASE_A): POWER_CHANNEL_SCHEMA, | ||||||
|  |             cv.Optional(CONF_PHASE_B): POWER_CHANNEL_SCHEMA, | ||||||
|  |             cv.Optional(CONF_PHASE_C): POWER_CHANNEL_SCHEMA, | ||||||
|  |             cv.Optional(CONF_NEUTRAL): NEUTRAL_CHANNEL_SCHEMA, | ||||||
|  |         } | ||||||
|  |     ) | ||||||
|  |     .extend(cv.polling_component_schema("60s")) | ||||||
|  |     .extend(i2c.i2c_device_schema(0x38)) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def neutral_channel(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |  | ||||||
|  |     current = config[CONF_CURRENT] | ||||||
|  |     sens = await sensor.new_sensor(current) | ||||||
|  |     cg.add(var.set_current(sens)) | ||||||
|  |  | ||||||
|  |     cg.add( | ||||||
|  |         var.set_current_gain_calibration(config[CONF_CALIBRATION][CONF_CURRENT_GAIN]) | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     return var | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def power_channel(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |  | ||||||
|  |     for sensor_type in [ | ||||||
|  |         CONF_CURRENT, | ||||||
|  |         CONF_VOLTAGE, | ||||||
|  |         CONF_ACTIVE_POWER, | ||||||
|  |         CONF_APPARENT_POWER, | ||||||
|  |         CONF_POWER_FACTOR, | ||||||
|  |         CONF_FORWARD_ACTIVE_ENERGY, | ||||||
|  |         CONF_REVERSE_ACTIVE_ENERGY, | ||||||
|  |     ]: | ||||||
|  |         if conf := config.get(sensor_type): | ||||||
|  |             sens = await sensor.new_sensor(conf) | ||||||
|  |             cg.add(getattr(var, f"set_{sensor_type}")(sens)) | ||||||
|  |  | ||||||
|  |     for calib_type in [ | ||||||
|  |         CONF_CURRENT_GAIN, | ||||||
|  |         CONF_VOLTAGE_GAIN, | ||||||
|  |         CONF_POWER_GAIN, | ||||||
|  |         CONF_PHASE_ANGLE, | ||||||
|  |     ]: | ||||||
|  |         cg.add( | ||||||
|  |             getattr(var, f"set_{calib_type}_calibration")( | ||||||
|  |                 config[CONF_CALIBRATION][calib_type] | ||||||
|  |             ) | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |     return var | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def final_validate(config): | ||||||
|  |     for channel in [CONF_PHASE_A, CONF_PHASE_B, CONF_PHASE_C]: | ||||||
|  |         if channel := config.get(channel): | ||||||
|  |             channel_name = channel.get(CONF_NAME) | ||||||
|  |  | ||||||
|  |             for sensor_type in [ | ||||||
|  |                 CONF_CURRENT, | ||||||
|  |                 CONF_VOLTAGE, | ||||||
|  |                 CONF_ACTIVE_POWER, | ||||||
|  |                 CONF_APPARENT_POWER, | ||||||
|  |                 CONF_POWER_FACTOR, | ||||||
|  |                 CONF_FORWARD_ACTIVE_ENERGY, | ||||||
|  |                 CONF_REVERSE_ACTIVE_ENERGY, | ||||||
|  |             ]: | ||||||
|  |                 if conf := channel.get(sensor_type): | ||||||
|  |                     sensor_name = conf.get(CONF_NAME) | ||||||
|  |                     if ( | ||||||
|  |                         sensor_name | ||||||
|  |                         and channel_name | ||||||
|  |                         and not sensor_name.startswith(channel_name) | ||||||
|  |                     ): | ||||||
|  |                         conf[CONF_NAME] = f"{channel_name} {sensor_name}" | ||||||
|  |  | ||||||
|  |     if channel := config.get(CONF_NEUTRAL): | ||||||
|  |         channel_name = channel.get(CONF_NAME) | ||||||
|  |         if conf := channel.get(CONF_CURRENT): | ||||||
|  |             sensor_name = conf.get(CONF_NAME) | ||||||
|  |             if ( | ||||||
|  |                 sensor_name | ||||||
|  |                 and channel_name | ||||||
|  |                 and not sensor_name.startswith(channel_name) | ||||||
|  |             ): | ||||||
|  |                 conf[CONF_NAME] = f"{channel_name} {sensor_name}" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | FINAL_VALIDATE_SCHEMA = final_validate | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     await cg.register_component(var, config) | ||||||
|  |     await i2c.register_i2c_device(var, config) | ||||||
|  |  | ||||||
|  |     if irq0_pin := config.get(CONF_IRQ0_PIN): | ||||||
|  |         pin = await cg.gpio_pin_expression(irq0_pin) | ||||||
|  |         cg.add(var.set_irq0_pin(pin)) | ||||||
|  |  | ||||||
|  |     pin = await cg.gpio_pin_expression(config[CONF_IRQ1_PIN]) | ||||||
|  |     cg.add(var.set_irq1_pin(pin)) | ||||||
|  |  | ||||||
|  |     if reset_pin := config.get(CONF_RESET_PIN): | ||||||
|  |         pin = await cg.gpio_pin_expression(reset_pin) | ||||||
|  |         cg.add(var.set_reset_pin(pin)) | ||||||
|  |  | ||||||
|  |     if frequency := config.get(CONF_FREQUENCY): | ||||||
|  |         cg.add(var.set_frequency(frequency)) | ||||||
|  |  | ||||||
|  |     if channel := config.get(CONF_PHASE_A): | ||||||
|  |         chan = await power_channel(channel) | ||||||
|  |         cg.add(var.set_channel_a(chan)) | ||||||
|  |  | ||||||
|  |     if channel := config.get(CONF_PHASE_B): | ||||||
|  |         chan = await power_channel(channel) | ||||||
|  |         cg.add(var.set_channel_b(chan)) | ||||||
|  |  | ||||||
|  |     if channel := config.get(CONF_PHASE_C): | ||||||
|  |         chan = await power_channel(channel) | ||||||
|  |         cg.add(var.set_channel_c(chan)) | ||||||
|  |  | ||||||
|  |     if channel := config.get(CONF_NEUTRAL): | ||||||
|  |         chan = await neutral_channel(channel) | ||||||
|  |         cg.add(var.set_channel_n(chan)) | ||||||
							
								
								
									
										56
									
								
								tests/components/ade7880/common.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								tests/components/ade7880/common.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | |||||||
|  | i2c: | ||||||
|  |   - id: i2c_ade7880 | ||||||
|  |     scl: ${scl_pin} | ||||||
|  |     sda: ${sda_pin} | ||||||
|  |  | ||||||
|  | sensor: | ||||||
|  |   - platform: ade7880 | ||||||
|  |     i2c_id: i2c_ade7880 | ||||||
|  |     irq0_pin: ${irq0_pin} | ||||||
|  |     irq1_pin: ${irq1_pin} | ||||||
|  |     reset_pin: ${reset_pin} | ||||||
|  |     frequency: 60Hz | ||||||
|  |     phase_a: | ||||||
|  |       name: Channel A | ||||||
|  |       voltage: Voltage | ||||||
|  |       current: Current | ||||||
|  |       active_power: Active Power | ||||||
|  |       power_factor: Power Factor | ||||||
|  |       forward_active_energy: Forward Active Energy | ||||||
|  |       reverse_active_energy: Reverse Active Energy | ||||||
|  |       calibration: | ||||||
|  |         current_gain: 3116628 | ||||||
|  |         voltage_gain: -757178 | ||||||
|  |         power_gain: -1344457 | ||||||
|  |         phase_angle: 188 | ||||||
|  |     phase_b: | ||||||
|  |       name: Channel B | ||||||
|  |       voltage: Voltage | ||||||
|  |       current: Current | ||||||
|  |       active_power: Active Power | ||||||
|  |       power_factor: Power Factor | ||||||
|  |       forward_active_energy: Forward Active Energy | ||||||
|  |       reverse_active_energy: Reverse Active Energy | ||||||
|  |       calibration: | ||||||
|  |         current_gain: 3133655 | ||||||
|  |         voltage_gain: -755235 | ||||||
|  |         power_gain: -1345638 | ||||||
|  |         phase_angle: 188 | ||||||
|  |     phase_c: | ||||||
|  |       name: Channel C | ||||||
|  |       voltage: Voltage | ||||||
|  |       current: Current | ||||||
|  |       active_power: Active Power | ||||||
|  |       power_factor: Power Factor | ||||||
|  |       forward_active_energy: Forward Active Energy | ||||||
|  |       reverse_active_energy: Reverse Active Energy | ||||||
|  |       calibration: | ||||||
|  |         current_gain: 3111158 | ||||||
|  |         voltage_gain: -743813 | ||||||
|  |         power_gain: -1351437 | ||||||
|  |         phase_angle: 180 | ||||||
|  |     neutral: | ||||||
|  |       name: Neutral | ||||||
|  |       current: Current | ||||||
|  |       calibration: | ||||||
|  |         current_gain: 3189 | ||||||
							
								
								
									
										8
									
								
								tests/components/ade7880/test.esp32-c3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								tests/components/ade7880/test.esp32-c3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | substitutions: | ||||||
|  |   scl_pin: GPIO5 | ||||||
|  |   sda_pin: GPIO4 | ||||||
|  |   irq0_pin: GPIO6 | ||||||
|  |   irq1_pin: GPIO7 | ||||||
|  |   reset_pin: GPIO10 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										8
									
								
								tests/components/ade7880/test.esp32-c3.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								tests/components/ade7880/test.esp32-c3.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | substitutions: | ||||||
|  |   scl_pin: GPIO5 | ||||||
|  |   sda_pin: GPIO4 | ||||||
|  |   irq0_pin: GPIO6 | ||||||
|  |   irq1_pin: GPIO7 | ||||||
|  |   reset_pin: GPIO10 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										8
									
								
								tests/components/ade7880/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								tests/components/ade7880/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | substitutions: | ||||||
|  |   scl_pin: GPIO5 | ||||||
|  |   sda_pin: GPIO4 | ||||||
|  |   irq0_pin: GPIO13 | ||||||
|  |   irq1_pin: GPIO15 | ||||||
|  |   reset_pin: GPIO16 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										8
									
								
								tests/components/ade7880/test.esp32.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								tests/components/ade7880/test.esp32.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | substitutions: | ||||||
|  |   scl_pin: GPIO5 | ||||||
|  |   sda_pin: GPIO4 | ||||||
|  |   irq0_pin: GPIO13 | ||||||
|  |   irq1_pin: GPIO15 | ||||||
|  |   reset_pin: GPIO16 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										8
									
								
								tests/components/ade7880/test.esp8266.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								tests/components/ade7880/test.esp8266.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | substitutions: | ||||||
|  |   scl_pin: GPIO5 | ||||||
|  |   sda_pin: GPIO4 | ||||||
|  |   irq0_pin: GPIO13 | ||||||
|  |   irq1_pin: GPIO15 | ||||||
|  |   reset_pin: GPIO16 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										8
									
								
								tests/components/ade7880/test.rp2040.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								tests/components/ade7880/test.rp2040.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | substitutions: | ||||||
|  |   scl_pin: GPIO5 | ||||||
|  |   sda_pin: GPIO4 | ||||||
|  |   irq0_pin: GPIO13 | ||||||
|  |   irq1_pin: GPIO15 | ||||||
|  |   reset_pin: GPIO16 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
| @@ -1758,6 +1758,62 @@ sensor: | |||||||
|       memory_location: 0x20 |       memory_location: 0x20 | ||||||
|       memory_address: 0x7d |       memory_address: 0x7d | ||||||
|       name: Adres sensor |       name: Adres sensor | ||||||
|  |   - platform: ade7880 | ||||||
|  |     i2c_id: i2c_bus | ||||||
|  |     irq0_pin: | ||||||
|  |       number: GPIO13 | ||||||
|  |       allow_other_uses: true | ||||||
|  |     irq1_pin: | ||||||
|  |       number: GPIO5 | ||||||
|  |       allow_other_uses: true | ||||||
|  |     reset_pin: | ||||||
|  |       number: GPIO16 | ||||||
|  |       allow_other_uses: true | ||||||
|  |     frequency: 60Hz | ||||||
|  |     phase_a: | ||||||
|  |       name: Channel A | ||||||
|  |       voltage: Voltage | ||||||
|  |       current: Current | ||||||
|  |       active_power: Active Power | ||||||
|  |       power_factor: Power Factor | ||||||
|  |       forward_active_energy: Forward Active Energy | ||||||
|  |       reverse_active_energy: Reverse Active Energy | ||||||
|  |       calibration: | ||||||
|  |         current_gain: 3116628 | ||||||
|  |         voltage_gain: -757178 | ||||||
|  |         power_gain: -1344457 | ||||||
|  |         phase_angle: 188 | ||||||
|  |     phase_b: | ||||||
|  |       name: Channel B | ||||||
|  |       voltage: Voltage | ||||||
|  |       current: Current | ||||||
|  |       active_power: Active Power | ||||||
|  |       power_factor: Power Factor | ||||||
|  |       forward_active_energy: Forward Active Energy | ||||||
|  |       reverse_active_energy: Reverse Active Energy | ||||||
|  |       calibration: | ||||||
|  |         current_gain: 3133655 | ||||||
|  |         voltage_gain: -755235 | ||||||
|  |         power_gain: -1345638 | ||||||
|  |         phase_angle: 188 | ||||||
|  |     phase_c: | ||||||
|  |       name: Channel C | ||||||
|  |       voltage: Voltage | ||||||
|  |       current: Current | ||||||
|  |       active_power: Active Power | ||||||
|  |       power_factor: Power Factor | ||||||
|  |       forward_active_energy: Forward Active Energy | ||||||
|  |       reverse_active_energy: Reverse Active Energy | ||||||
|  |       calibration: | ||||||
|  |         current_gain: 3111158 | ||||||
|  |         voltage_gain: -743813 | ||||||
|  |         power_gain: -1351437 | ||||||
|  |         phase_angle: 180 | ||||||
|  |     neutral: | ||||||
|  |       name: Neutral | ||||||
|  |       current: Current | ||||||
|  |       calibration: | ||||||
|  |         current_gain: 3189 | ||||||
|  |  | ||||||
| psram: | psram: | ||||||
|  |  | ||||||
|   | |||||||
| @@ -290,6 +290,62 @@ sensor: | |||||||
|     id: adc128s102_channel_0 |     id: adc128s102_channel_0 | ||||||
|     channel: 0 |     channel: 0 | ||||||
|  |  | ||||||
|  |   - platform: ade7880 | ||||||
|  |     irq0_pin: | ||||||
|  |       number: GPIO13 | ||||||
|  |       allow_other_uses: true | ||||||
|  |     irq1_pin: | ||||||
|  |       number: GPIO5 | ||||||
|  |       allow_other_uses: true | ||||||
|  |     reset_pin: | ||||||
|  |       number: GPIO16 | ||||||
|  |       allow_other_uses: true | ||||||
|  |     frequency: 60Hz | ||||||
|  |     phase_a: | ||||||
|  |       name: Channel A | ||||||
|  |       voltage: Voltage | ||||||
|  |       current: Current | ||||||
|  |       active_power: Active Power | ||||||
|  |       power_factor: Power Factor | ||||||
|  |       forward_active_energy: Forward Active Energy | ||||||
|  |       reverse_active_energy: Reverse Active Energy | ||||||
|  |       calibration: | ||||||
|  |         current_gain: 3116628 | ||||||
|  |         voltage_gain: -757178 | ||||||
|  |         power_gain: -1344457 | ||||||
|  |         phase_angle: 188 | ||||||
|  |     phase_b: | ||||||
|  |       name: Channel B | ||||||
|  |       voltage: Voltage | ||||||
|  |       current: Current | ||||||
|  |       active_power: Active Power | ||||||
|  |       power_factor: Power Factor | ||||||
|  |       forward_active_energy: Forward Active Energy | ||||||
|  |       reverse_active_energy: Reverse Active Energy | ||||||
|  |       calibration: | ||||||
|  |         current_gain: 3133655 | ||||||
|  |         voltage_gain: -755235 | ||||||
|  |         power_gain: -1345638 | ||||||
|  |         phase_angle: 188 | ||||||
|  |     phase_c: | ||||||
|  |       name: Channel C | ||||||
|  |       voltage: Voltage | ||||||
|  |       current: Current | ||||||
|  |       active_power: Active Power | ||||||
|  |       power_factor: Power Factor | ||||||
|  |       forward_active_energy: Forward Active Energy | ||||||
|  |       reverse_active_energy: Reverse Active Energy | ||||||
|  |       calibration: | ||||||
|  |         current_gain: 3111158 | ||||||
|  |         voltage_gain: -743813 | ||||||
|  |         power_gain: -1351437 | ||||||
|  |         phase_angle: 180 | ||||||
|  |     neutral: | ||||||
|  |       name: Neutral | ||||||
|  |       current: Current | ||||||
|  |       calibration: | ||||||
|  |         current_gain: 3189 | ||||||
|  |  | ||||||
| apds9960: | apds9960: | ||||||
|   address: 0x20 |   address: 0x20 | ||||||
|   update_interval: 60s |   update_interval: 60s | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user