diff --git a/components/ads1115_int/__init__.py b/components/ads1115_int/__init__.py index b49d2ba..a5d0ab2 100644 --- a/components/ads1115_int/__init__.py +++ b/components/ads1115_int/__init__.py @@ -20,7 +20,7 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(ADS1115Component), cv.Required(CONF_ALERT_RDY_PIN): pins.internal_gpio_input_pin_schema, - cv.Optional(CONF_CONTINUOUS_MODE, default=False): cv.boolean, + # cv.Optional(CONF_CONTINUOUS_MODE, default=False): cv.boolean, } ) .extend(cv.COMPONENT_SCHEMA) @@ -37,4 +37,4 @@ async def to_code(config): ) if alert_rdy is not None: cg.add(var.set_alert_pin(alert_rdy)) - cg.add(var.set_continuous_mode(config[CONF_CONTINUOUS_MODE])) + # cg.add(var.set_continuous_mode(config[CONF_CONTINUOUS_MODE])) diff --git a/components/ads1115_int/ads1115_int.cpp b/components/ads1115_int/ads1115_int.cpp index df5db46..91f175b 100644 --- a/components/ads1115_int/ads1115_int.cpp +++ b/components/ads1115_int/ads1115_int.cpp @@ -19,6 +19,7 @@ void ADS1115Component::setup() { this->mark_failed(); return; } + // setup with default values uint16_t config = 0; // Clear single-shot bit // 0b0xxxxxxxxxxxxxxx @@ -71,6 +72,28 @@ void ADS1115Component::setup() { return; } } +// Method to set mux data for later use, i.e. when data is to be read +void ADS1115Component::set_mux_data(ADS1115Multiplexer multiplexer, ADS1115Gain gain, ADS1115Resolution resolution, ADS1115Samplerate samplerate, sensor::Sensor *sensor_ptr) +{ + int index = -1; + for(int i=0; i<4; i++) { + if(this->muxdata_[i].multiplexer == multiplexer) { + index = i; + break; + } + if(this->muxdata_[i].multiplexer == ADS1115_MULTIPLEXER_INVALID && index == -1) { + index = i; + } + } + if(index != -1) { + this->muxdata_[index].multiplexer = multiplexer; + this->muxdata_[index].gain = gain; + this->muxdata_[index].resolution = resolution; + this->muxdata_[index].samplerate = samplerate; + this->muxdata_[index].sensor_ptr = sensor_ptr; + } +} + bool ADS1115Component::set_data_ready_mode() { uint16_t config = this->prev_config_; @@ -88,82 +111,95 @@ bool ADS1115Component::set_data_ready_mode() if(!this->write_byte_16(ADS1115_REGISTER_LO_TRESH, 0x0000)) { return false; } - // also clear all data_ready_ flags - for (int i = 0; i < 8; i++) - this->data_ready_[i] = false; return true; } // ISR function to handle interrupt from alert pin // only function that sets data_ready_ flags void IRAM_ATTR ADS1115Component::isr(ADS1115Component *arg) { - for (int i = 0; i < 8; i++) - arg->data_ready_[i] = true; -} -bool ADS1115Component::is_data_ready(ADS1115Multiplexer multiplexer) -{ - int index = static_cast(multiplexer); - if(index < 0 || index >= 8) - return false; - return this->data_ready_[index]; -} -void ADS1115Component::clear_data_ready(ADS1115Multiplexer multiplexer) -{ - int index = static_cast(multiplexer); - if(index < 0 || index >= 8) - return; - this->data_ready_[index] = false; + arg->update_sensor(); } -// call only when data_ready_ is true -double ADS1115Component::read_data(int16_t& raw_value, ADS1115Multiplexer multiplexer, ADS1115Gain gain, ADS1115Resolution resolution, ADS1115Samplerate samplerate) +void ADS1115Component::update_sensor() { + int mux_index = this->mux_data_index_; + ADS1115Multiplexer multiplexer = this->muxdata_[mux_index].multiplexer; + if (multiplexer != ADS1115_MULTIPLEXER_INVALID) { + int16_t raw_value = 0; + double v = this->read_data(raw_value, mux_index); + auto sensor_ptr = this->muxdata_[mux_index].sensor_ptr; + if (!std::isnan(v)) { + if(this->count_ % 10 == 0) { + ESP_LOGI(TAG, "'% -18s': Raw=% 6d %fV", sensor_ptr->get_name().c_str(), raw_value, v); + } + this->count_++; + ESP_LOGD(TAG, "'%s': Got Voltage=%fV", sensor_ptr->get_name().c_str(), v); + sensor_ptr->publish_state(v); + } + } + if(next_mux_data_index() != -1) { + this->start_single_shot_conversion(); + } +} + +bool ADS1115Component::start_single_shot_conversion() { - uint16_t config = this->prev_config_; - // Multiplexer - // 0bxBBBxxxxxxxxxxxx - config &= 0b1000111111111111; - config |= (multiplexer & 0b111) << 12; + int mux_index = this->mux_data_index_; + ADS1115Multiplexer multiplexer = this->muxdata_[mux_index].multiplexer; + if (multiplexer != ADS1115_MULTIPLEXER_INVALID) { + ADS1115Gain gain = this->muxdata_[mux_index].gain; + ADS1115Resolution resolution = this->muxdata_[mux_index].resolution; + ADS1115Samplerate samplerate = this->muxdata_[mux_index].samplerate; + uint16_t config = this->prev_config_; + // Multiplexer + // 0bxBBBxxxxxxxxxxxx + config &= 0b1000111111111111; + config |= (multiplexer & 0b111) << 12; - // Gain - // 0bxxxxBBBxxxxxxxxx - config &= 0b1111000111111111; - config |= (gain & 0b111) << 9; + // Gain + // 0bxxxxBBBxxxxxxxxx + config &= 0b1111000111111111; + config |= (gain & 0b111) << 9; - // Sample rate - // 0bxxxxxxxxBBBxxxxx - config &= 0b1111111100011111; - config |= (samplerate & 0b111) << 5; - - if (!this->continuous_mode_) { + // Sample rate + // 0bxxxxxxxxBBBxxxxx + config &= 0b1111111100011111; + config |= (samplerate & 0b111) << 5; + // Start conversion config |= 0b1000000000000000; - } - - this->clear_data_ready(multiplexer); - //ESP_LOGI(TAG, "'mux:%d': Gain=%d, Res=%d, CONF=<0x%04X>", static_cast(multiplexer), static_cast(gain), static_cast(resolution), config); - // write config if in single-shot mode or config has changed - if (!this->continuous_mode_ || this->prev_config_ != config) { + if (!this->write_byte_16(ADS1115_REGISTER_CONFIG, config)) { this->status_set_warning(); return false; } this->prev_config_ = config; - // - // removed delay - // - if (!this->continuous_mode_) { - uint32_t start = millis(); - // wait for conversion to complete - 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(); - } - } + return true; } + return false; +} +int ADS1115Component::next_mux_data_index() +{ + int start_index = this->mux_data_index_; + do { + this->mux_data_index_ = (this->mux_data_index_ + 1) % 4; + if(this->muxdata_[this->mux_data_index_].multiplexer != ADS1115_MULTIPLEXER_INVALID) { + return this->mux_data_index_; + } + } while(this->mux_data_index_ != start_index); + return -1; // no valid mux data found +} +// call only when data_ready_ is true +double ADS1115Component::read_data(int16_t& raw_value, int mux_index) +{ + ADS1115Multiplexer multiplexer = this->muxdata_[mux_index].multiplexer; + raw_value = 0; + if(multiplexer == ADS1115_MULTIPLEXER_INVALID) { + ESP_LOGE(TAG, "MUX data not set for index %d", mux_index); + return NAN; + } + ADS1115Gain gain = this->muxdata_[mux_index].gain; + ADS1115Resolution resolution = this->muxdata_[mux_index].resolution; + uint16_t raw_conversion; if (!this->read_byte_16(ADS1115_REGISTER_CONVERSION, &raw_conversion)) { this->status_set_warning(); diff --git a/components/ads1115_int/ads1115_int.h b/components/ads1115_int/ads1115_int.h index 669409a..24b742d 100644 --- a/components/ads1115_int/ads1115_int.h +++ b/components/ads1115_int/ads1115_int.h @@ -2,6 +2,7 @@ #include "esphome/components/i2c/i2c.h" // Ensure this header defines i2c::I2CDevice #include "esphome/core/component.h" // Ensure this header defines Component +#include "esphome/components/sensor/sensor.h" #include #include @@ -18,6 +19,7 @@ enum ADS1115Multiplexer { ADS1115_MULTIPLEXER_P1_NG = 0b101, ADS1115_MULTIPLEXER_P2_NG = 0b110, ADS1115_MULTIPLEXER_P3_NG = 0b111, + ADS1115_MULTIPLEXER_INVALID = 0xFF }; enum ADS1115Gain { @@ -46,25 +48,41 @@ enum ADS1115Samplerate { }; class ADS1115Component : public Component, public i2c::I2CDevice { - public: - void setup() override; - void dump_config() override; - /// HARDWARE_LATE setup priority - void set_continuous_mode(bool continuous_mode) { continuous_mode_ = continuous_mode; } - - // Method to read converted data - double read_data(int16_t& raw_value, ADS1115Multiplexer multiplexer, ADS1115Gain gain, ADS1115Resolution resolution, ADS1115Samplerate samplerate); - void set_alert_pin(InternalGPIOPin *pin) { alert_pin_ = pin; } - bool set_data_ready_mode(); - bool is_data_ready(ADS1115Multiplexer multiplexer); - void clear_data_ready(ADS1115Multiplexer multiplexer); + private: + struct mux_data_item { + ADS1115Multiplexer multiplexer; + ADS1115Gain gain; + ADS1115Resolution resolution; + ADS1115Samplerate samplerate; + sensor::Sensor *sensor_ptr; // ADS1115Sensor *sensor_ptr + mux_data_item() { multiplexer = ADS1115_MULTIPLEXER_INVALID; } + }; + void request_data(); + int next_mux_data_index(); + void update_sensor(); + int mux_data_index_{0}; + mux_data_item muxdata_[4]; + uint64_t count_{0}; + + public: + void setup() override; + void dump_config() override; + /// HARDWARE_LATE setup priority + // we will force single-shot mode for interrupt operation; kept continuous_mode_ for ease of reversal if needed + //void set_continuous_mode(bool continuous_mode) { continuous_mode_ = continuous_mode; } + // Method to read converted data + double read_data(int16_t& raw_value, int mux_index); + bool start_single_shot_conversion(); + void set_alert_pin(InternalGPIOPin *pin) { alert_pin_ = pin; } + bool set_data_ready_mode(); + void set_mux_data(ADS1115Multiplexer multiplexer, ADS1115Gain gain, ADS1115Resolution resolution, ADS1115Samplerate samplerate, sensor::Sensor *sensor_ptr); + protected: - uint16_t prev_config_{0}; - bool continuous_mode_; - InternalGPIOPin *alert_pin_; - static void isr(ADS1115Component *arg); - volatile bool data_ready_[8]{false}; + uint16_t prev_config_{0}; + bool continuous_mode_{false}; + InternalGPIOPin *alert_pin_; + static void isr(ADS1115Component *arg); }; diff --git a/components/ads1115_int/sensor/ads1115_int_sensor.cpp b/components/ads1115_int/sensor/ads1115_int_sensor.cpp index b447d0d..8575d71 100644 --- a/components/ads1115_int/sensor/ads1115_int_sensor.cpp +++ b/components/ads1115_int/sensor/ads1115_int_sensor.cpp @@ -8,19 +8,13 @@ namespace ads1115_int { static const char *const TAG = "ads1115_int.sensor"; void ADS1115Sensor::loop() { - if (parent_->is_data_ready(this->multiplexer_)) { - this->parent_->clear_data_ready(this->multiplexer_); - int16_t raw_value = -1000; - double v = this->parent_->read_data(raw_value, this->multiplexer_, this->gain_, this->resolution_, this->samplerate_); - if (!std::isnan(v)) { - if(this->count_ % 10 == 0) { - ESP_LOGI(TAG, "'% -18s': Raw=% 6d %fV", this->get_name().c_str(), raw_value, v); - } - this->count_++; - ESP_LOGD(TAG, "'%s': Got Voltage=%fV", this->get_name().c_str(), v); - this->publish_state(v); - } + if(this->first_reading_) { + this->parent_->set_mux_data(this->multiplexer_, this->gain_, this->resolution_, this->samplerate_, this); + //delay(100); + this->first_reading_ = false; + this->parent_->start_single_shot_conversion(); // this will set off the first conversion; subsequent conversions will be triggered by the ISR } + // Data reading and publishing is handled in the parent component's update_sensor() method } void ADS1115Sensor::dump_config() { diff --git a/components/ads1115_int/sensor/ads1115_int_sensor.h b/components/ads1115_int/sensor/ads1115_int_sensor.h index b216739..ea159ad 100644 --- a/components/ads1115_int/sensor/ads1115_int_sensor.h +++ b/components/ads1115_int/sensor/ads1115_int_sensor.h @@ -30,7 +30,7 @@ class ADS1115Sensor : public sensor::Sensor, ADS1115Gain gain_; ADS1115Resolution resolution_; ADS1115Samplerate samplerate_; - uint64_t count_{0}; + bool first_reading_{true}; }; } // namespace ads1115 diff --git a/sthome-ut8.yaml b/sthome-ut8.yaml index 6c5efe1..af3fed6 100644 --- a/sthome-ut8.yaml +++ b/sthome-ut8.yaml @@ -274,7 +274,6 @@ ads1115_pol: ads1115_int: - address: 0x48 id: ads1115_48 - continuous_mode: true alert_rdy_pin: number: GPIO3 mode: