mirror of
https://github.com/esphome/esphome.git
synced 2025-08-31 06:20:26 +00:00
Compare commits
7 Commits
memory_api
...
2025.8.0
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2adb993242 | ||
![]() |
8e67df8059 | ||
![]() |
c5b2c8d971 | ||
![]() |
104906ca11 | ||
![]() |
ad5f6f0cfe | ||
![]() |
8356f7fcd3 | ||
![]() |
225de226b0 |
2
Doxyfile
2
Doxyfile
@@ -48,7 +48,7 @@ PROJECT_NAME = ESPHome
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = 2025.8.0b3
|
||||
PROJECT_NUMBER = 2025.8.0
|
||||
|
||||
# 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
|
||||
|
@@ -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)
|
||||
// Peakdetect period: 05H. Bit 15:8 are PeakDet_period in ms. 7:0 are Sag_period
|
||||
// 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 addrl = (a_register & 0xFF);
|
||||
uint8_t data[4] = {addrh, addrl, 0x00, 0x00};
|
||||
this->transfer_array(data, 4);
|
||||
uint16_t output = encode_uint16(data[2], data[3]);
|
||||
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
|
||||
this->disable();
|
||||
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) {
|
||||
this->enable();
|
||||
delay_microseconds_safe(1);
|
||||
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 uint16_t val_h = this->read16_(addr_h);
|
||||
const uint16_t val_l = this->read16_(addr_l);
|
||||
const int32_t val = (val_h << 16) | val_l;
|
||||
|
||||
ESP_LOGVV(TAG,
|
||||
|
@@ -140,7 +140,6 @@ class ATM90E32Component : public PollingComponent,
|
||||
number::Number *ref_currents_[3]{nullptr, nullptr, nullptr};
|
||||
#endif
|
||||
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);
|
||||
void write16_(uint16_t a_register, uint16_t val, bool validate = true);
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
@@ -23,20 +23,18 @@ void Pipsolar::loop() {
|
||||
// Read message
|
||||
if (this->state_ == STATE_IDLE) {
|
||||
this->empty_uart_buffer_();
|
||||
switch (this->send_next_command_()) {
|
||||
case 0:
|
||||
// no command send (empty queue) time to poll
|
||||
if (millis() - this->last_poll_ > this->update_interval_) {
|
||||
this->send_next_poll_();
|
||||
this->last_poll_ = millis();
|
||||
}
|
||||
return;
|
||||
break;
|
||||
case 1:
|
||||
// command send
|
||||
return;
|
||||
break;
|
||||
|
||||
if (this->send_next_command_()) {
|
||||
// command sent
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->send_next_poll_()) {
|
||||
// poll sent
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
if (this->state_ == STATE_COMMAND_COMPLETE) {
|
||||
if (this->check_incoming_length_(4)) {
|
||||
@@ -530,7 +528,7 @@ void Pipsolar::loop() {
|
||||
// '(00000000000000000000000000000000'
|
||||
// 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_faults_present_ = true;
|
||||
this->value_faults_present_ = false;
|
||||
|
||||
for (size_t i = 1; i < strlen(tmp); i++) {
|
||||
enabled = tmp[i] == '1';
|
||||
@@ -708,6 +706,7 @@ void Pipsolar::loop() {
|
||||
return;
|
||||
}
|
||||
// crc ok
|
||||
this->used_polling_commands_[this->last_polling_command_].needs_update = false;
|
||||
this->state_ = STATE_POLL_CHECKED;
|
||||
return;
|
||||
} else {
|
||||
@@ -788,7 +787,7 @@ uint8_t Pipsolar::check_incoming_crc_() {
|
||||
}
|
||||
|
||||
// send next command used
|
||||
uint8_t Pipsolar::send_next_command_() {
|
||||
bool Pipsolar::send_next_command_() {
|
||||
uint16_t crc16;
|
||||
if (!this->command_queue_[this->command_queue_position_].empty()) {
|
||||
const char *command = this->command_queue_[this->command_queue_position_].c_str();
|
||||
@@ -809,37 +808,43 @@ uint8_t Pipsolar::send_next_command_() {
|
||||
// end Byte
|
||||
this->write(0x0D);
|
||||
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;
|
||||
this->last_polling_command_ = (this->last_polling_command_ + 1) % 15;
|
||||
if (this->used_polling_commands_[this->last_polling_command_].length == 0) {
|
||||
this->last_polling_command_ = 0;
|
||||
|
||||
for (uint8_t i = 0; i < POLLING_COMMANDS_MAX; i++) {
|
||||
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) {
|
||||
// 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);
|
||||
return false;
|
||||
}
|
||||
|
||||
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) {
|
||||
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.identifier = polling_command;
|
||||
used_polling_command.length = length - 1;
|
||||
used_polling_command.needs_update = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@@ -25,6 +25,7 @@ struct PollingCommand {
|
||||
uint8_t length = 0;
|
||||
uint8_t errors;
|
||||
ENUMPollingCommand identifier;
|
||||
bool needs_update;
|
||||
};
|
||||
|
||||
#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 COMMAND_QUEUE_LENGTH = 10;
|
||||
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 empty_uart_buffer_();
|
||||
uint8_t check_incoming_crc_();
|
||||
uint8_t check_incoming_length_(uint8_t length);
|
||||
uint16_t pipsolar_crc_(uint8_t *msg, uint8_t len);
|
||||
uint8_t send_next_command_();
|
||||
void send_next_poll_();
|
||||
bool send_next_command_();
|
||||
bool send_next_poll_();
|
||||
void queue_command_(const char *command, uint8_t length);
|
||||
std::string command_queue_[COMMAND_QUEUE_LENGTH];
|
||||
uint8_t command_queue_position_ = 0;
|
||||
@@ -216,7 +217,7 @@ class Pipsolar : public uart::UARTDevice, public PollingComponent {
|
||||
};
|
||||
|
||||
uint8_t last_polling_command_ = 0;
|
||||
PollingCommand used_polling_commands_[15];
|
||||
PollingCommand used_polling_commands_[POLLING_COMMANDS_MAX];
|
||||
};
|
||||
|
||||
} // namespace pipsolar
|
||||
|
@@ -4,7 +4,7 @@ from enum import Enum
|
||||
|
||||
from esphome.enum import StrEnum
|
||||
|
||||
__version__ = "2025.8.0b3"
|
||||
__version__ = "2025.8.0"
|
||||
|
||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||
VALID_SUBSTITUTIONS_CHARACTERS = (
|
||||
|
Reference in New Issue
Block a user