1
0
mirror of https://github.com/esphome/esphome.git synced 2025-04-15 23:30:28 +01:00

Initialize Dallas PIO component to manage 1-wire Dallas addressable switches as DS2413, DS2406, DS2408

This commit is contained in:
Thierry DUVERNOY 2025-01-15 15:31:35 +01:00
parent df26ace0f1
commit efcefe6627
11 changed files with 977 additions and 0 deletions

View File

@ -0,0 +1,8 @@
from .dallas_pio import CONFIG_SCHEMA, DallasPio, to_code
CODEOWNERS = ["@tdy91"]
DEPENDENCIES = ["one_wire", "binary_sensor", "switch"]
AUTO_LOAD = ["binary_sensor", "switch"]
__all__ = ["CONFIG_SCHEMA", "DallasPio", "to_code"]

View File

@ -0,0 +1,84 @@
#include "binary_sensor.h"
namespace esphome {
namespace dallas_pio {
void DallasPioBinarySensor::setup() {
if (this->dallas_pio_ == nullptr) {
ESP_LOGE(TAG, "DallasPioBinarySensor setup failed - DallasPio not set for this binary sensor.");
return;
}
ESP_LOGI(TAG, "DallasPioBinarySensor setup - DallasPio set for this binary sensor.");
this->address_ = this->dallas_pio_->get_address();
this->reference_ = this->dallas_pio_->get_reference();
this->family_code_ = this->dallas_pio_->get_family_code();
// this->bus_ = this->dallas_pio_->get_bus();
}
void DallasPioBinarySensor::dump_config() {
ESP_LOGCONFIG(TAG, "Dallas PIO Binary Sensor:");
ESP_LOGCONFIG(TAG, " dallas_pio_id: %s", this->dallas_pio_->get_id().c_str());
if (this->reference_ == "DS2408") {
ESP_LOGCONFIG(TAG, " pin: P%c", '0' - 1 + this->pin_); // P0, P1, ...
} else {
ESP_LOGCONFIG(TAG, " pin: PIO%c", 'A' - 1 + this->pin_); // PIOA, PIOB, ...
}
ESP_LOGCONFIG(TAG, " pin inverted: %s", this->pin_inverted_ ? "true" : "false");
/*
if (this->address_ == 0) {
ESP_LOGCONFIG(TAG, " address: invalid (null)");
} else {
ESP_LOGCONFIG(TAG, " address: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
(uint8_t) (this->address_ >> 56),
(uint8_t) (this->address_ >> 48),
(uint8_t) (this->address_ >> 40),
(uint8_t) (this->address_ >> 32),
(uint8_t) (this->address_ >> 24),
(uint8_t) (this->address_ >> 16),
(uint8_t) (this->address_ >> 8),
(uint8_t) (this->address_));
ESP_LOGCONFIG(TAG, " Family code: 0x%02X", this->family_code_);
ESP_LOGCONFIG(TAG, " Reference: %s", this->reference_.c_str());
}
*/
ESP_LOGCONFIG(TAG, " Name: %s", this->EntityBase::name_.c_str());
// this->component_->log_one_wire_device();
LOG_UPDATE_INTERVAL(this);
}
void DallasPioBinarySensor::update() {
// Ref Analog Devices DS2413.pdf p6 of 19
// | b7 b6 b5 b4 | b3 | b2 | b1 | b0 |
// | Complement of b3 to b0 | PIOB Output | PIOB Pin | PIOA Output | PIOA Pin |
// | | Latch State | State | Latch State | State |
// ESP_LOGCONFIG(TAG, "Dallas PIO Binary Sensor Update !");
uint8_t state = 0;
if (this->dallas_pio_->check_address() == 0) {
this->status_set_warning();
return;
}
this->status_clear_warning();
if (this->reference_ == "DS2413") {
if (!this->dallas_pio_->read_state(state, this->pin_)) {
return;
}
} else if (this->reference_ == "DS2406") {
// Action pour DS2406
} else if (this->reference_ == "DS2408") {
// Action pour DS2408
} else {
// Action par défaut
}
if (this->pin_inverted_) {
state = !state;
}
this->publish_state(state);
}
} // namespace dallas_pio
} // namespace esphome

View File

@ -0,0 +1,42 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/binary_sensor/binary_sensor.h"
#include "dallas_pio_constants.h"
#include "dallas_pio.h"
namespace esphome {
namespace dallas_pio {
class DallasPioBinarySensor : public PollingComponent, public binary_sensor::BinarySensor {
public:
DallasPioBinarySensor() : dallas_pio_(nullptr), pio_pin_(0) {}
DallasPioBinarySensor(DallasPio *dallas_pio, uint8_t pio_pin) : dallas_pio_(dallas_pio), pio_pin_(pio_pin) {}
void setup() override;
void dump_config() override;
void update() override;
using EntityBase::set_name;
void set_dallas_pio(DallasPio *dallas_pio) { this->dallas_pio_ = dallas_pio; }
void set_address(uint64_t address) { this->address_ = address; }
void set_pin(uint8_t pin) { this->pin_ = pin; }
void set_pin_inverted(bool pin_inverted) { this->pin_inverted_ = pin_inverted; }
void set_pin_mode(bool input, bool output) {
this->is_input_ = input;
this->is_output_ = output;
}
// void set_inverted(bool inverted) { this->inverted_ = inverted; }
protected:
DallasPio *dallas_pio_;
uint8_t pio_pin_;
std::string reference_;
uint8_t family_code_;
uint64_t address_;
uint8_t pin_;
bool pin_inverted_;
bool is_input_;
bool is_output_;
};
} // namespace dallas_pio
} // namespace esphome

View File

@ -0,0 +1,68 @@
import esphome.codegen as cg
from esphome.components import binary_sensor
import esphome.config_validation as cv
from esphome.const import CONF_INVERTED, CONF_MODE, CONF_PIN
DEPENDENCIES = ["binary_sensor", "dallas_pio"]
AUTO_LOAD = ["binary_sensor"]
dallas_pio_ns = cg.esphome_ns.namespace("dallas_pio")
DallasPioBinarySensor = dallas_pio_ns.class_(
"DallasPioBinarySensor",
cg.PollingComponent,
binary_sensor.BinarySensor,
)
def validate_mode(value):
if value.get("input", False) is not True:
raise cv.Invalid(
"The 'input' field must always be 'true' for Dallas PIO binary sensors."
)
if value.get("output", False) is True:
raise cv.Invalid("The 'output' field must be 'false' if 'input' is 'true'.")
return value
CUSTOM_PIN_SCHEMA = cv.Schema(
{
cv.Required("number"): cv.one_of("PIOA", "PIOB", upper=True),
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
cv.Optional(CONF_MODE, default={"input": True}): validate_mode,
}
)
CONFIG_SCHEMA = (
binary_sensor.binary_sensor_schema(
DallasPioBinarySensor,
)
.extend(
{
cv.Required(CONF_PIN): CUSTOM_PIN_SCHEMA,
cv.Required("dallas_pio_id"): cv.use_id(dallas_pio_ns.class_("DallasPio")),
}
)
.extend(cv.polling_component_schema("1s"))
)
async def to_code(config):
var = await binary_sensor.new_binary_sensor(config)
await cg.register_component(var, config)
dallas_pio_ref = await cg.get_variable(config["dallas_pio_id"])
cg.add(var.set_dallas_pio(dallas_pio_ref))
# Extract pin configuration
pin_config = config[CONF_PIN]
pin_number = pin_config["number"] # "PIOA" or "PIOB"
pin_inverted = pin_config[CONF_INVERTED]
pin_mode = pin_config[CONF_MODE]
# C++ configuration association
if pin_number == "PIOA":
cg.add(var.set_pin(0x01)) # PIOA assiociated to 0x01
elif pin_number == "PIOB":
cg.add(var.set_pin(0x02)) # PIOB assiociated to 0x02
cg.add(var.set_pin_inverted(pin_inverted))
cg.add(var.set_pin_mode(pin_mode.get("input", True), pin_mode.get("output", False)))
# cg.add(var.set_inverted(inverted))

View File

@ -0,0 +1,406 @@
#include "dallas_pio.h"
namespace esphome {
namespace dallas_pio {
DallasPio::DallasPio()
: id_(""),
one_wire_id_(),
name_(""),
reference_(""),
address_(0),
reference_from_address_(""),
family_code_(0),
is_setup_done_(false) {}
void DallasPio::set_id(const std::string &id) { this->id_ = id; }
void DallasPio::set_name(const std::string &name) { this->name_ = name; }
void DallasPio::set_address(uint64_t address) {
this->address_ = address;
OneWireDevice::set_address(address);
}
void DallasPio::set_reference(const std::string &reference) { this->reference_ = reference; }
void DallasPio::set_crc_enabled(bool enabled) { this->crc_enabled_ = enabled; }
void DallasPio::set_one_wire_id(const std::string &one_wire_id) { this->one_wire_id_ = one_wire_id; }
bool DallasPio::check_address() { return this->check_address_(); }
void DallasPio::setup() {
if (this->is_setup_done_)
return;
// ESP_LOGD("dallas_pio", "Setting up DallasPio: %s", this->name_.c_str());
this->initialize_reference_();
this->is_setup_done_ = true;
}
void DallasPio::dump_config() {
ESP_LOGCONFIG(TAG, "Dallas PIO :");
ESP_LOGCONFIG(TAG, " Id: %s", this->id_.c_str());
ESP_LOGCONFIG(TAG, " Reference: %s", this->reference_.c_str());
if (this->address_ == 0) {
ESP_LOGCONFIG(TAG, " address: invalid (null)");
} else {
ESP_LOGCONFIG(TAG, " address: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", (uint8_t) (this->address_ >> 56),
(uint8_t) (this->address_ >> 48), (uint8_t) (this->address_ >> 40), (uint8_t) (this->address_ >> 32),
(uint8_t) (this->address_ >> 24), (uint8_t) (this->address_ >> 16), (uint8_t) (this->address_ >> 8),
(uint8_t) (this->address_));
ESP_LOGCONFIG(TAG, " Family code: 0x%02X", this->family_code_);
if (reference_ != reference_from_address_) {
ESP_LOGCONFIG(TAG, " Reference from family code: %s", this->reference_from_address_.c_str());
ESP_LOGW(TAG, " WARNING: reference from family code does not match reference !!!");
}
}
ESP_LOGCONFIG(TAG, " Name: %s", this->name_.c_str());
if (this->one_wire_id_.has_value()) {
ESP_LOGCONFIG(TAG, " OneWire ID: %s", this->one_wire_id_->c_str());
} else {
ESP_LOGCONFIG(TAG, " OneWire ID: not defined");
}
LOG_ONE_WIRE_DEVICE(this);
}
bool DallasPio::read_state(uint8_t &state, uint8_t pin) {
this->pin_ = pin;
if (this->reference_ == "DS2413") {
// ESP_LOGD(TAG, "DallasPio read_state %u pin %u", state, this->pin_);
return this->ds2413_get_state_(state);
} else if (this->reference_ == "DS2406") {
return this->ds2406_get_state_(state, this->crc_enabled_);
} else if (this->reference_ == "DS2408") {
// Action pour DS2408
} else {
// Action par défaut
}
return true;
}
bool DallasPio::write_state(bool state, uint8_t pin, bool pin_inverted) {
this->pin_ = pin;
this->pin_inverted_ = pin_inverted;
// ESP_LOGW(TAG, "DallasPio write_state %u pin %u pin_ %u", state, pin, this->pin_);
if (this->reference_ == "DS2413") {
this->ds2413_write_state_(state);
} else if (this->reference_ == "DS2406") {
this->ds2406_write_state_(state, this->crc_enabled_);
} else if (this->reference_ == "DS2408") {
// Action for DS2408
} else {
// Default action
}
return true;
}
/************/
/* DS2413 */
/************/
bool DallasPio::ds2413_get_state_(uint8_t &state) {
// Ref DS2413.pdf p6 of 9
// | b7 b6 b5 b4 | b3 | b2 | b1 | b0 |
// | Complement of b3 to b0 | PIOB Output | PIOB Pin | PIOA Output | PIOA Pin |
// | | Latch State | State | Latch State | State |
// ESP_LOGCONFIG(TAG, "Dallas PIO Binary Sensor Update !");
uint8_t results;
bool ok = false;
// Initialize One-Wire bus for this device
if (!this->check_address_()) {
this->status_set_warning();
return false;
}
if (!this->bus_->reset()) {
ESP_LOGW(TAG, "Failed to reset One-Wire bus.");
this->status_set_warning();
return false;
}
{
InterruptLock lock;
this->send_command_(DALLAS_COMMAND_PIO_ACCESS_READ);
results = this->bus_->read8();
}
ok = (~results & 0x0F) == (results >> 4);
// ESP_LOGD(TAG, "results1=%02x", results);
results &= 0x0F;
// ESP_LOGD(TAG, "results2=%02x", results);
if (!this->bus_->reset()) {
ESP_LOGW(TAG, "Failed to reset One-Wire bus.");
this->status_set_warning();
return false;
}
switch (this->pin_) {
case 0x01: // PIOA
state = (results & 0x01);
break;
case 0x02: // PIOB
state = ((results >> 2) & 0x01);
break;
default:
return false;
break;
}
return true;
} // ds2413_get_state_
void DallasPio::ds2413_write_state_(bool state) {
// Ref Analog Devices DS2413.pdf p8 of 19
// | b7 b6 b5 b4 b3 b2 | b1 | b0 |
// | x x x x x x | PIOB | PIOA |
uint8_t ack = 0;
// Initialize One-Wire bus for this device
if (!this->check_address_()) {
this->status_set_warning();
return;
}
if (!this->bus_->reset()) {
ESP_LOGW(TAG, "Failed to reset One-Wire bus.");
this->status_set_warning();
return;
}
if ((this->pin_ >= 1) && (this->pin_ <= 2)) {
uint8_t mask = 1 << (this->pin_ - 1);
// If state different than this->pin_inverted_
if (state ^ this->pin_inverted_) {
this->PioOutputRegister_ &= ~mask; // set bit bx to 0
} else {
this->PioOutputRegister_ |= mask; // set bx to 1
}
} else {
return;
}
{
InterruptLock lock;
this->send_command_(DALLAS_COMMAND_PIO_ACCESS_WRITE);
this->bus_->write8(this->PioOutputRegister_); // Send data
this->bus_->write8(~this->PioOutputRegister_); // Invert data and resend
ack = this->bus_->read8(); // 0xAA=success, 0xFF=failure
}
if (ack == DALLAS_COMMAND_PIO_ACK_SUCCESS) {
this->bus_->read8(); // Read the PIOA PIOB status byte
} else {
return;
}
if (!this->bus_->reset()) { // reset to end command
ESP_LOGW(TAG, "Failed to reset One-Wire bus.");
this->status_set_warning();
return;
}
} // ds2413_write_state
/************/
/* DS2406 */
/************/
bool DallasPio::ds2406_get_state_(uint8_t &state, bool use_crc = false) {
// Ref Dallas Semiconductor MAXIM DS2406.pdf
// Dallas Semiconductor Application Note 27 app27.pdf
// CHANNEL CONTROL BYTE 1
// b7 b6 b5 b4 b3 b2 b1 b0
// ALR IM TOG IC CHS1 CHS0 CRC1 CRC0
// ALR=0 & IM=1, TOG=0 & IC=0 : do not change activity latch, read all bits from the selected channel & async mode
// CHANNEL CONTROL BYTE 2
// reserved for future development, must always be 0xFF
// CHANNEL INFO BYTE
// b7 b6 b5 b4 b3 b2 b1 b0
// Supply Number of PIOB PIOA PIOB PIOA PIOB PIOA
// Indication Channels Activity Activity Sensed Sensed Channel Channel
// 0 = no 0 = channel Latch Latch Level Level Flip-Flop Q Flip-Flop Q
// supply A only
// Please note :
// CRC1 CRC0
// 0 0 : CRC mode 0 = CRC disabled (no CRC at all)
// 0 1 : CRC mode 1 = CRC after every byte
uint8_t channel_control_byte_1;
uint8_t channel_control_byte_2 = 0xFF;
uint8_t channel_info_byte;
uint8_t received_crc = 0;
const char *strPIO = nullptr;
// Initialize One-Wire bus for this device
if (!this->check_address_()) {
this->status_set_warning();
return false;
}
if (!this->bus_->reset()) {
ESP_LOGW(TAG, "Failed to reset One-Wire bus.");
this->status_set_warning();
return false;
}
switch (this->pin_) {
case 0x01: // PIOA
channel_control_byte_1 = use_crc ? 0b10000101 : 0b10000100; // ALR=1, CHS0=1, CRC mode 1 or mode 0
break;
case 0x02: // PIOB
channel_control_byte_1 = use_crc ? 0b10001001 : 0b10001000; // ALR=1, CHS1=1, CRC mode 1 or mode 0
break;
default:
return false;
break;
}
{
InterruptLock lock;
this->send_command_(DALLAS_COMMAND_PIO_ACCESS_READ);
// write CHANNEL CONTROL BYTE 1
this->bus_->write8(channel_control_byte_1);
// write CHANNEL CONTROL BYTE 2
this->bus_->write8(channel_control_byte_2);
// read CHANNEL INFO BYTE
channel_info_byte = this->bus_->read8();
if (use_crc) {
received_crc = this->bus_->read8();
}
}
if (use_crc) {
ESP_LOGD(TAG, "CRC for Channel Info Byte: 0x%04X", use_crc);
if (!this->ds2406_verify_crc_(channel_control_byte_1, channel_control_byte_2, channel_info_byte, use_crc)) {
ESP_LOGW(TAG, "CRC verification failed!");
this->status_set_warning();
return false;
}
}
if (!this->bus_->reset()) {
ESP_LOGW(TAG, "Failed to reset One-Wire bus.");
this->status_set_warning();
return false;
}
// read CHANNEL INFO BYTE
bool pio_flipflop;
bool pio_sensed_level;
bool pio_activity_latch;
const bool has_channel_b = channel_info_byte & 0x40;
const bool has_supply = channel_info_byte & 0x80;
switch (this->pin_) {
case 0x01: // PIOA
pio_flipflop = channel_info_byte & 0x01;
pio_sensed_level = channel_info_byte & 0x04;
pio_activity_latch = channel_info_byte & 0x10;
strPIO = "PIOA";
break;
case 0x02: // PIOB
pio_flipflop = channel_info_byte & 0x02;
pio_sensed_level = channel_info_byte & 0x08;
pio_activity_latch = channel_info_byte & 0x20;
strPIO = "PIOB";
break;
default:
ESP_LOGW(TAG, "DallasPio DS2406 pin %u does not exist !", this->pin_);
this->status_set_warning();
return false;
break;
}
if (pio_flipflop == 0) {
ESP_LOGW(TAG, "DallasPio DS2406 PIO flipflop must be 1 to read %s", strPIO);
this->status_set_warning();
return false;
}
state = pio_sensed_level;
return true;
} // ds2406_get_state_
void DallasPio::ds2406_write_state_(bool state, bool use_crc = false) {
// Ref Dallas Semiconductor MAXIM DS2406.pdf
// Dallas Semiconductor Application Note 27 app27.pdf
// CHANNEL CONTROL BYTE 1
// b7 b6 b5 b4 b3 b2 b1 b0
// ALR IM TOG IC CHS1 CHS0 CRC1 CRC0
// ALR=0 & IM=0, TOG=0 & IC=0 : do not change activity latch, write all bits to the selected channel & async mode
// CHS1=01 CHS0=1 : PIOA, CHS1=1 CHS0=0 : PIOB
// CHANNEL CONTROL BYTE 2
// reserved for future development, must always be 0xFF
// CHANNEL INFO BYTE
// b7 b6 b5 b4 b3 b2 b1 b0
// Supply Number of PIOB PIOA PIOB PIOA PIOB PIOA
// Indication Channels Activity Activity Sensed Sensed Channel Channel
// 0 = no 0 = channel Latch Latch Level Level Flip-Flop Q Flip-Flop Q
// supply A only
// Initialize One-Wire bus for this device
if (!this->check_address_()) {
this->status_set_warning();
return;
}
if (!this->bus_->reset()) {
ESP_LOGW(TAG, "Failed to reset One-Wire bus.");
this->status_set_warning();
return;
}
// ALR=0,IM=0,TOG=0,IC=0, PIOA:CHS1=0,CHS0=1, PIOB:CHS1=1,CHS0=0, CRC1=0, CRC0=0
uint8_t channel_control_byte_1;
switch (this->pin_) {
case 0x01: // PIOA
channel_control_byte_1 = use_crc ? 0b00000101 : 0b00000100;
break;
case 0x02: // PIOB
channel_control_byte_1 = use_crc ? 0b00001001 : 0b00001000;
break;
default:
return;
break;
}
uint8_t channel_control_byte_2 = 0xFF;
uint8_t channel_info_byte;
{
InterruptLock lock;
this->send_command_(DALLAS_COMMAND_PIO_ACCESS_READ);
// write CHANNEL CONTROL BYTE 1
this->bus_->write8(channel_control_byte_1);
// write CHANNEL CONTROL BYTE 2
this->bus_->write8(channel_control_byte_2);
channel_info_byte = this->bus_->read8();
this->bus_->write8(state ? 0xFF : 0x00);
}
if (!this->bus_->reset()) {
ESP_LOGW(TAG, "Failed to reset One-Wire bus.");
this->status_set_warning();
return;
}
} // ds2406_write_state
bool DallasPio::ds2406_verify_crc_(uint8_t control1, uint8_t control2, uint8_t info, uint16_t received_crc) {
uint16_t computed_crc = 0;
this->crc_reset_();
this->crc_shift_byte_(DALLAS_COMMAND_PIO_ACCESS_READ);
this->crc_shift_byte_(control1);
this->crc_shift_byte_(control2);
this->crc_shift_byte_(info);
computed_crc = this->crc_read_();
ESP_LOGD(TAG, "Computed CRC: 0x%04X", computed_crc);
return computed_crc == received_crc;
}
/************/
/* DS2408 */
/************/
bool DallasPio::ds2408_get_state_(uint8_t &state, bool use_crc = false) {
ESP_LOGW(TAG, "DallasPio DS2408 : ds2408_get_state_ to be implemented");
this->status_set_warning();
return false;
}
void DallasPio::ds2408_write_state_(bool state, bool use_crc = false) {
ESP_LOGW(TAG, "DallasPio DS2408 : ds2408_write_state_ to be implemented");
this->status_set_warning();
return;
}
void DallasPio::crc_reset_() { this->crc_ = 0x0000; }
void DallasPio::crc_shift_byte_(uint8_t byte) {
for (int i = 0; i < 8; i++) {
bool mix = (this->crc_ ^ byte) & 0x01;
this->crc_ >>= 1;
if (mix)
this->crc_ ^= 0xA001;
byte >>= 1;
}
}
uint16_t DallasPio::crc_read_() const { return this->crc_; }
} // namespace dallas_pio
} // namespace esphome

View File

@ -0,0 +1,96 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/one_wire/one_wire.h"
#include "dallas_pio_constants.h"
namespace esphome {
namespace dallas_pio {
class DallasPio : public Component, public one_wire::OneWireDevice {
public:
DallasPio();
std::string id_;
optional<std::string> one_wire_id_;
void set_id(const std::string &id);
void set_name(const std::string &name);
void set_address(uint64_t address);
void set_reference(const std::string &reference);
void set_crc_enabled(bool enabled);
void set_one_wire_id(const std::string &one_wire_id);
bool check_address();
void setup() override;
void dump_config() override;
void initialize_reference_() {
this->family_code_ = static_cast<uint8_t>(this->address_ & 0xFF);
switch (this->family_code_) {
case DALLAS_MODEL_DS2413:
this->reference_from_address_ = "DS2413";
break;
case DALLAS_MODEL_DS2406:
this->reference_from_address_ = "DS2406";
break;
case DALLAS_MODEL_DS2408:
this->reference_from_address_ = "DS2408";
break;
default:
this->reference_from_address_ = "Unknown";
break;
}
if (this->reference_ == "") {
if (this->reference_from_address_ == "Unknown") {
this->reference_ = "DS2413";
} else {
this->reference_ = this->reference_from_address_;
}
}
if (this->reference_ == "DS2413") {
PioOutputRegister_ = 0xFF;
} else if (this->reference_ == "DS2406") {
// Action pour DS2406
} else if (this->reference_ == "DS2408") {
// Action pour DS2408
} else {
// Action par défaut
}
}
bool read_state(uint8_t &state, uint8_t pin);
bool write_state(bool state, uint8_t pin, bool pin_inverted);
const std::string &get_name() const { return this->name_; }
const std::string &get_id() const { return this->id_; }
uint64_t get_address() const { return this->address_; }
const std::string &get_reference() const { return this->reference_; }
uint8_t get_family_code() const { return this->family_code_; }
protected:
std::string name_;
std::string reference_;
uint64_t address_;
std::string reference_from_address_;
uint8_t family_code_;
bool is_setup_done_ = false;
bool ds2413_get_state_(uint8_t &state);
void ds2413_write_state_(bool state);
bool ds2406_get_state_(uint8_t &state, bool use_crc);
void ds2406_write_state_(bool state, bool use_crc);
bool ds2408_get_state_(uint8_t &state, bool use_crc);
void ds2408_write_state_(bool state, bool use_crc);
uint16_t crc_;
bool crc_enabled_ = false;
bool ds2406_verify_crc_(uint8_t control1, uint8_t control2, uint8_t info, uint16_t received_crc);
void crc_reset_();
void crc_shift_byte_(uint8_t byte);
uint16_t crc_read_() const;
// uint8_t calculate_crc_(std::initializer_list<uint8_t> data);
uint8_t pin_;
bool pin_inverted_;
uint8_t PioOutputRegister_;
};
} // namespace dallas_pio
} // namespace esphome

View File

@ -0,0 +1,62 @@
import esphome.codegen as cg
from esphome.components import one_wire
import esphome.config_validation as cv
from esphome.const import CONF_ADDRESS, CONF_ID, CONF_NAME
dallas_pio_ns = cg.esphome_ns.namespace("dallas_pio")
DallasPio = dallas_pio_ns.class_(
"DallasPio",
cg.Component,
one_wire.OneWireDevice,
)
CONF_REFERENCE = "reference"
CONF_CRC = "crc"
def validate_crc_option(config_list):
for conf in config_list:
reference = conf.get("reference", "").upper()
if not reference: # Si 'reference' n'est pas défini, on passe
continue
if reference == "DS2406" and "crc" not in conf:
raise cv.Invalid("Option 'crc' is required when 'reference' is DS2406.")
if reference != "DS2406" and "crc" in conf:
raise cv.Invalid("Option 'crc' is not supported for this reference.")
return config_list
CONFIG_SCHEMA = cv.All(
cv.ensure_list(
cv.Schema(
{
cv.GenerateID(): cv.declare_id(DallasPio),
cv.Optional(CONF_NAME): cv.string_strict,
cv.Required(CONF_ADDRESS): cv.hex_uint64_t,
cv.Optional(CONF_REFERENCE, default=""): cv.one_of(
"", "DS2413", "DS2406", "DS2408", upper=True
),
cv.Optional(CONF_CRC, default=False): cv.boolean,
}
).extend(one_wire.one_wire_device_schema())
),
validate_crc_option,
)
async def to_code(config):
for conf in config:
var = cg.new_Pvariable(conf[CONF_ID])
if CONF_NAME in conf:
cg.add(var.set_name(conf[CONF_NAME]))
cg.add(var.set_address(conf[CONF_ADDRESS]))
if CONF_REFERENCE in conf:
cg.add(var.set_reference(conf[CONF_REFERENCE]))
if CONF_CRC in conf and conf[CONF_REFERENCE] == "DS2406":
cg.add(var.set_crc_enabled(conf[CONF_CRC]))
if CONF_ID in conf:
cg.add(var.set_id(conf[CONF_ID].id))
if "one_wire_id" in conf:
cg.add(var.set_one_wire_id(conf["one_wire_id"].id))
await cg.register_component(var, config)
await one_wire.register_one_wire_device(var, conf)

View File

@ -0,0 +1,17 @@
#pragma once
namespace esphome {
namespace dallas_pio {
static const char *const TAG = "dallas_pio";
static const uint8_t DALLAS_MODEL_DS2413 = 0xBA;
static const uint8_t DALLAS_MODEL_DS2406 = 0x12;
static const uint8_t DALLAS_MODEL_DS2408 = 0x29;
static const uint8_t DALLAS_COMMAND_PIO_ACCESS_READ = 0xF5;
static const uint8_t DALLAS_COMMAND_PIO_ACCESS_WRITE = 0x5A;
static const uint8_t DALLAS_COMMAND_PIO_ACK_SUCCESS = 0xAA;
static const uint8_t DALLAS_COMMAND_PIO_ACK_ERROR = 0xFF;
} // namespace dallas_pio
} // namespace esphome

View File

@ -0,0 +1,81 @@
#include "switch.h"
namespace esphome {
namespace dallas_pio {
void DallasPioSwitch::setup() {
if (this->dallas_pio_ == nullptr) {
ESP_LOGE(TAG, "DallasPioSwitch setup failed - DallasPio not set for this switch.");
return;
}
ESP_LOGI(TAG, "DallasPioSwitch setup - DallasPio set for this switch.");
this->address_ = this->dallas_pio_->get_address();
this->reference_ = this->dallas_pio_->get_reference();
this->family_code_ = this->dallas_pio_->get_family_code();
}
void DallasPioSwitch::dump_config() {
ESP_LOGCONFIG(TAG, "Dallas PIO Switch:");
ESP_LOGCONFIG(TAG, " dallas_pio_id: %s", this->dallas_pio_->get_id().c_str());
if (this->reference_ == "DS2408") {
ESP_LOGCONFIG(TAG, " pin: P%c", '0' - 1 + this->pin_); // P0, P1, ...
} else {
ESP_LOGCONFIG(TAG, " pin: PIO%c", 'A' - 1 + this->pin_); // PIOA, PIOB, ...
}
ESP_LOGCONFIG(TAG, " pin inverted: %s", this->pin_inverted_ ? "true" : "false");
ESP_LOGCONFIG(TAG, " inverted: %s", this->inverted_ ? "true" : "false");
/*
if (this->address_ == 0) {
ESP_LOGCONFIG(TAG, " address: invalid (null)");
} else {
ESP_LOGCONFIG(TAG, " address: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
(uint8_t) (this->address_ >> 56),
(uint8_t) (this->address_ >> 48),
(uint8_t) (this->address_ >> 40),
(uint8_t) (this->address_ >> 32),
(uint8_t) (this->address_ >> 24),
(uint8_t) (this->address_ >> 16),
(uint8_t) (this->address_ >> 8),
(uint8_t) (this->address_));
ESP_LOGCONFIG(TAG, " Family code: 0x%02X", this->family_code_);
ESP_LOGCONFIG(TAG, " Reference: %s", this->reference_.c_str());
}
*/
ESP_LOGCONFIG(TAG, " Name: %s", this->EntityBase::name_.c_str());
// this->component_->log_one_wire_device();
// LOG_UPDATE_INTERVAL(this);
}
void DallasPioSwitch::loop() {}
void DallasPioSwitch::write_state(bool state) {
ESP_LOGD(TAG, "DallasPioSwitch write_state %u", state);
if (this->inverted_) {
state = !state;
}
if (this->dallas_pio_->check_address() == 0) {
this->status_set_warning();
return;
}
this->status_clear_warning();
if (this->reference_ == "DS2413") {
if (!this->dallas_pio_->write_state(state, this->pin_, this->pin_inverted_)) {
return;
}
} else if (this->reference_ == "DS2406") {
// Action pour DS2406
} else if (this->reference_ == "DS2408") {
// Action pour DS2408
} else {
// Action par défaut
}
this->publish_state(state); // Set state in ESPHome
}
} // namespace dallas_pio
} // namespace esphome

View File

@ -0,0 +1,45 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/switch/switch.h"
#include "dallas_pio_constants.h"
#include "dallas_pio.h"
namespace esphome {
namespace dallas_pio {
class DallasPioSwitch : public Component, public switch_::Switch {
public:
DallasPioSwitch() : dallas_pio_(nullptr), pio_pin_(0) {}
DallasPioSwitch(DallasPio *dallas_pio, uint8_t pio_pin) : dallas_pio_(dallas_pio), pio_pin_(pio_pin) {}
void setup() override;
void dump_config() override;
void loop() override;
void write_state(bool state) override;
using EntityBase::set_name;
void set_dallas_pio(DallasPio *dallas_pio) { this->dallas_pio_ = dallas_pio; }
void set_address(uint64_t address) { this->address_ = address; }
void set_pin(uint8_t pin) { this->pin_ = pin; }
void set_pin_inverted(bool pin_inverted) { this->pin_inverted_ = pin_inverted; }
void set_pin_mode(bool input, bool output) {
this->is_input_ = input;
this->is_output_ = output;
}
void set_inverted(bool inverted) { this->inverted_ = inverted; }
protected:
DallasPio *dallas_pio_;
uint8_t pio_pin_;
std::string reference_;
uint8_t family_code_;
uint64_t address_;
uint8_t pin_;
bool pin_inverted_;
bool inverted_;
bool is_input_;
bool is_output_;
};
} // namespace dallas_pio
} // namespace esphome

View File

@ -0,0 +1,68 @@
import esphome.codegen as cg
from esphome.components import switch
import esphome.config_validation as cv
from esphome.const import CONF_INVERTED, CONF_MODE, CONF_PIN
DEPENDENCIES = ["switch", "dallas_pio"]
AUTO_LOAD = ["switch"]
dallas_pio_ns = cg.esphome_ns.namespace("dallas_pio")
DallasPioSwitch = dallas_pio_ns.class_(
"DallasPioSwitch",
cg.Component,
switch.Switch,
)
def validate_mode(value):
if value.get("output", False) is not True:
raise cv.Invalid(
"The 'output' field must always be 'true' for Dallas PIO switches."
)
if value.get("input", False) is True:
raise cv.Invalid("The 'input' field must be 'false' if 'output' is 'true'.")
return value
CUSTOM_PIN_SCHEMA = cv.Schema(
{
cv.Required("number"): cv.one_of("PIOA", "PIOB", upper=True),
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
cv.Optional(CONF_MODE, default={"output": True}): validate_mode,
}
)
CONFIG_SCHEMA = switch.switch_schema(
DallasPioSwitch,
).extend(
{
cv.Required(CONF_PIN): CUSTOM_PIN_SCHEMA,
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
cv.Required("dallas_pio_id"): cv.use_id(dallas_pio_ns.class_("DallasPio")),
}
)
async def to_code(config):
var = await switch.new_switch(config)
await cg.register_component(var, config)
dallas_pio_ref = await cg.get_variable(config["dallas_pio_id"])
cg.add(var.set_dallas_pio(dallas_pio_ref))
# cg.add(dallas_pio_ref.setup())
# cg.add(var.set_address(dallas_pio_ref.get_address()))
# Extract pin configuration
pin_config = config[CONF_PIN]
pin_number = pin_config["number"] # "PIOA" or "PIOB"
pin_inverted = pin_config[CONF_INVERTED]
pin_mode = pin_config[CONF_MODE]
# C++ configuration association
if pin_number == "PIOA":
cg.add(var.set_pin(0x01)) # PIOA assiociated to 0x01
elif pin_number == "PIOB":
cg.add(var.set_pin(0x02)) # PIOB assiociated to 0x02
cg.add(var.set_pin_inverted(pin_inverted))
cg.add(var.set_pin_mode(pin_mode.get("input", False), pin_mode.get("output", True)))
if CONF_INVERTED in config:
cg.add(var.set_inverted(config[CONF_INVERTED]))