mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	[ds2484] New component (#9147)
This commit is contained in:
		
							
								
								
									
										1
									
								
								esphome/components/ds2484/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								esphome/components/ds2484/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| CODEOWNERS = ["@mrk-its"] | ||||
							
								
								
									
										209
									
								
								esphome/components/ds2484/ds2484.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										209
									
								
								esphome/components/ds2484/ds2484.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,209 @@ | ||||
| #include "ds2484.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace ds2484 { | ||||
| static const char *const TAG = "ds2484.onewire"; | ||||
|  | ||||
| void DS2484OneWireBus::setup() { | ||||
|   ESP_LOGCONFIG(TAG, "Running setup"); | ||||
|   this->reset_device(); | ||||
|   this->search(); | ||||
| } | ||||
|  | ||||
| void DS2484OneWireBus::dump_config() { | ||||
|   ESP_LOGCONFIG(TAG, "1-wire bus:"); | ||||
|   this->dump_devices_(TAG); | ||||
| } | ||||
|  | ||||
| bool DS2484OneWireBus::read_status_(uint8_t *status) { | ||||
|   for (uint8_t retry_nr = 0; retry_nr < 10; retry_nr++) { | ||||
|     if (this->read(status, 1) != i2c::ERROR_OK) { | ||||
|       ESP_LOGE(TAG, "read status error"); | ||||
|       return false; | ||||
|     } | ||||
|     ESP_LOGVV(TAG, "status: %02x", *status); | ||||
|     if (!(*status & 1)) { | ||||
|       return true; | ||||
|     } | ||||
|   } | ||||
|   ESP_LOGE(TAG, "read status error: too many retries"); | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| bool DS2484OneWireBus::wait_for_completion_() { | ||||
|   uint8_t status; | ||||
|   return this->read_status_(&status); | ||||
| } | ||||
|  | ||||
| bool DS2484OneWireBus::reset_device() { | ||||
|   ESP_LOGVV(TAG, "reset_device"); | ||||
|   uint8_t device_reset_cmd = 0xf0; | ||||
|   uint8_t response; | ||||
|   if (this->write(&device_reset_cmd, 1) != i2c::ERROR_OK) { | ||||
|     return false; | ||||
|   } | ||||
|   if (!this->wait_for_completion_()) { | ||||
|     ESP_LOGE(TAG, "reset_device: can't complete"); | ||||
|     return false; | ||||
|   } | ||||
|   uint8_t config = (this->active_pullup_ ? 1 : 0) | (this->strong_pullup_ ? 4 : 0); | ||||
|   uint8_t write_config[2] = {0xd2, (uint8_t) (config | (~config << 4))}; | ||||
|   if (this->write(write_config, 2) != i2c::ERROR_OK) { | ||||
|     ESP_LOGE(TAG, "reset_device: can't write config"); | ||||
|     return false; | ||||
|   } | ||||
|   if (this->read(&response, 1) != i2c::ERROR_OK) { | ||||
|     ESP_LOGE(TAG, "can't read read8 response"); | ||||
|     return false; | ||||
|   } | ||||
|   if (response != (write_config[1] & 0xf)) { | ||||
|     ESP_LOGE(TAG, "configuration didn't update"); | ||||
|     return false; | ||||
|   } | ||||
|   return true; | ||||
| }; | ||||
|  | ||||
| int DS2484OneWireBus::reset_int() { | ||||
|   ESP_LOGVV(TAG, "reset"); | ||||
|   uint8_t reset_cmd = 0xb4; | ||||
|   if (this->write(&reset_cmd, 1) != i2c::ERROR_OK) { | ||||
|     return -1; | ||||
|   } | ||||
|   return this->wait_for_completion_() ? 1 : 0; | ||||
| }; | ||||
|  | ||||
| void DS2484OneWireBus::write8_(uint8_t value) { | ||||
|   uint8_t buffer[2] = {0xa5, value}; | ||||
|   this->write(buffer, 2); | ||||
|   this->wait_for_completion_(); | ||||
| }; | ||||
|  | ||||
| void DS2484OneWireBus::write8(uint8_t value) { | ||||
|   ESP_LOGVV(TAG, "write8: %02x", value); | ||||
|   this->write8_(value); | ||||
| }; | ||||
|  | ||||
| void DS2484OneWireBus::write64(uint64_t value) { | ||||
|   ESP_LOGVV(TAG, "write64: %llx", value); | ||||
|   for (uint8_t i = 0; i < 8; i++) { | ||||
|     this->write8_((value >> (i * 8)) & 0xff); | ||||
|   } | ||||
| } | ||||
|  | ||||
| uint8_t DS2484OneWireBus::read8() { | ||||
|   uint8_t read8_cmd = 0x96; | ||||
|   uint8_t set_read_reg_cmd[2] = {0xe1, 0xe1}; | ||||
|   uint8_t response = 0; | ||||
|   if (this->write(&read8_cmd, 1) != i2c::ERROR_OK) { | ||||
|     ESP_LOGE(TAG, "can't write read8 cmd"); | ||||
|     return 0; | ||||
|   } | ||||
|   this->wait_for_completion_(); | ||||
|   if (this->write(set_read_reg_cmd, 2) != i2c::ERROR_OK) { | ||||
|     ESP_LOGE(TAG, "can't set read data reg"); | ||||
|     return 0; | ||||
|   } | ||||
|   if (this->read(&response, 1) != i2c::ERROR_OK) { | ||||
|     ESP_LOGE(TAG, "can't read read8 response"); | ||||
|     return 0; | ||||
|   } | ||||
|   return response; | ||||
| } | ||||
|  | ||||
| uint64_t DS2484OneWireBus::read64() { | ||||
|   uint8_t response = 0; | ||||
|   for (uint8_t i = 0; i < 8; i++) { | ||||
|     response |= (this->read8() << (i * 8)); | ||||
|   } | ||||
|   return response; | ||||
| } | ||||
|  | ||||
| void DS2484OneWireBus::reset_search() { | ||||
|   this->last_discrepancy_ = 0; | ||||
|   this->last_device_flag_ = false; | ||||
|   this->address_ = 0; | ||||
| } | ||||
|  | ||||
| bool DS2484OneWireBus::one_wire_triple_(bool *branch, bool *id_bit, bool *cmp_id_bit) { | ||||
|   uint8_t buffer[2] = {(uint8_t) 0x78, (uint8_t) (*branch ? 0x80u : 0)}; | ||||
|   uint8_t status; | ||||
|   if (!this->read_status_(&status)) { | ||||
|     ESP_LOGE(TAG, "one_wire_triple start: read status error"); | ||||
|     return false; | ||||
|   } | ||||
|   if (this->write(buffer, 2) != i2c::ERROR_OK) { | ||||
|     ESP_LOGV(TAG, "one_wire_triple: can't write cmd"); | ||||
|     return false; | ||||
|   } | ||||
|   if (!this->read_status_(&status)) { | ||||
|     ESP_LOGE(TAG, "one_wire_triple: read status error"); | ||||
|     return false; | ||||
|   } | ||||
|   *id_bit = bool(status & 0x20); | ||||
|   *cmp_id_bit = bool(status & 0x40); | ||||
|   *branch = bool(status & 0x80); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| uint64_t IRAM_ATTR DS2484OneWireBus::search_int() { | ||||
|   ESP_LOGVV(TAG, "search_int"); | ||||
|   if (this->last_device_flag_) { | ||||
|     ESP_LOGVV(TAG, "last device flag set, quitting"); | ||||
|     return 0u; | ||||
|   } | ||||
|  | ||||
|   uint8_t last_zero = 0; | ||||
|   uint64_t bit_mask = 1; | ||||
|   uint64_t address = this->address_; | ||||
|  | ||||
|   // Initiate search | ||||
|   for (uint8_t bit_number = 1; bit_number <= 64; bit_number++, bit_mask <<= 1) { | ||||
|     bool branch; | ||||
|  | ||||
|     // compute branch value for the case when there is a discrepancy | ||||
|     // (there are devices with both 0s and 1s at this bit) | ||||
|     if (bit_number < this->last_discrepancy_) { | ||||
|       branch = (address & bit_mask) > 0; | ||||
|     } else { | ||||
|       branch = bit_number == this->last_discrepancy_; | ||||
|     } | ||||
|  | ||||
|     bool id_bit, cmp_id_bit; | ||||
|     bool branch_before = branch; | ||||
|     if (!this->one_wire_triple_(&branch, &id_bit, &cmp_id_bit)) { | ||||
|       ESP_LOGW(TAG, "one wire triple error, quitting"); | ||||
|       return 0; | ||||
|     } | ||||
|  | ||||
|     if (id_bit && cmp_id_bit) { | ||||
|       ESP_LOGW(TAG, "no devices on the bus, quitting"); | ||||
|       // No devices participating in search | ||||
|       return 0; | ||||
|     } | ||||
|  | ||||
|     if (!id_bit && !cmp_id_bit && !branch) { | ||||
|       last_zero = bit_number; | ||||
|     } | ||||
|  | ||||
|     ESP_LOGVV(TAG, "%d %d branch: %d %d", id_bit, cmp_id_bit, branch_before, branch); | ||||
|  | ||||
|     if (branch) { | ||||
|       address |= bit_mask; | ||||
|     } else { | ||||
|       address &= ~bit_mask; | ||||
|     } | ||||
|   } | ||||
|   ESP_LOGVV(TAG, "last_discepancy: %d", last_zero); | ||||
|   ESP_LOGVV(TAG, "address: %llx", address); | ||||
|   this->last_discrepancy_ = last_zero; | ||||
|   if (this->last_discrepancy_ == 0) { | ||||
|     // we're at root and have no choices left, so this was the last one. | ||||
|     this->last_device_flag_ = true; | ||||
|   } | ||||
|  | ||||
|   this->address_ = address; | ||||
|   return address; | ||||
| } | ||||
|  | ||||
| }  // namespace ds2484 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										43
									
								
								esphome/components/ds2484/ds2484.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								esphome/components/ds2484/ds2484.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/core/hal.h" | ||||
| #include "esphome/core/preferences.h" | ||||
| #include "esphome/components/i2c/i2c.h" | ||||
| #include "esphome/components/one_wire/one_wire.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace ds2484 { | ||||
|  | ||||
| class DS2484OneWireBus : public one_wire::OneWireBus, public i2c::I2CDevice, public Component { | ||||
|  public: | ||||
|   void setup() override; | ||||
|   void dump_config() override; | ||||
|   float get_setup_priority() const override { return setup_priority::BUS - 1.0; } | ||||
|  | ||||
|   bool reset_device(); | ||||
|   int reset_int() override; | ||||
|   void write8(uint8_t) override; | ||||
|   void write64(uint64_t) override; | ||||
|   uint8_t read8() override; | ||||
|   uint64_t read64() override; | ||||
|  | ||||
|   void set_active_pullup(bool value) { this->active_pullup_ = value; } | ||||
|   void set_strong_pullup(bool value) { this->strong_pullup_ = value; } | ||||
|  | ||||
|  protected: | ||||
|   void reset_search() override; | ||||
|   uint64_t search_int() override; | ||||
|   bool read_status_(uint8_t *); | ||||
|   bool wait_for_completion_(); | ||||
|   void write8_(uint8_t); | ||||
|   bool one_wire_triple_(bool *branch, bool *id_bit, bool *cmp_id_bit); | ||||
|  | ||||
|   uint64_t address_; | ||||
|   uint8_t last_discrepancy_{0}; | ||||
|   bool last_device_flag_{false}; | ||||
|   bool active_pullup_{false}; | ||||
|   bool strong_pullup_{false}; | ||||
| }; | ||||
| }  // namespace ds2484 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										37
									
								
								esphome/components/ds2484/one_wire.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								esphome/components/ds2484/one_wire.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| import esphome.codegen as cg | ||||
| from esphome.components import i2c | ||||
| from esphome.components.one_wire import OneWireBus | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import CONF_ID | ||||
|  | ||||
| ds2484_ns = cg.esphome_ns.namespace("ds2484") | ||||
|  | ||||
| CONF_ACTIVE_PULLUP = "active_pullup" | ||||
| CONF_STRONG_PULLUP = "strong_pullup" | ||||
|  | ||||
| CODEOWNERS = ["@mrk-its"] | ||||
| DEPENDENCIES = ["i2c"] | ||||
|  | ||||
| DS2484OneWireBus = ds2484_ns.class_( | ||||
|     "DS2484OneWireBus", OneWireBus, i2c.I2CDevice, cg.Component | ||||
| ) | ||||
|  | ||||
| CONFIG_SCHEMA = ( | ||||
|     cv.Schema( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(DS2484OneWireBus), | ||||
|             cv.Optional(CONF_ACTIVE_PULLUP, default=False): cv.boolean, | ||||
|             cv.Optional(CONF_STRONG_PULLUP, default=False): cv.boolean, | ||||
|         } | ||||
|     ) | ||||
|     .extend(cv.COMPONENT_SCHEMA) | ||||
|     .extend(i2c.i2c_device_schema(0x18)) | ||||
| ) | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     await i2c.register_i2c_device(var, config) | ||||
|     await cg.register_component(var, config) | ||||
|     cg.add(var.set_active_pullup(config[CONF_ACTIVE_PULLUP])) | ||||
|     cg.add(var.set_strong_pullup(config[CONF_STRONG_PULLUP])) | ||||
		Reference in New Issue
	
	Block a user