Hayward AquaLogic / ProLogic automation

Hi @aming-miyembro ,
I’d like to see the work you’ve done to make a USB serial to work. Could you push your changes to a fork on GitHub, and point us to it? If/when you do that, you could also create a pull request to have those changes applied/reviewed for the main source.

My system is a Hayward Pro Logic PL-PS-4. I had to modify some stuff to get cli.py to run, change serial to write() from send(), and deal with display updates where additional byte encodings were used. The system state seems to be read without issue now. When I try to send a serial command like the SPA mode using the cli.py, it doesn’t take effect. Before I start debugging, I’d rather see if/how you’ve dealt with it.

I created a PR on aqualogic source to address the display issues.

Here’s my branch for what it’s worth:

Hey!

Yes, I also applied the send() to write() fix (in core.py) to get my serial connection working properly. Also made the following mod for sending instructions, hopefully it helps you:

        if key.value > 0xffff:
            self._append_data(frame, self.FRAME_TYPE_WIRELESS_KEY_EVENT)
            self._append_data(frame, b'\x01')
            self._append_data(frame, key.value.to_bytes(4, byteorder='little'))
            self._append_data(frame, key.value.to_bytes(4, byteorder='little'))
            self._append_data(frame, b'\x00')
        else:
# MOD BEGIN
            # self._append_data(frame, self.FRAME_TYPE_LOCAL_WIRED_KEY_EVENT)
            self._append_data(frame, self.FRAME_TYPE_REMOTE_WIRED_KEY_EVENT)
            self._append_data(frame, key.value.to_bytes(2, byteorder='little'))
            self._append_data(frame, b'\x00')
            self._append_data(frame, b'\x00')
            self._append_data(frame, key.value.to_bytes(2, byteorder='little'))
            self._append_data(frame, b'\x00')
            self._append_data(frame, b'\x00')
# MOD END

Someone who understands bytecode better than myself might have a better way to write that.

I didn’t use cli.py, no longer remember the issue why. To get output I simply turned logging on (temporarily) in configuration.yaml:

logger:
  default: info
  logs:
    custom_components.aqualogic: debug

I’ve been away from this since the Spring, but hope over the next week to attempt getting a switch working to toggle superchlorination on&off. Once that’s done I might post it all to GitHub – I’ve not used git in enough years that I’d have to relearn it – so no promises at this time.

But feel free to ask any questions!

@aming-miyembro , Thanks! I’ll compare with my latest and see if your changes help.

Button presses go from phases of very reliable to very unreliable. I’ve looked at the various timing suggestions that are mentioned in this thread and the sources they point to. At present, I can navigate the menu system using HA - with patience. The Pool/Filter/etc direct buttons are more reliable probably because the python can retry those since the expected final state is known.

I made an mqtt interface so that I could hack around without the overhead of a custom component.

Done&dusted! It was less difficult than I had expected, made easier by the index of command data in the Hayward AQ-CO-SERIAL manual.

Now that this works, I hope next Spring to add an inexpensive connected ORP sensor to the pool system so Home Assistant can determine when free chlorine is low, so as to automate turning on super chlorination until the chlorine level is satisfactory.


If you have a custom aqualogic implementation for which you do not yet have a superchlorination switch, you can add it as follows:

  1. For switch.py add the following:

    i. to the SWITCH_TYPES array…

    “super_chlorinate”: “Super Chlorinate”,

    ii. to the AquaLogicSwitch class…

    “super_chlorinate”: States.SUPER_CHLORINATE,

  2. For core.py (or keys.py, if there’s no Keys class in core.py) add to the Keys class:

    SUPER_CHLORINATE = 0x04000000

  3. For configuration.yaml, ensure these items are specified:

    sensor:
      - platform: aqualogic
        monitored_conditions:
          - is_super_chlorinate_enabled
    switch:
      - platform: aqualogic
        monitored_conditions:
          - super_chlorinate

1 Like

@b3nj1 @swilson

Hello!
Thank you for all the amazing work you’ve done with Hayward pool hardware interfacing! I was very excited to see this was available for Home Assistant.

I am new to HA since recently switching from Homeseer.

I wonder if you can give me a little insight as to how you created the neat dashboard to navigate the ProLogic menu?

I’ve cloned the pl_ps_4 branch and I am receiving data from my system onto a basic entities card. I’ve added the following to my configuration.yaml file.

#####  Hayward Aqualogic/ProLogic  ##########################################
#####  SENSORS can be found in sensors.yaml  ################################
aqualogic:
  host: 10.0.1.64
  port: 8899

switch:
  - platform: aqualogic
    monitored_conditions:
    - lights
    - filter
    - aux_1
    - aux_2
    - aux_3
    - aux_4

In sensors.yaml:

#####  Hayward Aqualogic/ProLogic Sensors  #################################
- platform: aqualogic
  monitored_conditions:
    - pool_temp
    - air_temp
    - pump_speed
    - status
    - pump_power
    - salt_level

Is it safe to assume that I am using the cloned version as opposed to the native integration?

I also spotted the web.py and web.hml files in the aqualogic folder and they appear to be used for websockets, but I’ve no idea how to create the entities for the LEFT, RIGHT, MENU, + and - which I assume are needed to create a dashboard similar to yours?

Can you provide any suggestions, please?
Thank you again!

@amit1 ,

I am NOT using my fork of aqualogic as an integration. I thought this would be too cumbersome to restart HA every time I tried a new fix in the aqualogic core. More on that below along with code for what I am using. At this point, I could possibly update to using the integration, but since things are working for me, that’s not a priority.

I just pushed my latest changes to my fork. I don’t remember all I’ve done, but roughly speaking:

  • I tweaked how and when commands are inserted. Generally, I get most key presses to work from HA, but sometimes it goes into a funky state where they don’t. Just waiting a few seconds seems to let it recover. I mainly split out the sending of messages into another thread that could using timing events and response messages from the main thread to know when was a good time to send and what the result looked like.
  • I added a “key logger” file that tracks what response occurs whenever a button is pressed. This is whether it was pressed on the console, on my wireless keypad, or by HA. I hope to use this to “learn” how to detect when the HA-initiated button press doesn’t work and then re-send smartly. Since things work well enough, I might not ever go back to this.
  • I added an MQTT front-end. I did this because much of my system is on MQTT and node-red, so I can do quite a bit of fixing things up this way without restarting HA every time.
  • I changed the accessory names to match my system (eg, I have a blower on one of the aux devices).
  • I added NO documentation and made no effort to make this easily customized to the details of any given system (I don’t know enough about what those could even look like to try), so sorry and good luck :wink:

Earlier in this thread, I posted a screen grab of my HA dashboard. Here’s the latest along with the frontend yaml for it. It works well enough that I can press buttons to navigate the menu and accomplish what I want. I made it look/work roughly like the keypad console.

Dashboard yaml:

type: vertical-stack
cards:
  - show_name: false
    show_icon: false
    show_state: true
    type: glance
    entities:
      - entity: sensor.pool_display
  - square: false
    columns: 3
    type: grid
    cards:
      - type: custom:mushroom-light-card
        entity: switch.pool_menu_switch
        icon_type: icon
        name: Menu
        secondary_info: name
        layout: horizontal
        primary_info: none
        icon: mdi:menu-open
      - type: custom:mushroom-light-card
        entity: switch.pool_plus_switch
        icon_type: icon
        layout: vertical
        secondary_info: none
        icon: mdi:plus
        primary_info: none
      - type: custom:mushroom-title-card
      - type: custom:mushroom-light-card
        entity: switch.pool_left_switch
        icon_type: icon
        layout: vertical
        secondary_info: none
        icon: mdi:menu-left
        primary_info: none
      - type: custom:mushroom-light-card
        entity: switch.pool_minus_switch
        icon_type: icon
        layout: vertical
        secondary_info: none
        icon: mdi:minus
        primary_info: none
      - type: custom:mushroom-light-card
        entity: switch.pool_right_switch
        icon_type: icon
        layout: vertical
        secondary_info: none
        icon: mdi:menu-right
        primary_info: none
  - square: false
    columns: 3
    type: grid
    cards:
      - type: custom:mushroom-entity-card
        entity: binary_sensor.pool_pool_mode
        name: Pool
        tap_action:
          action: call-service
          service: switch.turn_on
          data: {}
          target:
            entity_id: switch.pool_pool_switch
        primary_info: none
        secondary_info: name
      - type: custom:mushroom-entity-card
        entity: binary_sensor.pool_heater_mode
        name: Heater
        tap_action:
          action: call-service
          service: switch.turn_on
          data: {}
          target:
            entity_id: switch.pool_heater_switch
        secondary_info: name
        primary_info: none
      - type: custom:mushroom-entity-card
        entity: binary_sensor.pool_heater_auto_mode
        name: Heater Auto
        tap_action:
          action: call-service
          service: switch.turn_on
          data: {}
          target:
            entity_id: switch.pool_heater_switch
        secondary_info: name
        primary_info: none
      - type: custom:mushroom-entity-card
        entity: binary_sensor.pool_spa_mode
        name: Spa
        tap_action:
          action: call-service
          service: switch.turn_on
          data: {}
          target:
            entity_id: switch.pool_spa_switch
        primary_info: none
        secondary_info: name
      - type: custom:mushroom-entity-card
        entity: binary_sensor.pool_blower_mode
        name: Blower
        tap_action:
          action: call-service
          service: switch.turn_on
          data: {}
          target:
            entity_id: switch.pool_blower_switch
        secondary_info: name
        primary_info: none
      - type: custom:mushroom-entity-card
        secondary_info: name
        primary_info: none
      - type: custom:mushroom-entity-card
        entity: binary_sensor.pool_filter_mode
        name: Filter
        tap_action:
          action: call-service
          service: switch.turn_on
          data: {}
          target:
            entity_id: switch.pool_filter_switch
        secondary_info: name
        primary_info: none
      - type: custom:mushroom-entity-card
        entity: binary_sensor.pool_lights_mode
        name: Lights
        tap_action:
          action: call-service
          service: switch.turn_on
          data: {}
          target:
            entity_id: switch.pool_lights_switch
        secondary_info: name
        primary_info: none

I’m using node-red to receive status, create sensors, and create switches which then turn into MQTT commands for button presses from/to the aqua logic MQTT interface. Here’s my node-red flow.

[{"id":"c704a53ed403401a","type":"tab","label":"Pool","disabled":false,"info":"","env":[]},{"id":"ee6f9c95a572c983","type":"junction","z":"c704a53ed403401a","x":520,"y":840,"wires":[["c555b498e722c912","dfe4e95db26c3b34"]]},{"id":"0b9ed40c4708e333","type":"junction","z":"c704a53ed403401a","x":40,"y":1180,"wires":[["ae35ea489576f8ac","3a338b0e7902447e","ce724bc00d066e66","ea0e4b95a09f71c2","e1b00ec3910d1e3f","1c3180f7f3f5313c","523f87eb3bb090cf","179e38dfd95028b0","8fa7d58d0b19f384","e0d8347e8c4cc962","b6e40e13bc5701c9","8524255cc8766b0d"]]},{"id":"6fe9b274fd9fec23","type":"mqtt in","z":"c704a53ed403401a","name":"","topic":"aqualogic/status/#","qos":"2","datatype":"utf8","broker":"62d4a8d7.7b1c88","nl":false,"rap":true,"rh":0,"inputs":0,"x":110,"y":220,"wires":[["587b1d5cf542a32a"]]},{"id":"5e722f82966547e4","type":"debug","z":"c704a53ed403401a","name":"debug 18","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":260,"y":120,"wires":[]},{"id":"c204d47a2b5d8d07","type":"switch","z":"c704a53ed403401a","name":"","property":"key","propertyType":"msg","rules":[{"t":"eq","v":"available","vt":"str"},{"t":"eq","v":"display","vt":"str"},{"t":"eq","v":"air_temp","vt":"str"},{"t":"eq","v":"pool_temp","vt":"str"},{"t":"eq","v":"pump_speed","vt":"str"},{"t":"eq","v":"pump_power","vt":"str"},{"t":"eq","v":"POOL","vt":"str"},{"t":"eq","v":"SPA","vt":"str"},{"t":"eq","v":"FILTER","vt":"str"},{"t":"eq","v":"HEATER_1","vt":"str"},{"t":"eq","v":"HEATER_AUTO_MODE","vt":"str"},{"t":"eq","v":"BLOWER","vt":"str"},{"t":"eq","v":"LIGHTS","vt":"str"}],"checkall":"false","repair":false,"outputs":13,"x":450,"y":220,"wires":[["22286e59905bf2e0"],["22286e59905bf2e0"],["329e5351bde42910"],["71401de35fc5d95e"],["11ab7fc17cf79c02"],["3e83276e66ee3780"],["bfd30b47a1b42817"],["0a4a962f1534cb5a"],["1abf44bcd6302bfb"],["58089d5cbb0160f5"],["29671f5272173a52"],["0eaa72c4d8302b2c"],["6062440072052c3a"]]},{"id":"587b1d5cf542a32a","type":"change","z":"c704a53ed403401a","name":"","rules":[{"t":"set","p":"key","pt":"msg","to":"$replace(topic, \"aqualogic/status/\", \"\")","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":290,"y":220,"wires":[["5e722f82966547e4","c204d47a2b5d8d07"]]},{"id":"22286e59905bf2e0","type":"ha-entity","z":"c704a53ed403401a","name":"Pool Display","server":"1777b72c.cb0709","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"Pool Display"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"","outputPayloadType":"str","x":750,"y":40,"wires":[[]]},{"id":"329e5351bde42910","type":"ha-entity","z":"c704a53ed403401a","name":"Pool Air Temperature","server":"1777b72c.cb0709","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"Pool Air Temperature"},{"property":"device_class","value":"temperature"},{"property":"icon","value":""},{"property":"unit_of_measurement","value":"°F"},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"","outputPayloadType":"str","x":780,"y":80,"wires":[[]]},{"id":"a47045e73d18696f","type":"ha-entity","z":"c704a53ed403401a","name":"Pool Water Temperature","server":"1777b72c.cb0709","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"Pool Water Temperature"},{"property":"device_class","value":"temperature"},{"property":"icon","value":""},{"property":"unit_of_measurement","value":"°F"},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"","outputPayloadType":"str","x":1390,"y":100,"wires":[[]]},{"id":"11ab7fc17cf79c02","type":"ha-entity","z":"c704a53ed403401a","name":"Pool Pump Speed","server":"1777b72c.cb0709","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"Pool Pump Speed"},{"property":"device_class","value":"power_factor"},{"property":"icon","value":""},{"property":"unit_of_measurement","value":"%"},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"","outputPayloadType":"str","x":770,"y":260,"wires":[[]]},{"id":"3e83276e66ee3780","type":"ha-entity","z":"c704a53ed403401a","name":"Pool Pump Power","server":"1777b72c.cb0709","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"Pool Pump Power"},{"property":"device_class","value":"power"},{"property":"icon","value":""},{"property":"unit_of_measurement","value":"W"},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"","outputPayloadType":"str","x":770,"y":300,"wires":[[]]},{"id":"bfd30b47a1b42817","type":"ha-entity","z":"c704a53ed403401a","name":"Pool Pool Mode","server":"1777b72c.cb0709","version":2,"debugenabled":false,"outputs":1,"entityType":"binary_sensor","config":[{"property":"name","value":"Pool Pool Mode"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"","outputPayloadType":"str","x":760,"y":360,"wires":[[]]},{"id":"0a4a962f1534cb5a","type":"ha-entity","z":"c704a53ed403401a","name":"Pool Spa Mode","server":"1777b72c.cb0709","version":2,"debugenabled":false,"outputs":1,"entityType":"binary_sensor","config":[{"property":"name","value":"Pool Spa Mode"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"","outputPayloadType":"str","x":760,"y":400,"wires":[[]]},{"id":"1abf44bcd6302bfb","type":"ha-entity","z":"c704a53ed403401a","name":"Pool Filter Mode","server":"1777b72c.cb0709","version":2,"debugenabled":false,"outputs":1,"entityType":"binary_sensor","config":[{"property":"name","value":"Pool Filter Mode"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"","outputPayloadType":"str","x":760,"y":440,"wires":[[]]},{"id":"58089d5cbb0160f5","type":"ha-entity","z":"c704a53ed403401a","name":"Pool Heater Mode","server":"1777b72c.cb0709","version":2,"debugenabled":false,"outputs":1,"entityType":"binary_sensor","config":[{"property":"name","value":"Pool Heater Mode"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"","outputPayloadType":"str","x":770,"y":520,"wires":[[]]},{"id":"71401de35fc5d95e","type":"api-current-state","z":"c704a53ed403401a","name":"","server":"1777b72c.cb0709","version":3,"outputs":2,"halt_if":"on","halt_if_type":"str","halt_if_compare":"is","entity_id":"binary_sensor.pool_filter_mode","state_type":"str","blockInputOverrides":true,"outputProperties":[],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":860,"y":140,"wires":[["a47045e73d18696f"],["e00758629ab5b0ae"]]},{"id":"e00758629ab5b0ae","type":"change","z":"c704a53ed403401a","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"offline","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1140,"y":160,"wires":[["a47045e73d18696f"]]},{"id":"ae35ea489576f8ac","type":"ha-entity","z":"c704a53ed403401a","name":"Pool Filter Switch","server":"1777b72c.cb0709","version":2,"debugenabled":false,"outputs":2,"entityType":"switch","config":[{"property":"name","value":"Pool Filter Switch"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":true,"outputPayload":"","outputPayloadType":"str","x":190,"y":740,"wires":[["a814f80c5cb4ddc3"],[]]},{"id":"3a338b0e7902447e","type":"ha-entity","z":"c704a53ed403401a","name":"Pool Pool Switch","server":"1777b72c.cb0709","version":2,"debugenabled":false,"outputs":2,"entityType":"switch","config":[{"property":"name","value":"Pool Pool Switch"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":true,"outputPayload":"","outputPayloadType":"str","x":190,"y":780,"wires":[["083068017d4d5288","fcacd26161586052"],[]]},{"id":"a814f80c5cb4ddc3","type":"change","z":"c704a53ed403401a","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"FILTER","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":400,"y":740,"wires":[["ee6f9c95a572c983"]]},{"id":"083068017d4d5288","type":"change","z":"c704a53ed403401a","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"POOL","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":400,"y":780,"wires":[["ee6f9c95a572c983"]]},{"id":"edc914744c56fddf","type":"change","z":"c704a53ed403401a","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"SPA","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":400,"y":820,"wires":[["ee6f9c95a572c983"]]},{"id":"228ee673e2912a3d","type":"change","z":"c704a53ed403401a","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"HEATER_1","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":400,"y":860,"wires":[["ee6f9c95a572c983"]]},{"id":"40e6385c5c375a6c","type":"change","z":"c704a53ed403401a","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"LIGHTS","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":400,"y":900,"wires":[["ee6f9c95a572c983"]]},{"id":"fa37afe966a5c4af","type":"change","z":"c704a53ed403401a","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"BLOWER","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":400,"y":940,"wires":[["ee6f9c95a572c983"]]},{"id":"0eaa72c4d8302b2c","type":"ha-entity","z":"c704a53ed403401a","name":"Pool Blower Mode","server":"1777b72c.cb0709","version":2,"debugenabled":false,"outputs":1,"entityType":"binary_sensor","config":[{"property":"name","value":"Pool Blower Mode"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"","outputPayloadType":"str","x":770,"y":600,"wires":[[]]},{"id":"c555b498e722c912","type":"mqtt out","z":"c704a53ed403401a","name":"","topic":"aqualogic/command","qos":"2","retain":"false","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"62d4a8d7.7b1c88","x":680,"y":840,"wires":[]},{"id":"dfe4e95db26c3b34","type":"trigger","z":"c704a53ed403401a","name":"","op1":"","op2":"","op1type":"nul","op2type":"payl","duration":"200","extend":false,"overrideDelay":false,"units":"ms","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":640,"y":1180,"wires":[["c39be751337193dc"]]},{"id":"a6e9bc02780b086a","type":"inject","z":"c704a53ed403401a","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"600","crontab":"","once":true,"onceDelay":"120","topic":"","payload":"","payloadType":"date","x":470,"y":1180,"wires":[["dfe4e95db26c3b34"]]},{"id":"c39be751337193dc","type":"change","z":"c704a53ed403401a","name":"","rules":[{"t":"set","p":"enable","pt":"msg","to":"false","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":820,"y":1180,"wires":[["0b9ed40c4708e333"]]},{"id":"6062440072052c3a","type":"ha-entity","z":"c704a53ed403401a","name":"Pool Lights Mode","server":"1777b72c.cb0709","version":2,"debugenabled":false,"outputs":1,"entityType":"binary_sensor","config":[{"property":"name","value":"Pool Lights Mode"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"","outputPayloadType":"str","x":770,"y":660,"wires":[[]]},{"id":"ce724bc00d066e66","type":"debug","z":"c704a53ed403401a","name":"debug 19","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":160,"y":1180,"wires":[]},{"id":"fcacd26161586052","type":"debug","z":"c704a53ed403401a","name":"debug 20","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":360,"y":700,"wires":[]},{"id":"ea0e4b95a09f71c2","type":"ha-entity","z":"c704a53ed403401a","name":"Pool Spa Switch","server":"1777b72c.cb0709","version":2,"debugenabled":false,"outputs":2,"entityType":"switch","config":[{"property":"name","value":"Pool Spa Switch"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":true,"outputPayload":"","outputPayloadType":"str","x":180,"y":820,"wires":[["edc914744c56fddf"],[]]},{"id":"e1b00ec3910d1e3f","type":"ha-entity","z":"c704a53ed403401a","name":"Pool Heater Switch","server":"1777b72c.cb0709","version":2,"debugenabled":false,"outputs":2,"entityType":"switch","config":[{"property":"name","value":"Pool Heater Switch"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":true,"outputPayload":"","outputPayloadType":"str","x":190,"y":860,"wires":[["228ee673e2912a3d"],[]]},{"id":"1c3180f7f3f5313c","type":"ha-entity","z":"c704a53ed403401a","name":"Pool Lights Switch","server":"1777b72c.cb0709","version":2,"debugenabled":false,"outputs":2,"entityType":"switch","config":[{"property":"name","value":"Pool Lights Switch"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":true,"outputPayload":"","outputPayloadType":"str","x":190,"y":900,"wires":[["40e6385c5c375a6c"],[]]},{"id":"523f87eb3bb090cf","type":"ha-entity","z":"c704a53ed403401a","name":"Pool Blower Switch","server":"1777b72c.cb0709","version":2,"debugenabled":false,"outputs":2,"entityType":"switch","config":[{"property":"name","value":"Pool Blower Switch"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":true,"outputPayload":"","outputPayloadType":"str","x":190,"y":940,"wires":[["fa37afe966a5c4af"],[]]},{"id":"179e38dfd95028b0","type":"ha-entity","z":"c704a53ed403401a","name":"Pool Menu Switch","server":"1777b72c.cb0709","version":2,"debugenabled":false,"outputs":2,"entityType":"switch","config":[{"property":"name","value":"Pool Menu Switch"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":true,"outputPayload":"","outputPayloadType":"str","x":190,"y":980,"wires":[["25cb496fe9eab358"],[]]},{"id":"25cb496fe9eab358","type":"change","z":"c704a53ed403401a","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"MENU","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":400,"y":980,"wires":[["ee6f9c95a572c983"]]},{"id":"8fa7d58d0b19f384","type":"ha-entity","z":"c704a53ed403401a","name":"Pool Left Switch","server":"1777b72c.cb0709","version":2,"debugenabled":false,"outputs":2,"entityType":"switch","config":[{"property":"name","value":"Pool Left Switch"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":true,"outputPayload":"","outputPayloadType":"str","x":180,"y":1020,"wires":[["77edf18b8c78fb81"],[]]},{"id":"77edf18b8c78fb81","type":"change","z":"c704a53ed403401a","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"LEFT","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":400,"y":1020,"wires":[["ee6f9c95a572c983"]]},{"id":"e0d8347e8c4cc962","type":"ha-entity","z":"c704a53ed403401a","name":"Pool Right Switch","server":"1777b72c.cb0709","version":2,"debugenabled":false,"outputs":2,"entityType":"switch","config":[{"property":"name","value":"Pool Right Switch"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":true,"outputPayload":"","outputPayloadType":"str","x":190,"y":1060,"wires":[["63a95269e4b13ee6"],[]]},{"id":"63a95269e4b13ee6","type":"change","z":"c704a53ed403401a","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"RIGHT","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":400,"y":1060,"wires":[["ee6f9c95a572c983"]]},{"id":"b6e40e13bc5701c9","type":"ha-entity","z":"c704a53ed403401a","name":"Pool Minus Switch","server":"1777b72c.cb0709","version":2,"debugenabled":false,"outputs":2,"entityType":"switch","config":[{"property":"name","value":"Pool Minus Switch"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":true,"outputPayload":"","outputPayloadType":"str","x":190,"y":1100,"wires":[["ae86948d3f9f0551"],[]]},{"id":"ae86948d3f9f0551","type":"change","z":"c704a53ed403401a","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"MINUS","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":400,"y":1100,"wires":[["ee6f9c95a572c983"]]},{"id":"8524255cc8766b0d","type":"ha-entity","z":"c704a53ed403401a","name":"Pool Plus Switch","server":"1777b72c.cb0709","version":2,"debugenabled":false,"outputs":2,"entityType":"switch","config":[{"property":"name","value":"Pool Plus Switch"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":true,"outputPayload":"","outputPayloadType":"str","x":190,"y":1140,"wires":[["1d2de971866ed5b6"],[]]},{"id":"1d2de971866ed5b6","type":"change","z":"c704a53ed403401a","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"PLUS","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":400,"y":1140,"wires":[["ee6f9c95a572c983"]]},{"id":"29671f5272173a52","type":"ha-entity","z":"c704a53ed403401a","name":"Pool Heater Auto Mode","server":"1777b72c.cb0709","version":2,"debugenabled":false,"outputs":1,"entityType":"binary_sensor","config":[{"property":"name","value":"Pool Heater Auto Mode"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"","outputPayloadType":"str","x":790,"y":560,"wires":[[]]},{"id":"62d4a8d7.7b1c88","type":"mqtt-broker","name":"","broker":"10.0.1.29","port":"8883","tls":"8f64fdf5.552818","clientid":"","autoConnect":true,"usetls":true,"protocolVersion":"4","keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthRetain":"false","birthPayload":"","birthMsg":{},"closeTopic":"","closeQos":"0","closeRetain":"false","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willRetain":"false","willPayload":"","willMsg":{},"sessionExpiry":""},{"id":"1777b72c.cb0709","type":"server","name":"Home Assistant","version":2,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30},{"id":"8f64fdf5.552818","type":"tls-config","name":"home ca","cert":"","key":"","ca":"/ssl/tendot_certs/tendot_ca.crt","certname":"","keyname":"","caname":"ca.crt","servername":"","verifyservercert":false}]

This may be completely useless to you, so sorry in advance :grinning_face_with_smiling_eyes:

  • Benjamin

I am looking for input on how you are or will be using the integration to the pool from HA?

I have created custom component that integrates to Dryden da-gen pool controllers and maybe more Hayden controllers. It uses the backend services for this site:Domotic for swimmingpools

For now it shows the following values and enables switching on/off the pool light:

I can’t believe I missed this. Thank you!!

One issue though, I tried adding AUX2 as a switch and it does not keep its state in HASS, it’ll immediately reset to an off position, even though it successfully turned on AUX2. Any suggestions @amscanne?

Hi all, I know this issue has been discussed a few times already in this thread but after reading the entire thing a number of times I’m still having some trouble. I am up to the software troubleshooting stage in that everything is connected and I am getting usable data in HA. Initially, I followed the steps to set up the default HomeAssistant/aqualogic integration. However, after getting everything set up I am only getting a few sensor readings showing up and am unable to effectively control any of the switches via HA. Upon reading some of the above posts I also created a custom configuration folder under config and git cloned the 3.3 version of the integration via SSH. (Not sure what exactly I have to do in order to make HA use this version over the one that ships with HA or if it’s even the same version). Anyway, nothing changed after that. Using the hex codes some people have provided above I am able to turn switches on and off using the USR IoT Test Software but it takes many attempts to go through (I guess normal from what I’ve read). I’m not getting any errors in the HA log when I try to toggle the switches there, they just revert shortly after pressing. And yes the switch status updates immediately in HA once it goes through either using the Hayward Remote or the USR test software. What can I do to troubleshoot these switches not working as well as the sensor data that isn’t showing?

Thanks for any help and Merry Christmas!

As a follow-up to this. I have figured out how to enable logging and can see the attempts from HA to send commands to the pool. When I toggle the Aux 1 switch I see the following in logs.


Thus the code that HA is trying to send is 10 02 00 02 00 02 00 02 00 18 10 03. However, In my testing with the USR-TCP232 Test software, the code that seems to work is 10 02 00 02 00 02 00 00 00 02 00 00 00 18 10 03. So it seems that my controller needs to see those extra 00 in the command. I have read that this is the case for some others but I am unsure how to adjust the code of AquaLogic to compensate for this and additionally where exactly it can be modified. Some people had mentioned possibly adjusting what I have highlighted below to 4 instead of 2 but that didn’t seem to change anything for me and the logs show that the same command format is sent. How can I verify that HA is using this custom configuration rather than the baked-in one?

Thanks again!

Here is the screenshot of my attempt at editing core.py I mentioned above.

Did you get it working?

If not yet, this is what worked for my system, though note I’m using a wired connection, not WiFI.

    def _get_key_event_frame(self, key):
        frame = bytearray()
        frame.append(self.FRAME_DLE)
        frame.append(self.FRAME_STX)

        if key.value > 0xffff:
            self._append_data(frame, self.FRAME_TYPE_WIRELESS_KEY_EVENT)
            self._append_data(frame, b'\x01')
            self._append_data(frame, key.value.to_bytes(4, byteorder='little'))
            self._append_data(frame, key.value.to_bytes(4, byteorder='little'))
            self._append_data(frame, b'\x00')
        else:
            # self._append_data(frame, self.FRAME_TYPE_LOCAL_WIRED_KEY_EVENT)
            self._append_data(frame, self.FRAME_TYPE_REMOTE_WIRED_KEY_EVENT)
            self._append_data(frame, key.value.to_bytes(2, byteorder='little'))
            self._append_data(frame, b'\x00')
            self._append_data(frame, b'\x00')
            self._append_data(frame, key.value.to_bytes(2, byteorder='little'))
            self._append_data(frame, b'\x00')
            self._append_data(frame, b'\x00')

(I suspect the double self._append_data(frame, b’\x00’) could be written better, I’m straining my limits of Python here)

Unfortunately, nothing changed for me. I removed the def _get_key_event_frame block in the existing core.py and implemented your code in place but it seems the same command format is being sent. Was there anything you had to do in order to know that HA was using your custom integration over the base one or will any custom config override a built-in one? Just for reference, here is how I’m able to get the command to go through in testing, with send as hex checked on the USR Test software.


If I spam the send button with this method the command eventually takes, and again this is using the first code and HA is sending the second one.

10 02 00 02 00 02 00 00 00 02 00 00 00 18 10 03
10 02 00 02 00 02 00 02 00 18 10 03

I’m not super knowledgeable in hex or python but I feel like it should be possible to modify something to get the format correct for my system.

Thanks again for all your help here!

Actually, I am now realizing that my issues are stemming from HA not using the custom_components version of AquaLogic that I have created. Can anyone provide some insight on how you were able setup your custom component? Using SFTP I created the custom_components folder. From the swilson GitHub I selected Code → Dowload ZIP extracted the files and placed them within the custom_components folder. From my research I learned that HA needs a manifest.json to load the custom component so I created my own but now I get errors in the logs about loading switches and sensors (Do I need to create a switches.py and sensors.py) Heres what the folder setup looks like.

And my manifest.json has the following
{
“domain”: “aqualogic”,
“name”: “AquaLogic”,
“documentation”: “AquaLogic - Home Assistant”,
“requirements”: [],
“codeowners”: [],
“version”: “1.0”,
“iot_class”: “local_push”,
“loggers”: [“aqualogic”]
}

Can anyone using a custom implementation of this please share their file structure or explain what was needed to properly enable it?

I’m of the understanding that where things reside varies by the implementation method used for Home Assistant. I’m running HASS OS in a VirtualBox VM, and my custom AquaLogic code is located as follows:

config/
  custom_components/
    aqualogic/
	  __init__.py
	  core.py
	  keys.py
	  manifest.json
	  sensor.py
      states.py
      switch.py

I started with the latest default code I could find in a Home Assistant development install (as of spring 2022) – that is, I didn’t pull it from any git repository – and went from there.

Nothing needed be done for the custom code to be picked up, I believe it gets used by virtue of the right stuff being in the right place.

Thank you for that. However, I’m still not able to get the code format to change despite multiple attempts to edit core.py. Using your edits and some others suggested above the code that is sent is still the same according to the debug logger. I am wondering if you enable the logger does your system report that it’s sending the longer code? This is what my log looks like when I try to trigger the Aux_1 switch.


Are the unknown frame messages something I need to deal with as well or they can be ignored? And lastly, would you or anyone else here be willing to share your core.py file in it’s entirety? I’ve been trying to learn python this past week and still haven’t had any luck trying to get the chains to move.

Yes, the unknown frame messages are a nuisance, they can be ignored.

It looks like your debugger might be set to “info”, as that’s all your screen shot is showing. If you haven’t tried “debug” for the aqualogic integration, please do, as it may reveal some additional useful detail.

I’ve DM’d you through the forum with a link to my aqualogic code. As shown above in posting #327, I had added additional “self._append_data(frame, b’\x00’)” to pad out the frame message to the format the ProLogic integration required.

Hello. I have similar board as shown in post 175 by sj777fj for my Hayward and used those images as a guide for the hardware and wiring setup, but am having trouble making this work. Here is the hardware I used:

ESP8266 ESP-01 Serial/WiFi transeiver
https://www.amazon.com/dp/B010N1ROQS?psc=1&ref=ppx_yo2ov_dt_b_product_details

TTL to RS485 adapter
https://www.amazon.com/dp/B08ZNF55V9?psc=1&ref=ppx_yo2ov_dt_b_product_details

LM2596 Buck Converter
–new user link limitation–

I think my issue is the ESP is not sending the serial data. This is my first attempt at using one of these modules and to be honest don’t really know what I’m doing. I did upload a sketch with the Arduino IDE based on the built in WiFiTelnetToSerial example. Google has not been friendly and it’s the closest thing I can find that looks to do what I need it to. I do have the module connected to my network and can ping with a response and connect via putty over telnet. If someone has a sketch they’ve used successfully or a link to a detailed guide, that would be awesome. Thanks in advance.

Also, if someone could point me to a debugging tool so I can at least see the packets being sent (if any) from the ESP module, that would be a plus.

As for HA, I added the integration in the config.yaml file and while the sensors are exposed, they are all in an unknown state. The following error pops in the log every 10 seconds.

Logger: homeassistant.components.aqualogic
Source: components/aqualogic/init.py:90
Integration: AquaLogic
First occurred: 4:42:41 PM (46 occurrences)
Last logged: 4:53:59 PM

Connection to 10.0.7.167:4328 lost

I’m more of a software guy than hardware, but my python is rusty. If I’m reading the init code right, there’s no data received, so it doesn’t break the loop and tries again. Is that correct?

Any help is greatly appreciated! Let me know if any other info is needed.

Adam

Did some more digging and found others using ESP-Link. So I flashed that and am seeing data come over in the microcontroller console (screen shot below). Some plain text, e.g. pool temp, air temp, etc., some garbled. I can also putty to the IP port 23 over telnet and get the same data. I plugged in my IP and port 23 into my HA config, but I’m getting an error that the host is unreachable. I’m assuming it’s the wrong port, but I am not sure what it would be (don’t see it in ESP-Link web page). Any ideas?

Uncaught thread exception
Traceback (most recent call last):
File “/usr/local/lib/python3.10/threading.py”, line 1016, in _bootstrap_inner
self.run()
File “/usr/src/homeassistant/homeassistant/components/aqualogic/init.py”, line 84, in run
panel.connect(self._host, self._port)
File “/usr/local/lib/python3.10/site-packages/aqualogic/core.py”, line 130, in connect
self.connect_socket(host, port)
File “/usr/local/lib/python3.10/site-packages/aqualogic/core.py”, line 135, in connect_socket
self._socket.connect((host, port))
OSError: [Errno 113] Host is unreachable

Adam

OK, I’m up and running. Rebooted my network and port 23 started working. Sometimes it just helps to get the issue out in the open. While there were no responses to my posts (relatively short timeframe), I’d like to thank everyone in this thread. This is great!

Adam

1 Like