mirror of
https://github.com/esphome/esphome.git
synced 2026-11-15 17:45:57 +00:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94152b718f | ||
|
|
1942887031 | ||
|
|
5a43a6cbcf | ||
|
|
10ce4c6862 | ||
|
|
7356dd3eaf | ||
|
|
00a3d45614 |
No files matched your search
@@ -26,6 +26,7 @@ esphome/components/ade7953_base/* @angelnu
|
||||
esphome/components/ade7953_i2c/* @angelnu
|
||||
esphome/components/ade7953_spi/* @angelnu
|
||||
esphome/components/ads1118/* @solomondg1
|
||||
esphome/components/ads1xxx/* @bdraco
|
||||
esphome/components/ags10/* @mak-42
|
||||
esphome/components/aic3204/* @kbx81
|
||||
esphome/components/airthings_ble/* @jeromelaban
|
||||
|
||||
@@ -3,6 +3,7 @@ from esphome.components import i2c
|
||||
import esphome.config_validation as cv
|
||||
from esphome.types import ConfigType
|
||||
|
||||
AUTO_LOAD = ["ads1xxx"]
|
||||
DEPENDENCIES = ["i2c"]
|
||||
DOMAIN = "ads1115"
|
||||
MULTI_CONF = True
|
||||
@@ -26,6 +27,4 @@ CONFIG_SCHEMA = (
|
||||
|
||||
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
var = await i2c.new_i2c_component(config)
|
||||
|
||||
cg.add(var.set_continuous_mode(config[CONF_CONTINUOUS_MODE]))
|
||||
await i2c.new_i2c_component(config, config[CONF_CONTINUOUS_MODE])
|
||||
@@ -1,61 +1,19 @@
|
||||
#include "ads1115.h"
|
||||
#include "esphome/components/ads1xxx/ads1xxx.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome::ads1115 {
|
||||
|
||||
ESPHOME_LOG_TAG(TAG, "ads1115");
|
||||
static const uint8_t ADS1115_REGISTER_CONVERSION = 0x00;
|
||||
static const uint8_t ADS1115_REGISTER_CONFIG = 0x01;
|
||||
static constexpr uint8_t REGISTER_CONVERSION = 0x00;
|
||||
static constexpr uint8_t REGISTER_CONFIG = 0x01;
|
||||
static constexpr uint16_t CONFIG_COMPARATOR_DISABLE = 0b11;
|
||||
|
||||
void ADS1115Component::setup() {
|
||||
uint16_t value;
|
||||
if (!this->setup_check(this->read_byte_16(ADS1115_REGISTER_CONVERSION, &value)))
|
||||
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->setup_check(this->write_byte_16(ADS1115_REGISTER_CONFIG, config)))
|
||||
const uint16_t config = ads1xxx::CONFIG_DATA_RATE | CONFIG_COMPARATOR_DISABLE |
|
||||
(this->continuous_mode_ ? 0 : ads1xxx::CONFIG_SINGLE_SHOT);
|
||||
if (!this->setup_check(this->write_byte_16(REGISTER_CONFIG, config)))
|
||||
return;
|
||||
this->prev_config_ = config;
|
||||
}
|
||||
@@ -63,92 +21,23 @@ void ADS1115Component::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "ADS1115:");
|
||||
LOG_I2C_DEVICE(this);
|
||||
}
|
||||
float ADS1115Component::request_measurement(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;
|
||||
}
|
||||
float ADS1115Component::request_measurement(uint16_t config_bits, uint8_t conversion_delay_ms) {
|
||||
const uint16_t config = CONFIG_COMPARATOR_DISABLE | config_bits |
|
||||
(this->continuous_mode_ ? 0 : ads1xxx::CONFIG_SINGLE_SHOT | ads1xxx::CONFIG_START);
|
||||
|
||||
if (!this->continuous_mode_ || this->prev_config_ != config) {
|
||||
if (!this->status_comm_check(this->write_byte_16(ADS1115_REGISTER_CONFIG, config)))
|
||||
if (!this->status_comm_check(this->write_byte_16(REGISTER_CONFIG, config)))
|
||||
return NAN;
|
||||
this->prev_config_ = config;
|
||||
delay(conversion_delay_ms);
|
||||
|
||||
// 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?
|
||||
// In continuous mode the delay alone covers a conversion with the new settings
|
||||
if (!this->continuous_mode_) {
|
||||
uint32_t start = millis();
|
||||
while (this->read_byte_16(ADS1115_REGISTER_CONFIG, &config) && (config >> 15) == 0) {
|
||||
uint16_t status;
|
||||
while (this->read_byte_16(REGISTER_CONFIG, &status) && (status & ads1xxx::CONFIG_START) == 0) {
|
||||
if (millis() - start > 100) {
|
||||
ESP_LOGW(TAG, "Reading ADS1115 timed out");
|
||||
this->status_set_warning();
|
||||
this->status_comm_result(false, LOG_STR("Conversion timed out"));
|
||||
return NAN;
|
||||
}
|
||||
yield();
|
||||
@@ -156,43 +45,10 @@ float ADS1115Component::request_measurement(ADS1115Multiplexer multiplexer, ADS1
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t raw_conversion;
|
||||
if (!this->status_comm_result(this->read_byte_16(ADS1115_REGISTER_CONVERSION, &raw_conversion)))
|
||||
uint16_t raw;
|
||||
if (!this->status_comm_result(this->read_byte_16(REGISTER_CONVERSION, &raw)))
|
||||
return NAN;
|
||||
|
||||
if (resolution == ADS1015_12_BITS) {
|
||||
// ADS1015 returns 12-bit value left-justified in 16 bits; shift right and sign-extend
|
||||
raw_conversion = static_cast<uint16_t>(static_cast<int16_t>(raw_conversion) >> (16 - ADS1015_12_BITS));
|
||||
}
|
||||
|
||||
auto signed_conversion = static_cast<int16_t>(raw_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;
|
||||
}
|
||||
|
||||
return millivolts / 1e3f;
|
||||
return ads1xxx::to_volts(static_cast<int16_t>(raw), config_bits);
|
||||
}
|
||||
|
||||
} // namespace esphome::ads1115
|
||||
@@ -3,60 +3,20 @@
|
||||
#include "esphome/components/i2c/i2c.h"
|
||||
#include "esphome/core/component.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome::ads1115 {
|
||||
|
||||
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 final : public Component, public i2c::I2CDevice {
|
||||
public:
|
||||
explicit ADS1115Component(bool continuous_mode) : continuous_mode_(continuous_mode) {}
|
||||
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(ADS1115Multiplexer multiplexer, ADS1115Gain gain, ADS1115Resolution resolution,
|
||||
ADS1115Samplerate samplerate);
|
||||
/// Returns volts for `config_bits` (multiplexer, gain and data rate fields of the config register).
|
||||
float request_measurement(uint16_t config_bits, uint8_t conversion_delay_ms);
|
||||
|
||||
protected:
|
||||
uint16_t prev_config_{0};
|
||||
bool continuous_mode_;
|
||||
const bool continuous_mode_;
|
||||
};
|
||||
|
||||
} // namespace esphome::ads1115
|
||||
@@ -1,10 +1,10 @@
|
||||
import math
|
||||
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import sensor, voltage_sampler
|
||||
from esphome.components.ads1xxx import MUX_GAIN_SCHEMA, mux_gain_bits
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_GAIN,
|
||||
CONF_ID,
|
||||
CONF_MULTIPLEXER,
|
||||
CONF_RESOLUTION,
|
||||
CONF_SAMPLE_RATE,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
@@ -18,45 +18,13 @@ from .. import CONF_ADS1115_ID, ADS1115Component, ads1115_ns
|
||||
AUTO_LOAD = ["voltage_sampler"]
|
||||
DEPENDENCIES = ["ads1115"]
|
||||
|
||||
ADS1115Multiplexer = ads1115_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_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_ns.enum("ADS1115Resolution")
|
||||
RESOLUTION = {
|
||||
"16_BITS": ADS1115Resolution.ADS1115_16_BITS,
|
||||
"12_BITS": ADS1115Resolution.ADS1015_12_BITS,
|
||||
}
|
||||
|
||||
ADS1115Samplerate = ads1115_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,
|
||||
RESOLUTION = {"16_BITS": 16, "12_BITS": 12}
|
||||
# Samples per second of each data rate code; the ADS1015 (12 bits) runs faster
|
||||
DATA_RATES = {
|
||||
16: (8, 16, 32, 64, 128, 250, 475, 860),
|
||||
12: (128, 250, 490, 920, 1600, 2400, 3300, 3300),
|
||||
}
|
||||
SAMPLERATE = {str(sps): i for i, sps in enumerate(DATA_RATES[16])}
|
||||
|
||||
ADS1115Sensor = ads1115_ns.class_(
|
||||
"ADS1115Sensor", sensor.Sensor, cg.PollingComponent, voltage_sampler.VoltageSampler
|
||||
@@ -73,8 +41,7 @@ CONFIG_SCHEMA = (
|
||||
.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),
|
||||
**MUX_GAIN_SCHEMA,
|
||||
cv.Optional(CONF_RESOLUTION, default="16_BITS"): cv.enum(
|
||||
RESOLUTION, upper=True, space="_"
|
||||
),
|
||||
@@ -88,12 +55,9 @@ CONFIG_SCHEMA = (
|
||||
|
||||
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await sensor.register_sensor(var, config)
|
||||
rate = config[CONF_SAMPLE_RATE].enum_value
|
||||
sps = DATA_RATES[config[CONF_RESOLUTION].enum_value][rate]
|
||||
delay_ms = math.ceil(1000 / sps + 0.5)
|
||||
var = await sensor.new_sensor(config, mux_gain_bits(config) | rate << 5, delay_ms)
|
||||
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]))
|
||||
@@ -7,7 +7,7 @@ namespace esphome::ads1115 {
|
||||
ESPHOME_LOG_TAG(TAG, "ads1115.sensor");
|
||||
|
||||
float ADS1115Sensor::sample() {
|
||||
return this->parent_->request_measurement(this->multiplexer_, this->gain_, this->resolution_, this->samplerate_);
|
||||
return this->parent_->request_measurement(this->config_bits_, this->conversion_delay_ms_);
|
||||
}
|
||||
|
||||
void ADS1115Sensor::update() {
|
||||
@@ -21,11 +21,9 @@ void ADS1115Sensor::update() {
|
||||
void ADS1115Sensor::dump_config() {
|
||||
LOG_SENSOR(" ", "ADS1115 Sensor", this);
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Multiplexer: %u\n"
|
||||
" Gain: %u\n"
|
||||
" Resolution: %u\n"
|
||||
" Sample rate: %u",
|
||||
this->multiplexer_, this->gain_, this->resolution_, this->samplerate_);
|
||||
" Config: 0x%04X\n"
|
||||
" Conversion delay: %u ms",
|
||||
this->config_bits_, this->conversion_delay_ms_);
|
||||
}
|
||||
|
||||
} // namespace esphome::ads1115
|
||||
@@ -10,26 +10,21 @@
|
||||
|
||||
namespace esphome::ads1115 {
|
||||
|
||||
/// Internal holder class that is in instance of Sensor so that the hub can create individual sensors.
|
||||
class ADS1115Sensor final : public sensor::Sensor,
|
||||
public PollingComponent,
|
||||
public voltage_sampler::VoltageSampler,
|
||||
public Parented<ADS1115Component> {
|
||||
public:
|
||||
ADS1115Sensor(uint16_t config_bits, uint8_t conversion_delay_ms)
|
||||
: config_bits_(config_bits), conversion_delay_ms_(conversion_delay_ms) {}
|
||||
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() override;
|
||||
|
||||
void dump_config() override;
|
||||
|
||||
protected:
|
||||
ADS1115Multiplexer multiplexer_;
|
||||
ADS1115Gain gain_;
|
||||
ADS1115Resolution resolution_;
|
||||
ADS1115Samplerate samplerate_;
|
||||
const uint16_t config_bits_;
|
||||
const uint8_t conversion_delay_ms_;
|
||||
};
|
||||
|
||||
} // namespace esphome::ads1115
|
||||
@@ -4,6 +4,7 @@ import esphome.config_validation as cv
|
||||
from esphome.types import ConfigType
|
||||
|
||||
CODEOWNERS = ["@solomondg1"]
|
||||
AUTO_LOAD = ["ads1xxx"]
|
||||
DEPENDENCIES = ["spi"]
|
||||
DOMAIN = "ads1118"
|
||||
MULTI_CONF = True
|
||||
|
||||
@@ -1,81 +1,25 @@
|
||||
#include "ads1118.h"
|
||||
#include "esphome/components/ads1xxx/ads1xxx.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome::ads1118 {
|
||||
|
||||
ESPHOME_LOG_TAG(TAG, "ads1118");
|
||||
static const uint8_t ADS1118_DATA_RATE_860_SPS = 0b111;
|
||||
// DOUT pull-up, NOP 01 (write the config), reserved bit set
|
||||
static constexpr uint16_t CONFIG_BASE = ads1xxx::CONFIG_SINGLE_SHOT | ads1xxx::CONFIG_DATA_RATE | 0b1011;
|
||||
|
||||
void ADS1118::setup() {
|
||||
this->spi_setup();
|
||||
|
||||
this->config_ = 0;
|
||||
// Setup multiplexer
|
||||
// 0bx000xxxxxxxxxxxx
|
||||
this->config_ |= ADS1118_MULTIPLEXER_P0_NG << 12;
|
||||
|
||||
// Setup Gain
|
||||
// 0bxxxx000xxxxxxxxx
|
||||
this->config_ |= ADS1118_GAIN_6P144 << 9;
|
||||
|
||||
// Set singleshot mode
|
||||
// 0bxxxxxxx1xxxxxxxx
|
||||
this->config_ |= 0b0000000100000000;
|
||||
|
||||
// Set data rate - 860 samples per second (we're in singleshot mode)
|
||||
// 0bxxxxxxxx100xxxxx
|
||||
this->config_ |= ADS1118_DATA_RATE_860_SPS << 5;
|
||||
|
||||
// Set temperature sensor mode - ADC
|
||||
// 0bxxxxxxxxxxx0xxxx
|
||||
this->config_ |= 0b0000000000000000;
|
||||
|
||||
// Set DOUT pull up - enable
|
||||
// 0bxxxxxxxxxxxx0xxx
|
||||
this->config_ |= 0b0000000000001000;
|
||||
|
||||
// NOP - must be 01
|
||||
// 0bxxxxxxxxxxxxx01x
|
||||
this->config_ |= 0b0000000000000010;
|
||||
|
||||
// Not used - can be 0 or 1, lets be positive
|
||||
// 0bxxxxxxxxxxxxxxx1
|
||||
this->config_ |= 0b0000000000000001;
|
||||
}
|
||||
void ADS1118::setup() { this->spi_setup(); }
|
||||
|
||||
void ADS1118::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "ADS1118:");
|
||||
LOG_PIN(" CS Pin:", this->cs_);
|
||||
}
|
||||
|
||||
float ADS1118::request_measurement(ADS1118Multiplexer multiplexer, ADS1118Gain gain, bool temperature_mode) {
|
||||
uint16_t temp_config = this->config_;
|
||||
// Multiplexer
|
||||
// 0bxBBBxxxxxxxxxxxx
|
||||
temp_config &= 0b1000111111111111;
|
||||
temp_config |= (multiplexer & 0b111) << 12;
|
||||
|
||||
// Gain
|
||||
// 0bxxxxBBBxxxxxxxxx
|
||||
temp_config &= 0b1111000111111111;
|
||||
temp_config |= (gain & 0b111) << 9;
|
||||
|
||||
if (temperature_mode) {
|
||||
// Set temperature sensor mode
|
||||
// 0bxxxxxxxxxxx1xxxx
|
||||
temp_config |= 0b0000000000010000;
|
||||
} else {
|
||||
// Set ADC mode
|
||||
// 0bxxxxxxxxxxx0xxxx
|
||||
temp_config &= 0b1111111111101111;
|
||||
}
|
||||
|
||||
// Start conversion
|
||||
temp_config |= 0b1000000000000000;
|
||||
|
||||
float ADS1118::request_measurement(uint16_t config_bits) {
|
||||
this->enable();
|
||||
this->write_byte16(temp_config);
|
||||
this->write_byte16(CONFIG_BASE | ads1xxx::CONFIG_START | config_bits);
|
||||
this->disable();
|
||||
|
||||
// about 1.2 ms with 860 samples per second
|
||||
@@ -85,40 +29,11 @@ float ADS1118::request_measurement(ADS1118Multiplexer multiplexer, ADS1118Gain g
|
||||
uint8_t adc_first_byte = this->read_byte();
|
||||
uint8_t adc_second_byte = this->read_byte();
|
||||
this->disable();
|
||||
uint16_t raw_conversion = encode_uint16(adc_first_byte, adc_second_byte);
|
||||
auto raw = static_cast<int16_t>(encode_uint16(adc_first_byte, adc_second_byte));
|
||||
|
||||
auto signed_conversion = static_cast<int16_t>(raw_conversion);
|
||||
|
||||
if (temperature_mode) {
|
||||
return (signed_conversion >> 2) * 0.03125f;
|
||||
} else {
|
||||
float millivolts;
|
||||
float divider = 32768.0f;
|
||||
switch (gain) {
|
||||
case ADS1118_GAIN_6P144:
|
||||
millivolts = (signed_conversion * 6144) / divider;
|
||||
break;
|
||||
case ADS1118_GAIN_4P096:
|
||||
millivolts = (signed_conversion * 4096) / divider;
|
||||
break;
|
||||
case ADS1118_GAIN_2P048:
|
||||
millivolts = (signed_conversion * 2048) / divider;
|
||||
break;
|
||||
case ADS1118_GAIN_1P024:
|
||||
millivolts = (signed_conversion * 1024) / divider;
|
||||
break;
|
||||
case ADS1118_GAIN_0P512:
|
||||
millivolts = (signed_conversion * 512) / divider;
|
||||
break;
|
||||
case ADS1118_GAIN_0P256:
|
||||
millivolts = (signed_conversion * 256) / divider;
|
||||
break;
|
||||
default:
|
||||
millivolts = NAN;
|
||||
}
|
||||
|
||||
return millivolts / 1e3f;
|
||||
}
|
||||
if (config_bits & CONFIG_TEMPERATURE)
|
||||
return (raw >> 2) * 0.03125f;
|
||||
return ads1xxx::to_volts(raw, config_bits);
|
||||
}
|
||||
|
||||
} // namespace esphome::ads1118
|
||||
@@ -2,42 +2,19 @@
|
||||
|
||||
#include "esphome/components/spi/spi.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/hal.h"
|
||||
|
||||
namespace esphome::ads1118 {
|
||||
|
||||
enum ADS1118Multiplexer {
|
||||
ADS1118_MULTIPLEXER_P0_N1 = 0b000,
|
||||
ADS1118_MULTIPLEXER_P0_N3 = 0b001,
|
||||
ADS1118_MULTIPLEXER_P1_N3 = 0b010,
|
||||
ADS1118_MULTIPLEXER_P2_N3 = 0b011,
|
||||
ADS1118_MULTIPLEXER_P0_NG = 0b100,
|
||||
ADS1118_MULTIPLEXER_P1_NG = 0b101,
|
||||
ADS1118_MULTIPLEXER_P2_NG = 0b110,
|
||||
ADS1118_MULTIPLEXER_P3_NG = 0b111,
|
||||
};
|
||||
|
||||
enum ADS1118Gain {
|
||||
ADS1118_GAIN_6P144 = 0b000,
|
||||
ADS1118_GAIN_4P096 = 0b001,
|
||||
ADS1118_GAIN_2P048 = 0b010,
|
||||
ADS1118_GAIN_1P024 = 0b011,
|
||||
ADS1118_GAIN_0P512 = 0b100,
|
||||
ADS1118_GAIN_0P256 = 0b101,
|
||||
};
|
||||
static constexpr uint16_t CONFIG_TEMPERATURE = 1 << 4;
|
||||
|
||||
class ADS1118 final : public Component,
|
||||
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW,
|
||||
spi::CLOCK_PHASE_TRAILING, spi::DATA_RATE_1MHZ> {
|
||||
public:
|
||||
ADS1118() = default;
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
/// Helper method to request a measurement from a sensor.
|
||||
float request_measurement(ADS1118Multiplexer multiplexer, ADS1118Gain gain, bool temperature_mode);
|
||||
|
||||
protected:
|
||||
uint16_t config_{0};
|
||||
/// Returns volts, or degrees Celsius when `config_bits` has CONFIG_TEMPERATURE.
|
||||
float request_measurement(uint16_t config_bits);
|
||||
};
|
||||
|
||||
} // namespace esphome::ads1118
|
||||
@@ -1,9 +1,8 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import sensor, voltage_sampler
|
||||
from esphome.components.ads1xxx import MUX_GAIN_SCHEMA, mux_gain_bits
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_GAIN,
|
||||
CONF_MULTIPLEXER,
|
||||
CONF_TYPE,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
@@ -18,29 +17,6 @@ from .. import ADS1118, CONF_ADS1118_ID, ads1118_ns
|
||||
AUTO_LOAD = ["voltage_sampler"]
|
||||
DEPENDENCIES = ["ads1118"]
|
||||
|
||||
ADS1118Multiplexer = ads1118_ns.enum("ADS1118Multiplexer")
|
||||
MUX = {
|
||||
"A0_A1": ADS1118Multiplexer.ADS1118_MULTIPLEXER_P0_N1,
|
||||
"A0_A3": ADS1118Multiplexer.ADS1118_MULTIPLEXER_P0_N3,
|
||||
"A1_A3": ADS1118Multiplexer.ADS1118_MULTIPLEXER_P1_N3,
|
||||
"A2_A3": ADS1118Multiplexer.ADS1118_MULTIPLEXER_P2_N3,
|
||||
"A0_GND": ADS1118Multiplexer.ADS1118_MULTIPLEXER_P0_NG,
|
||||
"A1_GND": ADS1118Multiplexer.ADS1118_MULTIPLEXER_P1_NG,
|
||||
"A2_GND": ADS1118Multiplexer.ADS1118_MULTIPLEXER_P2_NG,
|
||||
"A3_GND": ADS1118Multiplexer.ADS1118_MULTIPLEXER_P3_NG,
|
||||
}
|
||||
|
||||
ADS1118Gain = ads1118_ns.enum("ADS1118Gain")
|
||||
GAIN = {
|
||||
"6.144": ADS1118Gain.ADS1118_GAIN_6P144,
|
||||
"4.096": ADS1118Gain.ADS1118_GAIN_4P096,
|
||||
"2.048": ADS1118Gain.ADS1118_GAIN_2P048,
|
||||
"1.024": ADS1118Gain.ADS1118_GAIN_1P024,
|
||||
"0.512": ADS1118Gain.ADS1118_GAIN_0P512,
|
||||
"0.256": ADS1118Gain.ADS1118_GAIN_0P256,
|
||||
}
|
||||
|
||||
|
||||
ADS1118Sensor = ads1118_ns.class_(
|
||||
"ADS1118Sensor",
|
||||
cg.PollingComponent,
|
||||
@@ -64,8 +40,7 @@ CONFIG_SCHEMA = cv.typed_schema(
|
||||
.extend(
|
||||
{
|
||||
cv.GenerateID(CONF_ADS1118_ID): cv.use_id(ADS1118),
|
||||
cv.Required(CONF_MULTIPLEXER): cv.enum(MUX, upper=True, space="_"),
|
||||
cv.Required(CONF_GAIN): cv.enum(GAIN, string=True),
|
||||
**MUX_GAIN_SCHEMA,
|
||||
}
|
||||
)
|
||||
.extend(cv.polling_component_schema("60s")),
|
||||
@@ -88,12 +63,11 @@ CONFIG_SCHEMA = cv.typed_schema(
|
||||
|
||||
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
var = await sensor.new_sensor(config)
|
||||
bits = (
|
||||
mux_gain_bits(config)
|
||||
if config[CONF_TYPE] == TYPE_ADC
|
||||
else ads1118_ns.CONFIG_TEMPERATURE
|
||||
)
|
||||
var = await sensor.new_sensor(config, bits)
|
||||
await cg.register_component(var, config)
|
||||
await cg.register_parented(var, config[CONF_ADS1118_ID])
|
||||
|
||||
if config[CONF_TYPE] == TYPE_ADC:
|
||||
cg.add(var.set_multiplexer(config[CONF_MULTIPLEXER]))
|
||||
cg.add(var.set_gain(config[CONF_GAIN]))
|
||||
if config[CONF_TYPE] == TYPE_TEMPERATURE:
|
||||
cg.add(var.set_temperature_mode(True))
|
||||
@@ -8,15 +8,10 @@ ESPHOME_LOG_TAG(TAG, "ads1118.sensor");
|
||||
|
||||
void ADS1118Sensor::dump_config() {
|
||||
LOG_SENSOR(" ", "ADS1118 Sensor", this);
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Multiplexer: %u\n"
|
||||
" Gain: %u",
|
||||
this->multiplexer_, this->gain_);
|
||||
ESP_LOGCONFIG(TAG, " Config: 0x%04X", this->config_bits_);
|
||||
}
|
||||
|
||||
float ADS1118Sensor::sample() {
|
||||
return this->parent_->request_measurement(this->multiplexer_, this->gain_, this->temperature_mode_);
|
||||
}
|
||||
float ADS1118Sensor::sample() { return this->parent_->request_measurement(this->config_bits_); }
|
||||
|
||||
void ADS1118Sensor::update() {
|
||||
float v = this->sample();
|
||||
|
||||
@@ -15,20 +15,15 @@ class ADS1118Sensor final : public PollingComponent,
|
||||
public voltage_sampler::VoltageSampler,
|
||||
public Parented<ADS1118> {
|
||||
public:
|
||||
explicit ADS1118Sensor(uint16_t config_bits) : config_bits_(config_bits) {}
|
||||
void update() override;
|
||||
|
||||
void set_multiplexer(ADS1118Multiplexer multiplexer) { this->multiplexer_ = multiplexer; }
|
||||
void set_gain(ADS1118Gain gain) { this->gain_ = gain; }
|
||||
void set_temperature_mode(bool temp) { this->temperature_mode_ = temp; }
|
||||
|
||||
float sample() override;
|
||||
|
||||
void dump_config() override;
|
||||
|
||||
protected:
|
||||
ADS1118Multiplexer multiplexer_{ADS1118_MULTIPLEXER_P0_NG};
|
||||
ADS1118Gain gain_{ADS1118_GAIN_6P144};
|
||||
bool temperature_mode_;
|
||||
const uint16_t config_bits_;
|
||||
};
|
||||
|
||||
} // namespace esphome::ads1118
|
||||
@@ -0,0 +1,27 @@
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_GAIN, CONF_MULTIPLEXER
|
||||
from esphome.types import ConfigType
|
||||
|
||||
CODEOWNERS = ["@bdraco"]
|
||||
DOMAIN = "ads1xxx"
|
||||
|
||||
_MUX = {
|
||||
name: i
|
||||
for i, name in enumerate(
|
||||
("A0_A1", "A0_A3", "A1_A3", "A2_A3", "A0_GND", "A1_GND", "A2_GND", "A3_GND")
|
||||
)
|
||||
}
|
||||
_GAIN = {
|
||||
name: i
|
||||
for i, name in enumerate(("6.144", "4.096", "2.048", "1.024", "0.512", "0.256"))
|
||||
}
|
||||
|
||||
MUX_GAIN_SCHEMA = {
|
||||
cv.Required(CONF_MULTIPLEXER): cv.enum(_MUX, upper=True, space="_"),
|
||||
cv.Required(CONF_GAIN): cv.enum(_GAIN, string=True),
|
||||
}
|
||||
|
||||
|
||||
def mux_gain_bits(config: ConfigType) -> int:
|
||||
"""Return the multiplexer and gain fields of the config register."""
|
||||
return config[CONF_MULTIPLEXER].enum_value << 12 | config[CONF_GAIN].enum_value << 9
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace esphome::ads1xxx {
|
||||
|
||||
// Config register fields shared by the ADS101x, ADS111x and ADS1118
|
||||
static constexpr uint16_t CONFIG_START = 1 << 15; // reads back as 1 once the conversion is done
|
||||
static constexpr uint16_t CONFIG_DATA_RATE = 0x00E0; // all bits set is the fastest rate
|
||||
static constexpr uint16_t CONFIG_SINGLE_SHOT = 1 << 8;
|
||||
|
||||
/// Volts for a conversion result taken with the gain field of `config`; 12-bit results are left-justified.
|
||||
inline float to_volts(int16_t raw, uint16_t config) {
|
||||
const uint8_t gain = (config >> 9) & 0b111;
|
||||
// Volts per count: 6.144 V full scale for gain 0, else 8.192 V >> gain
|
||||
return raw * (gain ? 0.00025f : 0.0001875f) / (1 << gain);
|
||||
}
|
||||
|
||||
} // namespace esphome::ads1xxx
|
||||
@@ -1,10 +1,23 @@
|
||||
ads1115:
|
||||
i2c_id: i2c_bus
|
||||
address: 0x48
|
||||
- id: ads1115_hub
|
||||
i2c_id: i2c_bus
|
||||
address: 0x48
|
||||
- id: ads1015_hub
|
||||
i2c_id: i2c_bus
|
||||
address: 0x49
|
||||
continuous_mode: true
|
||||
|
||||
sensor:
|
||||
- platform: ads1115
|
||||
ads1115_id: ads1115_hub
|
||||
multiplexer: A0_A1
|
||||
gain: 1.024
|
||||
sample_rate: 128
|
||||
id: ads1115_sensor
|
||||
- platform: ads1115
|
||||
ads1115_id: ads1015_hub
|
||||
multiplexer: A3_GND
|
||||
gain: 6.144
|
||||
resolution: 12_BITS
|
||||
sample_rate: 8
|
||||
id: ads1015_sensor
|
||||
@@ -1,4 +1,3 @@
|
||||
packages:
|
||||
i2c: !include ../../test_build_components/common/i2c/esp32-idf.yaml
|
||||
|
||||
<<: !include common.yaml
|
||||
ads1115: !include common.yaml
|
||||
@@ -1,4 +1,3 @@
|
||||
packages:
|
||||
i2c: !include ../../test_build_components/common/i2c/esp8266-ard.yaml
|
||||
|
||||
<<: !include common.yaml
|
||||
ads1115: !include common.yaml
|
||||
@@ -1,4 +1,3 @@
|
||||
packages:
|
||||
i2c: !include ../../test_build_components/common/i2c/nrf52.yaml
|
||||
|
||||
<<: !include common.yaml
|
||||
ads1115: !include common.yaml
|
||||
@@ -1,4 +1,3 @@
|
||||
packages:
|
||||
i2c: !include ../../test_build_components/common/i2c/nrf52.yaml
|
||||
|
||||
<<: !include common.yaml
|
||||
ads1115: !include common.yaml
|
||||
@@ -1,4 +1,3 @@
|
||||
packages:
|
||||
i2c: !include ../../test_build_components/common/i2c/rp2040-ard.yaml
|
||||
|
||||
<<: !include common.yaml
|
||||
ads1115: !include common.yaml
|
||||
Reference in new issue
Block a user