Intelliflow pump RS485 protocol

There is a "protocol" problem with transmitting on an "active" bus, and that is that the bus "controller" assumes that it, and only it, runs the bus (I've worked on a lot of buses that work that way). Only the controller can asynchronously drive the bus, and all other devices drive the bus synchronously in response to the controller. Otherwise, there can be contention on the bus, and I suspect that the controller doesn't have the firmware to even detect the collision (outside of a checksum failure), let alone recover from the collision.
 
Rocco and Tag,
 
Thanks again to both of you for your ongoing coaching and direction.  This has really been a fun project so far!  
 
I dug more into Michael's code.  The smaller modules are easy to understand and modify even with my very limited programming skills.  I was able to tinker with iPmon and get it to correctly read current status of my pump and send updates to me.  Very cool!!  But these modules triggered an idea to address the issues Rocco brings up:
 
PROBLEM: As Rocco correctly points out, I cannot have 2 controllers both trying to give commands to the same pump, especially when one of the controllers is sending updates every x seconds which will overwrite any command I give it.  There is also a small issue of collisions.
 
SOLUTION: Create a 'virtual' pump for my Intermatic controller to talk to and handshake with.  I could use the iFlow program to do this.  I would put that virtual pump on 0x61 and set my Intermatic, which is at 0x10, to talk to it.  Then, I also create a virtual controller at 0x11 to talk to my physical pump which will be at 0x60.  I could use the iComII or iPump program to do this I think.  Then I just have to write an interface program that reads from the Virtual Pump status and sends it to the Physical pump via iPump program.  If I need to override that the Intermatic is doing, I just tell the iPump program what I need the pump to do.  
 
                                 iFlow                                                iPump
Physical                   Virtual                      tbd                    Virtual                 Physical  
Controller     <==>    Pump      <==>     interface   <==>  Controller   <==>   Pump
@ 0x10                   @ 0x61                   Pgm                   @0x11                @0x60 
 
 
 
Any thoughts on if this could work?  
 
Well, I was able to confirm part of my idea above.  I disconnected my IntelliFlow pump from my controller and connected just my Pi to the Controller. I ran iFlow program and my Controller detected the virtual pump and immediately started communications.  From the iFlow program output I was able to confirm that my Intermatic Controller was correctly communicating and the program was receiving and displaying the correct data for Speed, status, etc.  To me, the handshake between my controller and the virtual pump was the most significant concern I had.  So my task now would be to write a Interface Program that would have 2 options:
  1. Default Pass Thru: Pass control messages received by the Virtual Pump directly to the Physical Pump at 0x60 via a virtual controller like iPump.  System would operate in normal mode.   
  2. Take Over Mode: Do no pass any info from iFlow.  Instead, take commands from another program such as iPump.  
And I just have to hope that the mixed communications between 0x10 <=> 0x60 and 0x11 <=> 0x61 do not cause issues.  If they do, I guess I could utilize 2 RS485 adapters, one physically connected to the Pump and one physically connected to the Intermatic Controller.  
 
My goal in doing all of this is to enable to take over the pump control from my ISY home automation system when I want to.  Eventually, I would create REST communications to the ISY to record key variables such as pump speed.  And in reverse I would accept REST PUT commands from the ISY to allow taking control of the pump and setting a different speed.  
 
A man-in-the-middle. I like it. The only issue I see with it is the possibility for collisions, and I think that problem can be easily avoided.
 
I would assume the Intermatic Controller's communication to the pump (in this case, the virtual pump) occurs at a particular interval. So when it speaks to the virtual pump, you respond to it, after which you have a period where you know the bus will be free. So all you would need to do is communicate with the real pump immediately after responding to the Intermatic Controller.
 
rocco said:
A man-in-the-middle. I like it. The only issue I see with it is the possibility for collisions, and I think that problem can be easily avoided.
 
I would assume the Intermatic Controller's communication to the pump (in this case, the virtual pump) occurs at a particular interval. So when it speaks to the virtual pump, you respond to it, after which you have a period where you know the bus will be free. So all you would need to do is communicate with the real pump immediately after responding to the Intermatic Controller.
 
Exactly.  I did some work today on the timing.  The message is sent every 10 seconds by the Intermatic Controller.  The time to send I estimate at 0.5 to 1.0 seconds.  The data set has 568 bytes = 4544 bits, @ 9600 bits per second, about 1/2 second.  Using od -x < /dev/ttyUAB0 to view the data stream, I measure about 1 seconds to display the data.  So worst case, that leaves 9 seconds for other messages without any collisions.  
 
I just put a new version on Github.  Many changes including improved logging, the beginnings of a REST & Sockets.io interface (which I plan to use to connect to home automation), and more clean up on the code.  
tag
 
tag said:
I just put a new version on Github.  Many changes including improved logging, the beginnings of a REST & Sockets.io interface (which I plan to use to connect to home automation), and more clean up on the code.  
tag
 Cool!   I will have to look at your code to get some pointers.  Most of my weekend was spent creating a Curl GET interface to send my pool data to my ISY home automation contrller which takes REST commands.   But I was able to modify Michael's code and now have all the key pump variables being updated in real time in my ISY!!!    The challenge I have now is how to allow the ISY to send variables to my program.  I want to do this so my ISY can start/stop my pump or change the speed program.   Does/will your program take REST commands and save variables from those commands?  
 
blueman2 said:
Does/will your program take REST commands...
I currently have a pretty basic REST API. Look at the very last section of code with the app.get commands. Right now you can call a URI and it will take some action (like output the system status, or toggle a circuit). It could pretty easily be expanded to suit your needs.  I still need to add a bunch more (like change the heat mode, heat set point, etc so let me know if there is something specific you would like to see.
 
blueman2 said:
...and save variables from those commands?
Not sure exactly what you mean by 'save variables'. What would you be looking to do?
 
tag
 
tag said:
I currently have a pretty basic REST API. Look at the very last section of code with the app.get commands. Right now you can call a URI and it will take some action (like output the system status, or toggle a circuit). It could pretty easily be expanded to suit your needs.  I still need to add a bunch more (like change the heat mode, heat set point, etc so let me know if there is something specific you would like to see.
 
Not sure exactly what you mean by 'save variables'. What would you be looking to do?
 
tag
 
Re-using Michael's code, I now have the ability now to strip commands being sent from my controller to my pump and then send a REST command via HTTP PUT from the Pi (hooked up to my Pool system) to my ISY home automation system.  This updates variables on my ISY with On/Off and Speed status.  I have already programmed an LED on a KPL switch on my back door to tell me if the pool pumps are running.  I like this because sometimes I manually turn on the pumps and leave them running all night long by mistake.  I can also do a program that sends me an email if my pumps have not run in the past 24 hours (indicating a problem), or have run more than 12 hours straight (which they should not for my setup).  So that was 50% of my goal already completed!   :)
 
Now I want to be able to send a JSON message from my ISY back to my Pi, and then have the Pi act on that by telling my pump to turn on or off.  I guess that would mean running a daemon that is always looking at a port number on my Pi for data, and when it gets it, triggers the pump to turn on or off.   This is the part that I am pretty lost on.  If you go this direction as well, I would love to learn from how you to it.  
 
If anyone wants the code I created for my setup, I am happy to share it.  It uses the aprs485.c program that Michael wrote (no changes) and leverages his iFlow program (lots of changes).  
 
blueman2 said:
Now I was to be able to send a JSON message from my ISY back to my Pi, and then have the Pi act on that by telling my pump to turn on or off.  I guess that would mean running a daemon that is always looking at a port number on my Pi for data, and when it gets it, triggers the pump to turn on or off.   This is the part that I am pretty lost on.  If you go this direction as well, I would love to learn from how you to it.
 
Here's how my code works.
1.  Express app (basically a web server) is running on port 3000 (could just as easily be standard port 80).  That's where all of my web pages are served up.
2.  The REST API is called via a URL.  For example, http://localhost:3000/circuit/1/toggle would toggle circuit 1.  You can see the exact code here.  
3.  This function that is being called is telling the app to write a specific message to the serial bus.
 
Since you're already using CURL (I believe), you could just use this to call a similar REST API that would send the correct command(s) to turn the pumps on/off.  Or, you could setup a generic REST API that would take in your JSON string and then parse it.  Either way, it shouldn't be too difficult.
 
Would that work?
 
Tag,
 
This sounds perfect.  I really should move over to your code rather than continue to use Michael's.  His was a great learning experience, but I think I need to use code that is in active development.  Time to do some more homework....
 
EDIT: Tag, I continue to have an error running your code unmodified.  It is (verbose logging):
 

18:08:09.894 VERBOSE Just Queued Message to send: 255,0,255,165,10,16,34,209,1,12,1,191
18:08:09.901 VERBOSE Done queueing messages to retrieve Custom Names and Circuit Names
18:08:09.931 VERBOSE Wrote 255,0,255,165,10,16,34,202,1,0,1,172 and # of bytes undefined Error?: null

/home/pi/pool2/index.js:590
if (b.data == 0) {
^
TypeError: Cannot read property '0' of undefined
at SerialPort.<anonymous> (/home/pi/pool2/index.js:590:35)
at SerialPort.emit (events.js:95:17)
at Object.module.exports.raw [as parser] (/home/pi/pool2/node_modules/serialport/lib/parsers.js:7:13)
at SerialPort.settings.dataCallback (/home/pi/pool2/node_modules/serialport/lib/serialport.js:147:14)
at SerialPort._emitData (/home/pi/pool2/node_modules/serialport/lib/serialport.js:350:18)
at SerialPort.<anonymous> (/home/pi/pool2/node_modules/serialport/lib/serialport.js:330:14)
at SerialPort.<anonymous> (/home/pi/pool2/node_modules/serialport/lib/serialport.js:343:7)
at Object.wrapper [as oncomplete] (fs.js:466:17)
pi@raspberrypi ~/pool2 $

Not able to run your code as is, I have made numerous attempts to strip out all code not related to talking to the pump, and it then runs without error, but does nothing.  On the http debug screen, nothing is shown when I select listen.  In silly logging mode, it shows no communications at all with my Pump.  Yet od -x < /dev/ttyUSB0 shows correct traffic signatures.  I also tried to talk to the program via http://localhost:3000/circuit/1/toggle or  http://localhost:3000/pump. They do show a response, with blank with no data.  
 
Any ideas on how to debug this?  The only difference is that I do not have a standard controller.  My controller is the Intermatic which acts like the IntelliComII, but keeping the pump always in remote mode.  It would be great if there was a way that your code would work with only a pump and a IntelliComII controller, which is pretty much what I have.  
 
blueman2 said:
Any ideas on how to debug this?  The only difference is that I do not have a standard controller.  My controller is the Intermatic which acts like the IntelliComII, but keeping the pump always in remote mode.  It would be great if there was a way that your code would work with only a pump and a IntelliComII controller, which is pretty much what I have.  
 
A new version, 0.0.9, is up on Github.  I've made a few changes, again.  Try this one and see if you are still having issues.  I've been racking my brain why you are getting that error, and I'm not able to come up with anything.  We can try adding some more debug code on your side to see what is happening if it is still not working.
 
Thanks!  I will give it a try tonight.  So far I really love being able to monitor my system using Michael's code, but being able to also control it would be ideal.  
 
Any idea why I am getting this?  I was not able to figure it out.  I tried uncommenting the prior line (you left that commented out), but no joy.  
 
Code:
/home/pi/pool2/index.js:12
var sp = new serialport("/dev/ttyUSB0", {
         ^
TypeError: object is not a function
    at Object.<anonymous> (/home/pi/pool2/index.js:12:10)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:929:3
 
blueman2 said:
Any idea why I am getting this?  I was not able to figure it out.  I tried uncommenting the prior line (you left that commented out), but no joy.  
 

/home/pi/pool2/index.js:12
var sp = new serialport("/dev/ttyUSB0", {
^
TypeError: object is not a function
at Object.<anonymous> (/home/pi/pool2/index.js:12:10)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
at node.js:929:3
 
I upgraded the SerialPort module to v4.0.1 (from 3.x).  Please use 
 

npm uninstall serialport

 
 and then 
 

npm install serialport

 
 The    -update and -upgrade options may do the trick as well, but I didn't try it.  
 
Back
Top