DAC7678 support (#3441)

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
Nick B 2022-06-21 07:12:15 +02:00 committed by GitHub
parent 29045b0435
commit fb2467f6f0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 235 additions and 0 deletions

View file

@ -52,6 +52,7 @@ esphome/components/cs5460a/* @balrog-kun
esphome/components/cse7761/* @berfenger
esphome/components/ct_clamp/* @jesserockz
esphome/components/current_based/* @djwmarcx
esphome/components/dac7678/* @NickB1
esphome/components/daly_bms/* @s1lvi0
esphome/components/dashboard_import/* @esphome/core
esphome/components/debug/* @OttoWinter

View file

@ -0,0 +1,32 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c
from esphome.const import CONF_ID
AUTO_LOAD = ["output"]
CODEOWNERS = ["@NickB1"]
DEPENDENCIES = ["i2c"]
MULTI_CONF = True
dac7678_ns = cg.esphome_ns.namespace("dac7678")
DAC7678Output = dac7678_ns.class_("DAC7678Output", cg.Component, i2c.I2CDevice)
CONF_INTERNAL_REFERENCE = "internal_reference"
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(DAC7678Output),
cv.Optional(CONF_INTERNAL_REFERENCE, default=False): cv.boolean,
}
)
.extend(cv.COMPONENT_SCHEMA)
.extend(i2c.i2c_device_schema(0x48))
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
cg.add(var.set_internal_reference(config[CONF_INTERNAL_REFERENCE]))
await i2c.register_i2c_device(var, config)
return var

View file

@ -0,0 +1,83 @@
#include "dac7678_output.h"
#include "esphome/core/log.h"
#include "esphome/core/helpers.h"
#include "esphome/core/hal.h"
namespace esphome {
namespace dac7678 {
static const char *const TAG = "dac7678";
static const uint8_t DAC7678_REG_INPUT_N = 0x00;
static const uint8_t DAC7678_REG_SELECT_UPDATE_N = 0x10;
static const uint8_t DAC7678_REG_WRITE_N_UPDATE_ALL = 0x20;
static const uint8_t DAC7678_REG_WRITE_N_UPDATE_N = 0x30;
static const uint8_t DAC7678_REG_POWER = 0x40;
static const uint8_t DAC7678_REG_CLEAR_CODE = 0x50;
static const uint8_t DAC7678_REG_LDAC = 0x60;
static const uint8_t DAC7678_REG_SOFTWARE_RESET = 0x70;
static const uint8_t DAC7678_REG_INTERNAL_REF_0 = 0x80;
static const uint8_t DAC7678_REG_INTERNAL_REF_1 = 0x90;
void DAC7678Output::setup() {
ESP_LOGCONFIG(TAG, "Setting up DAC7678OutputComponent...");
ESP_LOGV(TAG, "Resetting device...");
// Reset device
if (!this->write_byte_16(DAC7678_REG_SOFTWARE_RESET, 0x0000)) {
ESP_LOGE(TAG, "Reset failed");
this->mark_failed();
return;
} else
ESP_LOGV(TAG, "Reset succeeded");
delayMicroseconds(1000);
// Set internal reference
if (this->internal_reference_) {
if (!this->write_byte_16(DAC7678_REG_INTERNAL_REF_0, 1 << 4)) {
ESP_LOGE(TAG, "Set internal reference failed");
this->mark_failed();
return;
} else
ESP_LOGV(TAG, "Internal reference enabled");
}
}
void DAC7678Output::dump_config() {
if (this->is_failed()) {
ESP_LOGE(TAG, "Setting up DAC7678 failed!");
} else
ESP_LOGCONFIG(TAG, "DAC7678 initialised");
}
void DAC7678Output::register_channel(DAC7678Channel *channel) {
auto c = channel->channel_;
this->min_channel_ = std::min(this->min_channel_, c);
this->max_channel_ = std::max(this->max_channel_, c);
channel->set_parent(this);
ESP_LOGV(TAG, "Registered channel: %01u", channel->channel_);
}
void DAC7678Output::set_channel_value_(uint8_t channel, uint16_t value) {
if (this->dac_input_reg_[channel] != value) {
ESP_LOGV(TAG, "Channel %01u: input_reg=%04u ", channel, value);
if (!this->write_byte_16(DAC7678_REG_WRITE_N_UPDATE_N | channel, value << 4)) {
this->status_set_warning();
return;
}
}
this->dac_input_reg_[channel] = value;
this->status_clear_warning();
}
void DAC7678Channel::write_state(float state) {
const float input_rounded = roundf(state * this->full_scale_);
auto input = static_cast<uint16_t>(input_rounded);
this->parent_->set_channel_value_(this->channel_, input);
}
} // namespace dac7678
} // namespace esphome

View file

@ -0,0 +1,55 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/helpers.h"
#include "esphome/components/output/float_output.h"
#include "esphome/components/i2c/i2c.h"
namespace esphome {
namespace dac7678 {
class DAC7678Output;
class DAC7678Channel : public output::FloatOutput, public Parented<DAC7678Output> {
public:
void set_channel(uint8_t channel) { channel_ = channel; }
protected:
friend class DAC7678Output;
const uint16_t full_scale_ = 0xFFF;
void write_state(float state) override;
uint8_t channel_;
};
/// DAC7678 float output component.
class DAC7678Output : public Component, public i2c::I2CDevice {
public:
DAC7678Output() {}
void register_channel(DAC7678Channel *channel);
void set_internal_reference(const bool value) { this->internal_reference_ = value; }
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::HARDWARE; }
protected:
friend DAC7678Channel;
bool internal_reference_;
void set_channel_value_(uint8_t channel, uint16_t value);
uint8_t min_channel_{0xFF};
uint8_t max_channel_{0x00};
uint16_t dac_input_reg_[8] = {
0,
};
};
} // namespace dac7678
} // namespace esphome

View file

@ -0,0 +1,27 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import output
from esphome.const import CONF_CHANNEL, CONF_ID
from . import DAC7678Output, dac7678_ns
DEPENDENCIES = ["dac7678"]
DAC7678Channel = dac7678_ns.class_("DAC7678Channel", output.FloatOutput)
CONF_DAC7678_ID = "dac7678_id"
CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend(
{
cv.Required(CONF_ID): cv.declare_id(DAC7678Channel),
cv.GenerateID(CONF_DAC7678_ID): cv.use_id(DAC7678Output),
cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=7),
}
)
async def to_code(config):
paren = await cg.get_variable(config[CONF_DAC7678_ID])
var = cg.new_Pvariable(config[CONF_ID])
cg.add(var.set_channel(config[CONF_CHANNEL]))
cg.add(paren.register_channel(var))
await output.register_output(var, config)
return var

View file

@ -80,6 +80,11 @@ sx1509:
mcp3204:
cs_pin: GPIO23
dac7678:
address: 0x4A
id: dac7678_hub1
internal_reference: true
sensor:
- platform: homeassistant
entity_id: sensor.hello_world
@ -518,6 +523,38 @@ output:
pipsolar_id: inverter0
battery_recharge_voltage:
id: inverter0_battery_recharge_voltage_out
- platform: dac7678
dac7678_id: 'dac7678_hub1'
channel: 0
id: 'dac7678_1_ch0'
- platform: dac7678
dac7678_id: 'dac7678_hub1'
channel: 1
id: 'dac7678_1_ch1'
- platform: dac7678
dac7678_id: 'dac7678_hub1'
channel: 2
id: 'dac7678_1_ch2'
- platform: dac7678
dac7678_id: 'dac7678_hub1'
channel: 3
id: 'dac7678_1_ch3'
- platform: dac7678
dac7678_id: 'dac7678_hub1'
channel: 4
id: 'dac7678_1_ch4'
- platform: dac7678
dac7678_id: 'dac7678_hub1'
channel: 5
id: 'dac7678_1_ch5'
- platform: dac7678
dac7678_id: 'dac7678_hub1'
channel: 6
id: 'dac7678_1_ch6'
- platform: dac7678
dac7678_id: 'dac7678_hub1'
channel: 7
id: 'dac7678_1_ch7'
esp32_camera:
name: ESP-32 Camera
data_pins: [GPIO17, GPIO35, GPIO34, GPIO5, GPIO39, GPIO18, GPIO36, GPIO19]