1
0
mirror of https://github.com/esphome/esphome.git synced 2025-10-30 06:33:51 +00:00

change to new 1-wire platform (#6860)

Co-authored-by: Samuel Sieb <samuel@sieb.net>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
Samuel Sieb
2024-06-11 18:05:44 -07:00
committed by GitHub
parent 7b60543afd
commit 13fabf1cd8
28 changed files with 802 additions and 773 deletions

View File

@@ -0,0 +1,40 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.const import CONF_ADDRESS
CODEOWNERS = ["@ssieb"]
IS_PLATFORM_COMPONENT = True
CONF_ONE_WIRE_ID = "one_wire_id"
one_wire_ns = cg.esphome_ns.namespace("one_wire")
OneWireBus = one_wire_ns.class_("OneWireBus")
OneWireDevice = one_wire_ns.class_("OneWireDevice")
def one_wire_device_schema():
"""Create a schema for a 1-wire device.
:return: The 1-wire device schema, `extend` this in your config schema.
"""
schema = cv.Schema(
{
cv.GenerateID(CONF_ONE_WIRE_ID): cv.use_id(OneWireBus),
cv.Optional(CONF_ADDRESS): cv.hex_uint64_t,
}
)
return schema
async def register_one_wire_device(var, config):
"""Register an 1-wire device with the given config.
Sets the 1-wire bus to use and the 1-wire address.
This is a coroutine, you need to await it with a 'yield' expression!
"""
parent = await cg.get_variable(config[CONF_ONE_WIRE_ID])
cg.add(var.set_one_wire_bus(parent))
if (address := config.get(CONF_ADDRESS)) is not None:
cg.add(var.set_address(address))

View File

@@ -0,0 +1,40 @@
#include "one_wire.h"
namespace esphome {
namespace one_wire {
static const char *const TAG = "one_wire";
const std::string &OneWireDevice::get_address_name() {
if (this->address_name_.empty())
this->address_name_ = std::string("0x") + format_hex(this->address_);
return this->address_name_;
}
std::string OneWireDevice::unique_id() { return "dallas-" + str_lower_case(format_hex(this->address_)); }
bool OneWireDevice::send_command_(uint8_t cmd) {
if (!this->bus_->select(this->address_))
return false;
this->bus_->write8(cmd);
return true;
}
bool OneWireDevice::check_address_() {
if (this->address_ != 0)
return true;
auto devices = this->bus_->get_devices();
if (devices.empty()) {
ESP_LOGE(TAG, "No devices, can't auto-select address");
return false;
}
if (devices.size() > 1) {
ESP_LOGE(TAG, "More than one device, can't auto-select address");
return false;
}
this->address_ = devices[0];
return true;
}
} // namespace one_wire
} // namespace esphome

View File

@@ -0,0 +1,44 @@
#pragma once
#include "one_wire_bus.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome {
namespace one_wire {
#define LOG_ONE_WIRE_DEVICE(this) \
ESP_LOGCONFIG(TAG, " Address: %s (%s)", this->get_address_name().c_str(), \
LOG_STR_ARG(this->bus_->get_model_str(this->address_ & 0xff)));
class OneWireDevice {
public:
/// @brief store the address of the device
/// @param address of the device
void set_address(uint64_t address) { this->address_ = address; }
/// @brief store the pointer to the OneWireBus to use
/// @param bus pointer to the OneWireBus object
void set_one_wire_bus(OneWireBus *bus) { this->bus_ = bus; }
/// Helper to create (and cache) the name for this sensor. For example "0xfe0000031f1eaf29".
const std::string &get_address_name();
std::string unique_id();
protected:
uint64_t address_{0};
OneWireBus *bus_{nullptr}; ///< pointer to OneWireBus instance
std::string address_name_;
/// @brief find an address if necessary
/// should be called from setup
bool check_address_();
/// @brief send command on the bus
/// @param cmd command to send
bool send_command_(uint8_t cmd);
};
} // namespace one_wire
} // namespace esphome

View File

@@ -0,0 +1,88 @@
#include "one_wire_bus.h"
#include "esphome/core/helpers.h"
namespace esphome {
namespace one_wire {
static const char *const TAG = "one_wire";
static const uint8_t DALLAS_MODEL_DS18S20 = 0x10;
static const uint8_t DALLAS_MODEL_DS1822 = 0x22;
static const uint8_t DALLAS_MODEL_DS18B20 = 0x28;
static const uint8_t DALLAS_MODEL_DS1825 = 0x3B;
static const uint8_t DALLAS_MODEL_DS28EA00 = 0x42;
const uint8_t ONE_WIRE_ROM_SELECT = 0x55;
const uint8_t ONE_WIRE_ROM_SEARCH = 0xF0;
const std::vector<uint64_t> &OneWireBus::get_devices() { return this->devices_; }
bool IRAM_ATTR OneWireBus::select(uint64_t address) {
if (!this->reset())
return false;
this->write8(ONE_WIRE_ROM_SELECT);
this->write64(address);
return true;
}
void OneWireBus::search() {
this->devices_.clear();
this->reset_search();
uint64_t address;
while (true) {
{
InterruptLock lock;
if (!this->reset()) {
// Reset failed or no devices present
return;
}
this->write8(ONE_WIRE_ROM_SEARCH);
address = this->search_int();
}
if (address == 0)
break;
auto *address8 = reinterpret_cast<uint8_t *>(&address);
if (crc8(address8, 7) != address8[7]) {
ESP_LOGW(TAG, "Dallas device 0x%s has invalid CRC.", format_hex(address).c_str());
} else {
this->devices_.push_back(address);
}
}
}
void OneWireBus::skip() {
this->write8(0xCC); // skip ROM
}
const LogString *OneWireBus::get_model_str(uint8_t model) {
switch (model) {
case DALLAS_MODEL_DS18S20:
return LOG_STR("DS18S20");
case DALLAS_MODEL_DS1822:
return LOG_STR("DS1822");
case DALLAS_MODEL_DS18B20:
return LOG_STR("DS18B20");
case DALLAS_MODEL_DS1825:
return LOG_STR("DS1825");
case DALLAS_MODEL_DS28EA00:
return LOG_STR("DS28EA00");
default:
return LOG_STR("Unknown");
}
}
void OneWireBus::dump_devices_(const char *tag) {
if (this->devices_.empty()) {
ESP_LOGW(tag, " Found no devices!");
} else {
ESP_LOGCONFIG(tag, " Found devices:");
for (auto &address : this->devices_) {
ESP_LOGCONFIG(tag, " 0x%s (%s)", format_hex(address).c_str(), LOG_STR_ARG(get_model_str(address & 0xff)));
}
}
}
} // namespace one_wire
} // namespace esphome

View File

@@ -0,0 +1,61 @@
#pragma once
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
#include <vector>
namespace esphome {
namespace one_wire {
class OneWireBus {
public:
/** Reset the bus, should be done before all write operations.
*
* Takes approximately 1ms.
*
* @return Whether the operation was successful.
*/
virtual bool reset() = 0;
/// Write a word to the bus. LSB first.
virtual void write8(uint8_t val) = 0;
/// Write a 64 bit unsigned integer to the bus. LSB first.
virtual void write64(uint64_t val) = 0;
/// Write a command to the bus that addresses all devices by skipping the ROM.
void skip();
/// Read an 8 bit word from the bus.
virtual uint8_t read8() = 0;
/// Read an 64-bit unsigned integer from the bus.
virtual uint64_t read64() = 0;
/// Select a specific address on the bus for the following command.
bool select(uint64_t address);
/// Return the list of found devices.
const std::vector<uint64_t> &get_devices();
/// Search for 1-Wire devices on the bus.
void search();
/// Get the description string for this model.
const LogString *get_model_str(uint8_t model);
protected:
std::vector<uint64_t> devices_;
/// log the found devices
void dump_devices_(const char *tag);
/// Reset the device search.
virtual void reset_search() = 0;
/// Search for a 1-Wire device on the bus. Returns 0 if all devices have been found.
virtual uint64_t search_int() = 0;
};
} // namespace one_wire
} // namespace esphome