components/ads131m08/sensor/__init__.py

116 lines
4.2 KiB
Python

import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor, voltage_sampler
from esphome.const import (
CONF_ID,
CONF_GAIN,
CONF_CHANNEL,
DEVICE_CLASS_VOLTAGE,
STATE_CLASS_MEASUREMENT,
UNIT_VOLT,
)
from .. import CONF_ADS131M08_ID, ADS131M08Hub, ads131m08_ns
from ..sensor_rms import RMS_SENSOR_SCHEMA, to_code_ac
AUTO_LOAD = [
"sensor", "voltage_sampler",
]
MAX_CHANNELS = 15
CONF_OFFSET_CALIBRATION = "offset_calibration"
CONF_GAIN_CALIBRATION = "gain_calibration"
CONF_PHASE_CALIBRATION = "phase_calibration"
CONF_INPUT_SELECT = "input_select"
CONF_DC_BLOCK = "dc_block"
ICON_CURRENT_DC = "mdi:current-dc"
DEPENDENCIES = ["ads131m08"]
GAIN = ads131m08_ns.enum("ADC_PGA_GAIN")
ALLOWED_GAINS = {
"1": GAIN.PGA_1,
"2": GAIN.PGA_2,
"4": GAIN.PGA_4,
"8": GAIN.PGA_8,
"16": GAIN.PGA_16,
"32": GAIN.PGA_32,
"64": GAIN.PGA_64,
"128": GAIN.PGA_128,
1: GAIN.PGA_1,
2: GAIN.PGA_2,
4: GAIN.PGA_4,
8: GAIN.PGA_8,
16: GAIN.PGA_16,
32: GAIN.PGA_32,
64: GAIN.PGA_64,
128: GAIN.PGA_128,
}
ADC_INPUT = ads131m08_ns.enum("ADC_INPUT_CHANNEL_MUX")
ALLOWED_MUX_INP = {
"normal": ADC_INPUT.ICM_AIN0P_AIN0N,
"shorted" : ADC_INPUT.ICM_INPUT_SHORTED,
"positive_dc" : ADC_INPUT.ICM_POSITIVE_DC_TEST_SIGNAL,
"negative_dc" : ADC_INPUT.ICM_NEGATIVE_DC_TEST_SIGNAL,
}
Channel = ads131m08_ns.class_(
"Channel", sensor.Sensor, cg.Component, voltage_sampler.VoltageSampler
)
CONFIG_SCHEMA = (
sensor.sensor_schema(
Channel,
accuracy_decimals=6,
icon=ICON_CURRENT_DC,
unit_of_measurement=UNIT_VOLT,
device_class=DEVICE_CLASS_VOLTAGE,
state_class=STATE_CLASS_MEASUREMENT,
).extend(
RMS_SENSOR_SCHEMA
)
.extend(
{
cv.GenerateID(CONF_ADS131M08_ID): cv.use_id(ADS131M08Hub),
cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=MAX_CHANNELS),
cv.Optional(CONF_GAIN, default=1): cv.enum(ALLOWED_GAINS, int=True),
cv.Optional(CONF_OFFSET_CALIBRATION, default=0): cv.int_range(min=-8388608, max=8388607), # should use volts, but need to figure out conversion function first
cv.Optional(CONF_GAIN_CALIBRATION, default=1): cv.float_range(min=0, max=2),
cv.Optional(CONF_PHASE_CALIBRATION, default=0): cv.int_range(min=-512, max=511), # should use degrees, but need to figure out conversion function first
cv.Optional(CONF_INPUT_SELECT, default='normal'): cv.enum(ALLOWED_MUX_INP, int=False),
cv.Optional(CONF_DC_BLOCK, default=False): cv.boolean,
}
)
#.extend(cv.polling_component_schema("1s"))
.extend(cv.COMPONENT_SCHEMA)
)
# we are using 2 sensors:
# 1. channel_sensor: this represents 1 of the 8 ads131m08 channels and is used to program the adc channel gain, offset calibration, etc.
# This sensor publishes instantaneous sampled value and can be used for DC measurements
# 2. ac_sensor: to publish rms ac value; only use if absolutely necessary as it it expensive in terms of loop time
async def to_code(config):
channel_sensor = cg.new_Pvariable(config[CONF_ID])
await cg.register_parented(channel_sensor, config[CONF_ADS131M08_ID])
channel = config[CONF_CHANNEL]
cg.add(channel_sensor.set_channel_number(channel))
gain = config[CONF_GAIN]
cg.add(channel_sensor.set_gain(gain))
mux_inp = config[CONF_INPUT_SELECT]
cg.add(channel_sensor.set_mux_input(mux_inp))
gain_cal = config[CONF_GAIN_CALIBRATION]
cg.add(channel_sensor.set_gain_calibration(gain_cal))
offset_cal = config[CONF_OFFSET_CALIBRATION]
cg.add(channel_sensor.set_offset_calibration(offset_cal))
phase_cal = config[CONF_PHASE_CALIBRATION]
cg.add(channel_sensor.set_phase_calibration(phase_cal))
dc_block = config[CONF_DC_BLOCK]
cg.add(channel_sensor.set_dc_block(dc_block))
hub = await cg.get_variable(config[CONF_ADS131M08_ID])
cg.add(hub.register_sensor_dc(channel, channel_sensor))
await sensor.register_sensor(channel_sensor, config)
await cg.register_component(channel_sensor, config)
if ac_sensor := await to_code_ac(config):
await cg.register_parented(ac_sensor, channel_sensor)