PoolSync (Pool Heat Pump) Integration

Hi! - Has anyone been able to integrate PoolSync (pool heat pump control) ?

Much appreciated - Chad

1 Like

I also am in process of installing a TropiCal pool heater (pool heat pump) and I paid extra for the PoolSync WiFi controller. This will give me capabilities of controlling the pool heater via the PoolSync app on my phone.

Was hoping someone would have a PoolSync Intigraton…. I checked HACS, nothing there either…

1 Like

I have a pool sync. I have not found any integrations. It appears to be cloud based for the wifi controller. From the controller to the other devices it runs RS-485 serial wire protocol. The Jandy pump I have also uses RS-485 (it seems most pool control is either direct relays or rs-485), but the pump is not compatible with poolsync (i.e. the poolsync device does not understand the Jandy messages). If I was a little bit better programmer I’d build up a PoolSync replacement on raspberry Pi and make a local controller, but my expertise is more on the data side than the code side.

If anyone wants to take on this project I can be a tester.

Yea if anyone is up for the challenge, I can be a tester as well.

I’m following this one. I have a Waterway PD140 variable speed pump and an Aquacal Tropical T75 Heat pump with the Poolsync controller. About 2 years ago I spent a few days playing around with different software and RS-485 adapters trying to figure out how to control these, but I finally gave up. That said, I’m sure there are some more knowledgable on here that could point us in the right direction.

1 Like

+1 for the need or willingness to test!

1 Like

I have not attempted to create an integration yet, but I have poked around with the poolsync api.
Here is what I found:

  • You can connect directly to your poolsync IP which is listed in the app
  • Every request requires a token and user ID. This token is sent to your phone when you pair it with the poolsync. As far as I know the only way to get the token is to us a pcap/traffic sniffer
    EDIT: Looks like user ID can be any UUID

Example for getting info (like sensors and status):

curl --request GET \
  --url 'http://[your poolsync IP]/api/poolsync?cmd=poolSync&all=' \
  --header 'Authorization: [your token]' \
  --header 'user: [your user UUID]'

Example for updating temp:

curl --request PATCH \
  --url 'http://[your poolsync IP]/api/poolsync?cmd=devices&device=1' \
  --header 'Authorization: [your token]' \
  --header 'Content-Type: application/json' \
  --header 'user: [your user UUID]' \
  --data '{"setpoint":85}'
2 Likes

Interesting information, definitely on the right track! Over my head tho…

This is a great start. I’m opening the pool in the next few days and will try to do some investigating. Seems like getting the token is going to be the most difficult challenge ongoing assuming it’s possible to just sniff and document the small number of calls needed for the device. (I think the main functions are just Mode, get temp, and set temp.) @lfreijo please post if you documented any of the other commands or features other than your example. Thanks!

Here is the full output for /api/poolsync?cmd=devices&device=1. In my case device 1 is the heater, device 0 is the chlorsync. Anything under “status” would be a sensor. I tested that these can be added via the RESTful sensor integration but it’s quite manual and a bit of a pain. (at least for me)

Anything in the “config” section can be set using the patch method I posted above. It should work with the RESTful switch integration, but I haven’t had time to test it yet.

For the auth token, this might be in the app data somewhere, but I don’t know how to extract that.

{
	"devices": {
		"1": {
			"nodeAttr": {
				"name": "Heat Pump",
				"pid": 9984,
				"nodeAddr": 18,
				"idmpAddr": 0,
				"online": true,
				"flags": 2,
				"bootMode": 2,
				"fwUpdProg": 0,
				"fwUpdResult": 0
			},
			"status": {
				"stateFlags": 260,
				"ctrlFlags": 1,
				"boardTemp": 105.8,
				"waterTemp": 90.41,
				"waterTemp2": 90.75,
				"airTemp": 88.53,
				"solarTemp": 127,
				"ds1Temp": 91.07,
				"ds2Temp": 86,
				"compRPM": 0,
				"flowPeriod": 1440,
				"outletTemp": 127,
				"geoInlet": 91.07,
				"geoOutlet": 86
			},
			"system": {
				"serialNum": "XXXX",
				"modelNum": "XXXX",
				"hwVersion": "F",
				"blFwVersion": 262,
				"appFwVersion": 573,
				"dispFwVersion": 65,
				"compModelNum": "XXXX"
			},
			"config": {
				"mode": 1,
				"poolSpaMode": 0,
				"setpoint": 88,
				"spaSetpoint": 0,
				"efficiencyMode": 0,
				"turboBoost": 0,
				"serviceMode": 0,
				"schedMode": 1,
				"schedAwayEnd": 0,
				"multiUnitMode": 0,
				"multiUnitAddr": 0,
				"gasBoost": 0,
				"backupHeatStartTime": 0,
				"backupHeatStopTime": 0,
				"backupHeatMode": 0,
				"solarMode": 0,
				"solarSetpoint": 85,
				"setpointMin": 40,
				"setpointMax": 104
			},
			"faults": [
				0,
				0
			],
			"stats": [
				1,
				3758096387,
				76503669,
				10603773,
				10918800,
				1048727,
				0,
				10601409,
				0,
				67125804,
				108322,
				0,
				0,
				0,
				0,
				2,
				0,
				0,
				0,
				4,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				1,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0
			],
			"equip": {
				"0": [
					3,
					"HEAT PUMP",
					0,
					0,
					0,
					300,
					0,
					1
				],
				"1": null,
				"2": null,
				"3": null,
				"4": null,
				"5": null,
				"6": null,
				"7": null,
				"8": null,
				"9": null,
				"10": null,
				"11": null,
				"12": null,
				"13": null,
				"14": null,
				"15": null
			},
			"groups": {
				"0": {
					"config": [
						"POOL",
						0,
						192,
						2,
						172800,
						0,
						0,
						1
					],
					"equip": {
						"0": [
							1,
							88
						],
						"1": null,
						"2": null,
						"3": null,
						"4": null,
						"5": null,
						"6": null,
						"7": null,
						"8": null,
						"9": null,
						"10": null,
						"11": null
					}
				},
				"1": null,
				"2": null,
				"3": null,
				"4": null,
				"5": null,
				"6": null,
				"7": null,
				"8": null,
				"9": null,
				"10": null,
				"11": null
			},
			"schedules": {
				"0": {
					"0": [
						127,
						8,
						23
					],
					"1": [
						0,
						8,
						18
					],
					"2": [
						0,
						8,
						18
					],
					"3": [
						0,
						8,
						18
					]
				},
				"1": null,
				"2": null,
				"3": null,
				"4": null,
				"5": null,
				"6": null,
				"7": null,
				"8": null,
				"9": null,
				"10": null,
				"11": null
			}
		}
	}
}
1 Like

Now that the pool is open, I spent some time digging into this, but there is something I seem to be missing. I initially started with wireshark to do some packet sniffing. I got all of that working and was able to narrow down the filters to see the traffic to and from Poolsync (hosted on amazon). At that point, i realize that all the traffic is encrypted. Next step, I installed a proxy that would allow me to decrypt the traffic to see the service calls and authorization details. That seems to be working, but I’m not able to identify what client token you are referring to that would give me authorization to the local web server API.

Within the decrypted traffic to Amazon, I can see an authorization key that is used in every request, but when I try to use that to access the local web server API via curl, it tells me that the header is too long, so that must not be the right one. Screenshot, slightly redacted:

I went through the process of logging out, and logging back in several times to see if I could identify something unique being delivered to the app, but I seem to be missing it.

Any pointers would be appreciated!

The app talks differently to the web service verses to the local device directly. The token in my posts can be found by watching the traffic from your phone to the ip of your poolsync (no internet required). As far as I know the auth token cannot be taken from the web, it only gets sent to your phone when you go through the initial pairing process via bluetooth.

If you have the traffic from your phone to the web service decrypted, that could be another avenue for an integration, but it rely on their cloud service rather than a direct local connection.

@lfreijo this pointed me to exactly what I needed, thank you! I have a lot of notes and config that I’m going to document here in hopes of helping others, as well as for my own future reference. What I have right now is a fully functional system although it is a version 1.0, so might need a few tweaks.

#1 --------------- Finding “Authorization” key and “user” id ---------------
There is a short period of time after you initially pair your PoolSync device with your phone where the communication between the device and your phone is unencrypted HTTP. This is the only opportunity to get the two values needed, but of course you can always delete the device from the app and go through the setup process again. (Note that in my experience, each time I paired the device, the “Authorization” key and “user” id were the same, and I only had success when I used those values together)

This process does require the use of Wireshark or some other packet sniffing tool, which aren’t the most user friendly. In my case, I was able to use the remote SSH packet capture feature of Wireshark and connect to my Unifi access points. Here’s a screenshot of what the clear HTTP request would look like in Wireshark:

#2 --------------- Test access to the PoolSync device ---------------
I’m using Windows, so the curl commands I’m using have slightly different placement of single and double quotes than what others showed, so you may need to adjust based on platform.

Get all JSON values from device
curl --request GET --url "http://[ DEVICE IP ]/api/poolsync?cmd=poolSync&all=" --header "Authorization: [ AUTHORIZATION ]" --header "user: [ USER ]"

Set pool target temperature to 68
curl --request PATCH --url "http://[ DEVICE IP ]/api/poolsync?cmd=devices&device=0" --header "Authorization: [ AUTHORIZATION ]" --header "user: [ USER ]" --header "Content-Type: application/json" --header "Accept-Encoding: gzip, deflate" --data "{\"config\":{\"setpoint\":68}}"

If both of those are working, you are in good shape, but like I said, the syntax with curl can be finicky

#3 --------------- Configure Rest sensors and commands in Home Assistant ---------------
You’ll have to decide how you organize your Home Assistant, but I use “packages” with a yaml file for each major area of my configuration. (For instance, one package file that is only for the pool configuration and automations) I also use a “secrets.yaml” file to separate out confidential information from my config. Those are all important points if you’d like to use any of my configuration.

Include the following keys in your secrets.yaml. (Substitute your values for the bracketed items)

#Poolsync
poolsync_authorization: "[ AUTHORIZATION ]"
poolsync_user: "[ USER ]"
poolsync_json_url: "http://[ IPADDRESS ]/api/poolsync?cmd=poolSync&all"
poolsync_device0_url: "http://[ IPADDRESS ]/api/poolsync?cmd=devices&device=0"

The following will create all of your Rest sensors and rest command required. Note that Rest items typically require a full HA restart when adding or updating.

rest:
  resource: !secret poolsync_json_url
  scan_interval: 10
  headers:
    Authorization: !secret poolsync_authorization
    user: !secret poolsync_user
    Content-Type: application/json
  sensor:
    - name: Pool Heater Online
      json_attributes_path: "$.devices.0.status"
      value_template: "{{ value_json['devices']['0']['nodeAttr'].online }}"
      json_attributes:
        - "stateFlags"
        - "ctrlFlags"
        - "boardTemp"
        - "waterTemp"
        - "airTemp"
    - name: Pool Heater Mode
      json_attributes_path: "$.devices.0.config"
      value_template: >-
        {% if value_json['devices']['0']['config'].mode == 1 and value_json['devices']['0']['config'].poolSpaMode == 0 %}
            Heat Pool
          {% elif value_json['devices']['0']['config'].mode == 1 and value_json['devices']['0']['config'].poolSpaMode == 1 %}
            Heat Spa
          {% else %}
            Off
        {% endif %}
      json_attributes:
        - "mode"
        - "poolSpaMode"
        - "setpoint"
        - "spaSetpoint"
    - name: Pool Water Temperature
      value_template: "{{ value_json['devices']['0']['status'].waterTemp }}"
      device_class: temperature
      unit_of_measurement: "°F"
  binary_sensor:
    - name: Pool Heater Flow
      value_template: "{{ value_json['devices']['0']['status'].ctrlFlags != 0 }}"
    - name: Pool Heater Fan
      value_template: "{{ value_json['devices']['0']['status'].stateFlags >= 8 }}"
    - name: Pool Heater Compressor
      value_template: "{{ value_json['devices']['0']['status'].stateFlags == 8 }}"

rest_command:
  poolsync_control_device0:
    url: !secret poolsync_device0_url
    method: patch
    headers:
      Authorization: !secret poolsync_authorization
      user: !secret poolsync_user
      Content-Type: application/json
    payload: '{"config":{"{{ param }}":{{ value }}}}'

There are a lot of other values located in JSON data that are accessible, but I only included the ones I thought were relevant. Also, as you look through all of the sensor values, many are self explanatory like mode and poolSpaMode:

mode (0 off 1 heat)
poolSpaMode (0 pool 1 spa)

You’ll notice a few special items that I took a first pass at decoding. Seems to be working fine on mine, but I could have missed some status details, specifically for the “stateFlags” and “ctrlFlags” which you’ll see I’m using to determine things like flow, fan on, compressor on… Here are my notes:

s1 c0 = Fan: off, Compressor: off, Heat: off, Flow: off
s1 c1 = Fan: off, Compressor: off, Heat: off, Flow: on
s2 c0 = Fan: off, Compressor: off, Heat: on, Flow: off
s4 c1 = Fan: off, Compressor: off, Heat: on, Flow: on (water temp above setpoint)
s520 c9 = Fan: on, Compressor: off, Heat: on, Flow: on (water temp below setpoint preparing to run compressor)
s8 c13 = Fan: on, Compressor: on, Heat: on, Flow: on (water temp below setpoint)

c0 = Flow is off
c1+ = Flow is on
s1 = Heat is off
s2 = Heat is on but flow is off
s4 = Heat on, but water above setpoint
s520 = fan on
s8 = fan on and compressor on (Heating)

To use the rest command, I’ve made it so you can simply include the data in your service call, rather than create a bunch of those commands for each individual change to the controller. For example:

- service: rest_command.poolsync_control_device0
  data_template:
    param: setpoint
    value: 68

- service: rest_command.poolsync_control_device0
  data_template:
    param: mode
    value: 1

#4 --------------- Adding Helpers and Automations for complete HA control ---------------

If you want to be able to fully control your device from Home Assistant you’ll need to add some helpers and automations:

input_number:
  pool_heater_pool_target_temp:
    name: Pool Heater Pool Target Temp
    min: 40
    max: 104
    step: 1
    unit_of_measurement: "°F"
  pool_heater_spa_target_temp:
    name: Pool Heater Spa Target Temp
    min: 40
    max: 104
    step: 1
    unit_of_measurement: "°F"

input_select:
  pool_heater_mode:
    name: Pool Heater Mode
    options:
      - "Heat Pool"
      - "Heat Spa"
      - "Off"

automations:
  - alias: Pool Heater Mode Sync
    description: Keeps the Pool Heater Mode in sync with the input_select
    trigger:
      - platform: state
        entity_id:
          - sensor.pool_heater_mode
        id: sync_value_to_input_select
      - platform: state
        entity_id:
          - input_select.pool_heater_mode
        id: change_value_on_controller
      - platform: homeassistant
        event: start
        id: startup_sync
    condition:
      - condition: template
        value_template: >-
          {{ states('sensor.pool_heater_mode') !=
          states('input_select.pool_heater_mode') }}
    action:
      - choose:
          - conditions:
              - condition: trigger
                id:
                  - sync_value_to_input_select
                  - startup_sync
            sequence:
              - service: input_select.select_option
                target:
                  entity_id: input_select.pool_heater_mode
                data_template:
                  option: "{{ states('sensor.pool_heater_mode') }}"
          - conditions:
              - condition: trigger
                id:
                  - change_value_on_controller
            sequence:
              - if:
                  - condition: state
                    entity_id: input_select.pool_heater_mode
                    state: "Off"
                then:
                  - service: rest_command.poolsync_control_device0
                    metadata: {}
                    data:
                      param: mode
                      value: 0
              - if:
                  - condition: state
                    entity_id: input_select.pool_heater_mode
                    state: Heat Pool
                then:
                  - service: rest_command.poolsync_control_device0
                    metadata: {}
                    data:
                      param: mode
                      value: 1
                  - service: rest_command.poolsync_control_device0
                    metadata: {}
                    data:
                      param: poolSpaMode
                      value: 0
              - if:
                  - condition: state
                    entity_id: input_select.pool_heater_mode
                    state: Heat Spa
                then:
                  - service: rest_command.poolsync_control_device0
                    metadata: {}
                    data:
                      param: mode
                      value: 1
                  - service: rest_command.poolsync_control_device0
                    metadata: {}
                    data:
                      param: poolSpaMode
                      value: 1
      - delay:
          hours: 0
          minutes: 0
          seconds: 1
          milliseconds: 0
    mode: single

  - alias: Pool Heater Pool Target Temp Sync
    description: Keeps the Pool Heater Pool Target Temp in sync with the input_number
    trigger:
      - platform: state
        entity_id:
          - sensor.pool_heater_mode
        id: sync_value_to_input_number
        attribute: setpoint
      - platform: state
        entity_id:
          - input_number.pool_heater_pool_target_temp
        id: change_value_on_controller
      - platform: homeassistant
        event: start
        id: startup_sync
    condition:
      - condition: template
        value_template: >-
          {{ state_attr('sensor.pool_heater_mode','setpoint')|int !=
          states('input_number.pool_heater_pool_target_temp')|int }}
    action:
      - choose:
          - conditions:
              - condition: trigger
                id:
                  - startup_sync
                  - sync_value_to_input_number
            sequence:
              - service: input_number.set_value
                target:
                  entity_id: input_number.pool_heater_pool_target_temp
                data_template:
                  value: "{{ state_attr('sensor.pool_heater_mode','setpoint')|int }}"
          - conditions:
              - condition: trigger
                id:
                  - change_value_on_controller
            sequence:
              - service: rest_command.poolsync_control_device0
                metadata: {}
                data_template:
                  param: setpoint
                  value: "{{ states('input_number.pool_heater_pool_target_temp')|int }}"
      - delay:
          hours: 0
          minutes: 0
          seconds: 1
          milliseconds: 0
    mode: single

  - alias: Pool Heater Spa Target Temp Sync
    description: Keeps the Pool Heater Spa Target Temp in sync with the input_number
    trigger:
      - platform: state
        entity_id:
          - sensor.pool_heater_mode
        id: sync_value_to_input_number
        attribute: spaSetpoint
      - platform: state
        entity_id:
          - input_number.pool_heater_spa_target_temp
        id: change_value_on_controller
      - platform: homeassistant
        event: start
        id: startup_sync
    condition:
      - condition: template
        value_template: >-
          {{ state_attr('sensor.pool_heater_mode','spaSetpoint')|int !=
          states('input_number.pool_heater_spa_target_temp')|int }}
    action:
      - choose:
          - conditions:
              - condition: trigger
                id:
                  - startup_sync
                  - sync_value_to_input_number
            sequence:
              - service: input_number.set_value
                target:
                  entity_id: input_number.pool_heater_spa_target_temp
                data_template:
                  value: "{{ state_attr('sensor.pool_heater_mode','spaSetpoint')|int }}"
          - conditions:
              - condition: trigger
                id:
                  - change_value_on_controller
            sequence:
              - service: rest_command.poolsync_control_device0
                metadata: {}
                data_template:
                  param: spaSetpoint
                  value: "{{ states('input_number.pool_heater_spa_target_temp')|int }}"
      - delay:
          hours: 0
          minutes: 0
          seconds: 1
          milliseconds: 0
    mode: single

I’ve had this unit for 3 years now and it’s so nice to finally have it fully integrated into the rest of my system. Hope this helps others and I’d love to see any feedback or enhancements from others!

1 Like

Looking at getting a Aquacal with poolsync, this is fantastic. Is it stable within HA?

I have made a ton of progress setting up and monitoring my chlorSync with your work at @ccpk1 , Thank you!

I dont have a heater at this time, but using your work, it should be simple to include.

for the chlorSync, has anyone figured out how to set the Boost Mode? I dont see anything in the config section that would trigger it.

Dave

Figured this out, but due to timeouts in rest, i had to setup the commands as shell commands.

if anyone is interested i can put together small package of files for this

Since it’s just using the Rest capabilities in HA, it’s very stable in HA. The only thing I see through the day is occasional timeouts for one poll cycle, but then it picks up in the next cycle which for me is 10 seconds later. I tried a few different things to have it use the previous data for up to 3 minutes or immediately poll again on failure, but can’t seem to find the right combo. That said, it doesn’t cause any real issues for me, so more of an annoyance that Im sure there is a reasonable workaround for.

Great to hear people are using this. From what I can see, controlling multiple devices is only a matter of determining which device ID is assigned to each and then changing the url strings to match. (ie device 1 vs device 0)

Here’s an example response from the local api for a poolSync with a heat pump, chlorSync, and a pool pump. I changed all the serial numbers and mac addresses to anonymize it. Found someone who started writing a HA plugin but its not in a production state yet.

Has anyone figured out how to control the pool pump from here? I can control it from the PoolSync app but can’t figure out how to do it from HA

curl --request GET \
  --url 'http://LOCAL_IP_HERE/api/poolsync?cmd=poolSync&all' \
  --header 'Authorization: REDACTED' \
  --header 'user: REDACTED' | jq
{
  "poolSync": {
    "status": {
      "online": true,
      "flags": 0,
      "rssi": -84,
      "boardTemp": 38,
      "dateTime": "Wed Jun 26 22:35:14 2024"
    },
    "system": {
      "macAddr": "840D8EFFFFFF",
      "bssid": "FF:FF:FF:FF:FF:FF",
      "fwVersion": 828,
      "hwVersion": "2.0"
    },
    "config": {
      "name": "PoolSync™",
      "setupMode": 0,
      "serviceMode": 0,
      "brightness": 4,
      "timeZone": "EST5EDT,M3.2.0,M11.1.0",
      "latitude": 00.0000,
      "longitude": -00.0000,
      "optIns": 4294967295,
      "isWatching": 28657142
    },
    "faults": 0,
    "stats": {
      "numPowerups": 963,
      "lastEsp32ResetReason": 3,
      "restartHistory": "09080708",
      "cfgRamConflicts": 0,
      "cfgNvramConflicts": 0,
      "wifiDisconnects": 1745,
      "awsDisconnects": 1733,
      "caFileRestores": 1,
      "certFileRestores": 0,
      "certFlashRestores": 1,
      "pvtkeyFileRestores": 0,
      "pvtkeyFlashRestores": 1,
      "certRefreshes": 0,
      "systemRestarts": 610,
      "iRamFreeMin": 52511,
      "iRamMaxBlock": 48128,
      "iRamMaxBlockMin": 44032,
      "spiRamFreeMin": 2681803,
      "spiRamMaxBlock": 2621440,
      "spiRamMaxBlockMin": 2621440,
      "minTaskStackSize": 1504,
      "taskNameMinStack": "UDP",
      "numAwsIotTxMessages": 6678374,
      "numAwsIotRxMessages": 465,
      "numDeviceOffline": 67,
      "lastOfflineDevPid": 9730,
      "lastOfflineDevAddr": 17,
      "numDeviceCmdErrResp": 0,
      "numDeviceMsgNoResp": 21201,
      "minRssi": -100,
      "maxRssi": -52,
      "minBoardTemp": 20,
      "maxBoardTemp": 65,
      "numConnectButtonPresses": 2,
      "numServiceButtonPresses": 5,
      "numServiceAccessButtonPresses": 10,
      "numSetupButtonPresses": 0,
      "numConsoleLogins": 0,
      "numConsoleIncorrectPassword": 0,
      "upTimeSecs": 52688168,
      "numFatFsRegenerations": 0,
      "numDeviceInstallStableFw": 0,
      "lastDeviceInstallStableFwPid": 0
    }
  },
  "devices": {
    "0": {
      "nodeAttr": {
        "name": "Heat Pump",
        "pid": 9984,
        "nodeAddr": 16,
        "idmpAddr": 1,
        "online": true,
        "flags": 2,
        "bootMode": 2,
        "fwUpdProg": 0,
        "fwUpdResult": 0
      },
      "status": {
        "stateFlags": 257,
        "ctrlFlags": 0,
        "boardTemp": 106,
        "waterTemp": 85.27,
        "waterTemp2": 85.63,
        "airTemp": 83.46,
        "solarTemp": 127,
        "ds1Temp": 83.54,
        "ds2Temp": 83.38,
        "compRPM": 0,
        "flowPeriod": 539,
        "outletTemp": 127,
        "geoInlet": 83.54,
        "geoOutlet": 83.38
      },
      "system": {
        "serialNum": "000000000",
        "modelNum": "LT0800AHDSBND",
        "hwVersion": "F",
        "blFwVersion": 262,
        "appFwVersion": 573,
        "dispFwVersion": 65,
        "compModelNum": "ZPV038CE-2E9"
      },
      "config": {
        "mode": 0,
        "poolSpaMode": 0,
        "setpoint": 89,
        "spaSetpoint": 0,
        "efficiencyMode": 0,
        "turboBoost": 0,
        "serviceMode": 0,
        "schedMode": 1,
        "schedAwayEnd": 0,
        "multiUnitMode": 0,
        "multiUnitAddr": 0,
        "gasBoost": 0,
        "backupHeatStartTime": 0,
        "backupHeatStopTime": 0,
        "backupHeatMode": 0,
        "solarMode": 0,
        "solarSetpoint": 85,
        "setpointMin": 40,
        "setpointMax": 104
      },
      "faults": [
        0,
        0
      ],
      "stats": [
        1,
        3758096387,
        111143319,
        4943142,
        5124364,
        255094,
        0,
        4941706,
        0,
        37614093,
        5597,
        0,
        0,
        0,
        0,
        48,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0
      ],
      "equip": {
        "0": [
          3,
          "HEAT PUMP",
          0,
          0,
          0,
          300,
          0,
          0
        ],
        "1": [
          0,
          "CIRCULATION PUMP",
          2,
          2,
          0,
          300,
          0,
          0,
          12,
          69,
          52,
          5,
          52,
          0,
          0
        ],
        "2": [
          4,
          "CHLORINATOR",
          0,
          0,
          0
        ],
        "3": null,
        "4": null,
        "5": null,
        "6": null,
        "7": null,
        "8": null,
        "9": null,
        "10": null,
        "11": null,
        "12": null,
        "13": null,
        "14": null,
        "15": null
      },
      "groups": {
        "0": {
          "config": [
            "EVENING",
            9,
            48,
            0,
            43200,
            0,
            1,
            1
          ],
          "equip": {
            "2": [
              25,
              0
            ],
            "1": [
              36,
              0
            ],
            "0": null,
            "3": null,
            "4": null,
            "5": null,
            "6": null,
            "7": null,
            "8": null,
            "9": null,
            "10": null,
            "11": null
          }
        },
        "1": {
          "config": [
            "FILTRATION",
            2,
            48,
            0,
            43200,
            0,
            1,
            1
          ],
          "equip": {
            "1": [
              48,
              0
            ],
            "2": [
              25,
              0
            ],
            "0": null,
            "3": null,
            "4": null,
            "5": null,
            "6": null,
            "7": null,
            "8": null,
            "9": null,
            "10": null,
            "11": null
          }
        },
        "2": {
          "config": [
            "CLEANER",
            3,
            3,
            0,
            2700,
            0,
            1,
            1
          ],
          "equip": {
            "1": [
              64,
              0
            ],
            "0": null,
            "2": null,
            "3": null,
            "4": null,
            "5": null,
            "6": null,
            "7": null,
            "8": null,
            "9": null,
            "10": null,
            "11": null
          }
        },
        "3": null,
        "4": null,
        "5": null,
        "6": null,
        "7": null,
        "8": null,
        "9": null,
        "10": null,
        "11": null
      },
      "schedules": {
        "0": {
          "0": [
            127,
            13,
            17
          ],
          "1": [
            0,
            8,
            16
          ],
          "2": [
            0,
            8,
            16
          ],
          "3": [
            0,
            8,
            16
          ]
        },
        "1": {
          "0": [
            127,
            8,
            13
          ],
          "1": [
            0,
            8,
            18
          ],
          "2": [
            0,
            8,
            18
          ],
          "3": [
            0,
            8,
            18
          ]
        },
        "2": {
          "0": [
            0,
            8,
            11528
          ],
          "1": [
            0,
            8,
            11528
          ],
          "2": [
            0,
            8,
            11528
          ],
          "3": [
            0,
            8,
            11528
          ]
        },
        "3": null,
        "4": null,
        "5": null,
        "6": null,
        "7": null,
        "8": null,
        "9": null,
        "10": null,
        "11": null
      }
    },
    "1": {
      "nodeAttr": {
        "name": "ChlorSync®",
        "pid": 9730,
        "nodeAddr": 17,
        "idmpAddr": 0,
        "online": true,
        "flags": 2,
        "bootMode": 2,
        "fwUpdProg": 0,
        "fwUpdResult": 0
      },
      "config": {
        "chlorOutput": 25,
        "poolCoverCtrl": false,
        "tempCompEnable": true,
        "userSaltCalib": 0,
        "gallons": 15000,
        "polarityChangeTime": 48,
        "orpInputCtrl": false
      },
      "status": {
        "flags": 128,
        "waterTemp": 89.6,
        "boardTemp": 94.63,
        "maxBoardTemp": 159.64,
        "tempCompOutput": 39,
        "fwdCurrent": 1103,
        "revCurrent": 1060,
        "outVoltage": 608,
        "cellRailVoltage": 4180,
        "saltPPM": 3050,
        "cellRawSaltADC": 794,
        "boostRemaining": 0
      },
      "system": {
        "drvModelNum": "",
        "drvSerialNum": "",
        "drvFwVersion": 520,
        "drvBlFwVersion": 256,
        "drvHwVersion": "A",
        "numBlades": 11,
        "cellFwVersion": 7,
        "cellHwVersion": 66,
        "cellSerialNum": "000000000000"
      },
      "faults": [
        0
      ],
      "stats": [
        0,
        0,
        0,
        0,
        27406687,
        2502530,
        29367150,
        2738419,
        2771,
        225,
        132,
        27406687,
        0,
        0,
        0,
        1793,
        49664,
        0,
        0,
        40867
      ]
    },
    "2": null,
    "3": null,
    "4": null,
    "5": null,
    "6": null,
    "7": null,
    "8": null,
    "9": null,
    "10": null,
    "11": null,
    "12": null,
    "13": null,
    "14": null,
    "15": null
  },
  "deviceType": {
    "0": "heatPump",
    "1": "chlorSync",
    "2": "",
    "3": "",
    "4": "",
    "5": "",
    "6": "",
    "7": "",
    "8": "",
    "9": "",
    "10": "",
    "11": "",
    "12": "",
    "13": "",
    "14": "",
    "15": ""
  }
}
1 Like

Any update on HA plugin?? That would be amazing!

2 Likes