Intelliflow pump RS485 protocol

Hi Mark,
 
I apologize for not responding earlier. Work got pretty busy and had to shelve this pet project for a while :( The forum also didn't send me a notification that there was a reply *sigh*
 
Anyway, thank you for finding out about the 64-bit/32-bit issues. I'll setup a 32-bit VM tomorrow and will try it again. The last thing I tried, however, was to send the control sequence ( "A5 00 60 10 04 01 ff 02 19") to switch the pump into controller mode using another serial client. It didn't seem to have any effect, so I'm not sure if the sequence is not correct or if something else was wrong. I'll try to compile PAB014SHARE on a 32-bit machine again and will let you know what comes of it.
 
 
Best,
erie.
 
Hi erie,
 
No need to apologize - this is a pet project for me as well, and I too am buried in other "paying" projects. Those projects also have all of my Beaglebone RS485 interfaces tied up, so I haven't even been able to connect-up to my pump.
 
I have a circuit board designed that will control the pump, up to sixteen valves (sprinkler type or pool type), eight AC outlets, and read temperature, level and pressure sensors. It's meant to be configured and controlled through a web browser. Once I have the board fabricated and assembled, I hope to turn it into an open-source project (so that I don't have to write all of the software myself).
 
Unfortunately, it looks like pool season for the year will be over by the time I can get back to it.
 
mark
 
 
 
Hi all, new here, but have been closely reading this thread, along with a couple of others. I would start a new thread, but since this one has little traffic I'll just append to it.
 
I took the examples/knowledge here and combined them with a couple of other folks I found working on this and wrote a NodeJS application to read the RS-485 serial bus. I think I've uncovered a few new things, and can clearly see patterns of traffic now that should help lead to understanding the packets.
 
Take a look, and please feel free to contribute.  There is much to do, but this code reads the serial bus nicely.  I never actually played around with the code here from Michael, but I did use his README as a great guide.  
 
In my code, I tried to figure out what the physical circuits are.  The other two examples of code I more closely followed has the circuits hardcoded, but in reality they are different for every pool depending on your installer.  
 
https://github.com/tagyoureit/nodejs-Pentair
 
Hi Tag,    (I'm surprised that your nom de guerre had never been used here before)
 
And welcome to cocoontech (wow, I haven't said that in years!)
 
Thanks for joining in, and bringing your bag of goods with you. I've read your README and will look at your code and Jason's posts tomorrow. It appears that what you have learned is much more broad than what we have here on cocoontech (which is almost totally the work of Michael).
 
Now I may have to build another BeagleBone RS485 interface just so that I can run your nodejs code.
 
mark
 
Thank you for the link, Tag. That is very helpful!
 
Just a quick update on my progress... I was eventually able to poll my pump's status using Michael's tools. I just compiled the sources using the -m32 flag and suddenly I saw status message coming in from my pump! :)
 
Now, I'm back to where I had started the project. I followed this example here to use Arduino's SoftwareSerial for RS485 communication. The idea is to use the remote ATmega as a fake pump that spits out various messages while I'm working on my message parser, so I don't upset my actual pump. Just a few notes, if somebody wants to use this example:
  • RS485Serial connection needs to run also on 9600 (vs. 4800 in the example)
  • For some reason the RO pin cannot be mapped to any other pins than 10, 11, 12 or 13 (which is the LED on the ATmega2560 anyway). This blows because now you have the RS485 module hanging off the side instead of going across the ATmega :(
 
 
Erie.
 
Glad some people are still watching this thread.  I thought I might hear crickets!   :rockon:
 
Erie, I have the EasyTouch controller, so I would like to listen to my pump packets to gather the relevant information, but I'm only planning on controlling my equipment through the Pentair controller which adds a safety net of some sort.  Having said that, I probably get a lot of pump messages that are still relevant so I'd be happy to share them here if it helps.  Am I correct in assuming you want to directly control the pump?
 
Mark, thanks.  Let me know what feedback you have.  I'll continue working on the code of my end and try to publish any new changes when appropriate.
 
Hi all,
 
I've made a lot of progress on this code (even with a business trip this week).  I discovered that (with my novice coding skills) I was re-reading the same buffer many, many times because of the same asynchronous nature of the code.  And some of the objects I wanted to copy by value were being copied by reference, but I digress.
 
I am able to easily show what messages have valid checksums and are known, which are valid but aren't known, and which don't have a valid checksum.
[sharedmedia=gallery:images:1010]
 
I'm thinking about going through every single bit of the messages and seeing if there is a len bit for which there is a valid ChkHi*3 and ChkLow checksum.  Shouldn't be too hard.
 
Also, I wanted to know how I could isolate some messages.  Every single controller on the bus is powered by the Pentair (pool, controller, pumps, solar, wired controllers, etc), EXCEPT one.  Which is the wireless controller because it has it's own power brick.  If I can utilize this to try to login from my Screenlogic in theory the only message on there should be some sort of "hello" message.  This might open up a whole new set of messages.  
 
Looking forward to trying this out.  If you can think of any other clever ways to isolate messages, I have a pretty full system (Easy Touch controller, wired controller, 2 pumps, solar, heater, 2 Jandy valves, air blower, spa...) let me know and we can try to crack this thing once and for all.
 
Tag
 
tag said:
lso, I wanted to know how I could isolate some messages.  Every single controller on the bus is powered by the Pentair (pool, controller, pumps, solar, wired controllers, etc), EXCEPT one.  Which is the wireless controller because it has it's own power brick.  If I can utilize this to try to login from my Screenlogic in theory the only message on there should be some sort of "hello" message.  This might open up a whole new set of messages.  
 
Looking forward to trying this out.  If you can think of any other clever ways to isolate messages, I have a pretty full system (Easy Touch controller, wired controller, 2 pumps, solar, heater, 2 Jandy valves, air blower, spa...) let me know and we can try to crack this thing once and for all.
 
I've done quite a bit of reverse engineering with vehicle CAN (controller area network) messaging and it is actually similar to the functionality of the RS-485 network being that it is all broadcast traffic.  The way I isolate devices is to use two transceivers attached to a computer to do a "man-in-the-middle" type setup.  In your case, you could use two RS-485 serial devices to isolate something from the network.  You'll need to write your custom software to capture and forward traffic from the network to the isolated device as well as to capture responses from the isolated device and forward back to the network.  The initial benefit here is to see exactly what your isolated device puts back out onto the network without seeing the rest of the broadcast traffic.  The second thing you can then work on is conditionally forwarding the broadcast traffic to your isolated device to see what exact messages it needs to operate and what it may do with those messages.  Being how slow the RS-485 data is, you should have no problem monitoring that data.
 
All,
I just published a new version of the code to GitHub and to NPM.  There are MANY improvements.  See the Readme.
 
JonW, thanks for the great tip.  I'll see if I want to spring the ~$20 for another RS485 controller.  :)  But I think I should be able to see everything from the bus, so I'll keep this in my back pocket in case I need to use it.  
 
Here is a sample of the output from my code:
 
Code:
open
-->EQUIPMENT Msg#: 1 
 Equipment Status: %O { time: '9:54',
  waterTemp: 80,
  temp2: 80,
  airTemp: 66,
  Spa: 'off',
  Jets: 'off',
  'Air Blower': 'off',
  Cleaner: 'off',
  'WaterFall 1.5': 'off',
  Pool: 'on',
  'Spa Lights': 'off',
  'Pool Lights': 'off',
  'Path Lights': 'off',
  '<--SKIP ME-->': 'off',
  Spillway: 'off',
  'Waterfall 1': 'off',
  'Waterfall 2': 'off',
  'Waterfall 3': 'off',
  'Pool Low': 'off',
  Feature6: 'off',
  Feature7: 'off',
  Feature8: 'off' }
                          S       L                                                           W               A 
                          O       E           M   M   M                                       T               I 
                      D   U       N   H       O   O   O                                       R   T           R                                           C   C
                      E   R       G   O   M   D   D   D                                       T   M           T                                           H   H
                      S   C       T   U   I   E   E   E                                       M   P           M                                           K   K
                      T   E       H   R   N   1   2   3                                       P   2           P                                           H   L
Orig:                15, 16,  2, 29,  9, 54, 32,  0,  0,  0,  0,  0,  0,  0,  3,  0, 64,  4, 80, 80, 32,  0, 66, 65,  0,  0,  7,  0,  0, 93,215,  0, 13,  4,30


 <-- EQUIPMENT 

Msg#: 2   Duplicate broadcast.
Msg#: 3   Duplicate broadcast.
Msg#: 4   Duplicate broadcast.
Msg#: 5   Duplicate broadcast.
Msg#: 6   Duplicate broadcast.
Msg#: 7   Duplicate broadcast.
Msg#: 8   Duplicate broadcast.
Msg#: 9  Setting initial chatter as instruction: 96,16,7,0,1,28
Msg# 9   Main asking Pump1 for status: [96,16,7,0,1,28]
Msg#: 9 is [96,16,7,0,1,28]
--> PUMP Msg#:  10 
 Pump1 
 Pump Status:  {"pump":"Pump1","run":10,"mode":0,"drivestate":0,"watts":594,"rpm":2050,"gpm":2,"ppc":0,"err":0,"timer":0,"time":"9:54"} 
 Full Payload:  [16,96,7,15,10,0,0,2,82,8,2,0,0,0,0,0,1,9,54,1,211] 
<-- PUMP  Pump1 

Msg# 11   Main asking Pump2 for status: [97,16,7,0,1,29]
Msg#: 11 is [97,16,7,0,1,29]
--> PUMP Msg#:  12 
 Pump2 
 Pump Status:  {"pump":"Pump2","run":4,"mode":0,"drivestate":0,"watts":0,"rpm":0,"gpm":0,"ppc":0,"err":0,"timer":0,"time":"9:54"} 
 Full Payload:  [16,97,7,15,4,0,0,0,0,0,0,0,0,0,0,0,0,9,54,1,111] 
<-- PUMP  Pump2 

Msg#: 13   Duplicate broadcast.
Msg#: 14   Duplicate broadcast.
Msg#: 15   Duplicate broadcast.
Msg# 16   Main asking Pump1 for remote control (turn off pump control panel): [96,16,4,1,255,2,25]
Msg#: 17   Pump1 confirming it is in remote control: [16,96,4,1,255,2,25]
Msg# 18   Main asking Pump1 to set run to _10_: [96,16,6,1,10,1,38]
Msg# 19   Main confirming it is in run _10_: [16,96,6,1,10,1,38]
Msg# 20   Main asking Pump1 to write a _2, 196, 8, _ command: [96,16,1,4,2,196,8,2,1,234]
Msg# 21   Main sent response _8, 2_ to write command: [16,96,1,2,8,2,1,34]
Msg# 22   Main asking Pump2 for remote control (turn off pump control panel): [97,16,4,1,255,2,26]
Msg#: 23   Pump2 confirming it is in remote control: [16,97,4,1,255,2,26]
Msg# 24   Main asking Pump2 to set run to _4_: [97,16,6,1,4,1,33]
Msg# 25   Main confirming it is in run _4_: [16,97,6,1,4,1,33]
Msg#: 26   Duplicate broadcast.
Msg#: 27   Duplicate broadcast.
Msg#: 28   Duplicate broadcast.
Msg#: 29   Duplicate broadcast.
Msg# 30   Main asking Pump1 for status: [96,16,7,0,1,28]
Msg#: 30 is [96,16,7,0,1,28]
--> PUMP Msg#:  31 
 Pump1 
 Pump Status:  {"pump":"Pump1","run":10,"mode":0,"drivestate":0,"watts":593,"rpm":2050,"gpm":2,"ppc":0,"err":0,"timer":0,"time":"9:54"} 
 Full Payload:  [16,96,7,15,10,0,0,2,81,8,2,0,0,0,0,0,1,9,54,1,210] 
<-- PUMP  Pump1 

Msg# 32   Main asking Pump2 for status: [97,16,7,0,1,29]
Msg#: 32 is [97,16,7,0,1,29]
--> PUMP Msg#:  33 
 Pump2 
 Pump Status:  {"pump":"Pump2","run":4,"mode":0,"drivestate":0,"watts":0,"rpm":0,"gpm":0,"ppc":0,"err":0,"timer":0,"time":"9:54"} 
 Full Payload:  [16,97,7,15,4,0,0,0,0,0,0,0,0,0,0,0,0,9,54,1,111] 
<-- PUMP  Pump2 

Msg# 34   Wireless asking 16 to change _something_: [16,34,231,1,0,1,201]
Msg#: 35 is [15,16,39,32,7,0,0,0,8,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,45]
Msg#: 36   Duplicate broadcast.
Msg# 37   Wireless asking 16 to change _something_: [16,34,217,1,0,1,187]
Msg#: 38 is [15,16,25,22,0,70,1,0,0,0,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,3,68]
Msg#: 39   Duplicate broadcast.
Msg#: 40   Duplicate broadcast.
Msg# 41   Main asking Pump1 for remote control (turn off pump control panel): [96,16,4,1,255,2,25]
Msg#: 42   Pump1 confirming it is in remote control: [16,96,4,1,255,2,25]
Msg# 43   Main asking Pump1 to set run to _10_: [96,16,6,1,10,1,38]
Msg# 44   Main confirming it is in run _10_: [16,96,6,1,10,1,38]
Msg# 45   Main asking Pump1 to write a _2, 196, 8, _ command: [96,16,1,4,2,196,8,2,1,234]
Msg# 46   Main sent response _8, 2_ to write command: [16,96,1,2,8,2,1,34]
Msg# 47   Main asking Pump2 for remote control (turn off pump control panel): [97,16,4,1,255,2,26]
Msg#: 48   Pump2 confirming it is in remote control: [16,97,4,1,255,2,26]
Msg# 49   Main asking Pump2 to set run to _4_: [97,16,6,1,4,1,33]
Msg# 50   Main confirming it is in run _4_: [16,97,6,1,4,1,33]
 
This is great, Tag! I also made some progress on the Arduino side and can now reliably control my pump from Arduino's serial monitor.
 
I used Michael's C code as a base for the various commands and I'm not quite clear about the usage of two CFIs. Namely the difference between writing a register, which is CFI 0x01 and "setting a mode" (for the lack of a better term) which is CFI 0x05.
For example to set external program 1, one send CFI 0x01 and write to register 0x0321 (3, 33 in dec) the value 0x0008 (0, 8 in dec)
To "set the mode" to external program 1, one would send CFI 0x05 with the value 0x09.
 
From how I understand the readme the values written with CFI 0x01 are to change runtime values. That is, the pump is already running and it will keep running the desired program until the instructions are not repeated anymore.
With CFI 0x05 one sets a "mode" and then would turn issue the Run command to the pump. The pump will not automatically turn off, similar to when pressing one of the buttons on the physical control panel of the pump.
 
In other words, when would one send:
[0x01, 0x04, 0x03, 0x21, 0x00, 0x08] (write 0x0008 to address 0x0321)
versus
[0x05, 0x01, 0x09] (set mode to 0x09 (ext. prog. 1))
(destination, source and checksum omitted for brevity)
 
So, I was wondering if you ever came across a 0x05 CFI on your system and if you can tell under which circumstances one is used over the other.
 
//EDIT: If anybody cares, here's my experimental Arduino code: https://github.com/eriedl/pavsp_rs485_examples/tree/master/rs485_master
 
Great work, as well!  I also just discovered that if I change the heat set point (or really any configuration change) the controller broadcasts the entire configuration back out to all the devices.  I'm leaning towards the notion that the remote control and wireless i-link cache these.  I've been looking for the CONNECTHOST message (from a couple pages back) found in the TCP/IP packets but they don't see to be anywhere on the serial bus.
 
Regarding your question, what equipment do you have? It is likely causing the differences in the serial bus calls.  I have never seen either of those commands on my system. My sequence always seems to be more or less like I put above.  I think this might make a difference if you have a single speed, two speed, or variable speed pump.  On the variable speed pump, one model has only RPM and the other RPM/GPM.  (I'm super pissed I didn't realize my installer only put in the RPM because the GPM is so much more useful!).  It also will depend on your controller.
 
This is from the pump manual:
External Control
IntelliTouch®, EasyTouch®, SunTouch® Control Systems and IntelliComm® Communication Centers can remotely control the IntelliFlo pump. The pump’s communications address and other functions are accessible from the pump’s control panel. 
• RS-485 commincation cable included
• IntelliTouch systems control 8 IntelliFlo pumps using 8 speeds per pump.
• EasyTouch systems control 2 IntelliFlo pumps using 8 speeds per pump.
• SunTouch systems control one IntelliFlo pump using 8 speeds.
• IntelliComm systems control one IntelliFlo pump using the 4 External Control programs.
 
So maybe if you have the IntelliComm (or ComPool?) it will call the 4 External Programs, which would require the use of the 0x01, 0x04... and 0x05 to set/call the external programs whereas the others will just control the pump directly.
 
I have no controller at all! :) That's why I was curious about the usage of some of the commands as they seem to do similar things. Michael's code has most commands in it, so I will try them out one after the other and see what they do.
The only thing that my pump is not reporting, and I kind of hoped it would, is the flow rate. If I'd have known that, I'd have asked the installer to install either a flow meter on one of the pipes or get a pump that reports that value.
 
I have the basic Pentair IntelliFlo VS pump: http://www.pentairpool.com/products/pumps-inground-intelliflo-variable-speed-high-perfomance-pump-430.htm
 
Hi Erie,
 
I have the VF pump, which does tell me the flow rate (and also lets you set the flow-rate), but I also bought this flow-rate meter (your pipes may be 2", not 1.5"). It's easy to install - just drill a small hole (about 3/8", I think), and attach it with the supplied hose clamps wherever it's convenient. I have mine on the output of the filter.
 
What I have learned is that you cannot even pretend that the flow reported by the pump is accurate, so the flow-meter is necessary anyway. It's not bad where I have it set for the solar panels (16 gpm) as long as I tell the pump the correct water temperature in the pump's menu (it should have been designed to measure that itself, as it's an important parameter for the accuracy of the flow). If you set the flow rate up to 80 gpm, as an example, it reports the flow as 80 gpm, even though it might only get up to 50 gpm.
 
Thanks, Mark. I'll get one of those flow meters. I do have the VS model, so no flow rate for me then. I was also more interested in seeing the current flow rate than setting it. But what you explained makes total sense. You can set the flow rate, but it's no guaranteed. I just get a flow meter and install it on the existing pipe.
 
Erie, yes, that completely explains it!  Lol.  I don't have any need to write directly to the pumps.  
 
Rocco, that's good to know that the flow rates are way off.  I missed that feature (had it at my last house/pool) but knowing it isn't trustworthy makes me feel better.  I'll probably install that flow meter you linked to... too bad it isn't wireless.  
 
I just pushed 0.0.3 to my GitHub repo.  I discovered how to read the pool and spa heater settings.  
 
Here's from my code:

const heatMode = {
//Pentair controller sends the pool and spa heat status as a 4 digit binary byte from 0000 (0) to 1111 (15). The left two (xx__) is for the spa and the right two (__xx) are for the pool. EG 1001 (9) would mean 10xx = 2 (Spa mode Solar Pref) and xx01 = 1 (Pool mode Heater)
0: 'Off',
1: 'Heater',
2: 'Solar Pref',
3: 'Solar Only'
}

I read this on the following string {this is my output}:
 

Msg# 16   Wireless asking Main to change pool heat mode to Heater (@ 87 degrees) % spa heat mode to Solar Only (at 100 degrees): [16,34,136,4,87,100,13,0,2,53]
 
The 13 is the heat mode.  1101 in binary.  
 
Cheers.
 
Back
Top