From a105cf0748fcc017ea52195f77d242a61247decd Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 11 Jan 2026 20:34:38 +0200 Subject: [PATCH] Before changing ads1115_int to directly publish from ISR --- components/ads1115_int/__init__.py | 6 +- components/ads1115_int/ads1115_int.cpp | 14 +- components/ads1115_int/ads1115_int.h | 6 +- components/ads1115_int/sensor/__init__.py | 14 +- .../ads1115_int/sensor/ads1115_int_sensor.cpp | 9 +- .../ads1115_int/sensor/ads1115_int_sensor.h | 2 +- components/ads1115_pol/__init__.py | 32 + components/ads1115_pol/ads1115_pol.cpp | 223 ++++++ components/ads1115_pol/ads1115_pol.h | 64 ++ components/ads1115_pol/sensor/__init__.py | 98 +++ .../ads1115_pol/sensor/ads1115_pol_sensor.cpp | 36 + .../ads1115_pol/sensor/ads1115_pol_sensor.h | 38 + components/ads131m08/ads131m08.cpp | 708 +++++++++++++++++- sthome-ut8.yaml | 239 +++--- 14 files changed, 1324 insertions(+), 165 deletions(-) create mode 100644 components/ads1115_pol/__init__.py create mode 100644 components/ads1115_pol/ads1115_pol.cpp create mode 100644 components/ads1115_pol/ads1115_pol.h create mode 100644 components/ads1115_pol/sensor/__init__.py create mode 100644 components/ads1115_pol/sensor/ads1115_pol_sensor.cpp create mode 100644 components/ads1115_pol/sensor/ads1115_pol_sensor.h diff --git a/components/ads1115_int/__init__.py b/components/ads1115_int/__init__.py index b9670c9..b49d2ba 100644 --- a/components/ads1115_int/__init__.py +++ b/components/ads1115_int/__init__.py @@ -9,11 +9,11 @@ CONF_ALERT_RDY_PIN = "alert_rdy_pin" DEPENDENCIES = ["i2c"] MULTI_CONF = True -ads1115_ns = cg.esphome_ns.namespace("ads1115_int") -ADS1115Component = ads1115_ns.class_("ADS1115Component", cg.Component, i2c.I2CDevice) +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_ADS1115_ID = "ads1115_int_id" +CONF_ADS1115_ID = "ads1115_id" CONFIG_SCHEMA = ( cv.Schema( diff --git a/components/ads1115_int/ads1115_int.cpp b/components/ads1115_int/ads1115_int.cpp index 0272fb7..df5db46 100644 --- a/components/ads1115_int/ads1115_int.cpp +++ b/components/ads1115_int/ads1115_int.cpp @@ -66,12 +66,12 @@ void ADS1115Component::setup() { return; } this->prev_config_ = config; - if(!this->set_alert_ready_mode()) { + if(!this->set_data_ready_mode()) { this->mark_failed(); return; } } -bool ADS1115Component::set_alert_ready_mode() +bool ADS1115Component::set_data_ready_mode() { uint16_t config = this->prev_config_; // Set comparator que mode - assert after one conversion @@ -107,7 +107,7 @@ bool ADS1115Component::is_data_ready(ADS1115Multiplexer multiplexer) return false; return this->data_ready_[index]; } -void ADS1115Component::clear_alert_ready(ADS1115Multiplexer multiplexer) +void ADS1115Component::clear_data_ready(ADS1115Multiplexer multiplexer) { int index = static_cast(multiplexer); if(index < 0 || index >= 8) @@ -116,7 +116,7 @@ void ADS1115Component::clear_alert_ready(ADS1115Multiplexer multiplexer) } // call only when data_ready_ is true -double ADS1115Component::read_data(ADS1115Multiplexer multiplexer, ADS1115Gain gain, ADS1115Resolution resolution, ADS1115Samplerate samplerate) +double ADS1115Component::read_data(int16_t& raw_value, ADS1115Multiplexer multiplexer, ADS1115Gain gain, ADS1115Resolution resolution, ADS1115Samplerate samplerate) { uint16_t config = this->prev_config_; // Multiplexer @@ -139,7 +139,7 @@ double ADS1115Component::read_data(ADS1115Multiplexer multiplexer, ADS1115Gain g config |= 0b1000000000000000; } - this->clear_alert_ready(multiplexer); + 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) { @@ -148,6 +148,9 @@ double ADS1115Component::read_data(ADS1115Multiplexer multiplexer, ADS1115Gain g return false; } this->prev_config_ = config; + // + // removed delay + // if (!this->continuous_mode_) { uint32_t start = millis(); // wait for conversion to complete @@ -184,6 +187,7 @@ double ADS1115Component::read_data(ADS1115Multiplexer multiplexer, ADS1115Gain g } } auto signed_conversion = static_cast(raw_conversion); + raw_value = signed_conversion; double millivolts; double divider = (resolution == ADS1115_16_BITS) ? 32768.0f : 2048.0f; switch (gain) { diff --git a/components/ads1115_int/ads1115_int.h b/components/ads1115_int/ads1115_int.h index f28d4f3..669409a 100644 --- a/components/ads1115_int/ads1115_int.h +++ b/components/ads1115_int/ads1115_int.h @@ -53,11 +53,11 @@ class ADS1115Component : public Component, public i2c::I2CDevice { void set_continuous_mode(bool continuous_mode) { continuous_mode_ = continuous_mode; } // Method to read converted data - double read_data(ADS1115Multiplexer multiplexer, ADS1115Gain gain, ADS1115Resolution resolution, ADS1115Samplerate samplerate); + 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_alert_ready_mode(); + bool set_data_ready_mode(); bool is_data_ready(ADS1115Multiplexer multiplexer); - void clear_alert_ready(ADS1115Multiplexer multiplexer); + void clear_data_ready(ADS1115Multiplexer multiplexer); protected: uint16_t prev_config_{0}; diff --git a/components/ads1115_int/sensor/__init__.py b/components/ads1115_int/sensor/__init__.py index 5715fcc..10a09e0 100644 --- a/components/ads1115_int/sensor/__init__.py +++ b/components/ads1115_int/sensor/__init__.py @@ -12,12 +12,12 @@ from esphome.const import ( UNIT_VOLT, ) -from .. import CONF_ADS1115_ID, ADS1115Component, ads1115_ns +from .. import CONF_ADS1115_ID, ADS1115Component, ads1115_int_ns AUTO_LOAD = ["voltage_sampler"] -DEPENDENCIES = ["ads1115"] +DEPENDENCIES = ["ads1115_int"] -ADS1115Multiplexer = ads1115_ns.enum("ADS1115Multiplexer") +ADS1115Multiplexer = ads1115_int_ns.enum("ADS1115Multiplexer") MUX = { "A0_A1": ADS1115Multiplexer.ADS1115_MULTIPLEXER_P0_N1, "A0_A3": ADS1115Multiplexer.ADS1115_MULTIPLEXER_P0_N3, @@ -29,7 +29,7 @@ MUX = { "A3_GND": ADS1115Multiplexer.ADS1115_MULTIPLEXER_P3_NG, } -ADS1115Gain = ads1115_ns.enum("ADS1115Gain") +ADS1115Gain = ads1115_int_ns.enum("ADS1115Gain") GAIN = { "6.144": ADS1115Gain.ADS1115_GAIN_6P144, "4.096": ADS1115Gain.ADS1115_GAIN_4P096, @@ -39,13 +39,13 @@ GAIN = { "0.256": ADS1115Gain.ADS1115_GAIN_0P256, } -ADS1115Resolution = ads1115_ns.enum("ADS1115Resolution") +ADS1115Resolution = ads1115_int_ns.enum("ADS1115Resolution") RESOLUTION = { "16_BITS": ADS1115Resolution.ADS1115_16_BITS, "12_BITS": ADS1115Resolution.ADS1015_12_BITS, } -ADS1115Samplerate = ads1115_ns.enum("ADS1115Samplerate") +ADS1115Samplerate = ads1115_int_ns.enum("ADS1115Samplerate") SAMPLERATE = { "8": ADS1115Samplerate.ADS1115_8SPS, "16": ADS1115Samplerate.ADS1115_16SPS, @@ -57,7 +57,7 @@ SAMPLERATE = { "860": ADS1115Samplerate.ADS1115_860SPS, } -ADS1115Sensor = ads1115_ns.class_( +ADS1115Sensor = ads1115_int_ns.class_( "ADS1115Sensor", sensor.Sensor, cg.Component, voltage_sampler.VoltageSampler ) diff --git a/components/ads1115_int/sensor/ads1115_int_sensor.cpp b/components/ads1115_int/sensor/ads1115_int_sensor.cpp index 7e78aed..b447d0d 100644 --- a/components/ads1115_int/sensor/ads1115_int_sensor.cpp +++ b/components/ads1115_int/sensor/ads1115_int_sensor.cpp @@ -9,9 +9,14 @@ static const char *const TAG = "ads1115_int.sensor"; void ADS1115Sensor::loop() { if (parent_->is_data_ready(this->multiplexer_)) { - this->parent_->clear_alert_ready(this->multiplexer_); - double v = this->parent_->read_data(this->multiplexer_, this->gain_, this->resolution_, this->samplerate_); + 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); } diff --git a/components/ads1115_int/sensor/ads1115_int_sensor.h b/components/ads1115_int/sensor/ads1115_int_sensor.h index 13708b2..b216739 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}; }; } // namespace ads1115 diff --git a/components/ads1115_pol/__init__.py b/components/ads1115_pol/__init__.py new file mode 100644 index 0000000..503cd54 --- /dev/null +++ b/components/ads1115_pol/__init__.py @@ -0,0 +1,32 @@ +import esphome.codegen as cg +from esphome.components import i2c +import esphome.config_validation as cv +from esphome.const import CONF_ID + +DEPENDENCIES = ["i2c"] +MULTI_CONF = True + +ads1115_pol_ns = cg.esphome_ns.namespace("ads1115_pol") +ADS1115Component = ads1115_pol_ns.class_("ADS1115Component", cg.Component, i2c.I2CDevice) + +CONF_CONTINUOUS_MODE = "continuous_mode" +CONF_ADS1115_ID = "ads1115_id" + +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)) +) + + +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) + + cg.add(var.set_continuous_mode(config[CONF_CONTINUOUS_MODE])) diff --git a/components/ads1115_pol/ads1115_pol.cpp b/components/ads1115_pol/ads1115_pol.cpp new file mode 100644 index 0000000..35abc0a --- /dev/null +++ b/components/ads1115_pol/ads1115_pol.cpp @@ -0,0 +1,223 @@ +#include "ads1115_pol.h" +#include "esphome/core/hal.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace ads1115_pol { + +static const char *const TAG = "ads1115_pol"; +static const uint8_t ADS1115_REGISTER_CONVERSION = 0x00; +static const uint8_t ADS1115_REGISTER_CONFIG = 0x01; + +void ADS1115Component::setup() { + uint16_t value; + if (!this->read_byte_16(ADS1115_REGISTER_CONVERSION, &value)) { + this->mark_failed(); + return; + } + + uint16_t config = 0; + // Clear single-shot bit + // 0b0xxxxxxxxxxxxxxx + config |= 0b0000000000000000; + // Setup multiplexer + // 0bx000xxxxxxxxxxxx + config |= ADS1115_MULTIPLEXER_P0_N1 << 12; + + // Setup Gain + // 0bxxxx000xxxxxxxxx + config |= ADS1115_GAIN_6P144 << 9; + + if (this->continuous_mode_) { + // Set continuous mode + // 0bxxxxxxx0xxxxxxxx + config |= 0b0000000000000000; + } else { + // 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; + + if (!this->write_byte_16(ADS1115_REGISTER_CONFIG, config)) { + this->mark_failed(); + return; + } + this->prev_config_ = config; +} +void ADS1115Component::dump_config() { + ESP_LOGCONFIG(TAG, "ADS1115:"); + LOG_I2C_DEVICE(this); + if (this->is_failed()) { + ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL); + } +} +float ADS1115Component::request_measurement(int16_t& raw_value, ADS1115Multiplexer multiplexer, ADS1115Gain gain, + ADS1115Resolution resolution, ADS1115Samplerate samplerate) { + uint16_t config = this->prev_config_; + // Multiplexer + // 0bxBBBxxxxxxxxxxxx + config &= 0b1000111111111111; + config |= (multiplexer & 0b111) << 12; + + // Gain + // 0bxxxxBBBxxxxxxxxx + config &= 0b1111000111111111; + config |= (gain & 0b111) << 9; + + // Sample rate + // 0bxxxxxxxxBBBxxxxx + config &= 0b1111111100011111; + config |= (samplerate & 0b111) << 5; + + if (!this->continuous_mode_) { + // Start conversion + config |= 0b1000000000000000; + } + + if (!this->continuous_mode_ || this->prev_config_ != config) { + if (!this->write_byte_16(ADS1115_REGISTER_CONFIG, config)) { + this->status_set_warning(); + return NAN; + } + this->prev_config_ = config; + + // Delay calculated as: ceil((1000/SPS)+.5) + if (resolution == ADS1015_12_BITS) { + switch (samplerate) { + case ADS1115_8SPS: + delay(9); + break; + case ADS1115_16SPS: + delay(5); + break; + case ADS1115_32SPS: + delay(3); + break; + case ADS1115_64SPS: + case ADS1115_128SPS: + delay(2); + break; + default: + delay(1); + break; + } + } else { + switch (samplerate) { + case ADS1115_8SPS: + delay(126); // NOLINT + break; + case ADS1115_16SPS: + delay(63); // NOLINT + break; + case ADS1115_32SPS: + delay(32); + break; + case ADS1115_64SPS: + delay(17); + break; + case ADS1115_128SPS: + delay(9); + break; + case ADS1115_250SPS: + delay(5); + break; + case ADS1115_475SPS: + delay(3); + break; + case ADS1115_860SPS: + delay(2); + break; + } + } + + // in continuous mode, conversion will always be running, rely on the delay + // to ensure conversion is taking place with the correct settings + // can we use the rdy pin to trigger when a conversion is done? + if (!this->continuous_mode_) { + 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; + if (!this->read_byte_16(ADS1115_REGISTER_CONVERSION, &raw_conversion)) { + this->status_set_warning(); + return NAN; + } + + if (resolution == ADS1015_12_BITS) { + bool negative = (raw_conversion >> 15) == 1; + + // shift raw_conversion as it's only 12-bits, left justified + raw_conversion = raw_conversion >> (16 - ADS1015_12_BITS); + + // check if number was negative in order to keep the sign + if (negative) { + // the number was negative + // 1) set the negative bit back + raw_conversion |= 0x8000; + // 2) reset the former (shifted) negative bit + raw_conversion &= 0xF7FF; + } + } + + auto signed_conversion = static_cast(raw_conversion); + raw_value = signed_conversion; + float millivolts; + float divider = (resolution == ADS1115_16_BITS) ? 32768.0f : 2048.0f; + switch (gain) { + case ADS1115_GAIN_6P144: + millivolts = (signed_conversion * 6144) / divider; + break; + case ADS1115_GAIN_4P096: + millivolts = (signed_conversion * 4096) / divider; + break; + case ADS1115_GAIN_2P048: + millivolts = (signed_conversion * 2048) / divider; + break; + case ADS1115_GAIN_1P024: + millivolts = (signed_conversion * 1024) / divider; + break; + case ADS1115_GAIN_0P512: + millivolts = (signed_conversion * 512) / divider; + break; + case ADS1115_GAIN_0P256: + millivolts = (signed_conversion * 256) / divider; + break; + default: + millivolts = NAN; + } + + this->status_clear_warning(); + return millivolts / 1e3f; +} + +} // namespace ads1115 +} // namespace esphome diff --git a/components/ads1115_pol/ads1115_pol.h b/components/ads1115_pol/ads1115_pol.h new file mode 100644 index 0000000..006ea07 --- /dev/null +++ b/components/ads1115_pol/ads1115_pol.h @@ -0,0 +1,64 @@ +#pragma once + +#include "esphome/components/i2c/i2c.h" +#include "esphome/core/component.h" + +#include + +namespace esphome { +namespace ads1115_pol { + +enum ADS1115Multiplexer { + ADS1115_MULTIPLEXER_P0_N1 = 0b000, + ADS1115_MULTIPLEXER_P0_N3 = 0b001, + ADS1115_MULTIPLEXER_P1_N3 = 0b010, + ADS1115_MULTIPLEXER_P2_N3 = 0b011, + ADS1115_MULTIPLEXER_P0_NG = 0b100, + ADS1115_MULTIPLEXER_P1_NG = 0b101, + ADS1115_MULTIPLEXER_P2_NG = 0b110, + ADS1115_MULTIPLEXER_P3_NG = 0b111, +}; + +enum ADS1115Gain { + ADS1115_GAIN_6P144 = 0b000, + ADS1115_GAIN_4P096 = 0b001, + ADS1115_GAIN_2P048 = 0b010, + ADS1115_GAIN_1P024 = 0b011, + ADS1115_GAIN_0P512 = 0b100, + ADS1115_GAIN_0P256 = 0b101, +}; + +enum ADS1115Resolution { + ADS1115_16_BITS = 16, + ADS1015_12_BITS = 12, +}; + +enum ADS1115Samplerate { + ADS1115_8SPS = 0b000, + ADS1115_16SPS = 0b001, + ADS1115_32SPS = 0b010, + ADS1115_64SPS = 0b011, + ADS1115_128SPS = 0b100, + ADS1115_250SPS = 0b101, + ADS1115_475SPS = 0b110, + ADS1115_860SPS = 0b111 +}; + +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; } + + /// Helper method to request a measurement from a sensor. + float request_measurement(int16_t& raw_value, ADS1115Multiplexer multiplexer, ADS1115Gain gain, ADS1115Resolution resolution, + ADS1115Samplerate samplerate); + + protected: + uint16_t prev_config_{0}; + bool continuous_mode_; +}; + +} // namespace ads1115 +} // namespace esphome diff --git a/components/ads1115_pol/sensor/__init__.py b/components/ads1115_pol/sensor/__init__.py new file mode 100644 index 0000000..fcbeae2 --- /dev/null +++ b/components/ads1115_pol/sensor/__init__.py @@ -0,0 +1,98 @@ +import esphome.codegen as cg +from esphome.components import sensor, voltage_sampler +import esphome.config_validation as cv +from esphome.const import ( + CONF_GAIN, + CONF_ID, + CONF_MULTIPLEXER, + CONF_RESOLUTION, + CONF_SAMPLE_RATE, + DEVICE_CLASS_VOLTAGE, + STATE_CLASS_MEASUREMENT, + UNIT_VOLT, +) + +from .. import CONF_ADS1115_ID, ADS1115Component, ads1115_pol_ns + +AUTO_LOAD = ["voltage_sampler"] +DEPENDENCIES = ["ads1115_pol"] + +ADS1115Multiplexer = ads1115_pol_ns.enum("ADS1115Multiplexer") +MUX = { + "A0_A1": ADS1115Multiplexer.ADS1115_MULTIPLEXER_P0_N1, + "A0_A3": ADS1115Multiplexer.ADS1115_MULTIPLEXER_P0_N3, + "A1_A3": ADS1115Multiplexer.ADS1115_MULTIPLEXER_P1_N3, + "A2_A3": ADS1115Multiplexer.ADS1115_MULTIPLEXER_P2_N3, + "A0_GND": ADS1115Multiplexer.ADS1115_MULTIPLEXER_P0_NG, + "A1_GND": ADS1115Multiplexer.ADS1115_MULTIPLEXER_P1_NG, + "A2_GND": ADS1115Multiplexer.ADS1115_MULTIPLEXER_P2_NG, + "A3_GND": ADS1115Multiplexer.ADS1115_MULTIPLEXER_P3_NG, +} + +ADS1115Gain = ads1115_pol_ns.enum("ADS1115Gain") +GAIN = { + "6.144": ADS1115Gain.ADS1115_GAIN_6P144, + "4.096": ADS1115Gain.ADS1115_GAIN_4P096, + "2.048": ADS1115Gain.ADS1115_GAIN_2P048, + "1.024": ADS1115Gain.ADS1115_GAIN_1P024, + "0.512": ADS1115Gain.ADS1115_GAIN_0P512, + "0.256": ADS1115Gain.ADS1115_GAIN_0P256, +} + +ADS1115Resolution = ads1115_pol_ns.enum("ADS1115Resolution") +RESOLUTION = { + "16_BITS": ADS1115Resolution.ADS1115_16_BITS, + "12_BITS": ADS1115Resolution.ADS1015_12_BITS, +} + +ADS1115Samplerate = ads1115_pol_ns.enum("ADS1115Samplerate") +SAMPLERATE = { + "8": ADS1115Samplerate.ADS1115_8SPS, + "16": ADS1115Samplerate.ADS1115_16SPS, + "32": ADS1115Samplerate.ADS1115_32SPS, + "64": ADS1115Samplerate.ADS1115_64SPS, + "128": ADS1115Samplerate.ADS1115_128SPS, + "250": ADS1115Samplerate.ADS1115_250SPS, + "475": ADS1115Samplerate.ADS1115_475SPS, + "860": ADS1115Samplerate.ADS1115_860SPS, +} + +ADS1115Sensor = ads1115_pol_ns.class_( + "ADS1115Sensor", sensor.Sensor, cg.PollingComponent, voltage_sampler.VoltageSampler +) + +CONFIG_SCHEMA = ( + sensor.sensor_schema( + ADS1115Sensor, + unit_of_measurement=UNIT_VOLT, + accuracy_decimals=3, + device_class=DEVICE_CLASS_VOLTAGE, + state_class=STATE_CLASS_MEASUREMENT, + ) + .extend( + { + cv.GenerateID(CONF_ADS1115_ID): cv.use_id(ADS1115Component), + cv.Required(CONF_MULTIPLEXER): cv.enum(MUX, upper=True, space="_"), + cv.Required(CONF_GAIN): cv.enum(GAIN, string=True), + cv.Optional(CONF_RESOLUTION, default="16_BITS"): cv.enum( + RESOLUTION, upper=True, space="_" + ), + cv.Optional(CONF_SAMPLE_RATE, default="860"): cv.enum( + SAMPLERATE, string=True + ), + } + ) + .extend(cv.polling_component_schema("60s")) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await sensor.register_sensor(var, config) + await cg.register_component(var, config) + await cg.register_parented(var, config[CONF_ADS1115_ID]) + + cg.add(var.set_multiplexer(config[CONF_MULTIPLEXER])) + cg.add(var.set_gain(config[CONF_GAIN])) + cg.add(var.set_resolution(config[CONF_RESOLUTION])) + cg.add(var.set_samplerate(config[CONF_SAMPLE_RATE])) diff --git a/components/ads1115_pol/sensor/ads1115_pol_sensor.cpp b/components/ads1115_pol/sensor/ads1115_pol_sensor.cpp new file mode 100644 index 0000000..9395076 --- /dev/null +++ b/components/ads1115_pol/sensor/ads1115_pol_sensor.cpp @@ -0,0 +1,36 @@ +#include "ads1115_pol_sensor.h" + +#include "esphome/core/log.h" + +namespace esphome { +namespace ads1115_pol { + +static const char *const TAG = "ads1115_pol.sensor"; + +float ADS1115Sensor::sample(int16_t& raw_value) { + return this->parent_->request_measurement(raw_value, this->multiplexer_, this->gain_, this->resolution_, this->samplerate_); +} + +void ADS1115Sensor::update() { + int16_t raw_value = -1000; + float v = this->sample(raw_value); + 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); + } +} + +void ADS1115Sensor::dump_config() { + LOG_SENSOR(" ", "ADS1115_pol Sensor", this); + ESP_LOGCONFIG(TAG, " Multiplexer: %u", this->multiplexer_); + ESP_LOGCONFIG(TAG, " Gain: %u", this->gain_); + ESP_LOGCONFIG(TAG, " Resolution: %u", this->resolution_); + ESP_LOGCONFIG(TAG, " Sample rate: %u", this->samplerate_); +} + +} // namespace ads1115 +} // namespace esphome diff --git a/components/ads1115_pol/sensor/ads1115_pol_sensor.h b/components/ads1115_pol/sensor/ads1115_pol_sensor.h new file mode 100644 index 0000000..97e5cd5 --- /dev/null +++ b/components/ads1115_pol/sensor/ads1115_pol_sensor.h @@ -0,0 +1,38 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/helpers.h" + +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/voltage_sampler/voltage_sampler.h" + +#include "../ads1115_pol.h" + +namespace esphome { +namespace ads1115_pol { + +/// Internal holder class that is in instance of Sensor so that the hub can create individual sensors. +class ADS1115Sensor : public sensor::Sensor, + public PollingComponent, + //public voltage_sampler::VoltageSampler, + public Parented { + public: + void update() override; + void set_multiplexer(ADS1115Multiplexer multiplexer) { this->multiplexer_ = multiplexer; } + void set_gain(ADS1115Gain gain) { this->gain_ = gain; } + void set_resolution(ADS1115Resolution resolution) { this->resolution_ = resolution; } + void set_samplerate(ADS1115Samplerate samplerate) { this->samplerate_ = samplerate; } + float sample(int16_t& raw_value); + + void dump_config() override; + + protected: + ADS1115Multiplexer multiplexer_; + ADS1115Gain gain_; + ADS1115Resolution resolution_; + ADS1115Samplerate samplerate_; + uint64_t count_{0}; +}; + +} // namespace ads1115 +} // namespace esphome diff --git a/components/ads131m08/ads131m08.cpp b/components/ads131m08/ads131m08.cpp index 7ac4c09..473e5a6 100644 --- a/components/ads131m08/ads131m08.cpp +++ b/components/ads131m08/ads131m08.cpp @@ -84,6 +84,29 @@ void ADS131M08Hub::txf_init() } } +void ADS131M08Hub::initialize_ads131m08_datasheet() +{ + // enableSupplies(); + // GPIO.inputEnable('input'); // Enable GPIO connected to DRDY + // clkout.enable(8192000); // Enable 8.192 MHz clock to CLKIN + // SPI.enable(); // Enable SPI port + // SPI.wordLengthSet(24); // ADC default word length is 24 bits + // SPI.configCS(STAY_ASSERTED);// Configure CS to remain asserted until frame is complete + while(!GPIO.read()){} // Wait for DRDY to go high indicating it is ok to talk to ADC + adcRegisterWrite(REG_CLOCK, MASK_CLOCK_ALL_CH_DISABLE | OSR_1024 | PM_HIGH_RESOLUTION, 24); // Write CLOCK register; Turn off all channels so short frames can be written during config; // Re-write defaults for other bits in CLOCK register + adcRegisterWrite(REG_MODE, MODE_NO_RESET | DRDY_FMT_PULSE | WLENGTH_24_BITS | TIMEOUT_ENABLED, 24); // Write MODE register; Clear the RESET flag, make DRDY active low pulse; Re-write defaults for other bits in MODE register + adcRegisterWrite(REG_GAIN1, PGAGAIN3_32 | PGAGAIN1_32, 24); // Write GAIN1 register; Set channels 1 and 3 PGA gain to 32 in this example; Leave channels 0 and 2 at default gain of 1 + adcRegisterWrite(REG_THRSHLD_LSB, 0x09, 24); // Write THRSHLD_LSB register; Set DCBLOCK filter to have a corner frequency of 622 mHz + DMA.triggerSet(SPI);// Configure DMA to trigger when data comes in on the MCU SPI port + DMA.txAddrSet(SPI.rxAddr());// Set the DMA to take from the incoming SPI port + DMA.rxAddrSet(&adcData);// Set the DMA to send ADC data to a predefined memory location + adcRegisterWrite(REG_MODE, WLENGTH_32_BITS_MSB_SIGN_EXTEND | DRDY_FMT_PULSE | TIMEOUT_ENABLED, 24); // Write MODE register; Make ADC word size 32 bits to accommodate DMA; Re-write other set bits in MODE register + SPI.wordLengthSet(32); // Set SPI word size to 32 bits to accomodate DMA + adcRegisterWrite(REG_CLOCK, MASK_CLOCK_ALL_CH_ENABLE | OSR_1024 | PM_HIGH_RESOLUTION, 32); // Write CLOCK register; Turn on all ADC channels; Re-write defaults for other bits in CLOCK register + GPIO.interuptEnable();// Enable DRDY interrupt and begin streaming data +} + + /* adcRegisterWrite Short function that writes one ADC register at a time. Blocks return until SPI is idle. @@ -114,37 +137,10 @@ bool ADS131M08Hub::adcRegisterWrite(unsigned short addrMask, unsigned short data return true; } -void ADS131M08Hub::initialize_ads131m08_datasheet() -{ - // enableSupplies(); - // GPIO.inputEnable('input'); // Enable GPIO connected to DRDY - // clkout.enable(8192000); // Enable 8.192 MHz clock to CLKIN - // SPI.enable(); // Enable SPI port - // SPI.wordLengthSet(24); // ADC default word length is 24 bits - // SPI.configCS(STAY_ASSERTED);// Configure CS to remain asserted until frame is complete - while(!GPIO.read()){} // Wait for DRDY to go high indicating it is ok to talk to ADC - adcRegisterWrite(REG_CLOCK, MASK_CLOCK_ALL_CH_DISABLE | OSR_1024 | PM_HIGH_RESOLUTION, 24); // Write CLOCK register; Turn off all channels so short frames can be written during config - // Re-write defaults for other bits in CLOCK register - adcRegisterWrite(REG_MODE, MODE_NO_RESET | DRDY_FMT_PULSE | WLENGTH_24_BITS | TIMEOUT_ENABLED, 24); // Write MODE register; Clear the RESET flag, make DRDY active low pulse - // Re-write defaults for other bits in MODE register - adcRegisterWrite(REG_GAIN1, PGAGAIN3_32 | PGAGAIN1_32, 24); // Write GAIN1 register; Set channels 1 and 3 PGA gain to 32 in this example - // Leave channels 0 and 2 at default gain of 1 - adcRegisterWrite(REG_THRSHLD_LSB, 0x09, 24); // Write THRSHLD_LSB register; Set DCBLOCK filter to have a corner frequency of 622 mHz - DMA.triggerSet(SPI);// Configure DMA to trigger when data comes in on the MCU SPI port - DMA.txAddrSet(SPI.rxAddr());// Set the DMA to take from the incoming SPI port - DMA.rxAddrSet(&adcData);// Set the DMA to send ADC data to a predefined memory location - adcRegisterWrite(REG_MODE, WLENGTH_32_BITS_MSB_SIGN_EXTEND | DRDY_FMT_PULSE | TIMEOUT_ENABLED, 24); // Write MODE register; Make ADC word size 32 bits to accommodate DMA; - // Re-write other set bits in MODE register - SPI.wordLengthSet(32); // Set SPI word size to 32 bits to accomodate DMA - adcRegisterWrite(REG_CLOCK, MASK_CLOCK_ALL_CH_ENABLE | OSR_1024 | PM_HIGH_RESOLUTION, 32); // Write CLOCK register; Turn on all ADC channels; Re-write defaults for other bits in CLOCK register - GPIO.interuptEnable();// Enable DRDY interrupt and begin streaming data -} - - // ********************** end of from datasheet ************************ /* -void ADS131M08::read_all_channels() +void ADS131M08Hub::read_all_channels() { // Send RDATA command or read data directly SPI.transfer(0x12); // RDATA command @@ -187,6 +183,662 @@ void ADS131M08Hub::read_data_() } } +// =============== from tpcorrea ================= +ADS131M08Hub::ADS131M08Hub() : csPin(0), drdyPin(0), clkPin(0), misoPin(0), mosiPin(0), resetPin(0) +{ + for( uint16_t i = 0U; i < 8; i++){ + fullScale.ch[i].f = 1.2; // +-1.2V + pgaGain[i] = ADS131M08_PgaGain::PGA_1; + resultFloat.ch[i].f = 0.0; + resultRaw.ch[i].u[0] = 0U; + resultRaw.ch[i].u[1] = 0U; + } + +} + +uint8_t ADS131M08Hub::writeRegister(uint8_t address, uint16_t value) +{ + uint16_t res; + uint8_t addressRcv; + uint8_t bytesRcv; + uint16_t cmd = 0; + + digitalWrite(csPin, LOW); + delayMicroseconds(1); + + cmd = (CMD_WRITE_REG) | (address << 7) | 0; + + //res = spi.transfer16(cmd); + spi.transfer16(cmd); + spi.transfer(0x00); + + spi.transfer16(value); + spi.transfer(0x00); + + for(int i = 0; i < 8; i++) + { + spi.transfer16(0x0000); + spi.transfer(0x00); + } + + res = spi.transfer16(0x0000); + spi.transfer(0x00); + + for(int i = 0; i < 9; i++) + { + spi.transfer16(0x0000); + spi.transfer(0x00); + } + + delayMicroseconds(1); + digitalWrite(csPin, HIGH); + + addressRcv = (res & REGMASK_CMD_READ_REG_ADDRESS) >> 7; + bytesRcv = (res & REGMASK_CMD_READ_REG_BYTES); + + if (addressRcv == address) + { + return bytesRcv + 1; + } + return 0; +} + +void ADS131M08Hub::writeRegisterMasked(uint8_t address, uint16_t value, uint16_t mask) +{ + // Escribe un valor en el registro, aplicando la mascara para tocar unicamente los bits necesarios. + // No realiza el corrimiento de bits (shift), hay que pasarle ya el valor corrido a la posicion correcta + + // Leo el contenido actual del registro + uint16_t register_contents = readRegister(address); + + // Cambio bit aa bit la mascara (queda 1 en los bits que no hay que tocar y 0 en los bits a modificar) + // Se realiza un AND co el contenido actual del registro. Quedan "0" en la parte a modificar + register_contents = register_contents & ~mask; + + // se realiza un OR con el valor a cargar en el registro. Ojo, valor debe estar en el posicion (shitf) correcta + register_contents = register_contents | value; + + // Escribo nuevamente el registro + writeRegister(address, register_contents); +} + +uint16_t ADS131M08Hub::readRegister(uint8_t address) +{ + uint16_t cmd; + uint16_t data; + + cmd = CMD_READ_REG | (address << 7 | 0); + + digitalWrite(csPin, LOW); + delayMicroseconds(1); + + //data = spi.transfer16(cmd); + spi.transfer16(cmd); + spi.transfer(0x00); + + for(int i = 0; i < 9; i++) + { + spi.transfer16(0x0000); + spi.transfer(0x00); + } + + data = spi.transfer16(0x0000); + spi.transfer(0x00); + + for(int i = 0; i < 9; i++) + { + spi.transfer16(0x0000); + spi.transfer(0x00); + } + + delayMicroseconds(1); + digitalWrite(csPin, HIGH); + return data; +} + +void ADS131M08Hub::begin(uint8_t clk_pin, uint8_t miso_pin, uint8_t mosi_pin, uint8_t cs_pin, uint8_t drdy_pin, uint8_t reset_pin) +{ + // Set pins up + csPin = cs_pin; + drdyPin = drdy_pin; + clkPin = clk_pin; + misoPin = miso_pin; + mosiPin = mosi_pin; + resetPin = reset_pin; + + spi = SPIClass(mosi_pin, miso_pin, clk_pin, cs_pin); + spi.begin(); + spi.beginTransaction(settings); + // Configure chip select as an output + pinMode(csPin, OUTPUT); + pinMode(resetPin, OUTPUT); + // Configure DRDY as an input + pinMode(drdyPin, INPUT); +} + +int8_t ADS131M08Hub::isDataReadySoft(byte channel) +{ + if (channel == 0) + { + return (readRegister(REG_STATUS) & REGMASK_STATUS_DRDY0); + } + else if (channel == 1) + { + return (readRegister(REG_STATUS) & REGMASK_STATUS_DRDY1); + } + else if (channel == 2) + { + return (readRegister(REG_STATUS) & REGMASK_STATUS_DRDY2); + } + else if (channel == 3) + { + return (readRegister(REG_STATUS) & REGMASK_STATUS_DRDY3); + } + else if (channel == 4) + { + return (readRegister(REG_STATUS) & REGMASK_STATUS_DRDY4); + } + else if (channel == 5) + { + return (readRegister(REG_STATUS) & REGMASK_STATUS_DRDY5); + } + else if (channel == 6) + { + return (readRegister(REG_STATUS) & REGMASK_STATUS_DRDY6); + } + else if (channel == 7) + { + return (readRegister(REG_STATUS) & REGMASK_STATUS_DRDY7); + } + else + { + return -1; + } +} + +bool ADS131M08Hub::isResetStatus(void) +{ + return (readRegister(REG_STATUS) & REGMASK_STATUS_RESET); +} + +bool ADS131M08Hub::isLockSPI(void) +{ + return (readRegister(REG_STATUS) & REGMASK_STATUS_LOCK); +} + +bool ADS131M08Hub::setDrdyFormat(uint8_t drdyFormat) +{ + if (drdyFormat > 1) + { + return false; + } + else + { + writeRegisterMasked(REG_MODE, drdyFormat, REGMASK_MODE_DRDY_FMT); + return true; + } +} + +bool ADS131M08Hub::setDrdyStateWhenUnavailable(uint8_t drdyState) +{ + if (drdyState > 1) + { + return false; + } + else + { + writeRegisterMasked(REG_MODE, drdyState < 1, REGMASK_MODE_DRDY_HiZ); + return true; + } +} + +bool ADS131M08Hub::setPowerMode(uint8_t powerMode) +{ + if (powerMode > 3) + { + return false; + } + else + { + writeRegisterMasked(REG_CLOCK, powerMode, REGMASK_CLOCK_PWR); + return true; + } +} + +bool ADS131M08Hub::setOsr(uint16_t osr) +{ + if (osr > 7) + { + return false; + } + else + { + writeRegisterMasked(REG_CLOCK, osr << 2 , REGMASK_CLOCK_OSR); + return true; + } +} + +void ADS131M08Hub::setFullScale(uint8_t channel, float scale) +{ + if (channel > 7) { + return; + } + + this->fullScale.ch[channel].f = scale; + +} + +float ADS131M08Hub::getFullScale(uint8_t channel) +{ + if (channel > 7) { + return 0.0; + } + + return this->fullScale.ch[channel].f; + +} + +void ADS131M08Hub::reset() +{ + digitalWrite(this->resetPin, LOW); + delay(10); + digitalWrite(this->resetPin, HIGH); +} + +bool ADS131M08Hub::setChannelEnable(uint8_t channel, uint16_t enable) +{ + if (channel > 7) + { + return false; + } + if (channel == 0) + { + writeRegisterMasked(REG_CLOCK, enable << 8, REGMASK_CLOCK_CH0_EN); + return true; + } + else if (channel == 1) + { + writeRegisterMasked(REG_CLOCK, enable << 9, REGMASK_CLOCK_CH1_EN); + return true; + } + else if (channel == 2) + { + writeRegisterMasked(REG_CLOCK, enable << 10, REGMASK_CLOCK_CH2_EN); + return true; + } + else if (channel == 3) + { + writeRegisterMasked(REG_CLOCK, enable << 11, REGMASK_CLOCK_CH3_EN); + return true; + } + else if (channel == 4) + { + writeRegisterMasked(REG_CLOCK, enable << 11, REGMASK_CLOCK_CH4_EN); + return true; + } + else if (channel == 5) + { + writeRegisterMasked(REG_CLOCK, enable << 11, REGMASK_CLOCK_CH5_EN); + return true; + } + else if (channel == 6) + { + writeRegisterMasked(REG_CLOCK, enable << 11, REGMASK_CLOCK_CH6_EN); + return true; + } + else if (channel == 7) + { + writeRegisterMasked(REG_CLOCK, enable << 11, REGMASK_CLOCK_CH7_EN); + return true; + } + return false; +} + +bool ADS131M08Hub::setChannelPGA(uint8_t channel, ADS131M08_PgaGain pga) +{ uint16_t pgaCode = (uint16_t) pga; + + if (channel > 7) + { + return false; + } + if (channel == 0) + { + writeRegisterMasked(REG_GAIN1, pgaCode, REGMASK_GAIN_PGAGAIN0); + this->pgaGain[0] = pga; + return true; + } + else if (channel == 1) + { + writeRegisterMasked(REG_GAIN1, pgaCode << 4, REGMASK_GAIN_PGAGAIN1); + this->pgaGain[1] = pga; + return true; + } + else if (channel == 2) + { + writeRegisterMasked(REG_GAIN1, pgaCode << 8, REGMASK_GAIN_PGAGAIN2); + this->pgaGain[2] = pga; + return true; + } + else if (channel == 3) + { + writeRegisterMasked(REG_GAIN1, pgaCode << 12, REGMASK_GAIN_PGAGAIN3); + this->pgaGain[3] = pga; + return true; + } + if (channel == 4) + { + writeRegisterMasked(REG_GAIN2, pgaCode, REGMASK_GAIN_PGAGAIN4); + this->pgaGain[4] = pga; + return true; + } + else if (channel == 5) + { + writeRegisterMasked(REG_GAIN2, pgaCode << 4, REGMASK_GAIN_PGAGAIN5); + this->pgaGain[5] = pga; + return true; + } + else if (channel == 6) + { + writeRegisterMasked(REG_GAIN2, pgaCode << 8, REGMASK_GAIN_PGAGAIN6); + this->pgaGain[6] = pga; + return true; + } + else if (channel == 7) + { + writeRegisterMasked(REG_GAIN2, pgaCode << 12, REGMASK_GAIN_PGAGAIN7); + this->pgaGain[7] = pga; + return true; + } + return false; +} + +ADS131M08_PgaGain ADS131M08Hub::getChannelPGA(uint8_t channel) +{ + if(channel > 7) + { + return ADS131M08_PgaGain::PGA_INVALID; + } + return this->pgaGain[channel]; +} + +void ADS131M08Hub::setGlobalChop(uint16_t global_chop) +{ + writeRegisterMasked(REG_CFG, global_chop << 8, REGMASK_CFG_GC_EN); +} + +void ADS131M08Hub::setGlobalChopDelay(uint16_t delay) +{ + writeRegisterMasked(REG_CFG, delay << 9, REGMASK_CFG_GC_DLY); +} + +bool ADS131M08Hub::setInputChannelSelection(uint8_t channel, uint8_t input) +{ + if (channel > 3) + { + return false; + } + if (channel == 0) + { + writeRegisterMasked(REG_CH0_CFG, input, REGMASK_CHX_CFG_MUX); + return true; + } + else if (channel == 1) + { + writeRegisterMasked(REG_CH1_CFG, input, REGMASK_CHX_CFG_MUX); + return true; + } + else if (channel == 2) + { + writeRegisterMasked(REG_CH2_CFG, input, REGMASK_CHX_CFG_MUX); + return true; + } + else if (channel == 3) + { + writeRegisterMasked(REG_CH3_CFG, input, REGMASK_CHX_CFG_MUX); + return true; + } + else if (channel == 4) + { + writeRegisterMasked(REG_CH4_CFG, input, REGMASK_CHX_CFG_MUX); + return true; + } + else if (channel == 5) + { + writeRegisterMasked(REG_CH5_CFG, input, REGMASK_CHX_CFG_MUX); + return true; + } + else if (channel == 6) + { + writeRegisterMasked(REG_CH6_CFG, input, REGMASK_CHX_CFG_MUX); + return true; + } + else if (channel == 7) + { + writeRegisterMasked(REG_CH7_CFG, input, REGMASK_CHX_CFG_MUX); + return true; + } + return false; +} + +bool ADS131M08Hub::setChannelOffsetCalibration(uint8_t channel, int32_t offset) +{ + + uint16_t MSB = offset >> 8; + uint8_t LSB = offset; + + if (channel > 7) + { + return false; + } + if (channel == 0) + { + writeRegisterMasked(REG_CH0_OCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH0_OCAL_LSB, LSB << 8, REGMASK_CHX_OCAL0_LSB); + return true; + } + else if (channel == 1) + { + writeRegisterMasked(REG_CH1_OCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH1_OCAL_LSB, LSB << 8, REGMASK_CHX_OCAL0_LSB); + return true; + } + else if (channel == 2) + { + writeRegisterMasked(REG_CH2_OCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH2_OCAL_LSB, LSB << 8, REGMASK_CHX_OCAL0_LSB); + return true; + } + else if (channel == 3) + { + writeRegisterMasked(REG_CH3_OCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH3_OCAL_LSB, LSB << 8 , REGMASK_CHX_OCAL0_LSB); + return true; + } + else if (channel == 4) + { + writeRegisterMasked(REG_CH4_OCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH4_OCAL_LSB, LSB << 8 , REGMASK_CHX_OCAL0_LSB); + return true; + } + else if (channel == 5) + { + writeRegisterMasked(REG_CH5_OCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH5_OCAL_LSB, LSB << 8 , REGMASK_CHX_OCAL0_LSB); + return true; + } + else if (channel == 6) + { + writeRegisterMasked(REG_CH6_OCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH6_OCAL_LSB, LSB << 8 , REGMASK_CHX_OCAL0_LSB); + return true; + } + else if (channel == 7) + { + writeRegisterMasked(REG_CH7_OCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH7_OCAL_LSB, LSB << 8 , REGMASK_CHX_OCAL0_LSB); + return true; + } + return false; +} + +bool ADS131M08Hub::setChannelGainCalibration(uint8_t channel, uint32_t gain) +{ + + uint16_t MSB = gain >> 8; + uint8_t LSB = gain; + + if (channel > 7) + { + return false; + } + if (channel == 0) + { + writeRegisterMasked(REG_CH0_GCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH0_GCAL_LSB, LSB << 8, REGMASK_CHX_GCAL0_LSB); + return true; + } + else if (channel == 1) + { + writeRegisterMasked(REG_CH1_GCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH1_GCAL_LSB, LSB << 8, REGMASK_CHX_GCAL0_LSB); + return true; + } + else if (channel == 2) + { + writeRegisterMasked(REG_CH2_GCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH2_GCAL_LSB, LSB << 8, REGMASK_CHX_GCAL0_LSB); + return true; + } + else if (channel == 3) + { + writeRegisterMasked(REG_CH3_GCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH3_GCAL_LSB, LSB << 8, REGMASK_CHX_GCAL0_LSB); + return true; + } + else if (channel == 4) + { + writeRegisterMasked(REG_CH4_GCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH4_GCAL_LSB, LSB << 8, REGMASK_CHX_GCAL0_LSB); + return true; + } + else if (channel == 5) + { + writeRegisterMasked(REG_CH5_GCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH5_GCAL_LSB, LSB << 8, REGMASK_CHX_GCAL0_LSB); + return true; + } + else if (channel == 6) + { + writeRegisterMasked(REG_CH6_GCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH6_GCAL_LSB, LSB << 8, REGMASK_CHX_GCAL0_LSB); + return true; + } + else if (channel == 7) + { + writeRegisterMasked(REG_CH7_GCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH7_GCAL_LSB, LSB << 8, REGMASK_CHX_GCAL0_LSB); + return true; + } + return false; +} + +bool ADS131M08Hub::isDataReady() +{ + if (digitalRead(drdyPin) == HIGH) + { + return false; + } + return true; +} + +uint16_t ADS131M08Hub::getId() +{ + return readRegister(REG_ID); +} + +uint16_t ADS131M08Hub::getModeReg() +{ + return readRegister(REG_MODE); +} + +uint16_t ADS131M08Hub::getClockReg() +{ + return readRegister(REG_CLOCK); +} + +uint16_t ADS131M08Hub::getCfgReg() +{ + return readRegister(REG_CFG); +} + +AdcOutput ADS131M08Hub::readAdcRaw(void) +{ + uint8_t x = 0; + uint8_t x2 = 0; + uint8_t x3 = 0; + int32_t aux; + AdcOutput res; + + digitalWrite(csPin, LOW); + delayMicroseconds(1); + + x = spi.transfer(0x00); + x2 = spi.transfer(0x00); + spi.transfer(0x00); + + this->resultRaw.status = ((x << 8) | x2); + + for(int i = 0; i<8; i++) + { + x = spi.transfer(0x00); + x2 = spi.transfer(0x00); + x3 = spi.transfer(0x00); + + aux = (((x << 16) | (x2 << 8) | x3) & 0x00FFFFFF); + if (aux > 0x7FFFFF) + { + this->resultRaw.ch[i].i = ((~(aux)&0x00FFFFFF) + 1) * -1; + } + else + { + this->resultRaw.ch[i].i = aux; + } + } + + delayMicroseconds(1); + digitalWrite(csPin, HIGH); + + return this->resultRaw; +} + +float ADS131M08Hub::scaleResult(uint8_t num) +{ + if( num >= 8) { + return 0.0; + } + + return this->resultFloat.ch[num].f = (float)(this->resultRaw.ch[num].i * rawToVolts * this->fullScale.ch[num].f); +} + +AdcOutput ADS131M08Hub::scaleResult(void) +{ + // update status + this->resultFloat.status = this->resultRaw.status; + // Scale all channels + for(int i = 0; i<8; i++) + { + this->scaleResult(i); + } + + return this->resultFloat; +} + +AdcOutput ADS131M08Hub::readAdcFloat(void) +{ + this->readAdcRaw(); + return this->scaleResult(); +} +// end of from tpcorrea void ADS131M08Hub::dump_config() { ESP_LOGCONFIG(TAG, "ADS131M08:"); diff --git a/sthome-ut8.yaml b/sthome-ut8.yaml index ae88d47..6c5efe1 100644 --- a/sthome-ut8.yaml +++ b/sthome-ut8.yaml @@ -2,7 +2,7 @@ external_components: - source: type: local path: components # Path relative to this YAML file - components: [ ads131m08, ads1115_int ] + components: [ ads1115_int, ads1115_pol ] #, ads131m08 ] packages: - !include common/wifi.yaml @@ -259,21 +259,28 @@ i2c: scl: GPIO22 scan: true id: bus_a - frequency: 10kHz - -ads1115_int: - - address: 0x48 - id: ads1115_48 - alert_rdy_pin: GPIO3 - continuous_mode: true + frequency: 400kHz + ads1115: - - address: 0x49 - id: ads1115_49 - continuous_mode: true - address: 0x4A id: ads1115_4A continuous_mode: true +ads1115_pol: + - address: 0x49 + id: ads1115_49 + continuous_mode: true + +ads1115_int: + - address: 0x48 + id: ads1115_48 + continuous_mode: true + alert_rdy_pin: + number: GPIO3 + mode: + input: true + pullup: true + spi: - id: spi_bus0 clk_pin: GPIO18 @@ -1490,45 +1497,45 @@ binary_sensor: //ESP_LOGI("solar", "Heating enabled? : %s", enabled ? "Yes" : "No"); return enabled; -ads131m08: - id: highres_adc - cs_pin: GPIO5 - drdy_pin: GPIO10 - reference_voltage: 1.25 +#ads131m08: +# id: highres_adc +# cs_pin: GPIO5 +# drdy_pin: GPIO10 +# reference_voltage: 1.25 sensor: - - platform: ads131m08 - ads131m08_id: highres_adc - channel: 0 - name: "ADS Channel 0 Voltage" - - platform: ads131m08 - ads131m08_id: highres_adc - channel: 1 - name: "ADS Channel 1 Voltage" - - platform: ads131m08 - ads131m08_id: highres_adc - channel: 2 - name: "ADS Channel 2 Voltage" - - platform: ads131m08 - ads131m08_id: highres_adc - channel: 3 - name: "ADS Channel 3 Voltage" - - platform: ads131m08 - ads131m08_id: highres_adc - channel: 4 - name: "ADS Channel 4 Voltage" - - platform: ads131m08 - ads131m08_id: highres_adc - channel: 5 - name: "ADS Channel 5 Voltage" - - platform: ads131m08 - ads131m08_id: highres_adc - channel: 6 - name: "ADS Channel 6 Voltage" - - platform: ads131m08 - ads131m08_id: highres_adc - channel: 7 - name: "ADS Channel 7 Voltage" +# - platform: ads131m08 +# ads131m08_id: highres_adc +# channel: 0 +# name: "ADS Channel 0 Voltage" +# - platform: ads131m08 +# ads131m08_id: highres_adc +# channel: 1 +# name: "ADS Channel 1 Voltage" +# - platform: ads131m08 +# ads131m08_id: highres_adc +# channel: 2 +# name: "ADS Channel 2 Voltage" +# - platform: ads131m08 +# ads131m08_id: highres_adc +# channel: 3 +# name: "ADS Channel 3 Voltage" +# - platform: ads131m08 +# ads131m08_id: highres_adc +# channel: 4 +# name: "ADS Channel 4 Voltage" +# - platform: ads131m08 +# ads131m08_id: highres_adc +# channel: 5 +# name: "ADS Channel 5 Voltage" +# - platform: ads131m08 +# ads131m08_id: highres_adc +# channel: 6 +# name: "ADS Channel 6 Voltage" +# - platform: ads131m08 +# ads131m08_id: highres_adc +# channel: 7 +# name: "ADS Channel 7 Voltage" - platform: debug free: @@ -1542,7 +1549,7 @@ sensor: # NB! Keep all ads1115 sample rates the same. Update intervals should be more than or equal to 1/sample_rate # ads1115_48 - - platform: ads1115 + - platform: ads1115_pol multiplexer: 'A2_A3' gain: 2.048 # 4.096 ads1115_id: ads1115_49 @@ -1555,25 +1562,25 @@ sensor: unit_of_measurement: "A" icon: "mdi:current" update_interval: 8ms #5ms - filters: - # - offset: 0.0002 - - lambda: return x * x; - - sliding_window_moving_average: - window_size: 1250 #1250 #5000 - send_every: 208 #208 #416 - send_first_at: 208 #208 #416 - - lambda: return sqrt(x); - - multiply: 95 #88.44 - - offset: 0.0 #-0.2 - - lambda: |- - if(abs(x) < 0.1) - return 0.0; - return x; + #filters: + ## - offset: 0.0002 + # - lambda: return x * x; + # - sliding_window_moving_average: + # window_size: 1250 #1250 #5000 + # send_every: 208 #208 #416 + # send_first_at: 208 #208 #416 + # - lambda: return sqrt(x); + # - multiply: 95 #88.44 + # - offset: 0.0 #-0.2 + # - lambda: |- + # if(abs(x) < 0.1) + # return 0.0; + # return x; - platform: ads1115_int multiplexer: 'A0_A1' gain: 2.048 # 4.096 - ads1115_int_id: ads1115_48 + ads1115_id: ads1115_48 sample_rate: 860 # 475 #860 state_class: measurement device_class: current @@ -1583,26 +1590,26 @@ sensor: unit_of_measurement: "A" icon: "mdi:current" # update_interval: 8ms #5ms - filters: - # - offset: 0.0002 - - lambda: return x * x; - - sliding_window_moving_average: - window_size: 1250 #1250 #5000 - send_every: 208 #208 #416 - send_first_at: 208 #208 #416 - - lambda: return sqrt(x); - - multiply: 555 #95 #88.44 - - offset: 0.0 #-0.2 - - lambda: |- - if(abs(x) < 0.1) - return 0.0; - return x; + #filters: + ## - offset: 0.0002 + # - lambda: return x * x; + # - sliding_window_moving_average: + # window_size: 1250 #1250 #5000 + # send_every: 208 #208 #416 + # send_first_at: 208 #208 #416 + # - lambda: return sqrt(x); + # - multiply: 555 #95 #88.44 + # - offset: 0.0 #-0.2 + # - lambda: |- + # if(abs(x) < 0.1) + # return 0.0; + # return x; # ads1115_49 - platform: ads1115_int multiplexer: 'A2_A3' gain: 2.048 # 4.096 - ads1115_int_id: ads1115_48 + ads1115_id: ads1115_48 name: "ADC Geyser Current" id: geyser_current sample_rate: 860 #860 @@ -1612,30 +1619,30 @@ sensor: unit_of_measurement: "A" icon: "mdi:current" #update_interval: 8ms #5ms - filters: - - lambda: return x * x; - - sliding_window_moving_average: - window_size: 1250 #1250 #5000 - send_every: 208 #208 #416 - send_first_at: 208 #208 #416 - - lambda: return sqrt(x); - - multiply: 555 #92.1 #91.1 #88.44 - - offset: 0.0 #-0.2 - - lambda: |- - if(abs(x) < 0.1) - return 0.0; - return x; - on_value_range: - - below: 5.0 - then: - - lambda: |- - ESP_LOGI("geyser", "No geyser current detected. Geyser not heating."); - - above: 5.0 - then: - - lambda: |- - ESP_LOGI("geyser", "Geyser current detected. Geyser was energised."); + #filters: + # - lambda: return x * x; + # - sliding_window_moving_average: + # window_size: 1250 #1250 #5000 + # send_every: 208 #208 #416 + # send_first_at: 208 #208 #416 + # - lambda: return sqrt(x); + # - multiply: 555 #92.1 #91.1 #88.44 + # - offset: 0.0 #-0.2 + ## - lambda: |- + ## if(abs(x) < 0.1) + ## return 0.0; + ## return x; + ##on_value_range: + # - below: 5.0 + # then: + # - lambda: |- + # ESP_LOGI("geyser", "No geyser current detected. Geyser not heating."); + # - above: 5.0 + # then: + # - lambda: |- + # ESP_LOGI("geyser", "Geyser current detected. Geyser was energised."); # - - platform: ads1115 + - platform: ads1115_pol multiplexer: A0_A1 gain: 2.048 # 4.096 ads1115_id: ads1115_49 @@ -1651,20 +1658,20 @@ sensor: unit_of_measurement: "A" icon: "mdi:current" update_interval: 8ms #5ms - filters: - # - offset: 0.0002 - - lambda: return x * x; - - sliding_window_moving_average: - window_size: 1250 #1250 #5000 - send_every: 208 #208 #416 - send_first_at: 208 #208 #416 - - lambda: return sqrt(x); - - multiply: 95.8 #88.44 - - offset: 0.0 #-0.2 - - lambda: |- - if(abs(x) < 0.1) - return 0.0; - return x; + #filters: + ## - offset: 0.0002 + # - lambda: return x * x; + # - sliding_window_moving_average: + # window_size: 1250 #1250 #5000 + # send_every: 208 #208 #416 + # send_first_at: 208 #208 #416 + # - lambda: return sqrt(x); + # - multiply: 95.8 #88.44 + # - offset: 0.0 #-0.2 + # - lambda: |- + # if(abs(x) < 0.1) + # return 0.0; + # return x; # mod end ####################### # # ads1115_4A