devices.esphome.io
Pentek Intellidrive PID10
Pentek Intellidrive PID10
Device Type: sensorElectrical Standard: globalBoard: esp32
      
  
        
Data can be gathered from your Pentair Pentek Intellidrive PID Variable Frequency Pump Controller over Modbus. Tested with a PID10 Device.
The Intellidrive provides a 2-wire RS485 interface. Wire up a an RS485 transceiver like MAX485 to an ESP32 to interface with the device using Esphome's Modbus Component
Modbus Interface Notes
The Intellidrive Modbus interface is poorly documented. Most interesting registers should be provided below, but there may be more to discover. See the Unofficial Modbus Docs for more information on known or suspected registers.
Configuration example
esphome:  name: well-pump-controller  friendly_name: "Well Pump Controller"  comment: "Pentek Intellidrive PID10"
esp32:  board: nodemcu-32s
wifi:  ssid: YOUR_SSID  password: YOUR_PW  power_save_mode: none
ota:
api:
web_server:  port: 80
time:  - platform: sntp    id: sntp_time    timezone: America/Los_Angeles
# Example UART configurationuart:  id: mod_bus  tx_pin: GPIO16  rx_pin: GPIO17  baud_rate: 19200  data_bits: 8  parity: NONE  stop_bits: 1
modbus:  id: modbus1
modbus_controller:  - id: modctrl1    address: 0x1    modbus_id: modbus1    setup_priority: -10    update_interval: 10s  - id: modctrl2    address: 0x2    modbus_id: modbus1    setup_priority: -10    update_interval: 10s
sensor:  # SETTINGS PARAMS --------------
    # software version is a string, low-byte first  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x0000    name: "AOC Software Version"    register_type: holding    value_type: RAW    register_count: 10    accuracy_decimals: 2    lambda: |-      if (data.size() < item->offset + 20) return NAN;      std::string temp;      std::string result;      bool found_dot = false;
      for (int i = 0; i < 20; i+=2) {        char chars[] = {          static_cast<char>(data[item->offset + i]),      // low byte          static_cast<char>(data[item->offset + i + 1]),  // high byte        };        for (char c : chars) {          temp += c;        }      }      for (auto it = temp.rbegin(); it != temp.rend(); ++it) {          char c = *it;          if (c == '.' && !found_dot) {              result += c; found_dot = true;          } else if (c >= '0' && c <= '9') {              result += c;          }      }      return std::stof(result);
  # PID control settings  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x00D0    name: "PID P-Gain"    register_type: holding    value_type: U_WORD  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x00D1    name: "PID I-Time"    device_class: duration    unit_of_measurement: "ms"    register_type: holding    value_type: U_WORD  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x00D2    name: "PID D-Time"    device_class: duration    unit_of_measurement: "ms"    register_type: holding    value_type: U_WORD  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x00D3    name: "PID D-Limit"    register_type: holding    value_type: U_WORD
  # SLEEP settings  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x00FC    name: "Sleep Boost Differential"    unit_of_measurement: "psi"    device_class: "pressure"    register_type: holding    value_type: U_WORD    filters:      - multiply: 0.1450  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x00FB    name: "Sleep Boost Delay"    unit_of_measurement: "s"    device_class: duration    register_type: holding    value_type: U_WORD  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x00F9    name: "Sleep Wake Up Differential"    unit_of_measurement: "psi"    device_class: "pressure"    register_type: holding    value_type: U_WORD    filters:      - multiply: 0.1450  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x00FA    name: "Sleep Wake Delay"    unit_of_measurement: "s"    device_class: duration    register_type: holding    value_type: U_WORD
  # PASSWORD settings  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x00EE    name: "Password Lock Time"    unit_of_measurement: "min"    device_class: duration    register_type: holding    value_type: U_WORD  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x00EC    name: "App Password"    register_type: holding    value_type: U_WORD
  # SET POINTS  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x00DA    name: "Setpoint Internal"    unit_of_measurement: "psi"    device_class: "pressure"    register_type: holding    value_type: U_WORD    filters:      - multiply: 0.1450  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x00E5    name: "Setpoint External"    unit_of_measurement: "psi"    device_class: "pressure"    register_type: holding    value_type: U_WORD    filters:      - multiply: 0.1450
  # MOTOR settings  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x1452    name: "3PH Motor Type ID"    register_type: holding    value_type: U_WORD    internal: true    on_value:      then:        - lambda: |-            if (x == 0) {                id(ph3_motor_type).publish_state("Submersible");            } else if (x == 1) {                id(ph3_motor_type).publish_state("Above-Ground");            } else {              std::string mode_str = "Unknown Motor Type: " + std::to_string(x);              id(ph3_motor_type).publish_state(mode_str.c_str());            }  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x1450    name: "Motor Service Factor Amps"    unit_of_measurement: "A"    device_class: current    register_type: holding    value_type: FP32  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x00E9    name: "Motor Max Frequency"    register_type: holding    value_type: U_WORD    unit_of_measurement: "Hz"    device_class: "frequency"  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x00EA    name: "Motor Min Frequency"    register_type: holding    value_type: U_WORD    unit_of_measurement: "Hz"    device_class: "frequency"
  # SENSOR settings  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x00DC    name: "Sensor Max Pressure"    unit_of_measurement: "psi"    device_class: "pressure"    register_type: holding    value_type: U_WORD    filters:      - multiply: 0.1450
  # EX RUNTIME SETTINGS  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x00EF    name: "Excessive Runtime Hours"    unit_of_measurement: "h"    device_class: "duration"    register_type: holding    value_type: U_WORD
  # DRY RUN settings  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x00E1    name: "Dry Run Auto Restart Delay"    unit_of_measurement: "s"    device_class: "duration"    register_type: holding    value_type: U_WORD  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x00E0    name: "Dry Run Number of Resets"    register_type: holding    value_type: U_WORD  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x00DF    name: "Dry Run Detection Time"    register_type: holding    value_type: U_WORD    unit_of_measurement: "s"    device_class: "duration"  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x00E4    name: "Dry Run Fill Time"    register_type: holding    value_type: U_WORD    unit_of_measurement: "s"    device_class: "duration"
  # I/O Settings  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x00E6    name: "I/O Input 1 Mode ID"    register_type: holding    value_type: U_WORD    internal: true    on_value:      then:        - lambda: |-            if (x == 0) {                id(io_input_1_mode).publish_state("Unused");            } else if (x == 1) {                id(io_input_1_mode).publish_state("Run Enable");            } else if (x == 2) {                id(io_input_1_mode).publish_state("Ext Fault");            } else if (x == 3) {                id(io_input_1_mode).publish_state("Ext Setpoint");            } else {              std::string mode_str = "Unknown Input Mode: " + std::to_string(x);              id(io_input_1_mode).publish_state(mode_str.c_str());            }  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x00E7    name: "I/O Input 2 Mode ID"    register_type: holding    value_type: U_WORD    internal: true    on_value:      then:        - lambda: |-            if (x == 0) {                id(io_input_2_mode).publish_state("Unused");            } else if (x == 1) {                id(io_input_2_mode).publish_state("Run Enable");            } else if (x == 2) {                id(io_input_2_mode).publish_state("Ext Fault");            } else if (x == 3) {                id(io_input_2_mode).publish_state("Ext Setpoint");            } else {              std::string mode_str = "Unknown Input Mode: " + std::to_string(x);              id(io_input_2_mode).publish_state(mode_str.c_str());            }  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x00FE    name: "I/O Output Mode ID"    register_type: holding    value_type: U_WORD    internal: true    on_value:      then:        - lambda: |-            if (x == 0) {                id(io_output_mode).publish_state("Unused");            } else if (x == 1) {                id(io_output_mode).publish_state("Run");            } else if (x == 2) {                id(io_output_mode).publish_state("Fault");            } else {              std::string mode_str = "Unknown Output Mode: " + std::to_string(x);              id(io_output_mode).publish_state(mode_str.c_str());            }
  # Over Pressure  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x0101    name: "Over Pressure Setpoint"    unit_of_measurement: "psi"    device_class: "pressure"    register_type: holding    value_type: U_WORD    filters:      - multiply: 0.1450
  # MONITORING PARAMS --------------
    # software version is a string, low-byte first  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x13EC    name: "MOC Software Version"    register_type: holding    value_type: RAW    register_count: 10    accuracy_decimals: 2    lambda: |-      if (data.size() < item->offset + 20) return NAN;      std::string temp;      std::string result;      bool found_dot = false;
      for (int i = 0; i < 20; i+=2) {        char chars[] = {          static_cast<char>(data[item->offset + i]),      // low byte          static_cast<char>(data[item->offset + i + 1]),  // high byte        };        for (char c : chars) {          temp += c;        }      }      for (auto it = temp.rbegin(); it != temp.rend(); ++it) {          char c = *it;          if (c == '.' && !found_dot) {              result += c; found_dot = true;          } else if (c >= '0' && c <= '9') {              result += c;          }      }      return std::stof(result);
  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x141D    name: "Motor Power Consumption"    id: "motor_power_consumption"    unit_of_measurement: "W"    state_class: measurement    device_class: power    register_type: holding    value_type: U_DWORD
  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x141F    name: "Motor Phase A Current"    id: "phase_a_current"    unit_of_measurement: "A"    state_class: measurement    device_class: current    register_type: holding    value_type: FP32    filters:      - clamp:          min_value: 0          max_value: 20
  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x1421    name: "Motor Phase B Current"    id: "phase_b_current"    unit_of_measurement: "A"    state_class: measurement    device_class: current    register_type: holding    value_type: FP32    filters:      - clamp:          min_value: 0          max_value: 20
  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x1423    name: "Motor Phase C Current"    id: "phase_c_current"    unit_of_measurement: "A"    state_class: measurement    device_class: current    register_type: holding    value_type: FP32    filters:      - clamp:          min_value: 0          max_value: 20
  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x1425    name: "Motor Phase Voltage"    id: "motor_phase_voltage"    unit_of_measurement: "V"    state_class: measurement    device_class: voltage    register_type: holding    value_type: FP32
  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x1453    name: "Supply Voltage"    id: "supply_voltage"    unit_of_measurement: "V"    state_class: measurement    device_class: voltage    register_type: holding    value_type: U_DWORD
  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x1416    name: "Motor Speed Actual"    unit_of_measurement: "Hz"    device_class: "frequency"    state_class: measurement    register_type: holding    value_type: FP32
  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x001E    name: "Fault Code"    register_type: holding    value_type: U_DWORD    internal: true    on_value:      then:        - lambda: |-            if (x == 0 || x == 1) {                id(fault_state).publish_state("None");            } else if (x == 8192) {                id(fault_state).publish_state("Open Transducer");            } else if (x == 16384) {                id(fault_state).publish_state("Short Transducer");            } else if (x == 65536) {                id(fault_state).publish_state("Under Voltage");            } else if (x == 64) {                id(fault_state).publish_state("Can Not Start Motor");            } else if (x == 32) {                id(fault_state).publish_state("Dry Run");            } else if (x == 2048) {                id(fault_state).publish_state("Ground Fault");            } else if (x == 4096) {                id(fault_state).publish_state("System Not Grounded");            } else if (x == 256) {                id(fault_state).publish_state("Over Current");            } else if (x == 32768) {                id(fault_state).publish_state("Low Amps");            } else {                std::string mode_str = "Unknown Fault: " + std::to_string(x);                id(fault_state).publish_state(mode_str.c_str());            }
  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x0029    name: "Run Mode ID"    register_type: holding    value_type: U_WORD    internal: true    on_value:      then:        - lambda: |-            if (x == 0) {                id(run_mode).publish_state("Stop");            } else if (x == 1) {                id(run_mode).publish_state("Pump Out");            } else if (x == 2) {                id(run_mode).publish_state("Auto Start");            } else {              std::string mode_str = "Unknown Mode: " + std::to_string(x);              id(run_mode).publish_state(mode_str.c_str());            }
  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x1452    name: "Motor Type ID"    register_type: holding    value_type: U_WORD    internal: true    on_value:      then:        - lambda: |-            if (x == 0) {                id(motor_type).publish_state("3-Phase");            } else if (x == 1) {                id(motor_type).publish_state("1-Phase, 2-Wire");            } else if (x == 2) {                id(motor_type).publish_state("1-Phase, 3-Wire");            } else {              std::string mode_str = "Unknown Motor Type: " + std::to_string(x);              id(motor_type).publish_state(mode_str.c_str());            }
  # MONITORING PARAMS (UNDOCUMENTED) --------------
  - platform: modbus_controller    modbus_controller_id: modctrl1    address: 0x1419    name: "Motor Speed"    unit_of_measurement: "Hz"    device_class: "frequency"    state_class: measurement    register_type: holding    value_type: FP32
  - platform: modbus_controller    modbus_controller_id: modctrl1    address: 0x1455    name: "IGBT Temp"    unit_of_measurement: "°C"    state_class: measurement    register_type: holding    value_type: FP32
  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x00DD    name: "Current Pressure"    unit_of_measurement: "psi"    device_class: "pressure"    state_class: measurement    register_type: holding    value_type: U_WORD    filters:      - multiply: 0.1450
  # DERIVED SENSORS --------------  - platform: integration    name: "Motor Energy Consumption"    sensor: motor_power_consumption    time_unit: h    unit_of_measurement: "kWh"    device_class: energy    state_class: total_increasing
binary_sensor:  # MOTOR settings  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x157B    name: "Motor Above Ground"    register_type: holding  # EX RUNTIME settings  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x00F0    name: "Excessive Runtime Detection"    register_type: holding  # No GROUND settings  - platform: modbus_controller    modbus_controller_id: modctrl2    address: 0x15E1    name: "No Ground Detection"    register_type: holding
text_sensor:  - platform: template    name: "Run Mode"    id: run_mode  - platform: template    name: "Fault"    id: fault_state  - platform: template    name: "Motor Type"    id: motor_type  - platform: template    name: "3PH Motor Type"    id: ph3_motor_type  - platform: template    name: "I/O Input 1 Mode"    id: io_input_1_mode  - platform: template    name: "I/O Input 2 Mode"    id: io_input_2_mode  - platform: template    name: "I/O Output Mode"    id: io_output_mode