mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	DAC7678 support (#3441)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
		| @@ -52,6 +52,7 @@ esphome/components/cs5460a/* @balrog-kun | |||||||
| esphome/components/cse7761/* @berfenger | esphome/components/cse7761/* @berfenger | ||||||
| esphome/components/ct_clamp/* @jesserockz | esphome/components/ct_clamp/* @jesserockz | ||||||
| esphome/components/current_based/* @djwmarcx | esphome/components/current_based/* @djwmarcx | ||||||
|  | esphome/components/dac7678/* @NickB1 | ||||||
| esphome/components/daly_bms/* @s1lvi0 | esphome/components/daly_bms/* @s1lvi0 | ||||||
| esphome/components/dashboard_import/* @esphome/core | esphome/components/dashboard_import/* @esphome/core | ||||||
| esphome/components/debug/* @OttoWinter | esphome/components/debug/* @OttoWinter | ||||||
|   | |||||||
							
								
								
									
										32
									
								
								esphome/components/dac7678/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								esphome/components/dac7678/__init__.py
									
									
									
									
									
										Normal 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 | ||||||
							
								
								
									
										83
									
								
								esphome/components/dac7678/dac7678_output.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								esphome/components/dac7678/dac7678_output.cpp
									
									
									
									
									
										Normal 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 | ||||||
							
								
								
									
										55
									
								
								esphome/components/dac7678/dac7678_output.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								esphome/components/dac7678/dac7678_output.h
									
									
									
									
									
										Normal 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 | ||||||
							
								
								
									
										27
									
								
								esphome/components/dac7678/output.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								esphome/components/dac7678/output.py
									
									
									
									
									
										Normal 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 | ||||||
| @@ -80,6 +80,11 @@ sx1509: | |||||||
| mcp3204: | mcp3204: | ||||||
|   cs_pin: GPIO23 |   cs_pin: GPIO23 | ||||||
|  |  | ||||||
|  | dac7678: | ||||||
|  |     address: 0x4A | ||||||
|  |     id: dac7678_hub1 | ||||||
|  |     internal_reference: true | ||||||
|  |  | ||||||
| sensor: | sensor: | ||||||
|   - platform: homeassistant |   - platform: homeassistant | ||||||
|     entity_id: sensor.hello_world |     entity_id: sensor.hello_world | ||||||
| @@ -518,6 +523,38 @@ output: | |||||||
|     pipsolar_id: inverter0 |     pipsolar_id: inverter0 | ||||||
|     battery_recharge_voltage: |     battery_recharge_voltage: | ||||||
|       id: inverter0_battery_recharge_voltage_out |       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: | esp32_camera: | ||||||
|   name: ESP-32 Camera |   name: ESP-32 Camera | ||||||
|   data_pins: [GPIO17, GPIO35, GPIO34, GPIO5, GPIO39, GPIO18, GPIO36, GPIO19] |   data_pins: [GPIO17, GPIO35, GPIO34, GPIO5, GPIO39, GPIO18, GPIO36, GPIO19] | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user