There are times when HCA would want to communicate with one of the Arduinos, either to obtain information from it (like temperatures) or have it perform some task (like close a relay to turn something on). Unfortunately, HCA doesn’t support communicating with Arduinos directly. Recently they’ve add some IP functionality but so far I’ve not gotten it to work and suspect it would be problematic in its current implementation anyway. So I’ve created an intermediate Perl program that accepts commands from HCA and sends them to the Arduinos.
For the geeks: there are two basic techniques to do this, called synchronous and asynchronous. After screwing around with both I ended up simplifying it greatly by designing the interaction to always be asynchronous. I use UDP packets, which have no mechanism to detect missing or duplicate packets. The simplicity is that I can send and receive packets to/from either end without regard for what else is going on. The tradeoff is simplicity vs reliability. As a practical matter, as far as I know, the reliability has been rock-solid over my wired network. Wireless networks may present more of a problem.
The basic components are:
- An HCA program wants an Arduino to do something and sets up the Arduino’s address and a command.
- An HCA program that takes the address and command and calls the intermediate Perl program to send the packet out.
- The intermediate Perl program sends the packet out.
- The Arduino is programmed to continually be looking for incoming packets. When one arrives it looks for the command and takes the appropriate action.
HCA Wants Action
This picture gives you an idea of how easy programming HCA can be. The little boxes are the different functions HCA provides. You drag them into the program and connect them. Each box, depending upon its function, contains more instructions.
In this example HCA wants an Arduino connected to a fire alarm to reset the alarm. The Arduino’s IP address is 192.168.0.69 and the command to reset the fire alarm is a simple “1”. The HCA program flow:
The first box is a “compute” function (omitting the start and end boxes), allowing a variety of arithmetic functions. In our case, we use it to set HCA flags with the Arduino’s address and the command. If we open up that box’s properties, we see:
There are 2 statements inside the compute box. They set the “ardcmd1” flag to “1” and the “ardaddr1” flag to “192.168.0.69”.
The next box down is an “execute internal” function that runs some other HCA program. If you opened up its properties you would see it starting a another HCA program named “ardsendcmd”. Certainly I could have skipped the extra program and combined their functions into just this one, but it was easier for a variety of reasons to keep them separate.
HCA Calls the Perl Program
Ardsendcmd looks like:
There’s only one box, an “execute external” function. If you open up its properties you see the following:
This is an important function so I’ll spend some time on it. It calls the Perl interpreter, perl.exe. It assigns a working directory where, if that program opens any files, that’s where they will go, or will be found. Finally, it tells the Perl interpreter which Perl program to execute and passes some parameters to it. In this case the program is one I wrote, called send-udp-1.pl. The 3 parameters are HCA flags, the same ones I set up earlier with my compute function. In this example I am only using 2 of the 3 flags. The unused flag could be used, for example, to contain a thermostat’s set point.
Perl Sends the Packet
The send-udp-1.pl program in its entirety (minus my comments):
use IO::Socket::INET;
use Getopt::Long; #pick up parms
my $cmdIn = sprintf(“%.0f”,$ARGV[0]);
my $addrOut = $ARGV[1];
my $dataIn = sprintf(“%.0f”,$ARGV[2]);
my $dataOut = $cmdIn . $dataIn;
my $socket = new IO::Socket::INET (
LocalPort => 6001,
Proto => ‘udp’,
PeerPort => 5001,
PeerAddr => $addrOut,
) or die “ERROR in Socket Creation : $!\n”;
print $socket “$dataOut”;
$socket->close();
You can see the entire comment-riddled program here.
The Perl program picks up the 3 parameters, using the 2nd one to address the packet and the first and third ones to make up the packet’s content. In this example, the command had been set to “1” and the data was whatever was left over from the previous execution.
The Arduino Acts
The Arduino at 192.168.0.69 is programmed to continuously be checking for incoming packets. When it receives one it looks for the command and takes the appropriate action. The operational parts of the Arduino sketch are (in a very abbreviated form):
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x69 };
IPAddress ip(192, 168, 0, 69);
unsigned int localPort = 5001;
char cmdResetFire = ‘1’;
EthernetUDP Udp;
char packetBuffer[UDP_TX_PACKET_MAX_SIZE];
char cmdIn = ‘0’;
void setup()
{
Ethernet.begin(mac,ip);
Udp.begin(localPort);
}
void loop()
{
int packetSize = Udp.parsePacket();
if(packetSize)
{
Udp.read(packetBuffer,1);
cmdIn = (packetBuffer[0]);
if (cmdIn == cmdResetFire)
{
digitalWrite(fireRelayPin,LOW);
delay(1000);
digitalWrite(fireRelayPin,HIGH);
}
}
}
This entire Arduino sketch, about fire alarms, can be found here.