Pentair ScreenLogic

Is anyone willing to take a crack at getting support for Pentair’s ScreenLogic automation protocol? This is a system for Pool automation.

Pentair SceenLogic

it’s not really needed although a plugin would be nice for quick out of the box operation…

  1. buy this … it installs as a pentair remote … i installed mine in the outdoor control box inside the high-voltage section it is powered from the pentair 4wire interface … need to run an ethernet cable

Pool Control for Pentair Intellitouch & Easytouch

PC100PI wired version for Pentair Intellitouch & Easytouch systems.
More Info…

$249.99

  1. add these switches for each controllable device (on/off) status devices can be handled differently below
    switch:

    • platform: command_line
      switches:
      pool_pump:
      command_on: ‘curl -X GET --user admin:admin “192.168.1.253/set.cgi?name=circuit6&value=1”’
      command_off: ‘curl -X GET --user admin:admin “192.168.1.253/set.cgi?name=circuit6&value=0”’
      command_state: ‘curl --user admin:admin -X GET “192.168.1.253/status.xml” | xmllint --xpath “//response/equipment/circuit6/text()” -’
      value_template: ‘{{ value == “1” }}’
      friendly_name: Pool
      spa_pump:
      command_on: ‘curl -X GET --user admin:admin “192.168.1.253/set.cgi?name=circuit1&value=1”’
      command_off: ‘curl -X GET --user admin:admin “192.168.1.253/set.cgi?name=circuit1&value=0”’
      command_state: ‘curl --user admin:admin -X GET “192.168.1.253/status.xml” | xmllint --xpath “//response/equipment/circuit1/text()” -’
      value_template: ‘{{ value == “1” }}’
      friendly_name: Spa
      spa_air_blower:
      command_on: ‘curl -X GET --user admin:admin “192.168.1.253/set.cgi?name=circuit3&value=1”’
      command_off: ‘curl -X GET --user admin:admin “192.168.1.253/set.cgi?name=circuit3&value=0”’
      command_state: ‘curl --user admin:admin -X GET “192.168.1.253/status.xml” | xmllint --xpath “//response/equipment/circuit3/text()” -’
      value_template: ‘{{ value == “1” }}’
      friendly_name: Spa Air Blower
      spa_booster_pump:
      command_on: ‘curl -X GET --user admin:admin “192.168.1.253/set.cgi?name=circuit2&value=1”’
      command_off: ‘curl -X GET --user admin:admin “192.168.1.253/set.cgi?name=circuit2&value=0”’
      command_state: ‘curl --user admin:admin -X GET “192.168.1.253/status.xml” | xmllint --xpath “//response/equipment/circuit2/text()” -’
      value_template: ‘{{ value == “1” }}’
      friendly_name: Spa Booster Pump
      spa_light:
      command_on: ‘curl -X GET --user admin:admin “192.168.1.253/set.cgi?name=circuit8&value=1”’
      command_off: ‘curl -X GET --user admin:admin “192.168.1.253/set.cgi?name=circuit8&value=0”’
      command_state: ‘curl --user admin:admin -X GET “192.168.1.253/status.xml” | xmllint --xpath “//response/equipment/circuit8/text()” -’
      value_template: ‘{{ value == “1” }}’
      friendly_name: Spa Light
      pool_lights:
      command_on: ‘curl -X GET --user admin:admin “192.168.1.253/set.cgi?name=circuit4&value=1”’
      command_off: ‘curl -X GET --user admin:admin “192.168.1.253/set.cgi?name=circuit4&value=0”’
      command_state: ‘curl --user admin:admin -X GET “192.168.1.253/status.xml” | xmllint --xpath “//response/equipment/circuit4/text()” -’
      value_template: ‘{{ value == “1” }}’
      friendly_name: Pool Lights
      pool_waterfall:
      command_on: ‘curl -X GET --user admin:admin “192.168.1.253/set.cgi?name=circuit5&value=1”’
      command_off: ‘curl -X GET --user admin:admin “192.168.1.253/set.cgi?name=circuit5&value=0”’
      command_state: ‘curl --user admin:admin -X GET “192.168.1.253/status.xml” | xmllint --xpath “//response/equipment/circuit5/text()” -’
      value_template: ‘{{ value == “1” }}’
      friendly_name: Pool Waterfall
  2. for status devices …

Pool Controller

  - platform: command_line
    name: Pool Temp
    command: '/home/homeassistant/.homeassistant/bin/poolcontroller.py'
    value_template: '{{ value_json["response"]["temp"]["pooltemp"] }}'
    unit_of_measurement: "°F"
  - platform: command_line
    name: Time
    command: '/home/homeassistant/.homeassistant/bin/poolcontroller.py'
    value_template: '{{ strptime(value_json["response"]["system"]["time"], "%Y-%m-%d") }}'
  - platform: command_line
    name: Spa Temp
    command: '/home/homeassistant/.homeassistant/bin/poolcontroller.py'
    value_template: '{{ value_json["response"]["temp"]["spatemp"] }}'
    unit_of_measurement: "°F"
  - platform: command_line
    name: Air Temp
    command: '/home/homeassistant/.homeassistant/bin/poolcontroller.py'
    value_template: '{{ value_json["response"]["temp"]["airtemp"] }}'
    unit_of_measurement: "°F"
  - platform: command_line
    name: Model
    command: '/home/homeassistant/.homeassistant/bin/poolcontroller.py'
    value_template: '{% if value_json["response"]["system"]["model"] == "2" %} Screenlogic i9+3 {% else %} Error {% endif %}'
  - platform: command_line
    name: AUTELIS
    command: '/home/homeassistant/.homeassistant/bin/poolcontroller.py'
    value_template: '{% if value_json["response"]["system"]["runstate"] == "50" %} Ready {% elif value_json["response"]["system"]["runstate"] == "1"%}Starting up{% else %}Getting D$
  - platform: command_line
    name: Pentair
    command: '/home/homeassistant/.homeassistant/bin/poolcontroller.py'
    value_template: '{% if value_json["response"]["system"]["opmode"] == "0" %}Auto{% else %} Service|Timeout {% endif %}'
  - platform: command_line
    name: Freeze Protect
    command: '/home/homeassistant/.homeassistant/bin/poolcontroller.py'
    value_template: '{% if value_json["response"]["system"]["freeze"] == "0" %} OFF {% else %} ON {% endif %}'
  - platform: command_line
    name: Water Sensor
    command: '/home/homeassistant/.homeassistant/bin/poolcontroller.py'
    value_template: '{% if value_json["response"]["system"]["sensor1"] == "0" %} OK {% else %} Error {% endif %}'
  - platform: command_line
    name: Air Sensor
    command: '/home/homeassistant/.homeassistant/bin/poolcontroller.py'
    value_template: '{% if value_json["response"]["system"]["sensor3"] == "0" %} OK {% else %} Error {% endif %}'
  - platform: command_line
    name: Spa Heater
    command: '/home/homeassistant/.homeassistant/bin/poolcontroller.py'
    value_template: '{% if (value_json["response"]["temp"]["htstatus"] | float ) == 2 %} Heating {% else %}  OFF {% endif %}'
  - platform: command_line
    name: Pool Heater
    command: '/home/homeassistant/.homeassistant/bin/poolcontroller.py'
    value_template: '{% if (value_json["response"]["temp"]["htstatus"] | float ) == 1 %} Heating {% else %} OFF {% endif %}'
  - platform: command_line
    name: Pump Status
    command: '/home/homeassistant/.homeassistant/bin/pumps.py'
 - platform: command_line
    name: Floor Cleaner
    command: '/home/homeassistant/.homeassistant/bin/poolcontroller.py'
    value_template: '{% if value_json["response"]["equipment"]["feature1"] == "0" %} OFF {% else %} ON {% endif %}'
  1. poolcontroller.py
    #!/usr/bin/python

from requests import get

import json

import xmltodict

circuit1 = “SPA”

circuit2 = “BOOSTERPUMP”

circuit3 = “AIR BLOWER”

circuit4 = “POOL LIGHT”

circuit5 = “WATERFALL”

circuit6 = “POOL”

circuit8 = “SPA LIGHT”

feature1 = “FLOOR CLEANER”

url = “http://admin:[email protected]/status.xml

http = get(url)

json = json.dumps(xmltodict.parse(http.content), indent=4)

print json

  1. to get pump status
    #!/srv/homeassistant/bin/python3

from requests import get

import json

import untangle

import xmltodict

circuit1 = “SPA”

circuit2 = “BOOSTERPUMP”

circuit3 = “AIR BLOWER”

circuit4 = “POOL LIGHT”

circuit5 = “WATERFALL”

circuit6 = “POOL”

circuit8 = “SPA LIGHT”

feature1 = “FLOOR CLEANER”

url = “http://admin:[email protected]/status.xml

url2 = “http://admin:[email protected]/pumps.xml

http_status = get(url)

http_pumps = get(url2)

status = untangle.parse(http_status.text)

pumps = untangle.parse(http_pumps.text)

vsp_pool_status = status.response.equipment.circuit6.cdata

vsp_spa_status = status.response.equipment.circuit1.cdata

if vsp_pool_status == ‘0’ and vsp_spa_status == ‘0’:

print(“Pump OFF”)

else :

vsp = pumps.response.pumps.pump1.cdata

vsp = vsp.split(’,’,3)

power = vsp[0]

rpm = vsp[1]

print (power, “Watts”, rpm, “RPM”)

1 Like

Thanks for this info Dan, but it looks like all of the products are out of stock…maybe they folded??

I own a Pentair ScreenLogic2 > https://www.amazon.com/Pentair-522104-Screenlogic2-Interface-Connection/dp/B00N4SXR64

It looks like your solution relies upon Autelis equipment. Does anyone have the skills to create a ScreenLogic component for HA?

1 Like

Screen logic is not the protocol and just a pentair product to give you a remove control panel. It connects to the 4 wire RS485 bus that the pentair easytouch and intellitouch systems. For the same money you can get an Autelis which does the same but has an Ethernet port and runs a simple web front end you can use. Or you can use their API to add support into your automation system.

1 Like

We’ve made progress on the Screenlogic front!

Here’s an early prototype to check out. We’re looking for testors and anyone willing to to help.


3 Likes

Great Add-on @pgregg88! I have it running and it works perfectly. Do you know how to control the pool and spa lights too?

although i’m using Autelis interface adapter and it works well … after reading the above post, i though i would implement this node based system … my solution is slightly different and doesn’t rely on MQTT

  1. after installing node … install npm node-screenlogic

  2. in the node_modules/node-screenlogic i have the follow code to produce a status JSON message when called (PentairStatus.js) … note i’m using the local interface to screenlogic so you will need to change the IP … i don’t see any reason to use remote access

  3. you will then need to add the follow const for your system in node_modules/node-screenlogic/messages/SLPoolStatusMessage.js … my system doesn’t have a pentair chem/salt (based on PoolPilot) … to get a list of circuit IDs write a test.js program and print out this array … keep indexing until it’s undefined to get all your circuits enumerated … you will then need to add functions for each circuit as the default only provider for pool on/off and spa on/off … this functions are located in the same SLPoolStatusMessage.js program

  4. you will next need to make a *ON.js and *OFF.js function for each circuit you wish to control via HA, e.g. POOLLIGHTON.js … chmod +x for each js program

  5. than add the following package yaml file …

  6. i know this message is messy … i will post my config on github this weekend …

    package: pool and spa control using node driver (npm node-screenlogic)

    SCCS: @(#) 1.2 03/07/19

    homeassistant:
    customize:

    Pool

     sensor.node_freeze_protect:
       icon: mdi:snowflake
     sensor.node_heater_mode:
       icon: mdi:fire
       device_class: heat
     sensor.node_heater_status:
       icon: mdi:fire
       device_class: heat
     switch.node_pool:
       icon: mdi:swim
       device_class: power
     switch.node_spa:
       icon: mdi:hot-tub
       device_class: power
     switch.node_pool_waterfall:
       icon: mdi:fountain
       device_class: power
     switch.node_spa_booster_pump:
       icon: mdi:water-pump
       device_class: power
     switch.node_spa_light:
       icon: mdi:lightbulb-outline
       device_class: light
     switch.node_pool_lights:
       icon: mdi:lightbulb-outline
       device_class: light
     switch.node_spa_air_blower:
       icon: mdi:weather-windy
       device_class: power
     sensor.node_pentair_version:
       icon: mdi:database
    

    switch to control pool features

    switch:

    • platform: command_line
      switches:
      node_pool:
      command_on: ‘/home/dan/node_modules/node-screenlogic/POOLON.js’
      command_off: ‘/home/dan/node_modules/node-screenlogic/POOLOFF.js’
      command_state: ‘/home/dan/node_modules/node-screenlogic/PentairStatus.js’
      value_template: ‘{{ value_json[“PoolActive”] == “true” }}’
      friendly_name: Pool
      node_spa:
      command_on: ‘/home/dan/node_modules/node-screenlogic/SPAON.js’
      command_off: ‘/home/dan/node_modules/node-screenlogic/SPAOFF.js’
      command_state: ‘/home/dan/node_modules/node-screenlogic/PentairStatus.js’
      value_template: ‘{{ value_json[“SPAActive”] == “true” }}’
      friendly_name: Spa
      node_spa_air_blower:
      command_on: ‘/home/dan/node_modules/node-screenlogic/AIRBLOWERON.js’
      command_off: ‘/home/dan/node_modules/node-screenlogic/AIRBLOWEROFF.js’
      command_state: ‘/home/dan/node_modules/node-screenlogic/PentairStatus.js’
      value_template: ‘{{ value_json[“SPAAirBlowerActive”] == “true” }}’
      friendly_name: Spa Air Blower
      node_spa_booster_pump:
      command_on: ‘/home/dan/node_modules/node-screenlogic/BOOSTERPUMPON.js’
      command_off: ‘/home/dan/node_modules/node-screenlogic/BOOSTERPUMPOFF.js’
      command_state: ‘/home/dan/node_modules/node-screenlogic/PentairStatus.js’
      value_template: ‘{{ value_json[“SPABoosterPumpActive”] == “true” }}’
      friendly_name: Spa Booster Pump
      node_spa_light:
      command_on: ‘/home/dan/node_modules/node-screenlogic/SPALIGHTON.js’
      command_off: ‘/home/dan/node_modules/node-screenlogic/SPALIGHTOFF.js’
      command_state: ‘/home/dan/node_modules/node-screenlogic/PentairStatus.js’
      value_template: ‘{{ value_json[“SPALightON”] == “true” }}’
      friendly_name: Spa Light
      node_pool_lights:
      command_on: ‘/home/dan/node_modules/node-screenlogic/POOLLIGHTON.js’
      command_off: ‘/home/dan/node_modules/node-screenlogic/POOLLIGHTOFF.js’
      command_state: ‘/home/dan/node_modules/node-screenlogic/PentairStatus.js’
      value_template: ‘{{ value_json[“PoolLightON”] == “true” }}’
      friendly_name: Pool Lights
      node_pool_waterfall:
      command_on: ‘/home/dan/node_modules/node-screenlogic/WATERFALLON.js’
      command_off: ‘/home/dan/node_modules/node-screenlogic/WATERFALLOFF.js’
      command_state: ‘/home/dan/node_modules/node-screenlogic/PentairStatus.js’
      value_template: ‘{{ value_json[“WaterfallActive”] == “true” }}’
      friendly_name: Pool Waterfall

    Pool Controller via node Pentair.js

    sensor:

    • platform: command_line
      name: Node Pool Temp
      command: ‘/home/dan/node_modules/node-screenlogic/PentairStatus.js’
      value_template: ‘{{ value_json[“PoolTemp”] }}’
      unit_of_measurement: “°F”
    • platform: command_line
      name: Node Spa Temp
      command: ‘/home/dan/node_modules/node-screenlogic/PentairStatus.js’
      value_template: ‘{{ value_json[“SPATemp”] }}’
      unit_of_measurement: “°F”
    • platform: command_line
      name: Node Air Temp
      command: ‘/home/dan/node_modules/node-screenlogic/PentairStatus.js’
      value_template: ‘{{ value_json[“AirTemp”] }}’
      unit_of_measurement: “°F”
    • platform: command_line
      name: Node Pentair Version
      command: ‘/home/dan/node_modules/node-screenlogic/PentairStatus.js’
      value_template: ‘{{ value_json[“Version”].split(":")[1] }}’
    • platform: command_line
      name: Node Freeze Protect
      command: ‘/home/dan/node_modules/node-screenlogic/PentairStatus.js’
      value_template: ‘{% if value_json[“FreezeModeActive”] == 0 %} OFF {% else %} ON {% endif %}’
    • platform: command_line
      name: Node Pool Mode
      command: ‘/home/dan/node_modules/node-screenlogic/PentairStatus.js’
      value_template: >
      {% if value_json[“PoolMode”] == 1 %}
      {{ “Normal” }}
      {% elif value_json[“PoolMode”] == 0 %}
      {{ “SYNC” }}
      {% elif value_json[“PoolMode”] == 2 %}
      {{ “Timeout” }}
      {% elif value_json[“PoolMode”] == 3 %}
      {{ “Service” }}
      {% else %}
      {{ “UNKNOWN” }}
      {% endif %}
    • platform: command_line
      name: Node Heater Mode
      command: ‘/home/dan/node_modules/node-screenlogic/PentairStatus.js’
      value_template: ‘{{ value_json[“HeaterStatus”] }}’
    • platform: command_line
      name: Node Heater Status
      command: ‘/home/dan/node_modules/node-screenlogic/PentairStatus.js’
      value_template: ‘{{ value_json[“HeaterStatus”] }}’

    #!/usr/bin/node

    ‘use strict’;

    const ScreenLogic = require(’./index’);
    const POOL_LIGHT_CIRCUIT_ID = 503;

    connect(new ScreenLogic.UnitConnection(80, ‘192.168.1.59’));

    function connect(client) {

    client.on(‘loggedIn’, function() {

    this.setCircuitState(0, POOL_LIGHT_CIRCUIT_ID, 1);

    client.close();

    });

    client.connect();

    }


this.getControllerConfig();
console.log(‘bodyArray[0] =’, config.bodyArray[0]);
console.log(‘bodyArray[1] =’, config.bodyArray[1]);
console.log(‘bodyArray[2] =’, config.bodyArray[2]);
console.log(‘bodyArray[3] =’, config.bodyArray[3]);
console.log(‘bodyArray[4] =’, config.bodyArray[4]);
console.log(‘bodyArray[5] =’, config.bodyArray[5]);
console.log(‘bodyArray[6] =’, config.bodyArray[6]);
console.log(‘bodyArray[7] =’, config.bodyArray[7]);

const SPA_CIRCUIT_ID = 500;
const POOL_CIRCUIT_ID = 505;
const WATERFALL_CIRCUIT_ID = 504;
const SPA_BOOSTER_PUMP_CIRCUIT_ID = 501;
const SPA_AIR_BLOWER_CIRCUIT_ID = 502;
const SPA_LIGHT_CIRCUIT_ID = 507;
const POOL_LIGHT_CIRCUIT_ID = 503;
const POOL_FLOOR_CLEANER_CIRCUIT_ID = 540;
const INTELLIBRITE_CIRCUIT_ID = 12504;

#!/usr/bin/node
# PentairStatus.js
'use strict';

const ScreenLogic = require('./index');
var PentairData = {};
var HeaterMode;
var HeaterStatus;

connect(new ScreenLogic.UnitConnection(80, '192.168.1.59'));

// generic connection method used by all above examples
function connect(client) {
  client.on('loggedIn', function() {
    this.getVersion();
  }).on('version', function(version) {
    this.getPoolStatus();
    PentairData['Version'] = version.version;
  }).on('poolStatus', function(status) {
    PentairData['PoolMode'] =  status.ok;
    PentairData['PoolTemp'] =  status.currentTemp[0];
    PentairData['SPATemp'] = status.currentTemp[1];
    PentairData['AirTemp'] = status.airTemp;

    if (status.isSpaActive()) { 
      PentairData['SPAActive'] = "true" 
    } 
    else {
      PentairData['SPAActive'] = "false"
    }
     
    if (status.isPoolActive()) { 
      PentairData['Poolctive'] = "true" 
    } 
    else {
      PentairData['PoolActive'] = "false"
    }

    if (status.isFloorCleanerActive()) { 
      PentairData['FloorCleanerActive'] = "true" 
    } 
    else {
      PentairData['FloorCleanerActive'] = "false"
    }

    if (status.isWaterFallActive()) { 
      PentairData['WaterfallActive'] = "true" 
    } 
    else {
      PentairData['WaterfallActive'] = "false"
    }

    if (status.isSPAAirBlowerActive()) { 
      PentairData['SPAAirBlowerActive'] = "true" 
    } 
    else {
      PentairData['SPAAirBlowerActive'] = "false"
    }

    if (status.isSPALightActive()) { 
      PentairData['SPALightON'] = "true" 
    } 
    else {
      PentairData['SPALightON'] = "false"
    }

    if (status.isPoolLightActive()) { 
      PentairData['PoolLightON'] = "true" 
    } 
    else {
      PentairData['PoolLightON'] = "false"
    }

    PentairData['FreezeModeActive'] = status.freezeMode;
    if ((status.heatStatus[0] == "1") || (status.heatStatus[1] == "1")) {
      HeaterStatus = "ON";
    }
    else {
      HeaterStatus = "OFF";
    }
    PentairData['HeaterStatus'] = HeaterStatus; 

    if ((status.heatMode[0] == "0") && (status.heatMode[1] == "0")) {
      HeaterMode = "OFF";
    }
    else if ( status.heatMode[0] == "1")  {
      HeaterMode = "POOL";
    }
    else if ( status.heatMode[1] == "1") {
      HeaterMode = "SPA";
    }
    else {
      HeaterMode = "UNKNOWN";
    }
    PentairData['HeaterMode'] = HeaterMode;
    console.log(JSON.stringify(PentairData));
    client.close();
  })
  client.connect();
}

@danmarotta5 I am a newbie to all of this but I have been studing what you did with this pentair js and want to emulate. I jave a nodejs script printing my pool info in JSON very close to how you have done and I have studied your command line sensors and switches and understand and will emulate.

What I dont know how to do it get node js and npm running on my RPI4 running hassio. Your step 1 above. Can you elborate? I see other use a docker filew but not sure what is best here. When they say ssh into hassio and clone to addons folder when I ssh into hassio io ls and dir dooesnt work.

Can you advise how to get nodejs and npm running for this on hassio?

i’ve done some searching and i don’t see any indications how to install node/npm under hassio. one wacky way to accomplish this is to get a dedicated pi with stock debian OS, install npm and node, MQTT, get pool functions working … then send out MQTT messages to your hassio system or send remote commands to your dedicated pi to turn on/off function and get status information

OK thanks dan, if I cant figure out this dockerfile then that is what I will do (MQTT from a seperate PI). the Autelis not an option anymore.

Since this topic has been dead for a while I decided to learn from everyone else’s work and create a full addon. You can fine it here: https://github.com/bwoodworth/hassio-addons/tree/master/pentair-screenlogic

It is configurable through the addon page and allows control over every circuit in the controller.

1 Like

All: if you are not using HASSIO and want to use Brian Woodworth’s amazing work I decoupled it. Here is my walk through on the process:

1 Like