Well, after a lot of review and a conversation with China, V 1.5 does support scripts. Their just isn’t an easy way to verify they are there. After a wipe and a clean setup, all is working fine. Also have IOS app running as well but likely not need since HA does everything. Thanks for the response.
I implemented my first RS-485 integration today using the Waveshare ESP32-S3-RS485-CAN to integrate with my Hayward Pro Logic (V2.85 firmware). I decided to use the arjeousski/esphome_aqualogic package as it offers me configuration flexibility over the built-in aqualogic package.
I wanted to share my experience in case it helps somebody in the future, and take this opportunity to thank the folks who are responsible for making it so easy for us to monitor our pool controllers through Home Assistant.
I changed the default esphome_aqualogic waterfall nomenclature to solar (my valve 3 is for pool solar), and commented out the spa and heater sensors because I don’t use them. I changed the GPIO pins to match the Waveshare configuration, and set the baud rate for Hayward.
When I compiled the code, I received an error regarding Arduino.h and realized that @AndreiR wasn’t running on the esp-idf framework. I changed the framework setting to arduino, then after I recompiled I received an error for ArduinoJson. A quick bit of Googling led me to having to explicitly import the ArduinoJson package. This gave me a successful build. There were a handful of compilation warnings from the esphome_aqualogic code, but none of them fatal.
I did an initial test by wiring the J2 BLK and YEL pins of the Hayward circuit board to the the A+ and B- pins on the Waveshare, and using a USB-C power supply, and it worked first time. Turn off the breakers before you do the wiring, then power up when you’ve checked your wiring.
I then disconnected the USB-C power, wired the RED and GRN lines from the Hayward board to the VCC and GND pins on the Waveshare so that the device is powered directly from the pool controller. I put the Waveshare device in a waterproof case, and I’m up and running. Again, remember to turn off the breakers before you do this step.
My only issue is that the menu button doesn’t appear to be working, but I rarely change my system configuration, so it’s not a huge issue. Perhaps there’s something I’m missing in the dashboard configuration. If @AndreiR could possibly comment, I’d appreciate it.
I then added a Left Reimann integral helper to track cumulative energy use from the pump within the energy dashboard.
For those interested in my configuration, the key parts are as follows; the rest of the configuration (minus my personal tweaks) is directly from the esphome_aqualogic package:
esphome:
...
# Inject the missing library dependency directly into the component
libraries:
- bblanchon/ArduinoJson
# Settings for this Waveshare device
esp32:
board: esp32-s3-devkitc-1
variant: esp32s3
framework:
type: arduino
# Hardware configuration optimized for the Waveshare ESP32-S3-RS485-CAN
# and baud rate settings for Hayward Pro Logic
uart:
- id: prologic_uart
tx_pin: GPIO17
rx_pin: GPIO18
flow_control_pin: GPIO21
baud_rate: 19200
data_bits: 8
parity: NONE
stop_bits: 2
aqualogic:
uart_id: prologic_uart
One more thing. When @AndreiR mentions the ‘Available States’ in his README.md, it is not clear what he means by ‘Internal State’, nor provides an example of how to expose the state. For example, I use Aux 1 to enable super chlorination. I was able to expose the button, but not the state.
# Emulate buttons/controls
button:
- platform: template
name: "Aux 1"
on_press:
- aqualogic.send:
key: AUX_1
After wracking my brain, I used a helper template binary_sensor linked to the flags entity, and associated it with the pool controller device. The flags field is a string that contains all of the currently enabled states, so all I do is look for the presence of the state I’m looking for:
Aux 1 Helper: {{ 'AUX_1' in states('sensor.hayward_pro_logic_flags') }}
Aux 2 Helper: {{ 'AUX_2' in states('sensor.hayward_pro_logic_flags') }}
Super Chlorinate Helper: {{ 'SUPER_CHLORINATE' in states('sensor.hayward_pro_logic_flags') }}
I now have full control and visibility to my pool state.
@b3nj1 I decided to try switching from the @AndreiR implementation to yours for comparison, and to see if the menu button works.
My system: Goldline Aqua Plus; Main SW 2.85; Display 3.11; Filter Bridge r2.15; VSC r2.00; Motherboard: GLX-PCB-MAIN
Interface is ESP32-S3-RS485-CAN powered by pins 1 & 4.
Findings:
Menu button does not react, similar to @AndreiR implementation.
Left and right buttons work causing display to move to next item
Display partially works: Filter Speed; date/time
See attached screenshot for display issues: Air temp, Pool temp, etc. are being truncated, and therefore the sensors for pool, and air temperature are not functional. The values are actually lower case, but HA is upper-casing the first letter automatically.
It looks like bus.yaml:176 is not always working - at least for this firmware revision. The first character is lost, causing the downstream sensor to fail. There has to be another piece of logic missing with the assumption:
// Text starts immediately at payload[2] -- no header byte before it
// (decode_variations.md §5.1: "no fixed header before the text")."
Looking at the @swilson implementation of the text sensor, and @AndreiR, they are taking the entire text payload after the frame type and trimming it, versus making assumptions about the start byte of the text. Perhaps you’re on a more modern version of the firmware and Hayward have changed their methodology?
Let me know if there’s anything else I can help you with.
@mrmoorey ,
Thanks for giving mine a try. I’m glad I didn’t break the main version (I have a side feature that tries to count if commands fail to land that I accidentally checked part of to the main branch).
Anyway, if you’re game, we can try to debug. My package has a packet sniffer. We should be able to see what your main controller and/or OEM wireless controller sends out for MENU. We should also be able to see what your display payloads look like.
- Add this to your ESPHome configuration for your device. Just add it to the end. It will enable a periodic summary (30 seconds interval set by the yaml below) of the messages seen on your bus.
rs485_frame:
- id: !extend pool
dump_frames: false
sniffer_stats: { interval: 30s, max_frame_types: 64, payload_dump_top: 20 }
- Install it, and keep the logs running in the ESPHome console. But turn off the “States” because they can be noisy.
- Press your main controller and/or OEM wireless controller’s MENU button. You can press it a few times.
Here’s what I get in my log so you know what we’re looking for. Here I show 1. a period where I pressed nothing. 2. a period where I pressed MENU on my wireless controller 7 times. I annotated the output with ### comment ###.
If you try this, please share your output. We can add some details to the configuration examples with what we learn from your system.
###### IDLE Period output ####
[11:55:59.206][I][rs485_frame.stats:232]: RS485 sniffer stats over 30000 ms (sorted by count):
[11:55:59.211][I][rs485_frame.stats:237]: type cnt d-ref(min/med/max) d-same(min/med/max) payloads
[11:55:59.211][I][rs485_frame.stats:272]: 0101 300 - - - 95 100 117 1 unique
[11:55:59.211][I][rs485_frame.stats:272]: 0103 20 73 83 92 90 1992 2016 5 unique
[11:55:59.211][I][rs485_frame.stats:272]: 0C01 15 28 32 33 1997 2000 2013 1 unique
[11:55:59.215][I][rs485_frame.stats:272]: 000C 15 37 37 38 1997 2000 2017 2 unique
[11:55:59.219][I][rs485_frame.stats:272]: 0102 15 53 53 53 1999 2000 2017 1 unique
[11:55:59.219][I][rs485_frame.stats:272]: 0004 3 34 34 36 98 102 102 3 unique
[11:55:59.219][I][rs485_frame.stats:272]: 0407 1 32 32 32 - - - 1 unique
[11:55:59.222][I][rs485_frame.stats:272]: 04A0 1 32 32 32 - - - 1 unique
[11:55:59.222][I][rs485_frame.stats:272]: 04AE 1 32 32 32 - - - 1 unique
[11:55:59.222][I][rs485_frame.stats:307]: 0101 payloads:
[11:55:59.235][I][rs485_frame.stats:318]: 300 @ 01 01 |..|
[11:55:59.236][I][rs485_frame.stats:307]: 0103 payloads:
[11:55:59.236][I][rs485_frame.stats:318]: 4 @ 01 03 20 20 20 20 46 69 6C 74 65 72 20 53 70 65 65 64 20 20 20 20 20 20 20 33 35 25 20 53 70 65 |.. Filter Speed 35% Spe|
[11:55:59.236][I][rs485_frame.stats:318]: 4 @ 01 03 20 20 20 20 20 20 53 61 74 75 72 64 61 79 20 20 20 20 20 20 20 20 20 20 20 20 20 31 31 BA |.. Saturday 11.|
[11:55:59.236][I][rs485_frame.stats:318]: 4 @ 01 03 20 20 50 6F 6F 6C 20 54 65 6D 70 20 20 37 39 5F 46 20 20 20 20 20 20 20 20 20 20 20 20 20 |.. Pool Temp 79_F |
[11:55:59.236][I][rs485_frame.stats:318]: 4 @ 01 03 20 20 41 69 72 20 54 65 6D 70 20 20 20 38 31 5F 46 20 20 20 20 20 20 20 20 20 20 20 20 20 |.. Air Temp 81_F |
[11:55:59.236][I][rs485_frame.stats:318]: 4 @ 01 03 20 20 20 20 20 20 48 65 61 74 65 72 31 20 20 20 20 20 20 20 20 20 20 20 20 4D 61 6E 75 61 |.. Heater1 Manua|
[11:55:59.236][I][rs485_frame.stats:307]: 0C01 payloads:
[11:55:59.236][I][rs485_frame.stats:318]: 15 @ 0C 01 00 23 |...#|
[11:55:59.236][I][rs485_frame.stats:307]: 000C payloads:
[11:55:59.236][I][rs485_frame.stats:318]: 3 @ 00 0C 00 00 23 01 20 |....#. |
[11:55:59.236][I][rs485_frame.stats:318]: 12 @ 00 0C 00 00 23 01 14 |....#..|
[11:55:59.236][I][rs485_frame.stats:307]: 0102 payloads:
[11:55:59.236][I][rs485_frame.stats:318]: 15 @ 01 02 28 00 00 00 00 00 00 00 |..(.......|
[11:55:59.237][I][rs485_frame.stats:307]: 0004 payloads:
[11:55:59.237][I][rs485_frame.stats:318]: 1 @ 00 04 02 |...|
[11:55:59.237][I][rs485_frame.stats:318]: 1 @ 00 04 30 33 30 30 20 |..0300 |
[11:55:59.238][I][rs485_frame.stats:318]: 1 @ 00 04 CC 6D |...m|
[11:55:59.238][I][rs485_frame.stats:307]: 0407 payloads:
[11:55:59.238][I][rs485_frame.stats:318]: 1 @ 04 07 |..|
[11:55:59.238][I][rs485_frame.stats:307]: 04A0 payloads:
[11:55:59.242][I][rs485_frame.stats:318]: 1 @ 04 A0 |..|
[11:55:59.245][I][rs485_frame.stats:307]: 04AE payloads:
[11:55:59.250][I][rs485_frame.stats:318]: 1 @ 04 AE |..|
##### MENU 7 times output #####
[11:51:37.247][I][rs485_frame.stats:232]: RS485 sniffer stats over 30014 ms (sorted by count):
[11:51:37.248][I][rs485_frame.stats:237]: type cnt d-ref(min/med/max) d-same(min/med/max) payloads
[11:51:37.248][I][rs485_frame.stats:272]: 0101 300 - - - 67 100 134 1 unique
[11:51:37.253][I][rs485_frame.stats:272]: 0103 22 104 119 120 314 2000 2001 5 unique
[11:51:37.253][I][rs485_frame.stats:272]: 040A 22 75 82 82 306 2000 2001 9 unique
[11:51:37.253][I][rs485_frame.stats:272]: 0C01 15 29 32 33 1984 2000 2017 1 unique
[11:51:37.253][I][rs485_frame.stats:272]: 000C 15 37 37 39 1983 2000 2018 2 unique
[11:51:37.256][I][rs485_frame.stats:272]: 0102 15 90 90 91 1999 2000 2001 1 unique
[11:51:37.259][I][rs485_frame.stats:272]: 0083 7 6 7 7 800 1016 16098 1 unique
[11:51:37.262][I][rs485_frame.stats:272]: 0004 3 34 34 36 69 98 98 3 unique
[11:51:37.264][I][rs485_frame.stats:272]: 0407 1 32 32 32 - - - 1 unique
[11:51:37.267][I][rs485_frame.stats:272]: 04A0 1 32 32 32 - - - 1 unique
[11:51:37.270][I][rs485_frame.stats:272]: 04AE 1 32 32 32 - - - 1 unique
[11:51:37.273][I][rs485_frame.stats:307]: 0101 payloads:
[11:51:37.285][I][rs485_frame.stats:318]: 300 @ 01 01 |..|
#### Here we can see the detailed HEX and the associated ASCII text for the display payloads ####
[11:51:37.285][I][rs485_frame.stats:307]: 0103 payloads:
[11:51:37.285][I][rs485_frame.stats:318]: 4 @ 01 03 20 20 20 20 20 44 69 61 67 6E 6F 73 74 69 63 20 20 20 20 20 20 20 20 20 20 20 20 20 4D 65 |.. Diagnostic Me|
[11:51:37.285][I][rs485_frame.stats:318]: 6 @ 01 03 20 20 20 43 6F 6E 66 69 67 75 72 61 74 69 6F 6E 20 20 20 20 20 20 20 4D 65 6E 75 2D 4C 6F |.. Configuration Menu-Lo|
[11:51:37.285][I][rs485_frame.stats:318]: 2 @ 01 03 20 20 20 20 20 20 44 65 66 61 75 6C 74 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 4D 65 |.. Default Me|
[11:51:37.286][I][rs485_frame.stats:318]: 9 @ 01 03 20 20 20 20 20 20 53 65 74 74 69 6E 67 73 20 20 20 20 20 20 20 20 20 20 20 20 20 20 4D 65 |.. Settings Me|
[11:51:37.286][I][rs485_frame.stats:318]: 1 @ 01 03 20 20 20 20 20 20 20 54 69 6D 65 72 73 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 4D 65 |.. Timers Me|
[11:51:37.286][I][rs485_frame.stats:307]: 040A payloads:
[11:51:37.286][I][rs485_frame.stats:318]: 2 @ 04 0A 83 00 03 20 20 20 20 20 44 69 61 67 6E 6F 73 74 69 63 20 20 20 20 20 20 20 20 20 20 20 20 |..... Diagnostic |
[11:51:37.287][I][rs485_frame.stats:318]: 2 @ 04 0A 83 00 02 28 00 00 00 00 00 00 00 03 20 20 20 20 20 44 69 61 67 6E 6F 73 74 69 63 20 20 20 |.....(........ Diagnostic |
[11:51:37.287][I][rs485_frame.stats:318]: 2 @ 04 0A 83 00 03 20 20 20 43 6F 6E 66 69 67 75 72 61 74 69 6F 6E 20 20 20 20 20 20 20 4D 65 6E 75 |..... Configuration Menu|
[11:51:37.287][I][rs485_frame.stats:318]: 1 @ 04 0A 83 00 03 20 20 20 20 20 20 44 65 66 61 75 6C 74 20 20 20 20 20 20 20 20 20 20 20 20 20 20 |..... Default |
[11:51:37.287][I][rs485_frame.stats:318]: 1 @ 04 0A 83 00 02 28 00 00 00 00 00 00 00 03 20 20 20 20 20 20 44 65 66 61 75 6C 74 20 20 20 20 20 |.....(........ Default |
[11:51:37.293][I][rs485_frame.stats:318]: 1 @ 04 0A 83 00 03 20 20 20 20 20 20 53 65 74 74 69 6E 67 73 20 20 20 20 20 20 20 20 20 20 20 20 20 |..... Settings |
[11:51:37.293][I][rs485_frame.stats:318]: 8 @ 04 0A 83 00 02 28 00 00 00 00 00 00 00 03 20 20 20 20 20 20 53 65 74 74 69 6E 67 73 20 20 20 20 |.....(........ Settings |
[11:51:37.293][I][rs485_frame.stats:318]: 1 @ 04 0A 83 00 03 20 20 20 20 20 20 20 54 69 6D 65 72 73 20 20 20 20 20 20 20 20 20 20 20 20 20 20 |..... Timers |
[11:51:37.293][I][rs485_frame.stats:318]: 4 @ 04 0A 83 00 02 28 00 00 00 00 00 00 00 03 20 20 20 43 6F 6E 66 69 67 75 72 61 74 69 6F 6E 20 20 |.....(........ Configuration |
[11:51:37.295][I][rs485_frame.stats:307]: 0C01 payloads:
[11:51:37.295][I][rs485_frame.stats:318]: 15 @ 0C 01 00 23 |...#|
[11:51:37.296][I][rs485_frame.stats:307]: 000C payloads:
[11:51:37.298][I][rs485_frame.stats:318]: 13 @ 00 0C 00 00 23 01 14 |....#..|
[11:51:37.301][I][rs485_frame.stats:318]: 2 @ 00 0C 00 00 23 01 20 |....#. |
[11:51:37.304][I][rs485_frame.stats:307]: 0102 payloads:
[11:51:37.304][I][rs485_frame.stats:318]: 15 @ 01 02 28 00 00 00 00 00 00 00 |..(.......|
#### Here we can see the 7 MENU presses. My menu config in the yaml matches this: vars: { button_name: "Menu", button_command: [0x02000000, 0x02000000] } ####
[11:51:37.306][I][rs485_frame.stats:307]: 0083 payloads:
[11:51:37.309][I][rs485_frame.stats:318]: 7 @ 00 83 01 02 00 00 00 02 00 00 00 DB |............|
[11:51:37.312][I][rs485_frame.stats:307]: 0004 payloads:
[11:51:37.315][I][rs485_frame.stats:318]: 1 @ 00 04 02 |...|
[11:51:37.318][I][rs485_frame.stats:318]: 1 @ 00 04 30 33 30 30 20 |..0300 |
[11:51:37.327][I][rs485_frame.stats:318]: 1 @ 00 04 CC 6D |...m|
[11:51:37.327][I][rs485_frame.stats:307]: 0407 payloads:
[11:51:37.327][I][rs485_frame.stats:318]: 1 @ 04 07 |..|
[11:51:37.327][I][rs485_frame.stats:307]: 04A0 payloads:
[11:51:37.327][I][rs485_frame.stats:318]: 1 @ 04 A0 |..|
[11:51:37.327][I][rs485_frame.stats:307]: 04AE payloads:
[11:51:37.327][I][rs485_frame.stats:318]: 1 @ 04 AE |..|
Thanks for getting back to me so quickly. I’ve added the sniffer, and here’s the output you requested. Cycled the menus a couple of times. Thanks in advance.
[12:35:31.559][I][rs485_frame.stats:232]: RS485 sniffer stats over 30015 ms (sorted by count):
[12:35:31.564][I][rs485_frame.stats:237]: type cnt d-ref(min/med/max) d-same(min/med/max) payloads
[12:35:31.564][I][rs485_frame.stats:272]: 0101 300 - - - 64 100 116 1 unique
[12:35:31.564][I][rs485_frame.stats:272]: 0102 60 28 40 65 467 500 541 2 unique
[12:35:31.572][I][rs485_frame.stats:272]: 0103 33 44 58 89 282 690 2021 11 unique
[12:35:31.573][I][rs485_frame.stats:272]: 0002 22 3 3 4 99 700 1000 2 unique
[12:35:31.573][I][rs485_frame.stats:272]: 0C01 15 20 31 32 1992 2000 2016 1 unique
[12:35:31.573][I][rs485_frame.stats:272]: 000C 15 25 37 38 1992 2000 2017 5 unique
[12:35:31.580][I][rs485_frame.stats:272]: 0407 1 28 28 28 - - - 1 unique
[12:35:31.580][I][rs485_frame.stats:307]: 0101 payloads:
[12:35:31.580][I][rs485_frame.stats:318]: 300 @ 01 01 |..|
[12:35:31.586][I][rs485_frame.stats:307]: 0102 payloads:
[12:35:31.590][I][rs485_frame.stats:318]: 30 @ 01 02 2E 00 00 00 20 00 00 00 |...... ...|
[12:35:31.590][I][rs485_frame.stats:318]: 30 @ 01 02 0E 00 00 00 20 00 00 00 |...... ...|
[12:35:31.590][I][rs485_frame.stats:307]: 0103 payloads:
[12:35:31.591][I][rs485_frame.stats:318]: 4 @ 01 03 20 20 20 20 53 61 74 75 72 64 61 79 20 20 20 20 20 20 20 20 20 31 32 3A 33 34 50 20 20 20 |.. Saturday 12:34P |
[12:35:31.595][I][rs485_frame.stats:318]: 4 @ 01 03 20 20 20 20 53 61 74 75 72 64 61 79 20 20 20 20 20 20 20 20 20 31 32 20 33 34 50 20 20 20 |.. Saturday 12 34P |
[12:35:31.598][I][rs485_frame.stats:318]: 2 @ 01 03 50 6F 6F 6C 20 54 65 6D 70 20 20 38 39 DF 46 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 |..Pool Temp 89.F |
[12:35:31.603][I][rs485_frame.stats:318]: 2 @ 01 03 41 69 72 20 54 65 6D 70 20 20 31 30 33 DF 46 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 |..Air Temp 103.F |
[12:35:31.604][I][rs485_frame.stats:318]: 2 @ 01 03 50 6F 6F 6C 20 43 68 6C 6F 72 69 6E 61 74 6F 72 20 20 20 20 20 20 34 30 25 20 20 20 20 20 |..Pool Chlorinator 40% |
[12:35:31.610][I][rs485_frame.stats:318]: 2 @ 01 03 43 68 6C 6F 72 69 6E 61 74 6F 72 20 4F 66 66 20 20 48 69 67 68 20 53 61 6C 74 2F 41 6D 70 |..Chlorinator Off High Salt/Amp|
[12:35:31.613][I][rs485_frame.stats:318]: 3 @ 01 03 20 20 20 20 53 65 74 74 69 6E 67 73 20 20 20 20 20 20 20 20 20 20 4D 65 6E 75 20 20 20 20 |.. Settings Menu |
[12:35:31.613][I][rs485_frame.stats:318]: 3 @ 01 03 20 20 20 20 20 54 69 6D 65 72 73 20 20 20 20 20 20 20 20 20 20 20 4D 65 6E 75 20 20 20 20 |.. Timers Menu |
[12:35:31.613][I][rs485_frame.stats:318]: 4 @ 01 03 20 20 20 44 69 61 67 6E 6F 73 74 69 63 20 20 20 20 20 20 20 20 20 4D 65 6E 75 20 20 20 20 |.. Diagnostic Menu |
[12:35:31.620][I][rs485_frame.stats:318]: 3 @ 01 03 20 43 6F 6E 66 69 67 75 72 61 74 69 6F 6E 20 20 20 4D 65 6E 75 2D 4C 6F 63 6B 65 64 20 20 |.. Configuration Menu-Locked |
[12:35:31.620][I][rs485_frame.stats:318]: 4 @ 01 03 20 20 20 20 44 65 66 61 75 6C 74 20 20 20 20 20 20 20 20 20 20 20 4D 65 6E 75 20 20 20 20 |.. Default Menu |
[12:35:31.620][I][rs485_frame.stats:307]: 0002 payloads:
[12:35:31.620][I][rs485_frame.stats:318]: 14 @ 00 02 02 00 02 00 |......|
[12:35:31.624][I][rs485_frame.stats:318]: 8 @ 00 02 02 00 00 00 |......|
[12:35:31.624][I][rs485_frame.stats:307]: 0C01 payloads:
[12:35:31.624][I][rs485_frame.stats:318]: 15 @ 0C 01 00 32 |...2|
[12:35:31.624][I][rs485_frame.stats:307]: 000C payloads:
[12:35:31.633][I][rs485_frame.stats:318]: 8 @ 00 0C 00 00 32 01 59 |....2.Y|
[12:35:31.634][I][rs485_frame.stats:318]: 2 @ 00 0C 00 00 32 01 60 |....2.`|
[12:35:31.634][I][rs485_frame.stats:318]: 1 @ 00 0C 00 00 32 01 58 |....2.X|
[12:35:31.634][I][rs485_frame.stats:318]: 2 @ 00 0C 00 00 32 01 61 |....2.a|
[12:35:31.636][I][rs485_frame.stats:318]: 2 @ 00 0C 00 00 32 01 57 |....2.W|
[12:35:31.636][I][rs485_frame.stats:307]: 0407 payloads:
[12:35:31.636][I][rs485_frame.stats:318]: 1 @ 04 07 |..|
[12:35:31.636][W][component:473]: rs485_frame took a long time for an operation (77 ms), max is 70 ms
@b3nj1 I also see how your code will mess up the text display as your frame capture shows where the text begins at [0], and not [2] for a number of messages. I’m assuming this is a firmware variation compared to what you have tested on.
[12:35:01.579][I][rs485_frame.stats:307]: 0103 payloads:
[12:35:01.579][I][rs485_frame.stats:318]: 3 @ 01 03 20 20 46 69 6C 74 65 72 20 53 70 65 65 64 20 20 20 20 20 20 20 20 35 30 25 20 20 20 20 20 |.. Filter Speed 50% |
[12:35:01.582][I][rs485_frame.stats:318]: 4 @ 01 03 20 20 20 20 53 61 74 75 72 64 61 79 20 20 20 20 20 20 20 20 20 31 32 3A 33 34 50 20 20 20 |.. Saturday 12:34P |
[12:35:01.582][I][rs485_frame.stats:318]: 4 @ 01 03 20 20 20 20 53 61 74 75 72 64 61 79 20 20 20 20 20 20 20 20 20 31 32 20 33 34 50 20 20 20 |.. Saturday 12 34P |
[12:35:01.587][I][rs485_frame.stats:318]: 2 @ 01 03 50 6F 6F 6C 20 54 65 6D 70 20 20 38 39 DF 46 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 |..Pool Temp 89.F |
[12:35:01.587][I][rs485_frame.stats:318]: 2 @ 01 03 41 69 72 20 54 65 6D 70 20 20 31 30 33 DF 46 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 |..Air Temp 103.F |
[12:35:01.592][I][rs485_frame.stats:318]: 2 @ 01 03 50 6F 6F 6C 20 43 68 6C 6F 72 69 6E 61 74 6F 72 20 20 20 20 20 20 34 30 25 20 20 20 20 20 |..Pool Chlorinator 40% |
[12:35:01.592][I][rs485_frame.stats:318]: 2 @ 01 03 43 68 6C 6F 72 69 6E 61 74 6F 72 20 4F 66 66 20 20 48 69 67 68 20 53 61 6C 74 2F 41 6D 70 |..Chlorinator Off High Salt/Amp|
[12:35:01.592][I][rs485_frame.stats:318]: 2 @ 01 03 20 20 43 68 65 63 6B 20 53 79 73 74 65 6D 20 20 20 48 69 67 68 20 53 61 6C 74 2F 41 6D 70 |.. Check System High Salt/Amp|
@mrmoorey , I’m pretty sure this is your MENU button:
[12:35:31.620][I][rs485_frame.stats:307]: 0002 payloads:
[12:35:31.620][I][rs485_frame.stats:318]: 14 @ 00 02 02 00 02 00 |......|
[12:35:31.624][I][rs485_frame.stats:318]: 8 @ 00 02 02 00 00 00 |......|
From previous analysis, 0002 is the frame type for wired controller. The payload of 0200 twice is basically a shorter version of my 0200000.
Can you try changing your MENU button yaml to shorter commands:
button_command: [0x0200, 0x0200]
instead of button_command: [0x02000000, 0x02000000]?
If that doesn’t work, we might need to spoof your main controller. It would replace your MENU button yaml with a more elaborate setting like is done for Service:
- path: hayward/aqualogic/button.yaml
vars:
button_name: "Menu"
button_command: [0x0200, 0x0200]
btn_preamble: [0x00, 0x02] # wired local frame type — unquoted list
btn_postamble: []
btn_element_bytes: "2"
btn_endian: "big"
For your display decoding, the payload includes the frame type (0103), so that should be why it’s starting at 2 - not because of padding. I have to look more into the mismatch because you have 2 symptoms: 1. First char is dropped; 2: Second char is converted to uppercase. However, the sniffer’s output looks good. I’ll try running your text through the decoder and see if I can figure it out. I’ll let you know after I’ve tried.
Let me know if either of the MENU tweaks work.
I agree with your analysis. I just finished analyzing this myself. Ignore the mixed up timestamps; I kept having to run out to the pool to capture the keystrokes I performed, including the unlock and plus/minus keys so we had a complete picture:
[13:14:46.085][I][rs485_frame.stats:307]: 0002 payloads:
[13:14:46.110][I][rs485_frame.stats:318]: 7 @ 00 02 01 00 01 00 |......| Right
[13:14:46.110][I][rs485_frame.stats:318]: 8 @ 00 02 01 00 00 00 |......|
[13:14:16.047][I][rs485_frame.stats:318]: 9 @ 00 02 02 00 02 00 |......| Menu
[13:14:16.047][I][rs485_frame.stats:318]: 8 @ 00 02 02 00 00 00 |......|
[13:14:46.110][I][rs485_frame.stats:318]: 2 @ 00 02 04 00 04 00 |......| Left
[13:14:46.110][I][rs485_frame.stats:318]: 2 @ 00 02 04 00 00 00 |......|
[13:14:16.063][I][rs485_frame.stats:318]: 1 @ 00 02 05 00 05 00 |......| Unlock?
[13:14:16.065][I][rs485_frame.stats:318]: 31 @ 00 02 05 00 00 00 |......|
[13:14:46.110][I][rs485_frame.stats:318]: 2 @ 00 02 10 00 10 00 |......| Minus
[13:14:46.110][I][rs485_frame.stats:318]: 2 @ 00 02 10 00 00 00 |......|
[13:14:46.110][I][rs485_frame.stats:318]: 3 @ 00 02 20 00 20 00 |.. . .| Plus
[13:14:46.110][I][rs485_frame.stats:318]: 3 @ 00 02 20 00 00 00 |.. ...|
I’ll make the changes to my configuration and get back to you.
@mrmoorey , I edited my previous message to fix a typo in the more elaborate Menu setting. We need to change the ban_element_bytes to 2.
I changed the buttons to 2 bytes vs. 4 bytes. Menu still doesn’t appear to work, and when I adjusted the right button from:
vars: { button_name: "Right", button_command: [0x01000000, 0x01000000], button_id: "right", confirm_led_bit: -1 }
To:
vars: { button_name: "Right", button_command: [0x0100, 0x0100], button_id: "right", confirm_led_bit: -1 }
It activated Valve 3 vs the right button. The left button with the shortened code appears to do nothing.
Confirming the elaborate vars setting for the menu button now works; I will change the other buttons and let you know the outcome. Thanks!
@mrmoorey , that makes sense and also relates to why your Right button didin’t work. The size of the commands sent on the bus are set by the “btn_element_bytes” not the text of “button_command” (I tried but it was going against a lot of esphome conventions). This is one of a downside of pushing smarts to the yaml vs forcing code changes. So, your “{ button_name: “Right”, button_command: [0x0100, 0x0100], button_id: “right”, confirm_led_bit: -1 }” actually was more like { button_name: "Right", button_command: [0x00000100, 0x0000100], button_id: "right", confirm_led_bit: -1 }. You might be able to just override some keys. Try { button_name: "Right", button_command: [0x0100, 0x0100], btn_element_bytes: "2", button_id: "right", confirm_led_bit: -1 } instead of the more elaborate edits.
I’ve extracted the decoder, and ran it on your values… It got the Pool temp correct. I’m still confused.
# ./a.out "01 03 50 6F 6F 6C 20 54 65 6D 70 20 20 38 39 DF 46 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20"
uint8_t payload[32] = {0x01, 0x03, 0x50, 0x6F, 0x6F, 0x6C, 0x20, 0x54, 0x65, 0x6D, 0x70, 0x20, 0x20, 0x38, 0x39, 0xDF, 0x46, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20};
Decoded: Pool Temp 89°F
Filter speed [space][space]Filter Speed[spaces]…50%[spaces]
20 20 46 69 6C 74 65 72 20 53 70 65 65 64 20 20 20 20 20 20 20 20 35 30 25 20 20 20 20 20
Pool temperature Pool Temp[spaces]89[\xDF]F[spaces]
50 6F 6F 6C 20 54 65 6D 70 20 20 38 39 DF 46 20 20 20 20
Bus.yaml:
// Text starts immediately at payload[2] -- no header byte before it
// (decode_variations.md §5.1: "no fixed header before the text").
for (size_t i = 2; i < payload.size() && tlen < (BUF_LEN-2); i++) {
uint8_t b = payload[i];
isblink = bool(b > 0x7F);
b &= 0x7f;
if (b < 0x20 || b > 0x7E) continue;
if (b == '_') {
if (tlen + 2 <= (BUF_LEN-2)) {
text[tlen++] = '\xC2'; text[tlen++] = '\xB0';
if (isblink) { blink[blen++] = '\xC2'; blink[blen++] = '\xB0'; }
}
} else {
text[tlen++] = char(b);
if (isblink) blink[blen++] = char(b);
}
}
For me to be correct on this, I have to assume that the array 1-based, not 0-based. Since the first byte of text is read from payload[2], Filter speed is read correctly; if we read the pool temperature from payload[2], we get ‘ool temperature’, and the subsequent code cannot find the substring it is looking for to pass to the sensor.
I added this to the tail of my device yaml. It prints out 0 to 3 of every display payload to the console log along with the sniffer info.
rs485_frame:
- id: !extend pool
on_frame:
- frame_type: [0x01, 0x03]
then:
- lambda: |-
ESP_LOGI("pool", "payload[0..3]=%02X %02X %02X %02X", payload[0], payload[1], payload[2], payload[3]);
dump_frames: false # keep INFO logs clean; rely on sniffer_stats instead
sniffer_stats: { interval: 30s, max_frame_types: 64, payload_dump_top: 20 }
I get this which means the “frame type” of 0x0103 is included at payload[0..1], so we should start at payload 2. The “no header byte before it” is confusing - I’ll clear that up.
This doesn’t explain your problem. But what happened if you changed the size_t i = 2 to 1 or 0?
[14:52:44.100][I][pool:305]: payload[0..3]=01 03 20 20
[14:52:46.095][I][pool:305]: payload[0..3]=01 03 20 20
[14:52:46.191][I][pool:305]: payload[0..3]=01 03 20 20
[14:52:48.106][I][pool:305]: payload[0..3]=01 03 20 20
@mrmoorey ,
Can you post your full device yaml? When I try to use the example in GitHub, there’s a version problem related to the feature I mentioned slipped into the main branch. I’m curious how you solved it, and it will help me make sure I know what codes you’re running off in case that impacts the display decoding.
@b3nj1 Here’s the config minus some of the comments so we’re more compact. I’m looking at whether there’s a strange buffer issue, because the publish_state is using a static character array. If your parser is getting the entire string, why would we lose the first character unless the buffer is not being cleared properly. I also realized how I misunderstood the comments; payload is the entire frame, not just what I would call the payload. I assumed that the frame identifier had been consumed (wrong of me to assume).
substitutions:
name: aqualogic
friendly_name: Hayward Aqua Logic
board: esp32-s3-devkitc-1 # see https://esphome.io/components/esp32
variant: esp32s3
tx_pin: GPIO17 # if no data received, try swapping tx_pin and rx_pin
rx_pin: GPIO18
flow_control_pin: GPIO21 # DE/RE direction pin; delete this and the uart: line below
cmd_preamble: [0x00, 0x83, 0x01] # unquoted YAML list — wireless default
cmd_postamble: [0x00] # wireless trailing pad; wired uses []
cmd_element_bytes: "4" # Hayward: always 4 bytes per value
cmd_endian: "big" # Hayward: big-endian
# Temperature units — passed to bus.yaml decoders.
temp_unit: "°F"
temp_unit_short: "F"
esphome:
name: ${name}
friendly_name: ${friendly_name}
esp32:
board: ${board}
variant: ${variant}
framework:
type: esp-idf
external_components:
- source: github://b3nj1/esphome@rs485_frame
components: [rs485_frame]
# UART — Hayward AquaLogic / ProLogic: 19200 baud, 8N2; fixed by protocol.
uart:
id: pool_uart
tx_pin: ${tx_pin}
rx_pin: ${rx_pin}
baud_rate: 19200 # Hayward AquaLogic — do not change
data_bits: 8
parity: NONE
stop_bits: 2
rx_buffer_size: 512
flow_control_pin: ${flow_control_pin}
packages:
rs485:
url: https://github.com/b3nj1/rs485_frame-examples
ref: v3.0.1 # PINNED release tag — bump deliberately to update (see README)
refresh: 1d
files:
# Bus package is REQUIRED and stays uncommented.
- hayward/aqualogic/bus.yaml
# --- Equipment: uncomment the lines for gear you have, delete the rest. ---
- hayward/aqualogic/pump-vsp.yaml # Variable-speed pump — Status: tested
# - hayward/aqualogic/heater.yaml # Gas/heat-pump heater — Status: tested
# --- LED indicators — rename labels to match your load; remove bits your panel lacks. ---
# Enabled by default: states present on every AquaLogic panel.
# Disabled by default (hidden in HA; enable in Settings > Entities as needed):
# AUX channels, valves, Service, Spillover, Super Chlorinate.
# Bits 0-8 hardware-verified. Bits 9-25 confirmed by swilson, smith288, ChaseDurand.
# Use the "LED Mask" diagnostic sensor to verify bit layout on your specific panel.
- path: hayward/aqualogic/led.yaml
vars: { bit: 0, led_name: "Heater Active", device_class: heat }
- path: hayward/aqualogic/led.yaml
vars: { bit: 1, led_name: "Valve 3", device_class: running, disabled_by_default: "true" }
- path: hayward/aqualogic/led.yaml
vars: { bit: 2, led_name: "Check System", device_class: problem }
- path: hayward/aqualogic/led.yaml
vars: { bit: 3, led_name: "Pool Mode", device_class: running }
- path: hayward/aqualogic/led.yaml
vars: { bit: 4, led_name: "Spa Mode", device_class: running }
- path: hayward/aqualogic/led.yaml
vars: { bit: 5, led_name: "Filter", device_class: running }
- path: hayward/aqualogic/led.yaml
vars: { bit: 6, led_name: "Lights", device_class: light }
- path: hayward/aqualogic/led.yaml
vars: { bit: 7, led_name: "AUX 1", device_class: running, disabled_by_default: "true" }
- path: hayward/aqualogic/led.yaml
vars: { bit: 8, led_name: "AUX 2", device_class: running, disabled_by_default: "true" }
- path: hayward/aqualogic/led.yaml
vars: { bit: 9, led_name: "Service", device_class: running, disabled_by_default: "true" }
- path: hayward/aqualogic/led.yaml
vars: { bit: 10, led_name: "AUX 3", device_class: running, disabled_by_default: "true" }
- path: hayward/aqualogic/led.yaml
vars: { bit: 11, led_name: "AUX 4", device_class: running, disabled_by_default: "true" }
- path: hayward/aqualogic/led.yaml
vars: { bit: 12, led_name: "AUX 5", device_class: running, disabled_by_default: "true" }
- path: hayward/aqualogic/led.yaml
vars: { bit: 13, led_name: "AUX 6", device_class: running, disabled_by_default: "true" }
- path: hayward/aqualogic/led.yaml
vars: { bit: 14, led_name: "Valve 4", device_class: running, disabled_by_default: "true" }
- path: hayward/aqualogic/led.yaml
vars: { bit: 15, led_name: "Spillover", device_class: running, disabled_by_default: "true" }
- path: hayward/aqualogic/led.yaml
vars: { bit: 16, led_name: "System Off", device_class: problem }
- path: hayward/aqualogic/led.yaml
vars: { bit: 17, led_name: "AUX 7", device_class: running, disabled_by_default: "true" }
- path: hayward/aqualogic/led.yaml
vars: { bit: 18, led_name: "AUX 8", device_class: running, disabled_by_default: "true" }
- path: hayward/aqualogic/led.yaml
vars: { bit: 19, led_name: "AUX 9", device_class: running, disabled_by_default: "true" }
- path: hayward/aqualogic/led.yaml
vars: { bit: 20, led_name: "AUX 10", device_class: running, disabled_by_default: "true" }
- path: hayward/aqualogic/led.yaml
vars: { bit: 21, led_name: "AUX 11", device_class: running, disabled_by_default: "true" }
- path: hayward/aqualogic/led.yaml
vars: { bit: 22, led_name: "AUX 12", device_class: running, disabled_by_default: "true" }
- path: hayward/aqualogic/led.yaml
vars: { bit: 23, led_name: "AUX 13", device_class: running, disabled_by_default: "true" }
- path: hayward/aqualogic/led.yaml
vars: { bit: 24, led_name: "AUX 14", device_class: running, disabled_by_default: "true" }
- path: hayward/aqualogic/led.yaml
vars: { bit: 25, led_name: "Super Chlorinate", device_class: running, disabled_by_default: "true" }
# Navigation and mode: active by default on every panel.
- path: hayward/aqualogic/button.yaml
vars: { button_name: "Filter", button_command: [0x80000000, 0x80000000], button_id: "filter", confirm_led_bit: 5, confirm_disabled_by_default: "false" }
- path: hayward/aqualogic/button.yaml
# Toggles between the Pool-Mode (bit 3) and Spa-Mode (bit 4) LEDs -- a select between
# two different bits, not one bit flipping to its opposite. button.yaml's monitor
# models a single-bit toggle, so this doesn't fit; left at the -1 sentinel.
vars: { button_name: "Pool Spa Mode", button_command: [0x40000000, 0x40000000], button_id: "pool_spa_mode", confirm_led_bit: -1 }
- path: hayward/aqualogic/button.yaml
# vars: { button_name: "Plus", button_command: [0x20000000, 0x20000000], button_id: "plus", confirm_led_bit: -1 }
vars:
button_name: "Plus"
button_command: [0x2000, 0x2000]
btn_preamble: [0x00, 0x02] # wired local frame type — unquoted list
btn_postamble: []
btn_element_bytes: "2"
btn_endian: "big"
- path: hayward/aqualogic/button.yaml
# vars: { button_name: "Minus", button_command: [0x10000000, 0x10000000], button_id: "minus", confirm_led_bit: -1 }
vars:
button_name: "Minus"
button_command: [0x1000, 0x1000]
btn_preamble: [0x00, 0x02] # wired local frame type — unquoted list
btn_postamble: []
btn_element_bytes: "2"
btn_endian: "big"
- path: hayward/aqualogic/button.yaml
# vars: { button_name: "Menu", button_command: [0x02000000, 0x02000000], button_id: "menu", confirm_led_bit: -1 }
vars:
button_name: "Menu"
button_command: [0x0200, 0x0200]
btn_preamble: [0x00, 0x02] # wired local frame type — unquoted list
btn_postamble: []
btn_element_bytes: "2"
btn_endian: "big"
- path: hayward/aqualogic/button.yaml
# vars: { button_name: "Right", button_command: [0x01000000, 0x01000000], button_id: "right", confirm_led_bit: -1 }
vars:
button_name: "Right"
button_command: [0x0100, 0x0100]
btn_preamble: [0x00, 0x02] # wired local frame type — unquoted list
btn_postamble: []
btn_element_bytes: "2"
btn_endian: "big"
- path: hayward/aqualogic/button.yaml
# vars: { button_name: "Left", button_command: [0x04000000, 0x04000000], button_id: "left", confirm_led_bit: -1 }
vars:
button_name: "Left"
button_command: [0x0400, 0x0400]
btn_preamble: [0x00, 0x02] # wired local frame type — unquoted list
btn_postamble: []
btn_element_bytes: "2"
btn_endian: "big"
- path: hayward/aqualogic/button.yaml
vars: { button_name: "Lights", button_command: [0x0001, 0x0001], button_id: "lights", confirm_led_bit: 6, confirm_disabled_by_default: "false" }
# Menu Unlock — Hayward unlocks setup menus by holding Left+Right for several seconds,
# not a quick press. Two buttons bracket the hold instead of one: "Start" sets the
# Left+Right bits with nothing released (held), "End" releases them. Press Start, wait
# a few seconds, then press End.
# - path: hayward/aqualogic/button.yaml
# vars: { button_name: "Menu Unlock Start", button_command: [0x0500, 0x0000], button_id: "menu_unlock_start", confirm_led_bit: -1 }
# - path: hayward/aqualogic/button.yaml
# vars: { button_name: "Menu Unlock End", button_command: [0x0000, 0x0500], button_id: "menu_unlock_end", confirm_led_bit: -1 }
# Service — wired local frame (0x0002), no postamble. Disabled by default:
# maintenance use only; most users should not trigger this accidentally.
# LED bit 9 (Service) is community-sourced only (not proj hw-tested), so confirm_led_bit
# stays at the -1 sentinel until someone verifies it against real hardware.
- path: hayward/aqualogic/button.yaml
vars:
button_name: "Service"
button_command: [0x08000000, 0x08000000]
button_id: "service"
confirm_led_bit: -1
disabled_by_default: "true"
btn_preamble: [0x00, 0x02] # wired local frame type — unquoted list
btn_postamble: []
btn_element_bytes: "4"
btn_endian: "big"
# System Off — always wireless regardless of hub role.
# LED bit 16 (System Off) is community-sourced only (not proj hw-tested), so
# confirm_led_bit stays at the -1 sentinel until someone verifies it against real hardware.
- path: hayward/aqualogic/button.yaml
vars:
button_name: "System Off"
button_command: [0x08000000, 0x08000000]
button_id: "system_off"
confirm_led_bit: -1
btn_preamble: [0x00, 0x83, 0x01] # wireless — do not change
btn_postamble: [0x00]
btn_element_bytes: "4"
btn_endian: "big"
# AUX relays and valves — disabled by default; enable in HA Settings > Entities.
# Rename labels to match your load (e.g. "Pool Light", "Spa Jets", "Booster Pump").
# AUX 1-2 hardware-tested (bits 7-8, in led.yaml's proj-hw-tested 0-8 range) -- their
# confirm_led_bit is set to that real bit, but confirm_disabled_by_default is left at its
# default ("true") since neither was exercised by the 2026-07-26 confirm/fail capture.
# AUX 3-7 (bits 10-13, 17) are confirmed by swilson + smith288 only, not hw-tested --
# confirm_led_bit stays at the -1 sentinel until someone verifies these against hardware.
- path: hayward/aqualogic/button.yaml
vars: { button_name: "AUX 1", button_command: [0x00020000, 0x00020000], button_id: "aux_1", confirm_led_bit: 7, disabled_by_default: "true" }
- path: hayward/aqualogic/button.yaml
vars: { button_name: "AUX 2", button_command: [0x00040000, 0x00040000], button_id: "aux_2", confirm_led_bit: 8, disabled_by_default: "true" }
- path: hayward/aqualogic/button.yaml
vars: { button_name: "AUX 3", button_command: [0x00080000, 0x00080000], button_id: "aux_3", confirm_led_bit: -1, disabled_by_default: "true" }
- path: hayward/aqualogic/button.yaml
vars: { button_name: "AUX 4", button_command: [0x00100000, 0x00100000], button_id: "aux_4", confirm_led_bit: -1, disabled_by_default: "true" }
- path: hayward/aqualogic/button.yaml
vars: { button_name: "AUX 5", button_command: [0x00200000, 0x00200000], button_id: "aux_5", confirm_led_bit: -1, disabled_by_default: "true" }
- path: hayward/aqualogic/button.yaml
vars: { button_name: "AUX 6", button_command: [0x00400000, 0x00400000], button_id: "aux_6", confirm_led_bit: -1, disabled_by_default: "true" }
- path: hayward/aqualogic/button.yaml
vars: { button_name: "AUX 7", button_command: [0x00800000, 0x00800000], button_id: "aux_7", confirm_led_bit: -1, disabled_by_default: "true" }
# AUX 8-14: command bytes are in an unusual byte position; swilson source only,
# no independent wire-capture confirmation. Keep commented until hw-tested.
# - path: hayward/aqualogic/button.yaml
# vars: { button_name: "AUX 8", button_command: [0x00000800, 0x00000800], button_id: "aux_8", confirm_led_bit: -1, disabled_by_default: "true" }
# - path: hayward/aqualogic/button.yaml
# vars: { button_name: "AUX 9", button_command: [0x00001000, 0x00001000], button_id: "aux_9", confirm_led_bit: -1, disabled_by_default: "true" }
# - path: hayward/aqualogic/button.yaml
# vars: { button_name: "AUX 10", button_command: [0x00002000, 0x00002000], button_id: "aux_10", confirm_led_bit: -1, disabled_by_default: "true" }
# - path: hayward/aqualogic/button.yaml
# vars: { button_name: "AUX 11", button_command: [0x00004000, 0x00004000], button_id: "aux_11", confirm_led_bit: -1, disabled_by_default: "true" }
# - path: hayward/aqualogic/button.yaml
# vars: { button_name: "AUX 12", button_command: [0x00008000, 0x00008000], button_id: "aux_12", confirm_led_bit: -1, disabled_by_default: "true" }
# - path: hayward/aqualogic/button.yaml
# vars: { button_name: "AUX 13", button_command: [0x00000001, 0x00000001], button_id: "aux_13", confirm_led_bit: -1, disabled_by_default: "true" }
# - path: hayward/aqualogic/button.yaml
# vars: { button_name: "AUX 14", button_command: [0x00000002, 0x00000002], button_id: "aux_14", confirm_led_bit: -1, disabled_by_default: "true" }
# Valve 3 (bit 1) is hardware-tested (led.yaml's proj-hw-tested 0-8 range); Valve 4
# (bit 14) is community-sourced only -- confirm_led_bit stays at the -1 sentinel there.
- path: hayward/aqualogic/button.yaml
vars: { button_name: "Valve 3", button_command: [0x00000100, 0x00000100], button_id: "valve_3", confirm_led_bit: 1, disabled_by_default: "true" }
- path: hayward/aqualogic/button.yaml
vars: { button_name: "Valve 4", button_command: [0x00000200, 0x00000200], button_id: "valve_4", confirm_led_bit: -1, disabled_by_default: "true" }
@mrmoorey , I think I see the problem.
Try changing to this ref: v3.1.0-rc1 in your yaml:
packages:
rs485:
url: https://github.com/b3nj1/rs485_frame-examples
ref: v3.1.0-rc1
You’re using v3.0.1 which actually starts at payload[3]! This explains your lost character. It doesn’t explain your upper/lower case but maybe that’s a UI thing.
@b3nj1 That explains a lot!!
I now get a bunch of validation errors; here’s a couple of them:
Failed config
sensor.template: [source /data/packages/ac658772/hayward/aqualogic/button.yaml:210]
platform: template
ID btn_confirmed_count_unset redefined! Check sensor->16->id.
id: btn_confirmed_count_unset
name: Minus Confirmed
entity_category: diagnostic
state_class: total_increasing
accuracy_decimals: 0
disabled_by_default: True
force_update: False
update_interval: 60s
sensor.template: [source /data/packages/ac658772/hayward/aqualogic/button.yaml:221]
platform: template
ID btn_failed_count_unset redefined! Check sensor->17->id.
id: btn_failed_count_unset
name: Minus Failed
entity_category: diagnostic
state_class: total_increasing
accuracy_decimals: 0
disabled_by_default: True
force_update: False
update_interval: 60s
@mrmoorey , OK - sorry about that.
Give me a few minutes I’ll give you a new version.
