esphome:
  name: uart-mock-modbus-srv-rw

host:
api:
logger:
  level: VERBOSE

external_components:
  - source:
      type: local
      path: EXTERNAL_COMPONENT_PATH

# Dummy uart entry to satisfy modbus's DEPENDENCIES = ["uart"]
# The actual UART bus used is the uart_mock component below
uart:
  baud_rate: 115200
  port: /dev/null

uart_mock:
  - id: virtual_uart_dev
    baud_rate: 9600
    rx_full_threshold: 120
    rx_timeout: 2
    auto_start: false
    debug:
    injections:
      # FC 0x17 Read/Write Multiple Registers on device 1:
      #   write reg 0x0001 = 0x1234 (qty 1), then read regs 0x0001..0x0002 (qty 2).
      # Per Modbus 6.17 the write is performed before the read, so reg 0x0001 must
      # read back the just-written 0x1234 in the same request.
      - delay: 100ms
        inject_rx:
          [0x01, 0x17, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x02, 0x12, 0x34, 0x49, 0xD8]
      # FC 0x17: write reg 0x0003 = 0x5678 (qty 1), then read reg 0x0003 (qty 1) -
      # a write and read targeting a different register block.
      - delay: 100ms
        inject_rx:
          [0x01, 0x17, 0x00, 0x03, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x02, 0x56, 0x78, 0x9B, 0x10]

globals:
  - id: stored_1
    type: uint16_t
    initial_value: "0"
  - id: stored_3
    type: uint16_t
    initial_value: "0"

modbus:
  uart_id: virtual_uart_dev
  role: server

modbus_server:
  - address: 1
    registers:
      # Writable + readable register backed by a global. The read publishes what it
      # returns so the test can confirm the write half ran before the read half.
      - address: 0x01
        value_type: U_WORD
        read_lambda: |-
          id(rw_read_1).publish_state(id(stored_1));
          return id(stored_1);
        write_lambda: |-
          id(stored_1) = x;
          id(rw_write_1).publish_state(x);
          return true;
      # Read-only register, read together with 0x01 by the first request's 2-register read.
      - address: 0x02
        value_type: U_WORD
        read_lambda: |-
          id(rw_read_2).publish_state(0x00AA);
          return 0x00AA;
      # Second writable + readable register, targeted by the second request.
      - address: 0x03
        value_type: U_WORD
        read_lambda: |-
          id(rw_read_3).publish_state(id(stored_3));
          return id(stored_3);
        write_lambda: |-
          id(stored_3) = x;
          id(rw_write_3).publish_state(x);
          return true;

sensor:
  - platform: template
    name: "rw_write_1"
    id: rw_write_1
  - platform: template
    name: "rw_read_1"
    id: rw_read_1
  - platform: template
    name: "rw_read_2"
    id: rw_read_2
  - platform: template
    name: "rw_write_3"
    id: rw_write_3
  - platform: template
    name: "rw_read_3"
    id: rw_read_3

button:
  - platform: template
    name: "Start Scenario"
    id: start_scenario_btn
    on_press:
      - lambda: "id(virtual_uart_dev).start_scenario();"
