mirror of
https://github.com/esphome/esphome.git
synced 2026-08-18 03:59:08 +08:00
[modbus] Restore function code byte for custom codes in deprecated on_modbus_data (#18006)
CI / Create common environment (push) Canceled after 0s
CI / Determine which jobs to run (push) Canceled after 0s
CI / Run script/ci-custom (push) Canceled after 0s
CI / Check pylint (push) Canceled after 0s
CI / pre-commit.ci lite (push) Canceled after 0s
CI / Seed pre-commit cache (push) Canceled after 0s
CI / Run pytest (macOS-latest, 3.12) (push) Canceled after 0s
CI / Run pytest (macOS-latest, 3.14) (push) Canceled after 0s
CI / Run pytest (ubuntu-latest, 3.12) (push) Canceled after 0s
CI / Run pytest (ubuntu-latest, 3.13) (push) Canceled after 0s
CI / Run pytest (ubuntu-latest, 3.14) (push) Canceled after 0s
CI / Run pytest (windows-latest, 3.12) (push) Canceled after 0s
CI / Run pytest (windows-latest, 3.14) (push) Canceled after 0s
CI / Report no coverage to Codecov (push) Canceled after 0s
CI / Run integration tests () (push) Canceled after 0s
CI / Check import esphome.__main__ time (push) Canceled after 0s
CI / Run CodSpeed benchmarks (push) Canceled after 0s
CI / Run C++ unit tests (push) Canceled after 0s
CI / Run script/clang-tidy for LibreTiny (push) Canceled after 0s
CI / Run script/clang-tidy for ESP8266 (push) Canceled after 0s
CI / Run script/clang-tidy for RP2 (push) Canceled after 0s
CI / Run script/clang-tidy for ESP32 Arduino (push) Canceled after 0s
CI / Run script/clang-tidy for ZEPHYR (push) Canceled after 0s
CI / Run script/clang-tidy for ESP32 IDF (push) Canceled after 0s
CI / Run script/clang-tidy for ESP32 IDF 1/3 (push) Canceled after 0s
CI / Run script/clang-tidy for ESP32 IDF 2/3 (push) Canceled after 0s
CI / Run script/clang-tidy for ESP32 IDF 3/3 (push) Canceled after 0s
CI / Run script/clang-tidy for ESP32 C6 (push) Canceled after 0s
CI / Run script/clang-tidy for ESP32 P4 (push) Canceled after 0s
CI / Run script/clang-tidy for ESP32 S3 (push) Canceled after 0s
CI / Test components batch () (push) Canceled after 0s
CI / Test esp32 components with PlatformIO (push) Canceled after 0s
CI / Test downstream esphome/device-builder (push) Canceled after 0s
CI / Build target branch for memory impact (push) Canceled after 0s
CI / Build PR branch for memory impact (push) Canceled after 0s
CI / Comment memory impact (push) Canceled after 0s
CI / CI Status (push) Canceled after 0s
CI / Create common environment (push) Canceled after 0s
CI / Determine which jobs to run (push) Canceled after 0s
CI / Run script/ci-custom (push) Canceled after 0s
CI / Check pylint (push) Canceled after 0s
CI / pre-commit.ci lite (push) Canceled after 0s
CI / Seed pre-commit cache (push) Canceled after 0s
CI / Run pytest (macOS-latest, 3.12) (push) Canceled after 0s
CI / Run pytest (macOS-latest, 3.14) (push) Canceled after 0s
CI / Run pytest (ubuntu-latest, 3.12) (push) Canceled after 0s
CI / Run pytest (ubuntu-latest, 3.13) (push) Canceled after 0s
CI / Run pytest (ubuntu-latest, 3.14) (push) Canceled after 0s
CI / Run pytest (windows-latest, 3.12) (push) Canceled after 0s
CI / Run pytest (windows-latest, 3.14) (push) Canceled after 0s
CI / Report no coverage to Codecov (push) Canceled after 0s
CI / Run integration tests () (push) Canceled after 0s
CI / Check import esphome.__main__ time (push) Canceled after 0s
CI / Run CodSpeed benchmarks (push) Canceled after 0s
CI / Run C++ unit tests (push) Canceled after 0s
CI / Run script/clang-tidy for LibreTiny (push) Canceled after 0s
CI / Run script/clang-tidy for ESP8266 (push) Canceled after 0s
CI / Run script/clang-tidy for RP2 (push) Canceled after 0s
CI / Run script/clang-tidy for ESP32 Arduino (push) Canceled after 0s
CI / Run script/clang-tidy for ZEPHYR (push) Canceled after 0s
CI / Run script/clang-tidy for ESP32 IDF (push) Canceled after 0s
CI / Run script/clang-tidy for ESP32 IDF 1/3 (push) Canceled after 0s
CI / Run script/clang-tidy for ESP32 IDF 2/3 (push) Canceled after 0s
CI / Run script/clang-tidy for ESP32 IDF 3/3 (push) Canceled after 0s
CI / Run script/clang-tidy for ESP32 C6 (push) Canceled after 0s
CI / Run script/clang-tidy for ESP32 P4 (push) Canceled after 0s
CI / Run script/clang-tidy for ESP32 S3 (push) Canceled after 0s
CI / Test components batch () (push) Canceled after 0s
CI / Test esp32 components with PlatformIO (push) Canceled after 0s
CI / Test downstream esphome/device-builder (push) Canceled after 0s
CI / Build target branch for memory impact (push) Canceled after 0s
CI / Build PR branch for memory impact (push) Canceled after 0s
CI / Comment memory impact (push) Canceled after 0s
CI / CI Status (push) Canceled after 0s
This commit is contained in:
@@ -550,7 +550,12 @@ class ESPDEPRECATED("Subclass ModbusClientDevice and override on_response()/on_e
|
||||
virtual void on_modbus_error(uint8_t function_code, uint8_t exception_code) {}
|
||||
|
||||
void on_response(std::span<const uint8_t> request_pdu, std::span<const uint8_t> response_pdu) override {
|
||||
auto payload = helpers::server_pdu_payload(response_pdu);
|
||||
// Custom (user-defined) function codes historically delivered the payload starting AT the function
|
||||
// code byte (frame data_offset 1). server_pdu_payload() drops that byte, so pass the whole PDU for
|
||||
// them - external components match the first byte against the code they sent (issue #17994).
|
||||
auto payload = !response_pdu.empty() && helpers::is_function_code_custom(response_pdu[0])
|
||||
? response_pdu
|
||||
: helpers::server_pdu_payload(response_pdu);
|
||||
this->on_modbus_data(std::vector<uint8_t>(payload.begin(), payload.end()));
|
||||
}
|
||||
void on_error(std::span<const uint8_t> request_pdu, ExceptionCode exception_code) override {
|
||||
|
||||
@@ -341,4 +341,45 @@ TEST(ModbusTypedDispatch, SingleWriteAckPrefersTheResponseEcho) {
|
||||
EXPECT_EQ(device.write_single_register_calls.back().value, 0x002A); // exception: request copy
|
||||
}
|
||||
|
||||
// Deprecated on_modbus_data() compatibility shim (pre-2026.8 API). Records the vectors delivered to
|
||||
// the old callback so we can pin its payload framing against the pre-2026.7 behavior.
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
namespace {
|
||||
class LegacyDevice : public ModbusDevice {
|
||||
public:
|
||||
void on_modbus_data(const std::vector<uint8_t> &data) override { this->data_calls.push_back(data); }
|
||||
void on_modbus_error(uint8_t function_code, uint8_t exception_code) override {
|
||||
this->error_calls.emplace_back(function_code, exception_code);
|
||||
}
|
||||
std::vector<std::vector<uint8_t>> data_calls;
|
||||
std::vector<std::pair<uint8_t, uint8_t>> error_calls;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// Custom (user-defined) function codes historically delivered the payload INCLUDING the function code
|
||||
// byte (frame data_offset 1). External components such as the Century VS pump match that first byte
|
||||
// against the code they sent, so dropping it (issue #17994) makes every response get ignored.
|
||||
TEST(ModbusLegacyShim, CustomFunctionCodeKeepsFunctionCodeByte) {
|
||||
LegacyDevice device;
|
||||
const uint8_t request[] = {0x45, 0x01, 0x02}; // custom function 0x45
|
||||
const uint8_t response[] = {0x45, 0xAA, 0xBB, 0xCC}; // echo of the custom code + data
|
||||
device.on_response(request, response);
|
||||
|
||||
ASSERT_EQ(device.data_calls.size(), 1u);
|
||||
EXPECT_EQ(device.data_calls.front(), (std::vector<uint8_t>{0x45, 0xAA, 0xBB, 0xCC}));
|
||||
}
|
||||
|
||||
// Standard reads still strip the function code and byte-count header, matching the pre-2026.7 shim.
|
||||
TEST(ModbusLegacyShim, StandardReadStripsHeader) {
|
||||
LegacyDevice device;
|
||||
const uint8_t request[] = {0x03, 0x01, 0x00, 0x00, 0x02};
|
||||
const uint8_t response[] = {0x03, 0x04, 0x00, 0x2A, 0x01, 0x00};
|
||||
device.on_response(request, response);
|
||||
|
||||
ASSERT_EQ(device.data_calls.size(), 1u);
|
||||
EXPECT_EQ(device.data_calls.front(), (std::vector<uint8_t>{0x00, 0x2A, 0x01, 0x00}));
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
} // namespace esphome::modbus::testing
|
||||
|
||||
Reference in New Issue
Block a user