mirror of
https://github.com/esphome/esphome.git
synced 2025-07-29 06:36:45 +00:00
[ds2484] New component (#9147)
This commit is contained in:
parent
00eb56d8db
commit
b9391f2cd4
@ -124,6 +124,7 @@ esphome/components/dht/* @OttoWinter
|
||||
esphome/components/display_menu_base/* @numo68
|
||||
esphome/components/dps310/* @kbx81
|
||||
esphome/components/ds1307/* @badbadc0ffee
|
||||
esphome/components/ds2484/* @mrk-its
|
||||
esphome/components/dsmr/* @glmnet @zuidwijk
|
||||
esphome/components/duty_time/* @dudanov
|
||||
esphome/components/ee895/* @Stock-M
|
||||
|
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]))
|
11
tests/components/ds2484/common.yaml
Normal file
11
tests/components/ds2484/common.yaml
Normal file
@ -0,0 +1,11 @@
|
||||
i2c:
|
||||
- id: i2c_ds2484
|
||||
scl: ${scl_pin}
|
||||
sda: ${sda_pin}
|
||||
|
||||
one_wire:
|
||||
platform: ds2484
|
||||
i2c_id: i2c_ds2484
|
||||
address: 0x18
|
||||
active_pullup: true
|
||||
strong_pullup: false
|
5
tests/components/ds2484/test.esp32-ard.yaml
Normal file
5
tests/components/ds2484/test.esp32-ard.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
substitutions:
|
||||
scl_pin: GPIO16
|
||||
sda_pin: GPIO17
|
||||
|
||||
<<: !include common.yaml
|
5
tests/components/ds2484/test.esp32-c3-ard.yaml
Normal file
5
tests/components/ds2484/test.esp32-c3-ard.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
substitutions:
|
||||
scl_pin: GPIO5
|
||||
sda_pin: GPIO4
|
||||
|
||||
<<: !include common.yaml
|
5
tests/components/ds2484/test.esp32-c3-idf.yaml
Normal file
5
tests/components/ds2484/test.esp32-c3-idf.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
substitutions:
|
||||
scl_pin: GPIO5
|
||||
sda_pin: GPIO4
|
||||
|
||||
<<: !include common.yaml
|
5
tests/components/ds2484/test.esp32-idf.yaml
Normal file
5
tests/components/ds2484/test.esp32-idf.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
substitutions:
|
||||
scl_pin: GPIO16
|
||||
sda_pin: GPIO17
|
||||
|
||||
<<: !include common.yaml
|
5
tests/components/ds2484/test.esp8266-ard.yaml
Normal file
5
tests/components/ds2484/test.esp8266-ard.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
substitutions:
|
||||
scl_pin: GPIO5
|
||||
sda_pin: GPIO4
|
||||
|
||||
<<: !include common.yaml
|
5
tests/components/ds2484/test.rp2040-ard.yaml
Normal file
5
tests/components/ds2484/test.rp2040-ard.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
substitutions:
|
||||
scl_pin: GPIO5
|
||||
sda_pin: GPIO4
|
||||
|
||||
<<: !include common.yaml
|
Loading…
x
Reference in New Issue
Block a user