# =============================================================================
#  Gree Versati III  <->  Home Assistant  (ESPHome, Modbus RTU)
#  Full register map from Gree's "MODBUS [VERSATI III]" document, ver. 01 2021-08-09.
#  Based on koelec/EspHome-Gree and peca2345, extended to every documented register.
#  Source: https://smarthomeguide.blog
#
#  HARDWARE
#    ESP32 dev board + TTL-to-RS485 module. Two variants:
#    A) auto-direction module, 3.3 V logic:
#       ESP32 3V3 -> VCC, GND -> GND, GPIO17 (TX) -> module RXD, GPIO16 (RX) -> module TXD
#    B) MAX485 board with an EN pin (5 V supply):
#       ESP32 VIN -> VCC, GND -> GND, GPIO17 (TX) -> RXD, GPIO4 -> EN (uncomment
#       flow_control_pin below), module TXD -> 1k -> GPIO16 (RX), 2k from GPIO16 to GND
#    RS485 A/B -> 2-pin "BMS" port on the back of the Versati wired controller:
#       pin 1 = B, pin 2 = A (per Gree)
#    Shielded twisted pair, shield to GND at the ESP end only. 120 ohm termination.
#
#  BUS: 9600 baud, 8 data bits, no parity, 1 stop bit.
#  Controller address: Commissioning -> "Address", default 1 (never 0 or 126).
#
#  FUNCTION CODES supported by Versati: 0x01 read coils, 0x03 read registers,
#  0x0F write multiple coils, 0x10 write multiple registers.
#  Single writes (0x05/0x06) are NOT supported, so every write here uses
#  "use_write_multiple: true".
#
#  GREE NOTES
#   - Change Mode (Word 2) and On/Off (Word 42) only while the unit is off.
#   - Parameter changes apply at once but are saved to memory after 30 minutes.
#   - The DHW setpoint only applies while disinfection is off.
# =============================================================================

substitutions:
  name: versati-modbus
  friendly_name: Versati
  modbus_address: "1"
  # Gree documents temperatures in whole °C, but community projects (koelec, peca2345)
  # divide temperature readings by 10. Compare "Outdoor temperature" with the controller display:
  # if Home Assistant shows 10x too little, set this to "1".
  temp_scale: "0.1"

esphome:
  name: ${name}
  friendly_name: ${friendly_name}

esp32:
  board: esp32dev

logger:
  level: INFO

api:
  encryption:
    key: !secret api_key

ota:
  - platform: esphome
    # authenticated by the API encryption key, no separate password

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  ap:
    ssid: "Versati Fallback"
    password: !secret ap_password

captive_portal:

uart:
  id: mod_bus
  tx_pin: GPIO17
  rx_pin: GPIO16
  baud_rate: 9600
  data_bits: 8
  parity: NONE
  stop_bits: 1

modbus:
  id: modbus_versati
  uart_id: mod_bus
  send_wait_time: 200ms
  turnaround_time: 100ms
  # For a MAX485 board with an EN pin (no auto direction) uncomment and wire EN to GPIO4:
  # flow_control_pin: GPIO4

modbus_controller:
  - id: versati
    address: ${modbus_address}
    modbus_id: modbus_versati
    setup_priority: -10
    update_interval: 15s
    offline_skip_updates: 2

  # Same address, slower polling: setpoints and configuration (rarely change)
  - id: versati_slow
    address: ${modbus_address}
    modbus_id: modbus_versati
    setup_priority: -10
    update_interval: 120s
    offline_skip_updates: 2

# =============================================================================
#  READ-ONLY STATES (Word 117-143)
# =============================================================================
sensor:
  - platform: modbus_controller
    modbus_controller_id: versati
    id: unit_status_raw
    name: "Status (code)"
    internal: true
    address: 117
    register_type: holding
    value_type: U_WORD

  - platform: modbus_controller
    modbus_controller_id: versati
    id: t_outdoor
    name: "Outdoor temperature"
    address: 118
    register_type: holding
    value_type: S_WORD
    unit_of_measurement: "°C"
    device_class: temperature
    state_class: measurement
    accuracy_decimals: 1
    filters:
      - multiply: ${temp_scale}

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Discharge temperature"
    address: 119
    register_type: holding
    value_type: S_WORD
    unit_of_measurement: "°C"
    device_class: temperature
    state_class: measurement
    accuracy_decimals: 1
    entity_category: diagnostic
    filters:
      - multiply: ${temp_scale}

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Defrost temperature"
    address: 120
    register_type: holding
    value_type: S_WORD
    unit_of_measurement: "°C"
    device_class: temperature
    state_class: measurement
    accuracy_decimals: 1
    entity_category: diagnostic
    filters:
      - multiply: ${temp_scale}

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Suction temperature"
    address: 121
    register_type: holding
    value_type: S_WORD
    unit_of_measurement: "°C"
    device_class: temperature
    state_class: measurement
    accuracy_decimals: 1
    entity_category: diagnostic
    filters:
      - multiply: ${temp_scale}

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Economizer inlet"
    address: 122
    register_type: holding
    value_type: S_WORD
    unit_of_measurement: "°C"
    device_class: temperature
    state_class: measurement
    accuracy_decimals: 1
    entity_category: diagnostic
    filters:
      - multiply: ${temp_scale}

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Economizer outlet"
    address: 123
    register_type: holding
    value_type: S_WORD
    unit_of_measurement: "°C"
    device_class: temperature
    state_class: measurement
    accuracy_decimals: 1
    entity_category: diagnostic
    filters:
      - multiply: ${temp_scale}

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Discharge pressure (saturation temp)"
    address: 124
    register_type: holding
    value_type: S_WORD
    unit_of_measurement: "°C"
    device_class: temperature
    state_class: measurement
    accuracy_decimals: 1
    entity_category: diagnostic
    filters:
      - multiply: ${temp_scale}

  - platform: modbus_controller
    modbus_controller_id: versati
    id: t_water_out
    name: "Water flow"
    address: 125
    register_type: holding
    value_type: S_WORD
    unit_of_measurement: "°C"
    device_class: temperature
    state_class: measurement
    accuracy_decimals: 1
    filters:
      - multiply: ${temp_scale}

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Optional water sensor"
    address: 126
    register_type: holding
    value_type: S_WORD
    unit_of_measurement: "°C"
    device_class: temperature
    state_class: measurement
    accuracy_decimals: 1
    entity_category: diagnostic
    filters:
      - multiply: ${temp_scale}

  - platform: modbus_controller
    modbus_controller_id: versati
    id: t_water_in
    name: "Water return"
    address: 127
    register_type: holding
    value_type: S_WORD
    unit_of_measurement: "°C"
    device_class: temperature
    state_class: measurement
    accuracy_decimals: 1
    filters:
      - multiply: ${temp_scale}

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "DHW tank temperature"
    address: 128
    register_type: holding
    value_type: S_WORD
    unit_of_measurement: "°C"
    device_class: temperature
    state_class: measurement
    accuracy_decimals: 1
    filters:
      - multiply: ${temp_scale}

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Remote room temperature"
    address: 129
    register_type: holding
    value_type: S_WORD
    unit_of_measurement: "°C"
    device_class: temperature
    state_class: measurement
    accuracy_decimals: 1
    filters:
      - multiply: ${temp_scale}

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Vapor line temperature"
    address: 130
    register_type: holding
    value_type: S_WORD
    unit_of_measurement: "°C"
    device_class: temperature
    state_class: measurement
    accuracy_decimals: 1
    entity_category: diagnostic
    filters:
      - multiply: ${temp_scale}

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Liquid line temperature"
    address: 131
    register_type: holding
    value_type: S_WORD
    unit_of_measurement: "°C"
    device_class: temperature
    state_class: measurement
    accuracy_decimals: 1
    entity_category: diagnostic
    filters:
      - multiply: ${temp_scale}

  - platform: modbus_controller
    modbus_controller_id: versati
    id: thermostat_state_raw
    name: "Thermostat state (code)"
    internal: true
    address: 132
    register_type: holding
    value_type: U_WORD

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Floor debug temperature"
    address: 133
    register_type: holding
    value_type: S_WORD
    unit_of_measurement: "°C"
    device_class: temperature
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Floor debug time"
    address: 134
    register_type: holding
    value_type: U_WORD
    unit_of_measurement: "h"
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    id: disinfection_raw
    name: "Disinfection (code)"
    internal: true
    address: 135
    register_type: holding
    value_type: U_WORD

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Floor debug error time"
    address: 136
    register_type: holding
    value_type: U_WORD
    unit_of_measurement: "s"
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Weather curve target"
    address: 137
    register_type: holding
    value_type: S_WORD
    unit_of_measurement: "°C"
    device_class: temperature
    state_class: measurement

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Compressor target frequency"
    address: 142
    register_type: holding
    value_type: U_WORD
    unit_of_measurement: "Hz"
    device_class: frequency
    state_class: measurement

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Compressor frequency"
    address: 143
    register_type: holding
    value_type: U_WORD
    unit_of_measurement: "Hz"
    device_class: frequency
    state_class: measurement

  # Flow minus return (computed on the ESP)
  - platform: template
    name: "Water delta T"
    unit_of_measurement: "K"
    state_class: measurement
    accuracy_decimals: 1
    update_interval: 15s
    lambda: |-
      if (isnan(id(t_water_out).state) || isnan(id(t_water_in).state)) return {};
      return id(t_water_out).state - id(t_water_in).state;

text_sensor:
  - platform: template
    name: "Status"
    update_interval: 15s
    lambda: |-
      switch ((int) id(unit_status_raw).state) {
        case 1: return {"Cooling"};
        case 2: return {"Heating"};
        case 6: return {"Hot water"};
        case 8: return {"Off"};
        default: return {"Unknown"};
      }

  - platform: template
    name: "Thermostat state"
    update_interval: 15s
    lambda: |-
      switch ((int) id(thermostat_state_raw).state) {
        case 1: return {"Cooling"};
        case 2: return {"Heating"};
        case 3: return {"Off"};
        default: return {"Unknown"};
      }

  - platform: template
    name: "Disinfection state"
    update_interval: 15s
    lambda: |-
      switch ((int) id(disinfection_raw).state) {
        case 0: return {"Off"};
        case 1: return {"Running"};
        case 2: return {"Done"};
        case 3: return {"Failed"};
        default: return {"Unknown"};
      }

# =============================================================================
#  SELECTS (enumerations, write 0x10)
# =============================================================================
select:
  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Heat pump power"
    address: 42
    value_type: U_WORD
    use_write_multiple: true
    optionsmap:
      "On": 0xAA
      "Off": 0x55

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Mode"
    address: 2
    value_type: U_WORD
    use_write_multiple: true
    optionsmap:
      "Heat": 1
      "Hot water": 2
      "Cool + hot water": 3
      "Heat + hot water": 4
      "Cool": 5

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Backup heater"
    address: 3
    value_type: U_WORD
    use_write_multiple: true
    entity_category: config
    optionsmap:
      "1 stage": 1
      "2 stages": 2
      "Off": 3

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Other heat source logic"
    address: 35
    value_type: U_WORD
    use_write_multiple: true
    entity_category: config
    optionsmap:
      "Logic 1": 1
      "Logic 2": 2
      "Logic 3": 3

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "DHW tank heater logic"
    address: 36
    value_type: U_WORD
    use_write_multiple: true
    entity_category: config
    optionsmap:
      "Logic 1": 1
      "Logic 2": 2

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Backup heater logic"
    address: 37
    value_type: U_WORD
    use_write_multiple: true
    entity_category: config
    optionsmap:
      "Logic 1": 1
      "Logic 2": 2

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Room thermostat"
    address: 39
    value_type: U_WORD
    use_write_multiple: true
    entity_category: config
    optionsmap:
      "Without": 0
      "Air": 1
      "Air + hot water": 2

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Force mode"
    address: 40
    value_type: U_WORD
    use_write_multiple: true
    entity_category: config
    optionsmap:
      "Force cool": 1
      "Force heat": 2
      "Off": 3

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Air purge"
    address: 41
    value_type: U_WORD
    use_write_multiple: true
    entity_category: config
    optionsmap:
      "Heating circuit": 1
      "Water tank": 2
      "Off": 3

# =============================================================================
#  SETPOINTS (Word 4-43, write 0x10)
#  Polled every 2 min (versati_slow controller) - setpoints rarely change
# =============================================================================
number:
  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Water heating setpoint"
    address: 10
    value_type: U_WORD
    use_write_multiple: true
    min_value: 20
    max_value: 60
    step: 1
    unit_of_measurement: "°C"
    device_class: temperature

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Water cooling setpoint"
    address: 9
    value_type: U_WORD
    use_write_multiple: true
    min_value: 7
    max_value: 25
    step: 1
    unit_of_measurement: "°C"
    device_class: temperature

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Room heating setpoint"
    address: 12
    value_type: U_WORD
    use_write_multiple: true
    min_value: 18
    max_value: 30
    step: 1
    unit_of_measurement: "°C"
    device_class: temperature

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Room cooling setpoint"
    address: 11
    value_type: U_WORD
    use_write_multiple: true
    min_value: 18
    max_value: 30
    step: 1
    unit_of_measurement: "°C"
    device_class: temperature

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "DHW setpoint"
    address: 13
    value_type: U_WORD
    use_write_multiple: true
    min_value: 40
    max_value: 80
    step: 1
    unit_of_measurement: "°C"
    device_class: temperature

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Power limit"
    address: 43
    value_type: U_WORD
    use_write_multiple: true
    multiply: 10
    min_value: 0
    max_value: 10
    step: 0.1
    unit_of_measurement: "kW"
    device_class: power

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Current limit"
    address: 38
    value_type: U_WORD
    use_write_multiple: true
    min_value: 0
    max_value: 50
    step: 1
    unit_of_measurement: "A"
    device_class: current
    entity_category: config

  # --- weather curve, heating ---
  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Heating curve: upper outdoor temp"
    address: 17
    value_type: U_WORD
    use_write_multiple: true
    min_value: 10
    max_value: 37
    step: 1
    unit_of_measurement: "°C"
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Heating curve: lower outdoor temp"
    address: 18
    value_type: S_WORD
    use_write_multiple: true
    min_value: -20
    max_value: 9
    step: 1
    unit_of_measurement: "°C"
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Heating curve: upper room temp"
    address: 19
    value_type: U_WORD
    use_write_multiple: true
    min_value: 22
    max_value: 30
    step: 1
    unit_of_measurement: "°C"
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Heating curve: lower room temp"
    address: 20
    value_type: U_WORD
    use_write_multiple: true
    min_value: 18
    max_value: 21
    step: 1
    unit_of_measurement: "°C"
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Heating curve: upper water temp"
    address: 21
    value_type: U_WORD
    use_write_multiple: true
    min_value: 46
    max_value: 60
    step: 1
    unit_of_measurement: "°C"
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Heating curve: lower water temp"
    address: 22
    value_type: U_WORD
    use_write_multiple: true
    min_value: 20
    max_value: 45
    step: 1
    unit_of_measurement: "°C"
    entity_category: config

  # --- weather curve, cooling ---
  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Cooling curve: upper outdoor temp"
    address: 23
    value_type: U_WORD
    use_write_multiple: true
    min_value: 26
    max_value: 48
    step: 1
    unit_of_measurement: "°C"
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Cooling curve: lower outdoor temp"
    address: 24
    value_type: U_WORD
    use_write_multiple: true
    min_value: 10
    max_value: 25
    step: 1
    unit_of_measurement: "°C"
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Cooling curve: upper room temp"
    address: 25
    value_type: U_WORD
    use_write_multiple: true
    min_value: 24
    max_value: 30
    step: 1
    unit_of_measurement: "°C"
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Cooling curve: lower room temp"
    address: 26
    value_type: U_WORD
    use_write_multiple: true
    min_value: 18
    max_value: 23
    step: 1
    unit_of_measurement: "°C"
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Cooling curve: upper water temp"
    address: 27
    value_type: U_WORD
    use_write_multiple: true
    min_value: 15
    max_value: 25
    step: 1
    unit_of_measurement: "°C"
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Cooling curve: lower water temp"
    address: 28
    value_type: U_WORD
    use_write_multiple: true
    min_value: 7
    max_value: 14
    step: 1
    unit_of_measurement: "°C"
    entity_category: config

  # --- hysteresis and timers ---
  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Delta T cooling"
    address: 29
    value_type: U_WORD
    use_write_multiple: true
    min_value: 2
    max_value: 10
    step: 1
    unit_of_measurement: "K"
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Delta T heating"
    address: 30
    value_type: U_WORD
    use_write_multiple: true
    min_value: 2
    max_value: 10
    step: 1
    unit_of_measurement: "K"
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Delta T DHW"
    address: 31
    value_type: U_WORD
    use_write_multiple: true
    min_value: 2
    max_value: 8
    step: 1
    unit_of_measurement: "K"
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Delta T room"
    address: 32
    value_type: U_WORD
    use_write_multiple: true
    min_value: 1
    max_value: 5
    step: 1
    unit_of_measurement: "K"
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Cooling run time"
    address: 33
    value_type: U_WORD
    use_write_multiple: true
    min_value: 1
    max_value: 10
    step: 1
    unit_of_measurement: "min"
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Heating run time"
    address: 34
    value_type: U_WORD
    use_write_multiple: true
    min_value: 1
    max_value: 10
    step: 1
    unit_of_measurement: "min"
    entity_category: config

  # --- auxiliary heat sources ---
  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Backup heater: outdoor switch-on temp"
    address: 14
    value_type: S_WORD
    use_write_multiple: true
    min_value: -20
    max_value: 18
    step: 1
    unit_of_measurement: "°C"
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Other heat source: outdoor switch-on temp"
    address: 15
    value_type: S_WORD
    use_write_multiple: true
    min_value: -20
    max_value: 18
    step: 1
    unit_of_measurement: "°C"
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "DHW: max temp from heat pump"
    address: 16
    value_type: U_WORD
    use_write_multiple: true
    min_value: 40
    max_value: 55
    step: 1
    unit_of_measurement: "°C"
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Disinfection temperature"
    address: 4
    value_type: U_WORD
    use_write_multiple: true
    min_value: 40
    max_value: 70
    step: 1
    unit_of_measurement: "°C"
    entity_category: config

  # --- floor screed drying ---
  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Floor debug: segments"
    address: 5
    value_type: U_WORD
    use_write_multiple: true
    min_value: 1
    max_value: 10
    step: 1
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Floor debug: segment 1 temp"
    address: 6
    value_type: U_WORD
    use_write_multiple: true
    min_value: 25
    max_value: 35
    step: 1
    unit_of_measurement: "°C"
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Floor debug: delta T per segment"
    address: 7
    value_type: U_WORD
    use_write_multiple: true
    min_value: 2
    max_value: 10
    step: 1
    unit_of_measurement: "K"
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Floor debug: segment time"
    address: 8
    value_type: U_WORD
    use_write_multiple: true
    min_value: 12
    max_value: 72
    step: 12
    unit_of_measurement: "h"
    entity_category: config

# =============================================================================
#  FUNCTION SWITCHES (coils 8-37, write 0x0F)
# =============================================================================
switch:
  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Quiet mode"
    register_type: coil
    address: 21
    use_write_multiple: true

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Weather-dependent mode"
    register_type: coil
    address: 22
    use_write_multiple: true

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Fast hot water"
    register_type: coil
    address: 18
    use_write_multiple: true

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Disinfection"
    register_type: coil
    address: 23
    use_write_multiple: true

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Holiday mode"
    register_type: coil
    address: 34
    use_write_multiple: true

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Control by room temp (off = by water temp)"
    register_type: coil
    address: 17
    use_write_multiple: true
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "DHW priority when cooling"
    register_type: coil
    address: 19
    use_write_multiple: true
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "DHW priority when heating"
    register_type: coil
    address: 20
    use_write_multiple: true
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Weekly timer"
    register_type: coil
    address: 8
    use_write_multiple: true
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Clock timer"
    register_type: coil
    address: 9
    use_write_multiple: true
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Temperature timer"
    register_type: coil
    address: 10
    use_write_multiple: true
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Gate control"
    register_type: coil
    address: 11
    use_write_multiple: true
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Solar heater"
    register_type: coil
    address: 16
    use_write_multiple: true
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Floor debug"
    register_type: coil
    address: 24
    use_write_multiple: true
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Floor debug start"
    register_type: coil
    address: 25
    use_write_multiple: true
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Emergency mode"
    register_type: coil
    address: 26
    use_write_multiple: true
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Other heat source installed"
    register_type: coil
    address: 27
    use_write_multiple: true
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "DHW tank installed"
    register_type: coil
    address: 29
    use_write_multiple: true
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Solar kit installed"
    register_type: coil
    address: 31
    use_write_multiple: true
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Remote room sensor installed"
    register_type: coil
    address: 33
    use_write_multiple: true
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Refrigerant recovery"
    register_type: coil
    address: 35
    use_write_multiple: true
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Manual defrost"
    register_type: coil
    address: 36
    use_write_multiple: true
    entity_category: config

  - platform: modbus_controller
    modbus_controller_id: versati_slow
    name: "Cooling 2-way valve"
    register_type: coil
    address: 37
    use_write_multiple: true
    entity_category: config

# =============================================================================
#  STATES AND ERRORS (coils 38-191, read 0x01)
# =============================================================================
binary_sensor:
  # --- operating states ---
  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Compressor"
    register_type: coil
    address: 80
    device_class: running

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Outdoor fan"
    register_type: coil
    address: 81
    device_class: running

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "4-way valve"
    register_type: coil
    address: 83
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Crankcase heater"
    register_type: coil
    address: 84
    device_class: heat
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Base pan heater"
    register_type: coil
    address: 85
    device_class: heat
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Defrosting"
    register_type: coil
    address: 86
    device_class: running

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Oil return"
    register_type: coil
    address: 87
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Heating 2-way valve"
    register_type: coil
    address: 38
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Other heat source running"
    register_type: coil
    address: 169
    device_class: running

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Flow switch"
    register_type: coil
    address: 170
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Backup heater 1"
    register_type: coil
    address: 171
    device_class: heat

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Backup heater 2"
    register_type: coil
    address: 172
    device_class: heat

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "DHW tank heater"
    register_type: coil
    address: 173
    device_class: heat

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Indoor water pump"
    register_type: coil
    address: 175
    device_class: running

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Circulating 2-way valve"
    register_type: coil
    address: 176
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Plate heater"
    register_type: coil
    address: 177
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "3-way valve (DHW)"
    register_type: coil
    address: 178

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Gate control card inserted"
    register_type: coil
    address: 179
    entity_category: diagnostic

  # --- communication errors and protections ---
  - platform: modbus_controller
    modbus_controller_id: versati
    id: err_com_idu
    name: "Error: controller-indoor communication"
    register_type: coil
    address: 64
    device_class: problem

  - platform: modbus_controller
    modbus_controller_id: versati
    id: err_com_odu
    name: "Error: controller-outdoor communication"
    register_type: coil
    address: 65
    device_class: problem

  - platform: modbus_controller
    modbus_controller_id: versati
    id: err_com_drive
    name: "Error: controller-drive communication"
    register_type: coil
    address: 66
    device_class: problem

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Antifreeze protection"
    register_type: coil
    address: 67
    device_class: cold

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Error: outdoor temp sensor"
    register_type: coil
    address: 88
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Error: defrost sensor"
    register_type: coil
    address: 89
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Error: discharge sensor"
    register_type: coil
    address: 90
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Error: suction sensor"
    register_type: coil
    address: 91
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    id: err_fan
    name: "Error: outdoor fan"
    register_type: coil
    address: 92
    device_class: problem

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Error: high-pressure sensor"
    register_type: coil
    address: 93
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    id: err_hp
    name: "Protection: high pressure"
    register_type: coil
    address: 94
    device_class: problem

  - platform: modbus_controller
    modbus_controller_id: versati
    id: err_lp
    name: "Protection: low pressure"
    register_type: coil
    address: 95
    device_class: problem

  - platform: modbus_controller
    modbus_controller_id: versati
    id: err_discharge
    name: "Protection: high discharge temp"
    register_type: coil
    address: 96
    device_class: problem

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Error: capacity DIP setting"
    register_type: coil
    address: 97
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    id: err_com_idu_odu
    name: "Error: indoor-outdoor communication"
    register_type: coil
    address: 98
    device_class: problem

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Error: economizer inlet sensor"
    register_type: coil
    address: 99
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Error: economizer outlet sensor"
    register_type: coil
    address: 100
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    id: err_sys_rec
    name: "System protection (recoverable)"
    register_type: coil
    address: 102
    device_class: problem

  - platform: modbus_controller
    modbus_controller_id: versati
    id: err_sys_irrec
    name: "System protection (needs service)"
    register_type: coil
    address: 103
    device_class: problem

  - platform: modbus_controller
    modbus_controller_id: versati
    id: err_flow_odu
    name: "Protection: flow switch (outdoor)"
    register_type: coil
    address: 108
    device_class: problem

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Error: 4-way valve"
    register_type: coil
    address: 109
    device_class: problem
    entity_category: diagnostic

  # --- compressor drive errors ---
  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Drive: DC bus low voltage"
    register_type: coil
    address: 128
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Drive: DC bus overvoltage"
    register_type: coil
    address: 129
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Drive: AC current protection"
    register_type: coil
    address: 130
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Drive: IPM error"
    register_type: coil
    address: 131
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Drive: PFC error"
    register_type: coil
    address: 132
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Drive: startup error"
    register_type: coil
    address: 133
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Drive: phase loss"
    register_type: coil
    address: 134
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Drive: module reset"
    register_type: coil
    address: 135
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Drive: compressor overcurrent"
    register_type: coil
    address: 136
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Drive: over-speed"
    register_type: coil
    address: 137
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Drive: charging circuit or current sensor"
    register_type: coil
    address: 138
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Drive: desynchronization"
    register_type: coil
    address: 139
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Drive: compressor stalled"
    register_type: coil
    address: 140
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Drive: communication error"
    register_type: coil
    address: 141
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Drive: radiator, IPM or PFC overheat"
    register_type: coil
    address: 142
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Drive: defective radiator, IPM or PFC"
    register_type: coil
    address: 143
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Drive: charging circuit"
    register_type: coil
    address: 146
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Drive: AC input voltage"
    register_type: coil
    address: 147
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Drive: board temp sensor"
    register_type: coil
    address: 148
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Drive: AC contactor or zero-cross"
    register_type: coil
    address: 149
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Drive: temperature drift"
    register_type: coil
    address: 150
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Drive: sensor connection (phase U or V)"
    register_type: coil
    address: 151
    device_class: problem
    entity_category: diagnostic

  # --- indoor unit errors ---
  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Error: condenser leaving water sensor"
    register_type: coil
    address: 152
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Error: e-heater leaving water sensor"
    register_type: coil
    address: 153
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Error: liquid line sensor"
    register_type: coil
    address: 154
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Error: condenser entering water sensor"
    register_type: coil
    address: 155
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Error: DHW tank sensor"
    register_type: coil
    address: 156
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Error: vapor line sensor"
    register_type: coil
    address: 158
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Error: remote room sensor"
    register_type: coil
    address: 160
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Error: jumper cap"
    register_type: coil
    address: 184
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Protection: heater 1 relay welded"
    register_type: coil
    address: 185
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Protection: heater 2 relay welded"
    register_type: coil
    address: 186
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    name: "Protection: DHW heater relay welded"
    register_type: coil
    address: 187
    device_class: problem
    entity_category: diagnostic

  - platform: modbus_controller
    modbus_controller_id: versati
    id: err_flow_idu
    name: "Protection: water flow"
    register_type: coil
    address: 188
    device_class: problem

  - platform: modbus_controller
    modbus_controller_id: versati
    id: err_idu_rec
    name: "Indoor protection (recoverable)"
    register_type: coil
    address: 190
    device_class: problem

  - platform: modbus_controller
    modbus_controller_id: versati
    id: err_idu_irrec
    name: "Indoor protection (needs service)"
    register_type: coil
    address: 191
    device_class: problem

  # --- one "something is wrong" entity for notifications ---
  - platform: template
    name: "Fault"
    device_class: problem
    lambda: |-
      return id(err_com_idu).state || id(err_com_odu).state || id(err_com_drive).state ||
             id(err_fan).state || id(err_hp).state || id(err_lp).state || id(err_discharge).state ||
             id(err_com_idu_odu).state || id(err_sys_rec).state || id(err_sys_irrec).state ||
             id(err_flow_odu).state || id(err_flow_idu).state || id(err_idu_rec).state ||
             id(err_idu_irrec).state;

# =============================================================================
#  ACTIONS
# =============================================================================
button:
  - platform: template
    name: "Reset error"
    entity_category: config
    on_press:
      - lambda: |-
          auto cmd = esphome::modbus_controller::ModbusCommandItem::create_write_multiple_command(
              id(versati), 44, 1, {1});
          id(versati)->queue_command(cmd);

  - platform: restart
    name: "Restart bridge"
    entity_category: config
