From f95d4ca106711a94710b57772f485a2889c4ead5 Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Tue, 2 Jul 2019 13:02:46 +0200 Subject: [PATCH] CT Clamp ADS1115 Improvements (#647) Fixes https://github.com/esphome/issues/issues/457 --- esphome/components/ads1115/__init__.py | 4 ++ esphome/components/ads1115/ads1115.cpp | 57 ++++++++++--------- esphome/components/ads1115/ads1115.h | 13 +++-- .../components/ct_clamp/ct_clamp_sensor.cpp | 23 +++++++- esphome/components/ct_clamp/ct_clamp_sensor.h | 8 ++- 5 files changed, 72 insertions(+), 33 deletions(-) diff --git a/esphome/components/ads1115/__init__.py b/esphome/components/ads1115/__init__.py index 28cfac49ec..a41a521ba7 100644 --- a/esphome/components/ads1115/__init__.py +++ b/esphome/components/ads1115/__init__.py @@ -10,8 +10,10 @@ MULTI_CONF = True ads1115_ns = cg.esphome_ns.namespace('ads1115') ADS1115Component = ads1115_ns.class_('ADS1115Component', cg.Component, i2c.I2CDevice) +CONF_CONTINUOUS_MODE = 'continuous_mode' CONFIG_SCHEMA = cv.Schema({ cv.GenerateID(): cv.declare_id(ADS1115Component), + cv.Optional(CONF_CONTINUOUS_MODE, default=False): cv.boolean, }).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(None)) @@ -19,3 +21,5 @@ 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_continuous_mode(config[CONF_CONTINUOUS_MODE])) diff --git a/esphome/components/ads1115/ads1115.cpp b/esphome/components/ads1115/ads1115.cpp index 0d82fce533..0899571a47 100644 --- a/esphome/components/ads1115/ads1115.cpp +++ b/esphome/components/ads1115/ads1115.cpp @@ -29,9 +29,15 @@ void ADS1115Component::setup() { // 0bxxxx000xxxxxxxxx config |= ADS1115_GAIN_6P144 << 9; - // Set singleshot mode - // 0bxxxxxxx1xxxxxxxx - config |= 0b0000000100000000; + if (this->continuous_mode_) { + // Set continuous mode + // 0bxxxxxxx0xxxxxxxx + config |= 0b0000000000000000; + } else { + // Set singleshot mode + // 0bxxxxxxx1xxxxxxxx + config |= 0b0000000100000000; + } // Set data rate - 860 samples per second (we're in singleshot mode) // 0bxxxxxxxx100xxxxx @@ -57,6 +63,8 @@ void ADS1115Component::setup() { this->mark_failed(); return; } + this->prev_config_ = config; + for (auto *sensor : this->sensors_) { this->set_interval(sensor->get_name(), sensor->update_interval(), [this, sensor] { this->request_measurement(sensor); }); @@ -75,13 +83,8 @@ void ADS1115Component::dump_config() { ESP_LOGCONFIG(TAG, " Gain: %u", sensor->get_gain()); } } -float ADS1115Component::get_setup_priority() const { return setup_priority::DATA; } float ADS1115Component::request_measurement(ADS1115Sensor *sensor) { - uint16_t config; - if (!this->read_byte_16(ADS1115_REGISTER_CONFIG, &config)) { - this->status_set_warning(); - return NAN; - } + uint16_t config = this->prev_config_; // Multiplexer // 0bxBBBxxxxxxxxxxxx config &= 0b1000111111111111; @@ -91,25 +94,31 @@ float ADS1115Component::request_measurement(ADS1115Sensor *sensor) { // 0bxxxxBBBxxxxxxxxx config &= 0b1111000111111111; config |= (sensor->get_gain() & 0b111) << 9; - // Start conversion - config |= 0b1000000000000000; - if (!this->write_byte_16(ADS1115_REGISTER_CONFIG, config)) { - this->status_set_warning(); - return NAN; + if (!this->continuous_mode_) { + // Start conversion + config |= 0b1000000000000000; } - // about 1.6 ms with 860 samples per second - delay(2); - - uint32_t start = millis(); - while (this->read_byte_16(ADS1115_REGISTER_CONFIG, &config) && (config >> 15) == 0) { - if (millis() - start > 100) { - ESP_LOGW(TAG, "Reading ADS1115 timed out"); + if (!this->continuous_mode_ || this->prev_config_ != config) { + if (!this->write_byte_16(ADS1115_REGISTER_CONFIG, config)) { this->status_set_warning(); return NAN; } - yield(); + this->prev_config_ = config; + + // about 1.6 ms with 860 samples per second + delay(2); + + uint32_t start = millis(); + while (this->read_byte_16(ADS1115_REGISTER_CONFIG, &config) && (config >> 15) == 0) { + if (millis() - start > 100) { + ESP_LOGW(TAG, "Reading ADS1115 timed out"); + this->status_set_warning(); + return NAN; + } + yield(); + } } uint16_t raw_conversion; @@ -147,10 +156,6 @@ float ADS1115Component::request_measurement(ADS1115Sensor *sensor) { return millivolts / 1e3f; } -uint8_t ADS1115Sensor::get_multiplexer() const { return this->multiplexer_; } -void ADS1115Sensor::set_multiplexer(ADS1115Multiplexer multiplexer) { this->multiplexer_ = multiplexer; } -uint8_t ADS1115Sensor::get_gain() const { return this->gain_; } -void ADS1115Sensor::set_gain(ADS1115Gain gain) { this->gain_ = gain; } float ADS1115Sensor::sample() { return this->parent_->request_measurement(this); } void ADS1115Sensor::update() { float v = this->parent_->request_measurement(this); diff --git a/esphome/components/ads1115/ads1115.h b/esphome/components/ads1115/ads1115.h index 966541ef4f..059436d142 100644 --- a/esphome/components/ads1115/ads1115.h +++ b/esphome/components/ads1115/ads1115.h @@ -37,13 +37,16 @@ class ADS1115Component : public Component, public i2c::I2CDevice { void setup() override; void dump_config() override; /// HARDWARE_LATE setup priority - float get_setup_priority() const override; + float get_setup_priority() const override { return setup_priority::DATA; } + void set_continuous_mode(bool continuous_mode) { continuous_mode_ = continuous_mode; } /// Helper method to request a measurement from a sensor. float request_measurement(ADS1115Sensor *sensor); protected: std::vector sensors_; + uint16_t prev_config_{0}; + bool continuous_mode_; }; /// Internal holder class that is in instance of Sensor so that the hub can create individual sensors. @@ -51,12 +54,12 @@ class ADS1115Sensor : public sensor::Sensor, public PollingComponent, public vol public: ADS1115Sensor(ADS1115Component *parent) : parent_(parent) {} void update() override; - void set_multiplexer(ADS1115Multiplexer multiplexer); - void set_gain(ADS1115Gain gain); + void set_multiplexer(ADS1115Multiplexer multiplexer) { multiplexer_ = multiplexer; } + void set_gain(ADS1115Gain gain) { gain_ = gain; } float sample() override; - uint8_t get_multiplexer() const; - uint8_t get_gain() const; + uint8_t get_multiplexer() const { return multiplexer_; } + uint8_t get_gain() const { return gain_; } protected: ADS1115Component *parent_; diff --git a/esphome/components/ct_clamp/ct_clamp_sensor.cpp b/esphome/components/ct_clamp/ct_clamp_sensor.cpp index 1a7bac2844..8819f9711e 100644 --- a/esphome/components/ct_clamp/ct_clamp_sensor.cpp +++ b/esphome/components/ct_clamp/ct_clamp_sensor.cpp @@ -8,6 +8,18 @@ namespace ct_clamp { static const char *TAG = "ct_clamp"; +void CTClampSensor::setup() { + this->is_calibrating_offset_ = true; + this->high_freq_.start(); + this->set_timeout("calibrate_offset", this->sample_duration_, [this]() { + this->high_freq_.stop(); + this->is_calibrating_offset_ = false; + if (this->num_samples_ != 0) { + this->offset_ = this->sample_sum_ / this->num_samples_; + } + }); +} + void CTClampSensor::dump_config() { LOG_SENSOR("", "CT Clamp Sensor", this); ESP_LOGCONFIG(TAG, " Sample Duration: %.2fs", this->sample_duration_ / 1e3f); @@ -15,6 +27,9 @@ void CTClampSensor::dump_config() { } void CTClampSensor::update() { + if (this->is_calibrating_offset_) + return; + // Update only starts the sampling phase, in loop() the actual sampling is happening. // Request a high loop() execution interval during sampling phase. @@ -44,12 +59,18 @@ void CTClampSensor::update() { } void CTClampSensor::loop() { - if (!this->is_sampling_) + if (!this->is_sampling_ || !this->is_calibrating_offset_) return; // Perform a single sample float value = this->source_->sample(); + if (this->is_calibrating_offset_) { + this->sample_sum_ += value; + this->num_samples_++; + return; + } + // Adjust DC offset via low pass filter (exponential moving average) const float alpha = 0.001f; this->offset_ = this->offset_ * (1 - alpha) + value * alpha; diff --git a/esphome/components/ct_clamp/ct_clamp_sensor.h b/esphome/components/ct_clamp/ct_clamp_sensor.h index d816ac781a..c709f6718b 100644 --- a/esphome/components/ct_clamp/ct_clamp_sensor.h +++ b/esphome/components/ct_clamp/ct_clamp_sensor.h @@ -10,10 +10,14 @@ namespace ct_clamp { class CTClampSensor : public sensor::Sensor, public PollingComponent { public: + void setup() override; void update() override; void loop() override; void dump_config() override; - float get_setup_priority() const override { return setup_priority::DATA; } + float get_setup_priority() const override { + // After the base sensor has been initialized + return setup_priority::DATA - 1.0f; + } void set_sample_duration(uint32_t sample_duration) { sample_duration_ = sample_duration; } void set_source(voltage_sampler::VoltageSampler *source) { source_ = source; } @@ -40,6 +44,8 @@ class CTClampSensor : public sensor::Sensor, public PollingComponent { float sample_sum_ = 0.0f; uint32_t num_samples_ = 0; bool is_sampling_ = false; + /// Calibrate offset value once at boot + bool is_calibrating_offset_ = false; }; } // namespace ct_clamp