mirror of
https://github.com/esphome/esphome.git
synced 2025-09-24 22:22:22 +01:00
2
Doxyfile
2
Doxyfile
@@ -48,7 +48,7 @@ PROJECT_NAME = ESPHome
|
|||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
# control system is used.
|
# control system is used.
|
||||||
|
|
||||||
PROJECT_NUMBER = 2025.8.0b3
|
PROJECT_NUMBER = 2025.8.0b4
|
||||||
|
|
||||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||||
# for a project that appears at the top of each page and should give viewer a
|
# for a project that appears at the top of each page and should give viewer a
|
||||||
|
@@ -382,20 +382,15 @@ float ATM90E32Component::get_setup_priority() const { return setup_priority::IO;
|
|||||||
// R/C registers can conly be cleared after the LastSPIData register is updated (register 78H)
|
// R/C registers can conly be cleared after the LastSPIData register is updated (register 78H)
|
||||||
// Peakdetect period: 05H. Bit 15:8 are PeakDet_period in ms. 7:0 are Sag_period
|
// Peakdetect period: 05H. Bit 15:8 are PeakDet_period in ms. 7:0 are Sag_period
|
||||||
// Default is 143FH (20ms, 63ms)
|
// Default is 143FH (20ms, 63ms)
|
||||||
uint16_t ATM90E32Component::read16_transaction_(uint16_t a_register) {
|
uint16_t ATM90E32Component::read16_(uint16_t a_register) {
|
||||||
|
this->enable();
|
||||||
|
delay_microseconds_safe(1); // min delay between CS low and first SCK is 200ns - 1us is plenty
|
||||||
uint8_t addrh = (1 << 7) | ((a_register >> 8) & 0x03);
|
uint8_t addrh = (1 << 7) | ((a_register >> 8) & 0x03);
|
||||||
uint8_t addrl = (a_register & 0xFF);
|
uint8_t addrl = (a_register & 0xFF);
|
||||||
uint8_t data[4] = {addrh, addrl, 0x00, 0x00};
|
uint8_t data[4] = {addrh, addrl, 0x00, 0x00};
|
||||||
this->transfer_array(data, 4);
|
this->transfer_array(data, 4);
|
||||||
uint16_t output = encode_uint16(data[2], data[3]);
|
uint16_t output = encode_uint16(data[2], data[3]);
|
||||||
ESP_LOGVV(TAG, "read16_ 0x%04" PRIX16 " output 0x%04" PRIX16, a_register, output);
|
ESP_LOGVV(TAG, "read16_ 0x%04" PRIX16 " output 0x%04" PRIX16, a_register, output);
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t ATM90E32Component::read16_(uint16_t a_register) {
|
|
||||||
this->enable();
|
|
||||||
delay_microseconds_safe(1); // min delay between CS low and first SCK is 200ns - 1us is plenty
|
|
||||||
uint16_t output = this->read16_transaction_(a_register);
|
|
||||||
delay_microseconds_safe(1); // allow the last clock to propagate before releasing CS
|
delay_microseconds_safe(1); // allow the last clock to propagate before releasing CS
|
||||||
this->disable();
|
this->disable();
|
||||||
delay_microseconds_safe(1); // meet minimum CS high time before next transaction
|
delay_microseconds_safe(1); // meet minimum CS high time before next transaction
|
||||||
@@ -403,14 +398,8 @@ uint16_t ATM90E32Component::read16_(uint16_t a_register) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ATM90E32Component::read32_(uint16_t addr_h, uint16_t addr_l) {
|
int ATM90E32Component::read32_(uint16_t addr_h, uint16_t addr_l) {
|
||||||
this->enable();
|
const uint16_t val_h = this->read16_(addr_h);
|
||||||
delay_microseconds_safe(1);
|
const uint16_t val_l = this->read16_(addr_l);
|
||||||
const uint16_t val_h = this->read16_transaction_(addr_h);
|
|
||||||
delay_microseconds_safe(1);
|
|
||||||
const uint16_t val_l = this->read16_transaction_(addr_l);
|
|
||||||
delay_microseconds_safe(1);
|
|
||||||
this->disable();
|
|
||||||
delay_microseconds_safe(1);
|
|
||||||
const int32_t val = (val_h << 16) | val_l;
|
const int32_t val = (val_h << 16) | val_l;
|
||||||
|
|
||||||
ESP_LOGVV(TAG,
|
ESP_LOGVV(TAG,
|
||||||
|
@@ -140,7 +140,6 @@ class ATM90E32Component : public PollingComponent,
|
|||||||
number::Number *ref_currents_[3]{nullptr, nullptr, nullptr};
|
number::Number *ref_currents_[3]{nullptr, nullptr, nullptr};
|
||||||
#endif
|
#endif
|
||||||
uint16_t read16_(uint16_t a_register);
|
uint16_t read16_(uint16_t a_register);
|
||||||
uint16_t read16_transaction_(uint16_t a_register);
|
|
||||||
int read32_(uint16_t addr_h, uint16_t addr_l);
|
int read32_(uint16_t addr_h, uint16_t addr_l);
|
||||||
void write16_(uint16_t a_register, uint16_t val, bool validate = true);
|
void write16_(uint16_t a_register, uint16_t val, bool validate = true);
|
||||||
float get_local_phase_voltage_(uint8_t phase);
|
float get_local_phase_voltage_(uint8_t phase);
|
||||||
|
@@ -375,10 +375,19 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga
|
|||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case ESP_GATTC_DISCONNECT_EVT: {
|
case ESP_GATTC_DISCONNECT_EVT: {
|
||||||
this->reset_connection_(param->disconnect.reason);
|
// Don't reset connection yet - wait for CLOSE_EVT to ensure controller has freed resources
|
||||||
|
// This prevents race condition where we mark slot as free before controller cleanup is complete
|
||||||
|
ESP_LOGD(TAG, "[%d] [%s] Disconnect, reason=0x%02x", this->connection_index_, this->address_str_.c_str(),
|
||||||
|
param->disconnect.reason);
|
||||||
|
// Send disconnection notification but don't free the slot yet
|
||||||
|
this->proxy_->send_device_connection(this->address_, false, 0, param->disconnect.reason);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ESP_GATTC_CLOSE_EVT: {
|
case ESP_GATTC_CLOSE_EVT: {
|
||||||
|
ESP_LOGD(TAG, "[%d] [%s] Close, reason=0x%02x, freeing slot", this->connection_index_, this->address_str_.c_str(),
|
||||||
|
param->close.reason);
|
||||||
|
// Now the GATT connection is fully closed and controller resources are freed
|
||||||
|
// Safe to mark the connection slot as available
|
||||||
this->reset_connection_(param->close.reason);
|
this->reset_connection_(param->close.reason);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -23,20 +23,18 @@ void Pipsolar::loop() {
|
|||||||
// Read message
|
// Read message
|
||||||
if (this->state_ == STATE_IDLE) {
|
if (this->state_ == STATE_IDLE) {
|
||||||
this->empty_uart_buffer_();
|
this->empty_uart_buffer_();
|
||||||
switch (this->send_next_command_()) {
|
|
||||||
case 0:
|
if (this->send_next_command_()) {
|
||||||
// no command send (empty queue) time to poll
|
// command sent
|
||||||
if (millis() - this->last_poll_ > this->update_interval_) {
|
return;
|
||||||
this->send_next_poll_();
|
|
||||||
this->last_poll_ = millis();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
// command send
|
|
||||||
return;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this->send_next_poll_()) {
|
||||||
|
// poll sent
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (this->state_ == STATE_COMMAND_COMPLETE) {
|
if (this->state_ == STATE_COMMAND_COMPLETE) {
|
||||||
if (this->check_incoming_length_(4)) {
|
if (this->check_incoming_length_(4)) {
|
||||||
@@ -530,7 +528,7 @@ void Pipsolar::loop() {
|
|||||||
// '(00000000000000000000000000000000'
|
// '(00000000000000000000000000000000'
|
||||||
// iterate over all available flag (as not all models have all flags, but at least in the same order)
|
// iterate over all available flag (as not all models have all flags, but at least in the same order)
|
||||||
this->value_warnings_present_ = false;
|
this->value_warnings_present_ = false;
|
||||||
this->value_faults_present_ = true;
|
this->value_faults_present_ = false;
|
||||||
|
|
||||||
for (size_t i = 1; i < strlen(tmp); i++) {
|
for (size_t i = 1; i < strlen(tmp); i++) {
|
||||||
enabled = tmp[i] == '1';
|
enabled = tmp[i] == '1';
|
||||||
@@ -708,6 +706,7 @@ void Pipsolar::loop() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// crc ok
|
// crc ok
|
||||||
|
this->used_polling_commands_[this->last_polling_command_].needs_update = false;
|
||||||
this->state_ = STATE_POLL_CHECKED;
|
this->state_ = STATE_POLL_CHECKED;
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@@ -788,7 +787,7 @@ uint8_t Pipsolar::check_incoming_crc_() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// send next command used
|
// send next command used
|
||||||
uint8_t Pipsolar::send_next_command_() {
|
bool Pipsolar::send_next_command_() {
|
||||||
uint16_t crc16;
|
uint16_t crc16;
|
||||||
if (!this->command_queue_[this->command_queue_position_].empty()) {
|
if (!this->command_queue_[this->command_queue_position_].empty()) {
|
||||||
const char *command = this->command_queue_[this->command_queue_position_].c_str();
|
const char *command = this->command_queue_[this->command_queue_position_].c_str();
|
||||||
@@ -809,37 +808,43 @@ uint8_t Pipsolar::send_next_command_() {
|
|||||||
// end Byte
|
// end Byte
|
||||||
this->write(0x0D);
|
this->write(0x0D);
|
||||||
ESP_LOGD(TAG, "Sending command from queue: %s with length %d", command, length);
|
ESP_LOGD(TAG, "Sending command from queue: %s with length %d", command, length);
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pipsolar::send_next_poll_() {
|
bool Pipsolar::send_next_poll_() {
|
||||||
uint16_t crc16;
|
uint16_t crc16;
|
||||||
this->last_polling_command_ = (this->last_polling_command_ + 1) % 15;
|
|
||||||
if (this->used_polling_commands_[this->last_polling_command_].length == 0) {
|
for (uint8_t i = 0; i < POLLING_COMMANDS_MAX; i++) {
|
||||||
this->last_polling_command_ = 0;
|
this->last_polling_command_ = (this->last_polling_command_ + 1) % POLLING_COMMANDS_MAX;
|
||||||
|
if (this->used_polling_commands_[this->last_polling_command_].length == 0) {
|
||||||
|
// not enabled
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!this->used_polling_commands_[this->last_polling_command_].needs_update) {
|
||||||
|
// no update requested
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
this->state_ = STATE_POLL;
|
||||||
|
this->command_start_millis_ = millis();
|
||||||
|
this->empty_uart_buffer_();
|
||||||
|
this->read_pos_ = 0;
|
||||||
|
crc16 = this->pipsolar_crc_(this->used_polling_commands_[this->last_polling_command_].command,
|
||||||
|
this->used_polling_commands_[this->last_polling_command_].length);
|
||||||
|
this->write_array(this->used_polling_commands_[this->last_polling_command_].command,
|
||||||
|
this->used_polling_commands_[this->last_polling_command_].length);
|
||||||
|
// checksum
|
||||||
|
this->write(((uint8_t) ((crc16) >> 8))); // highbyte
|
||||||
|
this->write(((uint8_t) ((crc16) &0xff))); // lowbyte
|
||||||
|
// end Byte
|
||||||
|
this->write(0x0D);
|
||||||
|
ESP_LOGD(TAG, "Sending polling command : %s with length %d",
|
||||||
|
this->used_polling_commands_[this->last_polling_command_].command,
|
||||||
|
this->used_polling_commands_[this->last_polling_command_].length);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
if (this->used_polling_commands_[this->last_polling_command_].length == 0) {
|
return false;
|
||||||
// no command specified
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this->state_ = STATE_POLL;
|
|
||||||
this->command_start_millis_ = millis();
|
|
||||||
this->empty_uart_buffer_();
|
|
||||||
this->read_pos_ = 0;
|
|
||||||
crc16 = this->pipsolar_crc_(this->used_polling_commands_[this->last_polling_command_].command,
|
|
||||||
this->used_polling_commands_[this->last_polling_command_].length);
|
|
||||||
this->write_array(this->used_polling_commands_[this->last_polling_command_].command,
|
|
||||||
this->used_polling_commands_[this->last_polling_command_].length);
|
|
||||||
// checksum
|
|
||||||
this->write(((uint8_t) ((crc16) >> 8))); // highbyte
|
|
||||||
this->write(((uint8_t) ((crc16) &0xff))); // lowbyte
|
|
||||||
// end Byte
|
|
||||||
this->write(0x0D);
|
|
||||||
ESP_LOGD(TAG, "Sending polling command : %s with length %d",
|
|
||||||
this->used_polling_commands_[this->last_polling_command_].command,
|
|
||||||
this->used_polling_commands_[this->last_polling_command_].length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pipsolar::queue_command_(const char *command, uint8_t length) {
|
void Pipsolar::queue_command_(const char *command, uint8_t length) {
|
||||||
@@ -869,7 +874,13 @@ void Pipsolar::dump_config() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void Pipsolar::update() {}
|
void Pipsolar::update() {
|
||||||
|
for (auto &used_polling_command : this->used_polling_commands_) {
|
||||||
|
if (used_polling_command.length != 0) {
|
||||||
|
used_polling_command.needs_update = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Pipsolar::add_polling_command_(const char *command, ENUMPollingCommand polling_command) {
|
void Pipsolar::add_polling_command_(const char *command, ENUMPollingCommand polling_command) {
|
||||||
for (auto &used_polling_command : this->used_polling_commands_) {
|
for (auto &used_polling_command : this->used_polling_commands_) {
|
||||||
@@ -891,6 +902,7 @@ void Pipsolar::add_polling_command_(const char *command, ENUMPollingCommand poll
|
|||||||
used_polling_command.errors = 0;
|
used_polling_command.errors = 0;
|
||||||
used_polling_command.identifier = polling_command;
|
used_polling_command.identifier = polling_command;
|
||||||
used_polling_command.length = length - 1;
|
used_polling_command.length = length - 1;
|
||||||
|
used_polling_command.needs_update = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,6 +25,7 @@ struct PollingCommand {
|
|||||||
uint8_t length = 0;
|
uint8_t length = 0;
|
||||||
uint8_t errors;
|
uint8_t errors;
|
||||||
ENUMPollingCommand identifier;
|
ENUMPollingCommand identifier;
|
||||||
|
bool needs_update;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PIPSOLAR_VALUED_ENTITY_(type, name, polling_command, value_type) \
|
#define PIPSOLAR_VALUED_ENTITY_(type, name, polling_command, value_type) \
|
||||||
@@ -189,14 +190,14 @@ class Pipsolar : public uart::UARTDevice, public PollingComponent {
|
|||||||
static const size_t PIPSOLAR_READ_BUFFER_LENGTH = 110; // maximum supported answer length
|
static const size_t PIPSOLAR_READ_BUFFER_LENGTH = 110; // maximum supported answer length
|
||||||
static const size_t COMMAND_QUEUE_LENGTH = 10;
|
static const size_t COMMAND_QUEUE_LENGTH = 10;
|
||||||
static const size_t COMMAND_TIMEOUT = 5000;
|
static const size_t COMMAND_TIMEOUT = 5000;
|
||||||
uint32_t last_poll_ = 0;
|
static const size_t POLLING_COMMANDS_MAX = 15;
|
||||||
void add_polling_command_(const char *command, ENUMPollingCommand polling_command);
|
void add_polling_command_(const char *command, ENUMPollingCommand polling_command);
|
||||||
void empty_uart_buffer_();
|
void empty_uart_buffer_();
|
||||||
uint8_t check_incoming_crc_();
|
uint8_t check_incoming_crc_();
|
||||||
uint8_t check_incoming_length_(uint8_t length);
|
uint8_t check_incoming_length_(uint8_t length);
|
||||||
uint16_t pipsolar_crc_(uint8_t *msg, uint8_t len);
|
uint16_t pipsolar_crc_(uint8_t *msg, uint8_t len);
|
||||||
uint8_t send_next_command_();
|
bool send_next_command_();
|
||||||
void send_next_poll_();
|
bool send_next_poll_();
|
||||||
void queue_command_(const char *command, uint8_t length);
|
void queue_command_(const char *command, uint8_t length);
|
||||||
std::string command_queue_[COMMAND_QUEUE_LENGTH];
|
std::string command_queue_[COMMAND_QUEUE_LENGTH];
|
||||||
uint8_t command_queue_position_ = 0;
|
uint8_t command_queue_position_ = 0;
|
||||||
@@ -216,7 +217,7 @@ class Pipsolar : public uart::UARTDevice, public PollingComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
uint8_t last_polling_command_ = 0;
|
uint8_t last_polling_command_ = 0;
|
||||||
PollingCommand used_polling_commands_[15];
|
PollingCommand used_polling_commands_[POLLING_COMMANDS_MAX];
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pipsolar
|
} // namespace pipsolar
|
||||||
|
@@ -4,7 +4,7 @@ from enum import Enum
|
|||||||
|
|
||||||
from esphome.enum import StrEnum
|
from esphome.enum import StrEnum
|
||||||
|
|
||||||
__version__ = "2025.8.0b3"
|
__version__ = "2025.8.0b4"
|
||||||
|
|
||||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||||
VALID_SUBSTITUTIONS_CHARACTERS = (
|
VALID_SUBSTITUTIONS_CHARACTERS = (
|
||||||
|
Reference in New Issue
Block a user