Added node discovery

This commit is contained in:
Pieter Kokx 2024-11-16 23:49:37 +01:00
parent f5321024f1
commit 07fb218412
No known key found for this signature in database
GPG Key ID: BD73BAB527D54451
3 changed files with 119 additions and 4 deletions

View File

@ -9,12 +9,19 @@ DEPENDENCIES = ["uart"]
duco_ns = cg.esphome_ns.namespace("duco")
Duco = duco_ns.class_("Duco", cg.Component, uart.UARTDevice)
# ModbusDevice = duco_ns.class_("ModbusDevice")
DucoDiscovery = duco_ns.class_(
"DucoDiscovery", cg.PollingComponent, cg.Parented.template(Duco)
)
MULTI_CONF = True
CONF_DUCO_ID = "duco_id"
CONF_SEND_WAIT_TIME = "send_wait_time"
CONF_DISCOVERY = "discovery"
# A schema for components like sensors
DUCO_COMPONENT_SCHEMA = cv.Schema({cv.GenerateID(CONF_DUCO_ID): cv.use_id(Duco)})
CONFIG_SCHEMA = (
cv.Schema(
{
@ -23,15 +30,19 @@ CONFIG_SCHEMA = (
CONF_SEND_WAIT_TIME, default="250ms"
): cv.positive_time_period_milliseconds,
cv.Optional(CONF_DISABLE_CRC, default=False): cv.boolean,
cv.Optional(CONF_DISCOVERY): cv.Schema(
{
cv.GenerateID(): cv.declare_id(DucoDiscovery),
}
)
.extend(cv.polling_component_schema("60s"))
.extend(DUCO_COMPONENT_SCHEMA),
}
)
.extend(cv.COMPONENT_SCHEMA)
.extend(uart.UART_DEVICE_SCHEMA)
)
# A schema for components like sensors
DUCO_COMPONENT_SCHEMA = cv.Schema({cv.GenerateID(CONF_DUCO_ID): cv.use_id(Duco)})
async def to_code(config):
cg.add_global(duco_ns.using)
@ -42,3 +53,10 @@ async def to_code(config):
cg.add(var.set_send_wait_time(config[CONF_SEND_WAIT_TIME]))
cg.add(var.set_disable_crc(config[CONF_DISABLE_CRC]))
if CONF_DISCOVERY in config:
discovery_config = config[CONF_DISCOVERY]
discovery_var = cg.new_Pvariable(discovery_config[CONF_ID])
await cg.register_component(discovery_var, discovery_config)
cg.add(discovery_var.set_parent(var))

View File

@ -189,5 +189,73 @@ void Duco::debug_hex(std::vector<uint8_t> bytes, uint8_t separator) {
delay(10);
}
const std::string DucoDiscovery::NODE_TYPE_UCBAT = "UCBAT";
const std::string DucoDiscovery::NODE_TYPE_UC = "UC";
const std::string DucoDiscovery::NODE_TYPE_UCCO2 = "UCCO2";
const std::string DucoDiscovery::NODE_TYPE_BOX = "BOX";
const std::string DucoDiscovery::NODE_TYPE_SWITCH = "SWITCH";
const std::string DucoDiscovery::NODE_TYPE_UNKNOWN = "UNKNOWN";
const std::string friendly_node_type(uint8_t type_code) {
switch (type_code) {
case DucoDiscovery::NODE_TYPE_CODE_UCBAT:
return DucoDiscovery::NODE_TYPE_UCBAT;
case DucoDiscovery::NODE_TYPE_CODE_UC:
return DucoDiscovery::NODE_TYPE_UC;
case DucoDiscovery::NODE_TYPE_CODE_UCCO2:
return DucoDiscovery::NODE_TYPE_UCCO2;
case DucoDiscovery::NODE_TYPE_CODE_BOX:
return DucoDiscovery::NODE_TYPE_BOX;
case DucoDiscovery::NODE_TYPE_CODE_SWITCH:
return DucoDiscovery::NODE_TYPE_SWITCH;
default:
return DucoDiscovery::NODE_TYPE_UNKNOWN;
}
}
void DucoDiscovery::update() {
// display all found nodes
for (auto &node : nodes_) {
ESP_LOGW(TAG, "Node %d: type %d (%s)", std::get<0>(node), std::get<1>(node),
friendly_node_type(std::get<1>(node)).c_str());
}
}
void DucoDiscovery::loop() {
if (delay_ > 0) {
delay_--;
return;
}
if (next_node_ > 0x44) {
// discovery is finished
return;
}
if (!waiting_for_response_) {
ESP_LOGD(TAG, "Discover next node (%d = 0x%02x)", next_node_, next_node_);
// request the next node
std::vector<uint8_t> message = {0x01, next_node_};
this->parent_->send(0x0c, message, this);
waiting_for_response_ = true;
}
}
void DucoDiscovery::receive_response(std::vector<uint8_t> message) {
if (message[1] == 0x0e) {
ESP_LOGV(TAG, "Discovery response message: %s", format_hex_pretty(message).c_str());
this->parent_->stop_waiting(message[2]);
if (message[3] != 0x00) {
// node was found, store its information
nodes_.push_back(std::make_tuple(next_node_, message[3]));
}
next_node_++;
waiting_for_response_ = false;
// delay execution for 100 loops
delay_ = 100;
}
}
} // namespace duco
} // namespace esphome

View File

@ -53,5 +53,34 @@ class DucoDevice : public Parented<Duco> {
virtual void receive_response(std::vector<uint8_t> message) {}
};
class DucoDiscovery : public DucoDevice, public PollingComponent {
public:
void loop() override;
void update() override;
void receive_response(std::vector<uint8_t> message) override;
static const std::string NODE_TYPE_UCBAT;
static const std::string NODE_TYPE_UC;
static const std::string NODE_TYPE_UCCO2;
static const std::string NODE_TYPE_BOX;
static const std::string NODE_TYPE_SWITCH;
static const std::string NODE_TYPE_UNKNOWN;
static const uint8_t NODE_TYPE_CODE_UCBAT = 8;
static const uint8_t NODE_TYPE_CODE_UC = 9;
static const uint8_t NODE_TYPE_CODE_UCCO2 = 12;
static const uint8_t NODE_TYPE_CODE_BOX = 17;
static const uint8_t NODE_TYPE_CODE_SWITCH = 18;
protected:
// start with a delay of 1000 loops
uint32_t delay_{1000};
uint8_t next_node_{0};
bool waiting_for_response_ = false;
std::vector<std::tuple<uint8_t, uint8_t>> nodes_;
};
} // namespace duco
} // namespace esphome