From 27a62002faab469f93510d973f4ce80e9e661409 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 15 Jan 2026 21:37:28 +0200 Subject: [PATCH] Added continuous mode to ADS1115_int --- components/ads1115_int/__init__.py | 9 +- components/ads1115_int/ads1115_int.cpp | 109 ++++++++++-------- components/ads1115_int/ads1115_int.h | 7 +- .../ads1115_int/sensor/ads1115_int_sensor.cpp | 2 +- sthome-ut8.yaml | 109 +++++++++++------- 5 files changed, 144 insertions(+), 92 deletions(-) diff --git a/components/ads1115_int/__init__.py b/components/ads1115_int/__init__.py index cbeb6a5..74b18fd 100644 --- a/components/ads1115_int/__init__.py +++ b/components/ads1115_int/__init__.py @@ -12,7 +12,8 @@ MULTI_CONF = True ads1115_int_ns = cg.esphome_ns.namespace("ads1115_int") ADS1115Component = ads1115_int_ns.class_("ADS1115Component", cg.Component, i2c.I2CDevice) -#CONF_CONTINUOUS_MODE = "continuous_mode" +CONF_CONTINUOUS_MODE = "continuous_mode" +CONF_INTERLEAVED_MODE = "interleaved_mode" CONF_ADS1115_ID = "ads1115_id" CONFIG_SCHEMA = ( @@ -20,7 +21,8 @@ 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_INTERLEAVED_MODE, default=False): cv.boolean, + cv.Optional(CONF_CONTINUOUS_MODE, default=False): cv.boolean, } ) .extend(cv.COMPONENT_SCHEMA) @@ -36,4 +38,5 @@ async def to_code(config): config.get(CONF_ALERT_RDY_PIN) ) cg.add(var.set_alert_pin(alert_rdy)) - # cg.add(var.set_continuous_mode(config[CONF_CONTINUOUS_MODE])) + cg.add(var.set_interleaved_mode(config[CONF_INTERLEAVED_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 58dcd78..0ba04c1 100644 --- a/components/ads1115_int/ads1115_int.cpp +++ b/components/ads1115_int/ads1115_int.cpp @@ -35,38 +35,39 @@ void ADS1115Component::setup() // 0bxxxx000xxxxxxxxx config |= ADS1115_GAIN_6P144 << 9; - // Set singleshot mode - continuous mode does not make sense with interrupt - // 0bxxxxxxx1xxxxxxxx - config |= 0b0000000100000000; - + if(!this->continuous_mode_) { + // Set singleshot mode + // 0bxxxxxxx1xxxxxxxx + config |= 0b0000000100000000; + } // Set data rate - 860 samples per second // 0bxxxxxxxx100xxxxx config |= ADS1115_860SPS << 5; - // Set comparator mode - hysteresis - // 0bxxxxxxxxxxx0xxxx - config |= 0b0000000000000000; - - // Set comparator polarity - active low - // 0bxxxxxxxxxxxx0xxx - config |= 0b0000000000000000; - - // Set comparator latch enabled - false - // 0bxxxxxxxxxxxxx0xx - config |= 0b0000000000000000; - - // Set comparator que mode - disabled - // 0bxxxxxxxxxxxxxx11 - config |= 0b0000000000000011; +// // Set comparator mode - hysteresis +// // 0bxxxxxxxxxxx0xxxx +// config |= 0b0000000000000000; +// +// // Set comparator polarity - active low +// // 0bxxxxxxxxxxxx0xxx +// config |= 0b0000000000000000; +// +// // Set comparator latch enabled - false +// // 0bxxxxxxxxxxxxx0xx +// config |= 0b0000000000000000; +// +// // Set comparator que mode - disabled +// // 0bxxxxxxxxxxxxxx11 +// config |= 0b0000000000000011; if (!this->write_byte_16(ADS1115_REGISTER_CONFIG, config)) { - this->mark_failed("Could not write to ADS1115 config register on setup."); + this->mark_failed("ADS1115 config register write failed on setup."); return; } this->prev_config_ = config; if(!this->set_data_ready_mode()) { - this->mark_failed("Could not set ADS1115 data ready mode on setup."); + this->mark_failed("ADS1115 data ready mode setup failed."); return; } } @@ -95,16 +96,24 @@ void ADS1115Component::read_request_next() { uint16_t config = 0x0000; // We do not support multiple ads1115 sharing the same alert/rdy pin, however we still read the ads1115 config register to get the multiplexer value. This allows us to also check the operational status (OS) bit. - // If OS bit set, i.e. the conversion is done meaning we can read the data; this is valid only in single shot mode, in continuous mode (which is not supported by this code) we can read data without checking the status bit + // If OS bit set, i.e. the conversion is done meaning we can read the data; this is valid only in single shot mode, in continuous mode we can read data without checking the status bit //ESP_LOGD(TAG, "Config: 0x%04X", this->prev_config_); + //ESP_LOGD(TAG, "I2C bus frequency: %.1f kHz", bus_->bus_frequency_ / 1000.0f); if(this->read_byte_16(ADS1115_REGISTER_CONFIG, &config)) { //ESP_LOGD(TAG, "Config register: 0x%04X", config); int ads_mux = (config >> 12) & 0b111; - bool conversion_done = (config >> 15) == 1; + bool conversion_done = (config >> 15) == 1 || this->continuous_mode_; //ESP_LOGD(TAG, "Current MUX setting according to ADS1115: %d", ads_mux); int ads_mux_index = get_mux_index(static_cast(ads_mux)); //ESP_LOGD(TAG, "Current MUX index according to ADS1115: %d", ads_mux_index); - if (conversion_done && ads_mux_index != -1) { + if (conversion_done && ads_mux_index != -1) { + if(this->interleaved_mode_) { + // in interleaved mode, we request the next conversion already here + int next_index = next_mux_data_index(ads_mux_index); + if(next_index != -1) { + this->start_conversion(next_index); + } + } int16_t raw_value = 0; double v = this->read_data(raw_value, ads_mux_index); if (!std::isnan(v)) { @@ -112,10 +121,12 @@ void ADS1115Component::read_request_next() ESP_LOGV(TAG, "'% -18s': Raw=% 6d %fV", sensor_ptr->get_name().c_str(), raw_value, v); sensor_ptr->publish_state(v); } - // we have read data for the current mux index, move to next - int next_index = next_mux_data_index(ads_mux_index); - if(next_index != -1) { - this->start_single_shot_conversion(next_index); + if(!this->interleaved_mode_) { + // we have read data for the current mux index, move to next + int next_index = next_mux_data_index(ads_mux_index); + if(next_index != -1) { + this->start_conversion(next_index); + } } } } @@ -205,40 +216,32 @@ int ADS1115Component::set_mux_data(ADS1115Multiplexer multiplexer, ADS1115Gain g this->muxdata_[index].gain = gain; this->muxdata_[index].resolution = resolution; this->muxdata_[index].samplerate = samplerate; + this->muxdata_[index].sensor_ptr = sensor_ptr; } - this->muxdata_[index].sensor_ptr = sensor_ptr; return index; } bool ADS1115Component::set_data_ready_mode() { - bool success = true; uint16_t config = this->prev_config_; // Set comparator que mode - assert after one conversion // 0bxxxxxxxxxxxxxx00 config &= 0b1111111111111100; if (!this->write_byte_16(ADS1115_REGISTER_CONFIG, config)) { - ESP_LOGE(TAG, "Failed to write to ads1115 to set comparator que mode"); - success = false; + return false; } - else { - this->prev_config_ = config; - if(!this->write_byte_16(ADS1115_REGISTER_HI_TRESH, 0x8000)) { - ESP_LOGE(TAG, "Failed to write to ads1115 to set high threshold register for alert pin"); - success = false; - } - else { - if(!this->write_byte_16(ADS1115_REGISTER_LO_TRESH, 0x0000)) { - ESP_LOGE(TAG, "Failed to write to ads1115 to set low threshold register for alert pin"); - success = false; - } - } + this->prev_config_ = config; + if(!this->write_byte_16(ADS1115_REGISTER_HI_TRESH, 0x8000)) { + return false; } - return success; + if(!this->write_byte_16(ADS1115_REGISTER_LO_TRESH, 0x0000)) { + return false; + } + return true; } -bool ADS1115Component::start_single_shot_conversion(int mux_index) +bool ADS1115Component::start_conversion(int mux_index) { auto& muxdata = this->muxdata_[mux_index]; auto multiplexer = muxdata.multiplexer; @@ -262,7 +265,17 @@ bool ADS1115Component::start_single_shot_conversion(int mux_index) config &= 0b1111111100011111; config |= (samplerate & 0b111) << 5; - // Start conversion + if(!this->continuous_mode_) { + // Set single-shot mode + // 0bxxxxxxx1xxxxxxxx + config |= 0b0000000100000000; + } + else { + // Clear single-shot bit + // 0b0xxxxxxxxxxxxxxx + config |= 0b0000000000000000; + } + // Start conversion; this has no effect in continuous mode config |= 0b1000000000000000; if (!this->write_byte_16(ADS1115_REGISTER_CONFIG, config)) { @@ -291,6 +304,8 @@ void ADS1115Component::dump_config() { ESP_LOGCONFIG(TAG, "ADS1115_INT:"); LOG_I2C_DEVICE(this); + ESP_LOGCONFIG(TAG, " Interleaved mode: %s", YESNO(this->interleaved_mode_)); + ESP_LOGCONFIG(TAG, " Continuous mode: %s", YESNO(this->continuous_mode_)); LOG_PIN(" ALERT Pin:", this->alert_pin_); if (this->is_failed()) { ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL); diff --git a/components/ads1115_int/ads1115_int.h b/components/ads1115_int/ads1115_int.h index 9ee1ebc..b333c93 100644 --- a/components/ads1115_int/ads1115_int.h +++ b/components/ads1115_int/ads1115_int.h @@ -73,15 +73,20 @@ class ADS1115Component : public Component, public i2c::I2CDevice { void loop() override; void dump_config() override; double read_data(int16_t& raw_value, int mux_index); - bool start_single_shot_conversion(int mux_index); + bool start_conversion(int mux_index); void set_alert_pin(InternalGPIOPin *pin) { alert_pin_ = pin; } + void set_interleaved_mode(bool interleaved) { this->interleaved_mode_ = interleaved; } + void set_continuous_mode(bool continuous) { this->continuous_mode_ = continuous; } bool set_data_ready_mode(); int set_mux_data(ADS1115Multiplexer multiplexer, ADS1115Gain gain, ADS1115Resolution resolution, ADS1115Samplerate samplerate, sensor::Sensor *sensor_ptr); protected: + bool interleaved_mode_{false}; + bool continuous_mode_{false}; uint16_t prev_config_{0}; InternalGPIOPin *alert_pin_; static void IRAM_ATTR isr_handler(ADS1115Component *arg); + }; } // namespace ads1115_int diff --git a/components/ads1115_int/sensor/ads1115_int_sensor.cpp b/components/ads1115_int/sensor/ads1115_int_sensor.cpp index 0fdcdcb..3fe69f7 100644 --- a/components/ads1115_int/sensor/ads1115_int_sensor.cpp +++ b/components/ads1115_int/sensor/ads1115_int_sensor.cpp @@ -12,7 +12,7 @@ void ADS1115Sensor::loop() if(this->first_reading_) { int mux_index = this->parent_->set_mux_data(this->multiplexer_, this->gain_, this->resolution_, this->samplerate_, this); this->first_reading_ = false; - this->parent_->start_single_shot_conversion(mux_index); // this will set off the first conversion; subsequent conversions will be triggered by the ISR + this->parent_->start_conversion(mux_index); // this will set off the first conversion; subsequent conversions will be triggered by the ISR } } diff --git a/sthome-ut8.yaml b/sthome-ut8.yaml index e6c0769..003620e 100644 --- a/sthome-ut8.yaml +++ b/sthome-ut8.yaml @@ -26,6 +26,8 @@ esphome: # esp32: board: esp32dev + cpu_frequency: 240MHz + flash_size: 4MB framework: type: esp-idf #arduino # esp-idf @@ -98,40 +100,40 @@ time: # - logger.log: "Synchronized system clock" # -#tlc59208f: -# address: 0x20 -# id: tlc59208f_1 -# i2c_id: bus_a -# -#output: -# - platform: ledc -# pin: -# number: GPIO12 #GPIO26 # LED_LOW_BAT -# inverted: false #true -# id: led_inverter_battery_low -# -# - platform: tlc59208f -# channel: 0 -# tlc59208f_id: 'tlc59208f_1' -# id: led0 -# -# - platform: tlc59208f -# channel: 1 -# tlc59208f_id: 'tlc59208f_1' -# id: led1 -# -#light: -# - platform: monochromatic -# output: led0 -# name: "LED Geyser Temperature 0" -# id: led_geyser_temp0 -# default_transition_length: 20ms -# -# - platform: monochromatic -# output: led1 -# name: "LED Geyser Temperature 1" -# id: led_geyser_temp1 -# default_transition_length: 20ms +tlc59208f: + address: 0x50 + id: tlc59208f_1 + i2c_id: bus_b + +output: + - platform: ledc + pin: + number: GPIO12 #GPIO26 # LED_LOW_BAT + inverted: false #true + id: led_inverter_battery_low + + - platform: tlc59208f + channel: 0 + tlc59208f_id: 'tlc59208f_1' + id: led0 + + - platform: tlc59208f + channel: 1 + tlc59208f_id: 'tlc59208f_1' + id: led1 + +light: + - platform: monochromatic + output: led0 + name: "LED Geyser Temperature 0" + id: led_geyser_temp0 + default_transition_length: 20ms + + - platform: monochromatic + output: led1 + name: "LED Geyser Temperature 1" + id: led_geyser_temp1 + default_transition_length: 20ms binary_sensor: @@ -142,15 +144,23 @@ binary_sensor: i2c: - sda: GPIO21 - scl: GPIO22 - scan: true - id: bus_a - frequency: 400kHz + - id: bus_a + sda: GPIO21 + scl: GPIO22 + scan: true + frequency: 400kHz + - id: bus_b + sda: GPIO26 + scl: GPIO1 + scan: true + frequency: 100kHz ads1115_int: - address: 0x4A id: ads1115_4A + i2c_id: bus_a + interleaved_mode: true + continuous_mode: false alert_rdy_pin: number: GPIO27 mode: @@ -159,6 +169,9 @@ ads1115_int: - address: 0x49 id: ads1115_49 + i2c_id: bus_a + interleaved_mode: true + continuous_mode: false alert_rdy_pin: number: GPIO5 mode: @@ -167,6 +180,9 @@ ads1115_int: - address: 0x48 id: ads1115_48 + i2c_id: bus_a + interleaved_mode: true + continuous_mode: false alert_rdy_pin: number: GPIO3 mode: @@ -212,7 +228,7 @@ sensor: send_every: 104 #208 #416 send_first_at: 104 #208 #416 - lambda: return sqrt(x); - - multiply: 555 #92.1 #91.1 #88.44 + - multiply: 100 #92.1 #91.1 #88.44 - offset: 0.0 #-0.2 # - lambda: |- # if(abs(x) < 0.1) @@ -257,6 +273,19 @@ sensor: # mod ########################### unit_of_measurement: "A" icon: "mdi:current" + filters: + - lambda: return x * x; + - sliding_window_moving_average: + window_size: 625 #1250 #5000 + send_every: 104 #208 #416 + send_first_at: 104 #208 #416 + - lambda: return sqrt(x); + - multiply: 100 #92.1 #91.1 #88.44 + - offset: 0.0 #-0.2 + # - lambda: |- + # if(abs(x) < 0.1) + # return 0.0; + # return x; # ads1115_4A # Inverter voltage sensor