esphome 2025.9.3__py3-none-any.whl → 2025.10.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- esphome/__main__.py +87 -31
- esphome/address_cache.py +142 -0
- esphome/automation.py +130 -32
- esphome/build_gen/platformio.py +1 -3
- esphome/codegen.py +1 -0
- esphome/components/animation/animation.cpp +2 -2
- esphome/components/api/__init__.py +166 -3
- esphome/components/api/api_connection.cpp +84 -41
- esphome/components/api/api_connection.h +22 -16
- esphome/components/api/api_frame_helper.cpp +33 -19
- esphome/components/api/api_frame_helper.h +19 -4
- esphome/components/api/api_frame_helper_noise.cpp +41 -53
- esphome/components/api/api_frame_helper_noise.h +1 -1
- esphome/components/api/api_frame_helper_plaintext.cpp +22 -31
- esphome/components/api/api_frame_helper_plaintext.h +1 -1
- esphome/components/api/api_pb2.cpp +189 -15
- esphome/components/api/api_pb2.h +132 -20
- esphome/components/api/api_pb2_dump.cpp +97 -9
- esphome/components/api/api_pb2_service.cpp +118 -160
- esphome/components/api/api_pb2_service.h +31 -3
- esphome/components/api/api_server.cpp +68 -10
- esphome/components/api/api_server.h +32 -4
- esphome/components/api/custom_api_device.h +8 -8
- esphome/components/api/homeassistant_service.h +123 -6
- esphome/components/api/proto.h +6 -2
- esphome/components/api/user_services.h +2 -2
- esphome/components/as7341/sensor.py +1 -1
- esphome/components/audio/__init__.py +1 -1
- esphome/components/audio/audio.cpp +1 -1
- esphome/components/audio/audio_decoder.cpp +9 -9
- esphome/components/bl0906/bl0906.cpp +2 -2
- esphome/components/bl0942/bl0942.cpp +2 -2
- esphome/components/ble_client/__init__.py +1 -1
- esphome/components/bluetooth_proxy/__init__.py +4 -30
- esphome/components/bluetooth_proxy/bluetooth_connection.cpp +11 -4
- esphome/components/bluetooth_proxy/bluetooth_connection.h +2 -2
- esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +2 -2
- esphome/components/camera_encoder/__init__.py +2 -4
- esphome/components/camera_encoder/esp32_camera_jpeg_encoder.cpp +4 -2
- esphome/components/camera_encoder/esp32_camera_jpeg_encoder.h +3 -1
- esphome/components/canbus/canbus.cpp +7 -5
- esphome/components/canbus/canbus.h +4 -4
- esphome/components/captive_portal/__init__.py +18 -1
- esphome/components/captive_portal/captive_portal.cpp +40 -46
- esphome/components/captive_portal/captive_portal.h +20 -22
- esphome/components/captive_portal/dns_server_esp32_idf.cpp +205 -0
- esphome/components/captive_portal/dns_server_esp32_idf.h +27 -0
- esphome/components/ccs811/ccs811.cpp +1 -1
- esphome/components/climate/climate.cpp +10 -7
- esphome/components/cm1106/cm1106.cpp +1 -1
- esphome/components/copy/lock/copy_lock.cpp +1 -1
- esphome/components/cover/cover.cpp +1 -0
- esphome/components/daikin_arc/daikin_arc.cpp +19 -12
- esphome/components/deep_sleep/__init__.py +9 -2
- esphome/components/deep_sleep/deep_sleep_component.h +11 -9
- esphome/components/deep_sleep/deep_sleep_esp32.cpp +51 -27
- esphome/components/ektf2232/touchscreen/__init__.py +8 -5
- esphome/components/ektf2232/touchscreen/ektf2232.cpp +4 -4
- esphome/components/ektf2232/touchscreen/ektf2232.h +2 -2
- esphome/components/epaper_spi/__init__.py +1 -0
- esphome/components/epaper_spi/display.py +80 -0
- esphome/components/epaper_spi/epaper_spi.cpp +227 -0
- esphome/components/epaper_spi/epaper_spi.h +93 -0
- esphome/components/epaper_spi/epaper_spi_model_7p3in_spectra_e6.cpp +42 -0
- esphome/components/epaper_spi/epaper_spi_model_7p3in_spectra_e6.h +45 -0
- esphome/components/epaper_spi/epaper_spi_spectra_e6.cpp +135 -0
- esphome/components/epaper_spi/epaper_spi_spectra_e6.h +23 -0
- esphome/components/es7210/es7210.cpp +3 -3
- esphome/components/esp32/__init__.py +254 -339
- esphome/components/esp32/boards.py +81 -0
- esphome/components/esp32/preferences.cpp +23 -17
- esphome/components/esp32_ble/__init__.py +159 -44
- esphome/components/esp32_ble/ble.cpp +47 -3
- esphome/components/esp32_ble/ble.h +18 -0
- esphome/components/esp32_ble/ble_advertising.cpp +7 -3
- esphome/components/esp32_ble/ble_advertising.h +4 -0
- esphome/components/esp32_ble/ble_uuid.cpp +16 -42
- esphome/components/esp32_ble_beacon/__init__.py +3 -4
- esphome/components/esp32_ble_client/ble_client_base.cpp +14 -12
- esphome/components/esp32_ble_server/__init__.py +28 -14
- esphome/components/esp32_ble_server/ble_characteristic.cpp +67 -57
- esphome/components/esp32_ble_server/ble_characteristic.h +27 -16
- esphome/components/esp32_ble_server/ble_descriptor.cpp +4 -3
- esphome/components/esp32_ble_server/ble_descriptor.h +13 -9
- esphome/components/esp32_ble_server/ble_server.cpp +59 -24
- esphome/components/esp32_ble_server/ble_server.h +38 -20
- esphome/components/esp32_ble_server/ble_server_automations.cpp +49 -33
- esphome/components/esp32_ble_server/ble_server_automations.h +39 -24
- esphome/components/esp32_ble_tracker/__init__.py +25 -80
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +2 -4
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +0 -3
- esphome/components/esp32_camera/__init__.py +1 -3
- esphome/components/esp32_can/esp32_can.cpp +22 -4
- esphome/components/esp32_can/esp32_can.h +3 -0
- esphome/components/esp32_hosted/__init__.py +2 -1
- esphome/components/esp32_improv/esp32_improv_component.cpp +102 -44
- esphome/components/esp32_improv/esp32_improv_component.h +6 -1
- esphome/components/esp32_rmt_led_strip/led_strip.cpp +1 -1
- esphome/components/esp8266/__init__.py +3 -3
- esphome/components/esphome/ota/__init__.py +21 -2
- esphome/components/esphome/ota/ota_esphome.cpp +455 -145
- esphome/components/esphome/ota/ota_esphome.h +49 -2
- esphome/components/ethernet/__init__.py +39 -22
- esphome/components/ethernet/ethernet_component.cpp +28 -5
- esphome/components/ethernet/ethernet_component.h +5 -1
- esphome/components/external_components/__init__.py +8 -6
- esphome/components/fingerprint_grow/fingerprint_grow.cpp +1 -1
- esphome/components/fingerprint_grow/fingerprint_grow.h +2 -1
- esphome/components/font/__init__.py +5 -5
- esphome/components/graph/graph.cpp +1 -1
- esphome/components/graphical_display_menu/graphical_display_menu.cpp +3 -2
- esphome/components/haier/hon_climate.cpp +2 -2
- esphome/components/haier/hon_climate.h +1 -1
- esphome/components/hdc1080/hdc1080.cpp +42 -34
- esphome/components/hdc1080/hdc1080.h +1 -3
- esphome/components/homeassistant/number/homeassistant_number.cpp +2 -2
- esphome/components/homeassistant/switch/homeassistant_switch.cpp +2 -2
- esphome/components/http_request/__init__.py +3 -3
- esphome/components/htu21d/htu21d.cpp +13 -18
- esphome/components/htu21d/htu21d.h +1 -1
- esphome/components/i2s_audio/__init__.py +1 -2
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +1 -1
- esphome/components/ili9xxx/ili9xxx_display.cpp +2 -2
- esphome/components/improv_serial/improv_serial_component.cpp +12 -15
- esphome/components/improv_serial/improv_serial_component.h +6 -8
- esphome/components/json/json_util.cpp +35 -43
- esphome/components/json/json_util.h +57 -0
- esphome/components/kamstrup_kmp/kamstrup_kmp.cpp +2 -2
- esphome/components/key_collector/key_collector.h +4 -4
- esphome/components/libretiny/__init__.py +6 -6
- esphome/components/libretiny/preferences.cpp +23 -16
- esphome/components/light/light_call.cpp +98 -120
- esphome/components/light/light_call.h +17 -7
- esphome/components/lm75b/__init__.py +0 -0
- esphome/components/lm75b/lm75b.cpp +39 -0
- esphome/components/lm75b/lm75b.h +19 -0
- esphome/components/lm75b/sensor.py +34 -0
- esphome/components/lock/lock.h +12 -6
- esphome/components/logger/__init__.py +15 -27
- esphome/components/logger/logger.cpp +10 -20
- esphome/components/logger/logger.h +105 -62
- esphome/components/logger/logger_esp32.cpp +0 -48
- esphome/components/logger/logger_zephyr.cpp +2 -3
- esphome/components/logger/select/logger_level_select.cpp +6 -7
- esphome/components/logger/select/logger_level_select.h +7 -0
- esphome/components/ltr501/ltr501.cpp +7 -6
- esphome/components/ltr_als_ps/ltr_als_ps.cpp +7 -6
- esphome/components/matrix_keypad/matrix_keypad.h +4 -4
- esphome/components/max7219digit/max7219digit.cpp +1 -1
- esphome/components/mcp2515/mcp2515.cpp +31 -3
- esphome/components/mcp2515/mcp2515_defs.h +3 -1
- esphome/components/md5/md5.cpp +0 -26
- esphome/components/md5/md5.h +10 -20
- esphome/components/mdns/__init__.py +19 -6
- esphome/components/mdns/mdns_component.cpp +27 -59
- esphome/components/mdns/mdns_component.h +23 -10
- esphome/components/mdns/mdns_esp32.cpp +7 -7
- esphome/components/mdns/mdns_esp8266.cpp +6 -6
- esphome/components/mdns/mdns_libretiny.cpp +3 -3
- esphome/components/mdns/mdns_rp2040.cpp +3 -3
- esphome/components/mipi/__init__.py +1 -5
- esphome/components/mipi_spi/display.py +24 -8
- esphome/components/mipi_spi/mipi_spi.h +3 -3
- esphome/components/mixer/speaker/mixer_speaker.cpp +3 -3
- esphome/components/mmc5603/mmc5603.cpp +3 -3
- esphome/components/modbus/modbus.cpp +27 -13
- esphome/components/modbus/modbus.h +5 -3
- esphome/components/modbus/modbus_definitions.h +86 -0
- esphome/components/modbus_controller/__init__.py +29 -1
- esphome/components/modbus_controller/const.py +4 -0
- esphome/components/modbus_controller/modbus_controller.cpp +38 -13
- esphome/components/modbus_controller/modbus_controller.h +18 -29
- esphome/components/mpr121/mpr121.cpp +41 -42
- esphome/components/mpr121/mpr121.h +0 -1
- esphome/components/nau7802/nau7802.cpp +2 -2
- esphome/components/network/__init__.py +7 -3
- esphome/components/nextion/display.py +4 -4
- esphome/components/nextion/nextion.cpp +8 -8
- esphome/components/number/__init__.py +2 -0
- esphome/components/number/number_call.cpp +23 -12
- esphome/components/number/number_call.h +5 -0
- esphome/components/online_image/bmp_image.cpp +2 -1
- esphome/components/online_image/jpeg_image.cpp +4 -2
- esphome/components/openthread/openthread.cpp +6 -7
- esphome/components/openthread/openthread.h +0 -1
- esphome/components/ota/ota_backend.h +1 -0
- esphome/components/packages/__init__.py +10 -8
- esphome/components/packet_transport/packet_transport.cpp +2 -0
- esphome/components/pid/pid_controller.cpp +1 -1
- esphome/components/prometheus/prometheus_handler.cpp +239 -239
- esphome/components/psram/__init__.py +30 -28
- esphome/components/qmc5883l/qmc5883l.cpp +15 -0
- esphome/components/qmc5883l/qmc5883l.h +3 -0
- esphome/components/qmc5883l/sensor.py +31 -12
- esphome/components/remote_base/gobox_protocol.cpp +3 -3
- esphome/components/remote_receiver/__init__.py +14 -2
- esphome/components/remote_receiver/{remote_receiver_esp8266.cpp → remote_receiver.cpp} +2 -2
- esphome/components/remote_receiver/remote_receiver.h +4 -0
- esphome/components/remote_receiver/remote_receiver_esp32.cpp +18 -1
- esphome/components/remote_transmitter/__init__.py +2 -2
- esphome/components/remote_transmitter/remote_transmitter.cpp +103 -0
- esphome/components/rp2040/__init__.py +11 -11
- esphome/components/rtttl/rtttl.cpp +2 -2
- esphome/components/scd30/sensor.py +1 -1
- esphome/components/script/__init__.py +1 -1
- esphome/components/script/script.h +7 -7
- esphome/components/select/select.cpp +5 -4
- esphome/components/select/select_call.cpp +1 -1
- esphome/components/sensirion_common/i2c_sensirion.cpp +2 -1
- esphome/components/sensor/__init__.py +2 -0
- esphome/components/sha256/__init__.py +22 -0
- esphome/components/sha256/sha256.cpp +116 -0
- esphome/components/sha256/sha256.h +60 -0
- esphome/components/socket/lwip_raw_tcp_impl.cpp +34 -6
- esphome/components/sonoff_d1/sonoff_d1.cpp +1 -1
- esphome/components/spi/__init__.py +0 -3
- esphome/components/split_buffer/__init__.py +5 -0
- esphome/components/split_buffer/split_buffer.cpp +133 -0
- esphome/components/split_buffer/split_buffer.h +40 -0
- esphome/components/sps30/sps30.cpp +14 -10
- esphome/components/sps30/sps30.h +2 -0
- esphome/components/st7567_i2c/st7567_i2c.cpp +3 -1
- esphome/components/st7789v/st7789v.cpp +3 -2
- esphome/components/statsd/statsd.cpp +1 -1
- esphome/components/substitutions/__init__.py +3 -1
- esphome/components/substitutions/jinja.py +13 -3
- esphome/components/sx126x/__init__.py +16 -0
- esphome/components/sx126x/sx126x.cpp +15 -1
- esphome/components/sx126x/sx126x.h +9 -1
- esphome/components/sx126x/sx126x_reg.h +2 -0
- esphome/components/text_sensor/text_sensor.cpp +16 -0
- esphome/components/text_sensor/text_sensor.h +3 -10
- esphome/components/tormatic/tormatic_cover.cpp +1 -1
- esphome/components/tuya/select/tuya_select.cpp +1 -1
- esphome/components/tuya/tuya.cpp +29 -4
- esphome/components/uart/__init__.py +36 -26
- esphome/components/uart/uart.h +6 -0
- esphome/components/uart/uart_component.cpp +8 -0
- esphome/components/uart/uart_component.h +28 -0
- esphome/components/uart/uart_component_esp_idf.cpp +64 -10
- esphome/components/uart/uart_component_esp_idf.h +5 -2
- esphome/components/uponor_smatrix/climate/uponor_smatrix_climate.cpp +1 -1
- esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.cpp +1 -1
- esphome/components/uponor_smatrix/uponor_smatrix.cpp +3 -3
- esphome/components/usb_host/__init__.py +2 -1
- esphome/components/usb_host/usb_host.h +82 -13
- esphome/components/usb_host/usb_host_client.cpp +180 -24
- esphome/components/usb_host/usb_host_component.cpp +1 -1
- esphome/components/usb_uart/__init__.py +0 -1
- esphome/components/usb_uart/ch34x.cpp +4 -4
- esphome/components/usb_uart/cp210x.cpp +3 -3
- esphome/components/usb_uart/usb_uart.cpp +88 -32
- esphome/components/usb_uart/usb_uart.h +30 -6
- esphome/components/valve/valve.cpp +1 -0
- esphome/components/veml7700/veml7700.cpp +7 -6
- esphome/components/version/version_text_sensor.cpp +2 -1
- esphome/components/voice_assistant/voice_assistant.cpp +3 -2
- esphome/components/waveshare_epaper/waveshare_epaper.cpp +4 -4
- esphome/components/web_server/list_entities.cpp +3 -4
- esphome/components/web_server/list_entities.h +8 -10
- esphome/components/web_server/ota/__init__.py +1 -1
- esphome/components/web_server/ota/ota_web_server.cpp +9 -3
- esphome/components/web_server/web_server.cpp +509 -404
- esphome/components/web_server/web_server.h +5 -6
- esphome/components/web_server/web_server_v1.cpp +21 -19
- esphome/components/web_server_base/__init__.py +5 -2
- esphome/components/web_server_base/web_server_base.h +27 -7
- esphome/components/web_server_idf/__init__.py +1 -1
- esphome/components/web_server_idf/multipart.cpp +2 -2
- esphome/components/web_server_idf/multipart.h +2 -2
- esphome/components/web_server_idf/utils.cpp +2 -2
- esphome/components/web_server_idf/utils.h +2 -2
- esphome/components/web_server_idf/web_server_idf.cpp +118 -26
- esphome/components/web_server_idf/web_server_idf.h +12 -10
- esphome/components/wifi/__init__.py +13 -11
- esphome/components/wifi/wifi_component.cpp +73 -56
- esphome/components/wifi/wifi_component.h +4 -4
- esphome/components/wifi/wifi_component_esp8266.cpp +1 -1
- esphome/components/wifi/wifi_component_esp_idf.cpp +24 -4
- esphome/components/wireguard/__init__.py +1 -1
- esphome/components/wts01/__init__.py +0 -0
- esphome/components/wts01/sensor.py +41 -0
- esphome/components/wts01/wts01.cpp +91 -0
- esphome/components/wts01/wts01.h +27 -0
- esphome/components/zephyr/__init__.py +5 -5
- esphome/components/zwave_proxy/__init__.py +43 -0
- esphome/components/zwave_proxy/zwave_proxy.cpp +346 -0
- esphome/components/zwave_proxy/zwave_proxy.h +93 -0
- esphome/config.py +79 -24
- esphome/config_validation.py +13 -15
- esphome/const.py +9 -2
- esphome/core/__init__.py +31 -22
- esphome/core/component.cpp +28 -18
- esphome/core/component_iterator.h +2 -1
- esphome/core/config.py +15 -15
- esphome/core/defines.h +19 -0
- esphome/core/hash_base.h +56 -0
- esphome/core/helpers.cpp +19 -3
- esphome/core/helpers.h +26 -0
- esphome/core/scheduler.cpp +5 -21
- esphome/core/scheduler.h +19 -8
- esphome/core/string_ref.h +1 -1
- esphome/core/time.cpp +5 -5
- esphome/cpp_generator.py +4 -29
- esphome/dashboard/const.py +21 -4
- esphome/dashboard/core.py +10 -8
- esphome/dashboard/dns.py +15 -0
- esphome/dashboard/entries.py +15 -21
- esphome/dashboard/models.py +76 -0
- esphome/dashboard/settings.py +7 -7
- esphome/dashboard/status/mdns.py +46 -2
- esphome/dashboard/web_server.py +367 -93
- esphome/espota2.py +111 -31
- esphome/external_files.py +6 -7
- esphome/git.py +8 -0
- esphome/helpers.py +124 -77
- esphome/loader.py +8 -9
- esphome/platformio_api.py +25 -18
- esphome/storage_json.py +26 -21
- esphome/types.py +30 -2
- esphome/util.py +32 -16
- esphome/vscode.py +8 -8
- esphome/wizard.py +10 -10
- esphome/writer.py +50 -15
- esphome/yaml_util.py +37 -31
- esphome/zeroconf.py +12 -3
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/METADATA +11 -11
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/RECORD +332 -312
- esphome/components/event_emitter/__init__.py +0 -5
- esphome/components/event_emitter/event_emitter.cpp +0 -14
- esphome/components/event_emitter/event_emitter.h +0 -63
- esphome/components/remote_receiver/remote_receiver_libretiny.cpp +0 -125
- esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +0 -107
- esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +0 -110
- esphome/components/uart/uart_component_esp32_arduino.cpp +0 -214
- esphome/components/uart/uart_component_esp32_arduino.h +0 -60
- esphome/components/wifi/wifi_component_esp32_arduino.cpp +0 -860
- esphome/core/string_ref.cpp +0 -12
- esphome/dashboard/util/file.py +0 -63
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/WHEEL +0 -0
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/entry_points.txt +0 -0
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/licenses/LICENSE +0 -0
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/top_level.txt +0 -0
@@ -572,7 +572,7 @@ void MixerSpeaker::audio_mixer_task(void *params) {
|
|
572
572
|
}
|
573
573
|
} else {
|
574
574
|
// Determine how many frames to mix
|
575
|
-
for (
|
575
|
+
for (size_t i = 0; i < transfer_buffers_with_data.size(); ++i) {
|
576
576
|
const uint32_t frames_available_in_buffer =
|
577
577
|
speakers_with_data[i]->get_audio_stream_info().bytes_to_frames(transfer_buffers_with_data[i]->available());
|
578
578
|
frames_to_mix = std::min(frames_to_mix, frames_available_in_buffer);
|
@@ -581,7 +581,7 @@ void MixerSpeaker::audio_mixer_task(void *params) {
|
|
581
581
|
audio::AudioStreamInfo primary_stream_info = speakers_with_data[0]->get_audio_stream_info();
|
582
582
|
|
583
583
|
// Mix two streams together
|
584
|
-
for (
|
584
|
+
for (size_t i = 1; i < transfer_buffers_with_data.size(); ++i) {
|
585
585
|
mix_audio_samples(primary_buffer, primary_stream_info,
|
586
586
|
reinterpret_cast<int16_t *>(transfer_buffers_with_data[i]->get_buffer_start()),
|
587
587
|
speakers_with_data[i]->get_audio_stream_info(),
|
@@ -596,7 +596,7 @@ void MixerSpeaker::audio_mixer_task(void *params) {
|
|
596
596
|
}
|
597
597
|
|
598
598
|
// Update source transfer buffer lengths and add new audio durations to the source speaker pending playbacks
|
599
|
-
for (
|
599
|
+
for (size_t i = 0; i < transfer_buffers_with_data.size(); ++i) {
|
600
600
|
transfer_buffers_with_data[i]->decrease_buffer_length(
|
601
601
|
speakers_with_data[i]->get_audio_stream_info().frames_to_bytes(frames_to_mix));
|
602
602
|
speakers_with_data[i]->pending_playback_frames_ += frames_to_mix;
|
@@ -128,21 +128,21 @@ void MMC5603Component::update() {
|
|
128
128
|
raw_x |= buffer[1] << 4;
|
129
129
|
raw_x |= buffer[2] << 0;
|
130
130
|
|
131
|
-
const float x = 0.
|
131
|
+
const float x = 0.00625 * (raw_x - 524288);
|
132
132
|
|
133
133
|
int32_t raw_y = 0;
|
134
134
|
raw_y |= buffer[3] << 12;
|
135
135
|
raw_y |= buffer[4] << 4;
|
136
136
|
raw_y |= buffer[5] << 0;
|
137
137
|
|
138
|
-
const float y = 0.
|
138
|
+
const float y = 0.00625 * (raw_y - 524288);
|
139
139
|
|
140
140
|
int32_t raw_z = 0;
|
141
141
|
raw_z |= buffer[6] << 12;
|
142
142
|
raw_z |= buffer[7] << 4;
|
143
143
|
raw_z |= buffer[8] << 0;
|
144
144
|
|
145
|
-
const float z = 0.
|
145
|
+
const float z = 0.00625 * (raw_z - 524288);
|
146
146
|
|
147
147
|
const float heading = atan2f(0.0f - x, y) * 180.0f / M_PI;
|
148
148
|
ESP_LOGD(TAG, "Got x=%0.02fµT y=%0.02fµT z=%0.02fµT heading=%0.01f°", x, y, z, heading);
|
@@ -66,7 +66,10 @@ bool Modbus::parse_modbus_byte_(uint8_t byte) {
|
|
66
66
|
uint8_t data_offset = 3;
|
67
67
|
|
68
68
|
// Per https://modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf Ch 5 User-Defined function codes
|
69
|
-
if (((function_code >=
|
69
|
+
if (((function_code >= FUNCTION_CODE_USER_DEFINED_SPACE_1_INIT) &&
|
70
|
+
(function_code <= FUNCTION_CODE_USER_DEFINED_SPACE_1_END)) ||
|
71
|
+
((function_code >= FUNCTION_CODE_USER_DEFINED_SPACE_2_INIT) &&
|
72
|
+
(function_code <= FUNCTION_CODE_USER_DEFINED_SPACE_2_END))) {
|
70
73
|
// Handle user-defined function, since we don't know how big this ought to be,
|
71
74
|
// ideally we should delegate the entire length detection to whatever handler is
|
72
75
|
// installed, but wait, there is the CRC, and if we get a hit there is a good
|
@@ -91,10 +94,14 @@ bool Modbus::parse_modbus_byte_(uint8_t byte) {
|
|
91
94
|
} else {
|
92
95
|
// data starts at 2 and length is 4 for read registers commands
|
93
96
|
if (this->role == ModbusRole::SERVER) {
|
94
|
-
if (function_code ==
|
97
|
+
if (function_code == ModbusFunctionCode::READ_COILS ||
|
98
|
+
function_code == ModbusFunctionCode::READ_DISCRETE_INPUTS ||
|
99
|
+
function_code == ModbusFunctionCode::READ_HOLDING_REGISTERS ||
|
100
|
+
function_code == ModbusFunctionCode::READ_INPUT_REGISTERS ||
|
101
|
+
function_code == ModbusFunctionCode::WRITE_SINGLE_REGISTER) {
|
95
102
|
data_offset = 2;
|
96
103
|
data_len = 4;
|
97
|
-
} else if (function_code ==
|
104
|
+
} else if (function_code == ModbusFunctionCode::WRITE_MULTIPLE_REGISTERS) {
|
98
105
|
if (at < 6) {
|
99
106
|
return true;
|
100
107
|
}
|
@@ -104,7 +111,10 @@ bool Modbus::parse_modbus_byte_(uint8_t byte) {
|
|
104
111
|
}
|
105
112
|
} else {
|
106
113
|
// the response for write command mirrors the requests and data starts at offset 2 instead of 3 for read commands
|
107
|
-
if (function_code ==
|
114
|
+
if (function_code == ModbusFunctionCode::WRITE_SINGLE_COIL ||
|
115
|
+
function_code == ModbusFunctionCode::WRITE_SINGLE_REGISTER ||
|
116
|
+
function_code == ModbusFunctionCode::WRITE_MULTIPLE_COILS ||
|
117
|
+
function_code == ModbusFunctionCode::WRITE_MULTIPLE_REGISTERS) {
|
108
118
|
data_offset = 2;
|
109
119
|
data_len = 4;
|
110
120
|
}
|
@@ -112,7 +122,7 @@ bool Modbus::parse_modbus_byte_(uint8_t byte) {
|
|
112
122
|
|
113
123
|
// Error ( msb indicates error )
|
114
124
|
// response format: Byte[0] = device address, Byte[1] function code | 0x80 , Byte[2] exception code, Byte[3-4] crc
|
115
|
-
if ((function_code &
|
125
|
+
if ((function_code & FUNCTION_CODE_EXCEPTION_MASK) == FUNCTION_CODE_EXCEPTION_MASK) {
|
116
126
|
data_offset = 2;
|
117
127
|
data_len = 1;
|
118
128
|
}
|
@@ -143,10 +153,10 @@ bool Modbus::parse_modbus_byte_(uint8_t byte) {
|
|
143
153
|
if (device->address_ == address) {
|
144
154
|
found = true;
|
145
155
|
// Is it an error response?
|
146
|
-
if ((function_code &
|
156
|
+
if ((function_code & FUNCTION_CODE_EXCEPTION_MASK) == FUNCTION_CODE_EXCEPTION_MASK) {
|
147
157
|
ESP_LOGD(TAG, "Modbus error function code: 0x%X exception: %d", function_code, raw[2]);
|
148
158
|
if (waiting_for_response != 0) {
|
149
|
-
device->on_modbus_error(function_code &
|
159
|
+
device->on_modbus_error(function_code & FUNCTION_CODE_MASK, raw[2]);
|
150
160
|
} else {
|
151
161
|
// Ignore modbus exception not related to a pending command
|
152
162
|
ESP_LOGD(TAG, "Ignoring Modbus error - not expecting a response");
|
@@ -154,12 +164,14 @@ bool Modbus::parse_modbus_byte_(uint8_t byte) {
|
|
154
164
|
continue;
|
155
165
|
}
|
156
166
|
if (this->role == ModbusRole::SERVER) {
|
157
|
-
if (function_code ==
|
167
|
+
if (function_code == ModbusFunctionCode::READ_HOLDING_REGISTERS ||
|
168
|
+
function_code == ModbusFunctionCode::READ_INPUT_REGISTERS) {
|
158
169
|
device->on_modbus_read_registers(function_code, uint16_t(data[1]) | (uint16_t(data[0]) << 8),
|
159
170
|
uint16_t(data[3]) | (uint16_t(data[2]) << 8));
|
160
171
|
continue;
|
161
172
|
}
|
162
|
-
if (function_code ==
|
173
|
+
if (function_code == ModbusFunctionCode::WRITE_SINGLE_REGISTER ||
|
174
|
+
function_code == ModbusFunctionCode::WRITE_MULTIPLE_REGISTERS) {
|
163
175
|
device->on_modbus_write_registers(function_code, data);
|
164
176
|
continue;
|
165
177
|
}
|
@@ -199,7 +211,7 @@ void Modbus::send(uint8_t address, uint8_t function_code, uint16_t start_address
|
|
199
211
|
|
200
212
|
// Only check max number of registers for standard function codes
|
201
213
|
// Some devices use non standard codes like 0x43
|
202
|
-
if (number_of_entities > MAX_VALUES && function_code <=
|
214
|
+
if (number_of_entities > MAX_VALUES && function_code <= ModbusFunctionCode::WRITE_MULTIPLE_REGISTERS) {
|
203
215
|
ESP_LOGE(TAG, "send too many values %d max=%zu", number_of_entities, MAX_VALUES);
|
204
216
|
return;
|
205
217
|
}
|
@@ -210,15 +222,17 @@ void Modbus::send(uint8_t address, uint8_t function_code, uint16_t start_address
|
|
210
222
|
if (this->role == ModbusRole::CLIENT) {
|
211
223
|
data.push_back(start_address >> 8);
|
212
224
|
data.push_back(start_address >> 0);
|
213
|
-
if (function_code !=
|
225
|
+
if (function_code != ModbusFunctionCode::WRITE_SINGLE_COIL &&
|
226
|
+
function_code != ModbusFunctionCode::WRITE_SINGLE_REGISTER) {
|
214
227
|
data.push_back(number_of_entities >> 8);
|
215
228
|
data.push_back(number_of_entities >> 0);
|
216
229
|
}
|
217
230
|
}
|
218
231
|
|
219
232
|
if (payload != nullptr) {
|
220
|
-
if (this->role == ModbusRole::SERVER || function_code ==
|
221
|
-
|
233
|
+
if (this->role == ModbusRole::SERVER || function_code == ModbusFunctionCode::WRITE_MULTIPLE_COILS ||
|
234
|
+
function_code == ModbusFunctionCode::WRITE_MULTIPLE_REGISTERS) { // Write multiple
|
235
|
+
data.push_back(payload_len); // Byte count is required for write
|
222
236
|
} else {
|
223
237
|
payload_len = 2; // Write single register or coil
|
224
238
|
}
|
@@ -3,6 +3,8 @@
|
|
3
3
|
#include "esphome/core/component.h"
|
4
4
|
#include "esphome/components/uart/uart.h"
|
5
5
|
|
6
|
+
#include "esphome/components/modbus/modbus_definitions.h"
|
7
|
+
|
6
8
|
#include <vector>
|
7
9
|
|
8
10
|
namespace esphome {
|
@@ -65,12 +67,12 @@ class ModbusDevice {
|
|
65
67
|
this->parent_->send(this->address_, function, start_address, number_of_entities, payload_len, payload);
|
66
68
|
}
|
67
69
|
void send_raw(const std::vector<uint8_t> &payload) { this->parent_->send_raw(payload); }
|
68
|
-
void send_error(uint8_t function_code,
|
70
|
+
void send_error(uint8_t function_code, ModbusExceptionCode exception_code) {
|
69
71
|
std::vector<uint8_t> error_response;
|
70
72
|
error_response.reserve(3);
|
71
73
|
error_response.push_back(this->address_);
|
72
|
-
error_response.push_back(function_code |
|
73
|
-
error_response.push_back(exception_code);
|
74
|
+
error_response.push_back(function_code | FUNCTION_CODE_EXCEPTION_MASK);
|
75
|
+
error_response.push_back(static_cast<uint8_t>(exception_code));
|
74
76
|
this->send_raw(error_response);
|
75
77
|
}
|
76
78
|
// If more than one device is connected block sending a new command before a response is received
|
@@ -0,0 +1,86 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include "esphome/core/component.h"
|
4
|
+
|
5
|
+
namespace esphome {
|
6
|
+
namespace modbus {
|
7
|
+
|
8
|
+
/// Modbus definitions from specs:
|
9
|
+
/// https://modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf
|
10
|
+
// 5 Function Code Categories
|
11
|
+
const uint8_t FUNCTION_CODE_USER_DEFINED_SPACE_1_INIT = 65; // 0x41
|
12
|
+
const uint8_t FUNCTION_CODE_USER_DEFINED_SPACE_1_END = 72; // 0x48
|
13
|
+
|
14
|
+
const uint8_t FUNCTION_CODE_USER_DEFINED_SPACE_2_INIT = 100; // 0x64
|
15
|
+
const uint8_t FUNCTION_CODE_USER_DEFINED_SPACE_2_END = 110; // 0x6E
|
16
|
+
|
17
|
+
enum class ModbusFunctionCode : uint8_t {
|
18
|
+
CUSTOM = 0x00,
|
19
|
+
READ_COILS = 0x01,
|
20
|
+
READ_DISCRETE_INPUTS = 0x02,
|
21
|
+
READ_HOLDING_REGISTERS = 0x03,
|
22
|
+
READ_INPUT_REGISTERS = 0x04,
|
23
|
+
WRITE_SINGLE_COIL = 0x05,
|
24
|
+
WRITE_SINGLE_REGISTER = 0x06,
|
25
|
+
READ_EXCEPTION_STATUS = 0x07, // not implemented
|
26
|
+
DIAGNOSTICS = 0x08, // not implemented
|
27
|
+
GET_COMM_EVENT_COUNTER = 0x0B, // not implemented
|
28
|
+
GET_COMM_EVENT_LOG = 0x0C, // not implemented
|
29
|
+
WRITE_MULTIPLE_COILS = 0x0F,
|
30
|
+
WRITE_MULTIPLE_REGISTERS = 0x10,
|
31
|
+
REPORT_SERVER_ID = 0x11, // not implemented
|
32
|
+
READ_FILE_RECORD = 0x14, // not implemented
|
33
|
+
WRITE_FILE_RECORD = 0x15, // not implemented
|
34
|
+
MASK_WRITE_REGISTER = 0x16, // not implemented
|
35
|
+
READ_WRITE_MULTIPLE_REGISTERS = 0x17, // not implemented
|
36
|
+
READ_FIFO_QUEUE = 0x18, // not implemented
|
37
|
+
};
|
38
|
+
|
39
|
+
/*Allow comparison operators between ModbusFunctionCode and uint8_t*/
|
40
|
+
inline bool operator==(ModbusFunctionCode lhs, uint8_t rhs) { return static_cast<uint8_t>(lhs) == rhs; }
|
41
|
+
inline bool operator==(uint8_t lhs, ModbusFunctionCode rhs) { return lhs == static_cast<uint8_t>(rhs); }
|
42
|
+
inline bool operator!=(ModbusFunctionCode lhs, uint8_t rhs) { return !(static_cast<uint8_t>(lhs) == rhs); }
|
43
|
+
inline bool operator!=(uint8_t lhs, ModbusFunctionCode rhs) { return !(lhs == static_cast<uint8_t>(rhs)); }
|
44
|
+
inline bool operator<(ModbusFunctionCode lhs, uint8_t rhs) { return static_cast<uint8_t>(lhs) < rhs; }
|
45
|
+
inline bool operator<(uint8_t lhs, ModbusFunctionCode rhs) { return lhs < static_cast<uint8_t>(rhs); }
|
46
|
+
inline bool operator<=(ModbusFunctionCode lhs, uint8_t rhs) { return static_cast<uint8_t>(lhs) <= rhs; }
|
47
|
+
inline bool operator<=(uint8_t lhs, ModbusFunctionCode rhs) { return lhs <= static_cast<uint8_t>(rhs); }
|
48
|
+
inline bool operator>(ModbusFunctionCode lhs, uint8_t rhs) { return static_cast<uint8_t>(lhs) > rhs; }
|
49
|
+
inline bool operator>(uint8_t lhs, ModbusFunctionCode rhs) { return lhs > static_cast<uint8_t>(rhs); }
|
50
|
+
inline bool operator>=(ModbusFunctionCode lhs, uint8_t rhs) { return static_cast<uint8_t>(lhs) >= rhs; }
|
51
|
+
inline bool operator>=(uint8_t lhs, ModbusFunctionCode rhs) { return lhs >= static_cast<uint8_t>(rhs); }
|
52
|
+
|
53
|
+
// 4.3 MODBUS Data model
|
54
|
+
enum class ModbusRegisterType : uint8_t {
|
55
|
+
CUSTOM = 0x00,
|
56
|
+
COIL = 0x01,
|
57
|
+
DISCRETE_INPUT = 0x02,
|
58
|
+
HOLDING = 0x03,
|
59
|
+
READ = 0x04,
|
60
|
+
};
|
61
|
+
|
62
|
+
// 7 MODBUS Exception Responses:
|
63
|
+
const uint8_t FUNCTION_CODE_MASK = 0x7F;
|
64
|
+
const uint8_t FUNCTION_CODE_EXCEPTION_MASK = 0x80;
|
65
|
+
|
66
|
+
enum class ModbusExceptionCode : uint8_t {
|
67
|
+
ILLEGAL_FUNCTION = 0x01,
|
68
|
+
ILLEGAL_DATA_ADDRESS = 0x02,
|
69
|
+
ILLEGAL_DATA_VALUE = 0x03,
|
70
|
+
SERVICE_DEVICE_FAILURE = 0x04,
|
71
|
+
ACKNOWLEDGE = 0x05,
|
72
|
+
SERVER_DEVICE_BUSY = 0x06,
|
73
|
+
MEMORY_PARITY_ERROR = 0x08,
|
74
|
+
GATEWAY_PATH_UNAVAILABLE = 0x0A,
|
75
|
+
GATEWAY_TARGET_DEVICE_FAILED_TO_RESPOND = 0x0B,
|
76
|
+
};
|
77
|
+
|
78
|
+
// 6.12 16 (0x10) Write Multiple registers:
|
79
|
+
const uint8_t MAX_NUM_OF_REGISTERS_TO_WRITE = 123; // 0x7B
|
80
|
+
|
81
|
+
// 6.3 03 (0x03) Read Holding Registers
|
82
|
+
// 6.4 04 (0x04) Read Input Registers
|
83
|
+
const uint8_t MAX_NUM_OF_REGISTERS_TO_READ = 125; // 0x7D
|
84
|
+
/// End of Modbus definitions
|
85
|
+
} // namespace modbus
|
86
|
+
} // namespace esphome
|
@@ -20,6 +20,7 @@ from .const import (
|
|
20
20
|
CONF_BYTE_OFFSET,
|
21
21
|
CONF_COMMAND_THROTTLE,
|
22
22
|
CONF_CUSTOM_COMMAND,
|
23
|
+
CONF_ENABLED,
|
23
24
|
CONF_FORCE_NEW_RANGE,
|
24
25
|
CONF_MAX_CMD_RETRIES,
|
25
26
|
CONF_MODBUS_CONTROLLER_ID,
|
@@ -28,8 +29,11 @@ from .const import (
|
|
28
29
|
CONF_ON_OFFLINE,
|
29
30
|
CONF_ON_ONLINE,
|
30
31
|
CONF_REGISTER_COUNT,
|
32
|
+
CONF_REGISTER_LAST_ADDRESS,
|
31
33
|
CONF_REGISTER_TYPE,
|
34
|
+
CONF_REGISTER_VALUE,
|
32
35
|
CONF_RESPONSE_SIZE,
|
36
|
+
CONF_SERVER_COURTESY_RESPONSE,
|
33
37
|
CONF_SKIP_UPDATES,
|
34
38
|
CONF_VALUE_TYPE,
|
35
39
|
)
|
@@ -49,6 +53,7 @@ ModbusController = modbus_controller_ns.class_(
|
|
49
53
|
)
|
50
54
|
|
51
55
|
SensorItem = modbus_controller_ns.struct("SensorItem")
|
56
|
+
ServerCourtesyResponse = modbus_controller_ns.struct("ServerCourtesyResponse")
|
52
57
|
ServerRegister = modbus_controller_ns.struct("ServerRegister")
|
53
58
|
|
54
59
|
ModbusFunctionCode_ns = modbus_controller_ns.namespace("ModbusFunctionCode")
|
@@ -143,6 +148,14 @@ ModbusOfflineTrigger = modbus_controller_ns.class_(
|
|
143
148
|
|
144
149
|
_LOGGER = logging.getLogger(__name__)
|
145
150
|
|
151
|
+
SERVER_COURTESY_RESPONSE_SCHEMA = cv.Schema(
|
152
|
+
{
|
153
|
+
cv.Optional(CONF_ENABLED, default=False): cv.boolean,
|
154
|
+
cv.Optional(CONF_REGISTER_LAST_ADDRESS, default=0xFFFF): cv.hex_uint16_t,
|
155
|
+
cv.Optional(CONF_REGISTER_VALUE, default=0): cv.hex_uint16_t,
|
156
|
+
}
|
157
|
+
)
|
158
|
+
|
146
159
|
ModbusServerRegisterSchema = cv.Schema(
|
147
160
|
{
|
148
161
|
cv.GenerateID(): cv.declare_id(ServerRegister),
|
@@ -162,6 +175,7 @@ CONFIG_SCHEMA = cv.All(
|
|
162
175
|
cv.Optional(
|
163
176
|
CONF_COMMAND_THROTTLE, default="0ms"
|
164
177
|
): cv.positive_time_period_milliseconds,
|
178
|
+
cv.Optional(CONF_SERVER_COURTESY_RESPONSE): SERVER_COURTESY_RESPONSE_SCHEMA,
|
165
179
|
cv.Optional(CONF_MAX_CMD_RETRIES, default=4): cv.positive_int,
|
166
180
|
cv.Optional(CONF_OFFLINE_SKIP_UPDATES, default=0): cv.positive_int,
|
167
181
|
cv.Optional(
|
@@ -232,7 +246,7 @@ def validate_modbus_register(config):
|
|
232
246
|
|
233
247
|
|
234
248
|
def _final_validate(config):
|
235
|
-
if CONF_SERVER_REGISTERS in config:
|
249
|
+
if CONF_SERVER_COURTESY_RESPONSE in config or CONF_SERVER_REGISTERS in config:
|
236
250
|
return modbus.final_validate_modbus_device("modbus_controller", role="server")(
|
237
251
|
config
|
238
252
|
)
|
@@ -299,6 +313,20 @@ async def to_code(config):
|
|
299
313
|
var = cg.new_Pvariable(config[CONF_ID])
|
300
314
|
cg.add(var.set_allow_duplicate_commands(config[CONF_ALLOW_DUPLICATE_COMMANDS]))
|
301
315
|
cg.add(var.set_command_throttle(config[CONF_COMMAND_THROTTLE]))
|
316
|
+
if server_courtesy_response := config.get(CONF_SERVER_COURTESY_RESPONSE):
|
317
|
+
cg.add(
|
318
|
+
var.set_server_courtesy_response(
|
319
|
+
cg.StructInitializer(
|
320
|
+
ServerCourtesyResponse,
|
321
|
+
("enabled", server_courtesy_response[CONF_ENABLED]),
|
322
|
+
(
|
323
|
+
"register_last_address",
|
324
|
+
server_courtesy_response[CONF_REGISTER_LAST_ADDRESS],
|
325
|
+
),
|
326
|
+
("register_value", server_courtesy_response[CONF_REGISTER_VALUE]),
|
327
|
+
)
|
328
|
+
)
|
329
|
+
)
|
302
330
|
cg.add(var.set_max_cmd_retries(config[CONF_MAX_CMD_RETRIES]))
|
303
331
|
cg.add(var.set_offline_skip_updates(config[CONF_OFFLINE_SKIP_UPDATES]))
|
304
332
|
if CONF_SERVER_REGISTERS in config:
|
@@ -2,6 +2,7 @@ CONF_ALLOW_DUPLICATE_COMMANDS = "allow_duplicate_commands"
|
|
2
2
|
CONF_BITMASK = "bitmask"
|
3
3
|
CONF_BYTE_OFFSET = "byte_offset"
|
4
4
|
CONF_COMMAND_THROTTLE = "command_throttle"
|
5
|
+
CONF_ENABLED = "enabled"
|
5
6
|
CONF_OFFLINE_SKIP_UPDATES = "offline_skip_updates"
|
6
7
|
CONF_CUSTOM_COMMAND = "custom_command"
|
7
8
|
CONF_FORCE_NEW_RANGE = "force_new_range"
|
@@ -13,8 +14,11 @@ CONF_ON_ONLINE = "on_online"
|
|
13
14
|
CONF_ON_OFFLINE = "on_offline"
|
14
15
|
CONF_RAW_ENCODE = "raw_encode"
|
15
16
|
CONF_REGISTER_COUNT = "register_count"
|
17
|
+
CONF_REGISTER_LAST_ADDRESS = "register_last_address"
|
16
18
|
CONF_REGISTER_TYPE = "register_type"
|
19
|
+
CONF_REGISTER_VALUE = "register_value"
|
17
20
|
CONF_RESPONSE_SIZE = "response_size"
|
21
|
+
CONF_SERVER_COURTESY_RESPONSE = "server_courtesy_response"
|
18
22
|
CONF_SKIP_UPDATES = "skip_updates"
|
19
23
|
CONF_USE_WRITE_MULTIPLE = "use_write_multiple"
|
20
24
|
CONF_VALUE_TYPE = "value_type"
|
@@ -112,6 +112,12 @@ void ModbusController::on_modbus_read_registers(uint8_t function_code, uint16_t
|
|
112
112
|
"0x%X.",
|
113
113
|
this->address_, function_code, start_address, number_of_registers);
|
114
114
|
|
115
|
+
if (number_of_registers == 0 || number_of_registers > modbus::MAX_NUM_OF_REGISTERS_TO_READ) {
|
116
|
+
ESP_LOGW(TAG, "Invalid number of registers %d. Sending exception response.", number_of_registers);
|
117
|
+
this->send_error(function_code, ModbusExceptionCode::ILLEGAL_DATA_ADDRESS);
|
118
|
+
return;
|
119
|
+
}
|
120
|
+
|
115
121
|
std::vector<uint16_t> sixteen_bit_response;
|
116
122
|
for (uint16_t current_address = start_address; current_address < start_address + number_of_registers;) {
|
117
123
|
bool found = false;
|
@@ -136,9 +142,21 @@ void ModbusController::on_modbus_read_registers(uint8_t function_code, uint16_t
|
|
136
142
|
}
|
137
143
|
|
138
144
|
if (!found) {
|
139
|
-
|
140
|
-
|
141
|
-
|
145
|
+
if (this->server_courtesy_response_.enabled &&
|
146
|
+
(current_address <= this->server_courtesy_response_.register_last_address)) {
|
147
|
+
ESP_LOGD(TAG,
|
148
|
+
"Could not match any register to address 0x%02X, but default allowed. "
|
149
|
+
"Returning default value: %d.",
|
150
|
+
current_address, this->server_courtesy_response_.register_value);
|
151
|
+
sixteen_bit_response.push_back(this->server_courtesy_response_.register_value);
|
152
|
+
current_address += 1; // Just increment by 1, as the default response is a single register
|
153
|
+
} else {
|
154
|
+
ESP_LOGW(TAG,
|
155
|
+
"Could not match any register to address 0x%02X and default not allowed. Sending exception response.",
|
156
|
+
current_address);
|
157
|
+
this->send_error(function_code, ModbusExceptionCode::ILLEGAL_DATA_ADDRESS);
|
158
|
+
return;
|
159
|
+
}
|
142
160
|
}
|
143
161
|
}
|
144
162
|
|
@@ -156,27 +174,27 @@ void ModbusController::on_modbus_write_registers(uint8_t function_code, const st
|
|
156
174
|
uint16_t number_of_registers;
|
157
175
|
uint16_t payload_offset;
|
158
176
|
|
159
|
-
if (function_code ==
|
177
|
+
if (function_code == ModbusFunctionCode::WRITE_MULTIPLE_REGISTERS) {
|
160
178
|
number_of_registers = uint16_t(data[3]) | (uint16_t(data[2]) << 8);
|
161
|
-
if (number_of_registers == 0 || number_of_registers >
|
179
|
+
if (number_of_registers == 0 || number_of_registers > modbus::MAX_NUM_OF_REGISTERS_TO_WRITE) {
|
162
180
|
ESP_LOGW(TAG, "Invalid number of registers %d. Sending exception response.", number_of_registers);
|
163
|
-
send_error(function_code,
|
181
|
+
this->send_error(function_code, ModbusExceptionCode::ILLEGAL_DATA_VALUE);
|
164
182
|
return;
|
165
183
|
}
|
166
184
|
uint16_t payload_size = data[4];
|
167
185
|
if (payload_size != number_of_registers * 2) {
|
168
186
|
ESP_LOGW(TAG, "Payload size of %d bytes is not 2 times the number of registers (%d). Sending exception response.",
|
169
187
|
payload_size, number_of_registers);
|
170
|
-
send_error(function_code,
|
188
|
+
this->send_error(function_code, ModbusExceptionCode::ILLEGAL_DATA_VALUE);
|
171
189
|
return;
|
172
190
|
}
|
173
191
|
payload_offset = 5;
|
174
|
-
} else if (function_code ==
|
192
|
+
} else if (function_code == ModbusFunctionCode::WRITE_SINGLE_REGISTER) {
|
175
193
|
number_of_registers = 1;
|
176
194
|
payload_offset = 2;
|
177
195
|
} else {
|
178
196
|
ESP_LOGW(TAG, "Invalid function code 0x%X. Sending exception response.", function_code);
|
179
|
-
send_error(function_code,
|
197
|
+
this->send_error(function_code, ModbusExceptionCode::ILLEGAL_FUNCTION);
|
180
198
|
return;
|
181
199
|
}
|
182
200
|
|
@@ -211,7 +229,7 @@ void ModbusController::on_modbus_write_registers(uint8_t function_code, const st
|
|
211
229
|
if (!for_each_register([](ServerRegister *server_register, uint16_t offset) -> bool {
|
212
230
|
return server_register->write_lambda != nullptr;
|
213
231
|
})) {
|
214
|
-
send_error(function_code,
|
232
|
+
this->send_error(function_code, ModbusExceptionCode::ILLEGAL_FUNCTION);
|
215
233
|
return;
|
216
234
|
}
|
217
235
|
|
@@ -220,7 +238,7 @@ void ModbusController::on_modbus_write_registers(uint8_t function_code, const st
|
|
220
238
|
int64_t number = payload_to_number(data, server_register->value_type, offset, 0xFFFFFFFF);
|
221
239
|
return server_register->write_lambda(number);
|
222
240
|
})) {
|
223
|
-
send_error(function_code,
|
241
|
+
this->send_error(function_code, ModbusExceptionCode::SERVICE_DEVICE_FAILURE);
|
224
242
|
return;
|
225
243
|
}
|
226
244
|
|
@@ -431,8 +449,15 @@ void ModbusController::dump_config() {
|
|
431
449
|
"ModbusController:\n"
|
432
450
|
" Address: 0x%02X\n"
|
433
451
|
" Max Command Retries: %d\n"
|
434
|
-
" Offline Skip Updates: %d"
|
435
|
-
|
452
|
+
" Offline Skip Updates: %d\n"
|
453
|
+
" Server Courtesy Response:\n"
|
454
|
+
" Enabled: %s\n"
|
455
|
+
" Register Last Address: 0x%02X\n"
|
456
|
+
" Register Value: %d",
|
457
|
+
this->address_, this->max_cmd_retries_, this->offline_skip_updates_,
|
458
|
+
this->server_courtesy_response_.enabled ? "true" : "false",
|
459
|
+
this->server_courtesy_response_.register_last_address, this->server_courtesy_response_.register_value);
|
460
|
+
|
436
461
|
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
437
462
|
ESP_LOGCONFIG(TAG, "sensormap");
|
438
463
|
for (auto &it : this->sensorset_) {
|
@@ -16,35 +16,9 @@ namespace modbus_controller {
|
|
16
16
|
|
17
17
|
class ModbusController;
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
READ_DISCRETE_INPUTS = 0x02,
|
23
|
-
READ_HOLDING_REGISTERS = 0x03,
|
24
|
-
READ_INPUT_REGISTERS = 0x04,
|
25
|
-
WRITE_SINGLE_COIL = 0x05,
|
26
|
-
WRITE_SINGLE_REGISTER = 0x06,
|
27
|
-
READ_EXCEPTION_STATUS = 0x07, // not implemented
|
28
|
-
DIAGNOSTICS = 0x08, // not implemented
|
29
|
-
GET_COMM_EVENT_COUNTER = 0x0B, // not implemented
|
30
|
-
GET_COMM_EVENT_LOG = 0x0C, // not implemented
|
31
|
-
WRITE_MULTIPLE_COILS = 0x0F,
|
32
|
-
WRITE_MULTIPLE_REGISTERS = 0x10,
|
33
|
-
REPORT_SERVER_ID = 0x11, // not implemented
|
34
|
-
READ_FILE_RECORD = 0x14, // not implemented
|
35
|
-
WRITE_FILE_RECORD = 0x15, // not implemented
|
36
|
-
MASK_WRITE_REGISTER = 0x16, // not implemented
|
37
|
-
READ_WRITE_MULTIPLE_REGISTERS = 0x17, // not implemented
|
38
|
-
READ_FIFO_QUEUE = 0x18, // not implemented
|
39
|
-
};
|
40
|
-
|
41
|
-
enum class ModbusRegisterType : uint8_t {
|
42
|
-
CUSTOM = 0x0,
|
43
|
-
COIL = 0x01,
|
44
|
-
DISCRETE_INPUT = 0x02,
|
45
|
-
HOLDING = 0x03,
|
46
|
-
READ = 0x04,
|
47
|
-
};
|
19
|
+
using modbus::ModbusFunctionCode;
|
20
|
+
using modbus::ModbusRegisterType;
|
21
|
+
using modbus::ModbusExceptionCode;
|
48
22
|
|
49
23
|
enum class SensorValueType : uint8_t {
|
50
24
|
RAW = 0x00, // variable length
|
@@ -256,6 +230,12 @@ class SensorItem {
|
|
256
230
|
bool force_new_range{false};
|
257
231
|
};
|
258
232
|
|
233
|
+
struct ServerCourtesyResponse {
|
234
|
+
bool enabled{false};
|
235
|
+
uint16_t register_last_address{0xFFFF};
|
236
|
+
uint16_t register_value{0};
|
237
|
+
};
|
238
|
+
|
259
239
|
class ServerRegister {
|
260
240
|
using ReadLambda = std::function<int64_t()>;
|
261
241
|
using WriteLambda = std::function<bool(int64_t value)>;
|
@@ -530,6 +510,12 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice {
|
|
530
510
|
void set_max_cmd_retries(uint8_t max_cmd_retries) { this->max_cmd_retries_ = max_cmd_retries; }
|
531
511
|
/// get how many times a command will be (re)sent if no response is received
|
532
512
|
uint8_t get_max_cmd_retries() { return this->max_cmd_retries_; }
|
513
|
+
/// Called by esphome generated code to set the server courtesy response object
|
514
|
+
void set_server_courtesy_response(const ServerCourtesyResponse &server_courtesy_response) {
|
515
|
+
this->server_courtesy_response_ = server_courtesy_response;
|
516
|
+
}
|
517
|
+
/// Get the server courtesy response object
|
518
|
+
ServerCourtesyResponse get_server_courtesy_response() const { return this->server_courtesy_response_; }
|
533
519
|
|
534
520
|
protected:
|
535
521
|
/// parse sensormap_ and create range of sequential addresses
|
@@ -572,6 +558,9 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice {
|
|
572
558
|
CallbackManager<void(int, int)> online_callback_{};
|
573
559
|
/// Server offline callback
|
574
560
|
CallbackManager<void(int, int)> offline_callback_{};
|
561
|
+
/// Server courtesy response
|
562
|
+
ServerCourtesyResponse server_courtesy_response_{
|
563
|
+
.enabled = false, .register_last_address = 0xFFFF, .register_value = 0};
|
575
564
|
};
|
576
565
|
|
577
566
|
/** Convert vector<uint8_t> response payload to float.
|
@@ -11,47 +11,49 @@ namespace mpr121 {
|
|
11
11
|
static const char *const TAG = "mpr121";
|
12
12
|
|
13
13
|
void MPR121Component::setup() {
|
14
|
+
this->disable_loop();
|
14
15
|
// soft reset device
|
15
16
|
this->write_byte(MPR121_SOFTRESET, 0x63);
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
17
|
+
this->set_timeout(100, [this]() {
|
18
|
+
if (!this->write_byte(MPR121_ECR, 0x0)) {
|
19
|
+
this->error_code_ = COMMUNICATION_FAILED;
|
20
|
+
this->mark_failed();
|
21
|
+
return;
|
22
|
+
}
|
23
|
+
// set touch sensitivity for all 12 channels
|
24
|
+
for (auto *channel : this->channels_) {
|
25
|
+
channel->setup();
|
26
|
+
}
|
27
|
+
this->write_byte(MPR121_MHDR, 0x01);
|
28
|
+
this->write_byte(MPR121_NHDR, 0x01);
|
29
|
+
this->write_byte(MPR121_NCLR, 0x0E);
|
30
|
+
this->write_byte(MPR121_FDLR, 0x00);
|
31
|
+
|
32
|
+
this->write_byte(MPR121_MHDF, 0x01);
|
33
|
+
this->write_byte(MPR121_NHDF, 0x05);
|
34
|
+
this->write_byte(MPR121_NCLF, 0x01);
|
35
|
+
this->write_byte(MPR121_FDLF, 0x00);
|
36
|
+
|
37
|
+
this->write_byte(MPR121_NHDT, 0x00);
|
38
|
+
this->write_byte(MPR121_NCLT, 0x00);
|
39
|
+
this->write_byte(MPR121_FDLT, 0x00);
|
40
|
+
|
41
|
+
this->write_byte(MPR121_DEBOUNCE, 0);
|
42
|
+
// default, 16uA charge current
|
43
|
+
this->write_byte(MPR121_CONFIG1, 0x10);
|
44
|
+
// 0.5uS encoding, 1ms period
|
45
|
+
this->write_byte(MPR121_CONFIG2, 0x20);
|
46
|
+
|
47
|
+
// Write the Electrode Configuration Register
|
48
|
+
// * Highest 2 bits is "Calibration Lock", which we set to a value corresponding to 5 bits.
|
49
|
+
// * The 2 bits below is "Proximity Enable" and are left at 0.
|
50
|
+
// * The 4 least significant bits control how many electrodes are enabled. Electrodes are enabled
|
51
|
+
// as a range, starting at 0 up to the highest channel index used.
|
52
|
+
this->write_byte(MPR121_ECR, 0x80 | (this->max_touch_channel_ + 1));
|
53
|
+
|
54
|
+
this->flush_gpio_();
|
55
|
+
this->enable_loop();
|
56
|
+
});
|
55
57
|
}
|
56
58
|
|
57
59
|
void MPR121Component::set_touch_debounce(uint8_t debounce) {
|
@@ -73,9 +75,6 @@ void MPR121Component::dump_config() {
|
|
73
75
|
case COMMUNICATION_FAILED:
|
74
76
|
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
|
75
77
|
break;
|
76
|
-
case WRONG_CHIP_STATE:
|
77
|
-
ESP_LOGE(TAG, "MPR121 has wrong default value for CONFIG2?");
|
78
|
-
break;
|
79
78
|
case NONE:
|
80
79
|
default:
|
81
80
|
break;
|