All Quiet on the western front
Well not really, with a new baby , new job and christmas all happening in the last few months, time has been precious.
I managed to get my heatmiser PRT-HW/N and PRT-N working on my openwrt box with a usb serial and rs232 to 485 adapter. Now using a spare sony ericson z610i phone via usb , I can control my heatmiser controls via sms. This is done using smstools , a bash file that parses the sms body and then runs a perl script based on the commands in the message.
The perl script does some serial communication to program the 2 heatmiser stats. I can set the temp, turn on/off frost control etc.
I hope to tidy it up a little bit, but so far it's quite robust, so a small tidy before I put the code somewhere for others to copy/use.
Other things , I have been fixing some bugs in m0n0wall and adding some features and adding to ipv6 support. I just ordered a usb GPS unit, so I can use it on m0n0wall or openwrt with gpsd and ntpd to create a stratum 1 time source. It was only around $30 so will be fun, even though it's my 4th gps unit now ! A commercial ntp unit of this nature is 6000 euro, though does have a better local timesource if gps fails, but not 5950 euros worth !
I managed to get my heatmiser PRT-HW/N and PRT-N working on my openwrt box with a usb serial and rs232 to 485 adapter. Now using a spare sony ericson z610i phone via usb , I can control my heatmiser controls via sms. This is done using smstools , a bash file that parses the sms body and then runs a perl script based on the commands in the message.
The perl script does some serial communication to program the 2 heatmiser stats. I can set the temp, turn on/off frost control etc.
I hope to tidy it up a little bit, but so far it's quite robust, so a small tidy before I put the code somewhere for others to copy/use.
Other things , I have been fixing some bugs in m0n0wall and adding some features and adding to ipv6 support. I just ordered a usb GPS unit, so I can use it on m0n0wall or openwrt with gpsd and ntpd to create a stratum 1 time source. It was only around $30 so will be fun, even though it's my 4th gps unit now ! A commercial ntp unit of this nature is 6000 euro, though does have a better local timesource if gps fails, but not 5950 euros worth !
Comments
Any chance you can share some (or all) of the code? My aim was to use an exisiting cheapo USB to RS232 cable attached to a RS232 to RS485 adapter (ebay probably). Also which packages would need to be installed on the router? Thanks in advance!
I used bash to do the sms control piece and that script then called perl scripts that controlled the heatmiser unit.
http://www.heatmiser.co.uk/support/admin/attachments/protocolv3system.pdf
and I followed what these guys did http://www.comfortforums.com/view_topic.php?forum_id=47&highlight=hometronic&id=918
I will do two posts, one with getheatmiserstatus.pl which you run with the unit number you want to query (I have 2 units on my chain)
perl getheatmiserstatus.pl 1
The other post with have toggleheatmiser.pl which you also pass a unit number to, and a command
perl toggleheatmiser.pl unit 1 on
perl toggleheatmiser.pl unit 1 off
perl toggleheatmiser.pl frost 1 on
perl toggleheatmiser.pl frost 1 off
perl toggleheatmiser.pl settemp 1 24
perl toggleheatmiser.pl setfrost 1 7
settemp passes the temp you want to set the unit too
setfrost sets the frost temp
use Net::Telnet ();
$t = new Net::Telnet( Timeout => 15 );
my $address = 0x01;
if ($ARGV[0] =~ /\d{1,2}/ ) {
$address = $ARGV[0];
}else {
print "Missing unit number\n";
exit;
}
my $function = 0x26;
my $data = 0x00;
my ($sum) = ( $address + $function + $data );
$t->open( Host => "127.0.0.1", Port => 2009 );
@lines = $t->print( chr($address), chr($function), chr($data), chr($sum) );
$line = $t->getline;
$line2 = $t->getline;
$t->close;
$line = $line . $line2;
@bytes = split( //, $line );
foreach (@bytes) {
$lastone = ord($_);
$newcalcsum = $newcalcsum + $lastone;
}
$newcalcsum = $newcalcsum - $lastone;
$newcalcsum = ( $newcalcsum | 0xff00 ) - 0xff00;
if ( $newcalcsum == $lastone ) {
my $floor_status = $bytes[3] >> 7;
my $preheat = ( $bytes[3] >> 4 ) & 0x07;
my $week = $bytes[3] & 0x0F;
my $hour = ord( $bytes[4] );
my $minute = ord( $bytes[5] );
my $temp = ord( $bytes[6] );
my $switching_diff = ord( $bytes[7] ) >> 4;
my $part_no = ord( $bytes[7] ) % 0x0F;
my $tempformat = ord( $bytes[8] ) & 0x01;
my $frost_mode = ord( $bytes[8] ) & 0x02;
my $sensor = ord( $bytes[8] ) & 0x04;
my $floor_limit = ord( $bytes[8] ) & 0x08;
my $output = ord( $bytes[8] ) & 0x10;
my $frost_protect = ord( $bytes[8] ) & 0x20;
my $keys_locked = ord( $bytes[8] ) & 0x40;
my $state = ord( $bytes[8] ) & 0x80;
my $set_temp = ord( $bytes[9] );
my $frost_temp = ord( $bytes[10] );
my $output_delay = ord( $bytes[11] );
my $floor_temp = ord( $bytes[12] );
#print $line . "\n";
# print "Floor Status " . ( ($floor_status) ? "ON\n" : "OFF\n" );
# print "Pre-heat " . ( ($preheat) ? "ON\n" : "OFF\n" );
print "Switching Diff $switching_diff\n";
# print "Time " . $hour . ":" . $minute;
# print "Part No $part_no\n";
print "Temp Format " . ( ($tempformat) ? "F\n" : "C\n" );
print "Frost Mode " . ( ($frost_mode) ? "ENABLED\n" : "DISABLED\n" );
print "Keys " . ( ($keys_locked) ? "LOCKED\n" : "UNLOCKED\n" );
print "Temp = $temp\n";
print "Set Temp = $set_temp Frost Temp = $frost_temp\n";
print "Output delay = $output_delay\n";
print "Frost Protect " . ( ($frost_protect) ? "ON\n" : "OFF\n" );
print "State " . ( ($state) ? "ON\n" : "OFF\n" );
print "Output " . ( ($output) ? "ON\n" : "OFF\n" );
}
else {
print "Checksum Error\n";
foreach (@bytes) {
print ord($_) . " ";
}
}
use Net::Telnet ();
$t = new Net::Telnet( Timeout => 15 );
my $address = 0x01;
my $function = 0x00;
my $data = 0x00;
if ($ARGV[0] =~ /unit/i ) {
$function = 0x82;
} elsif ($ARGV[0] =~ /Frost$/i ) {
$function = 0xe4;
} elsif ($ARGV[0] =~ /settemp/i ) {
$function = 0x84;
} elsif ($ARGV[0] =~ /frosttemp/i ) {
$function = 0x87;
}else {
print "Missing function\n";
exit;
}
if ($ARGV[1] =~ /off/i ) {
$data = 0x00;
} elsif ($ARGV[1] =~ /on/i ) {
$data = 0xFF;
} elsif ($ARGV[1] =~ /\d{1,2}/ ) {
$data = $ARGV[1];
}else {
print "Missing data\n";
exit;
}
if ($ARGV[2] =~ /\d{1,2}/ ) {
$address = $ARGV[2];
}else {
print "Missing unit number\n";
exit;
}
my ($sum) = ( ($address + $function + $data ) | 0xff00 ) - 0xff00;
$t->open( Host => "127.0.0.1", Port => 2009 );
#print chr($address) .chr($function) . chr(0xff) . chr($sum);
@lines = $t->print( chr($address), chr($function), chr($data), chr($sum) );
$line = $t->getline;
$t->close;
@bytes = split( //, $line );
$lastone = 'fail';
foreach (@bytes) {
$lastone = ord($_);
$newcalcsum = $newcalcsum + $lastone;
}
$newcalcsum = $newcalcsum - $lastone;
$newcalcsum = ( $newcalcsum | 0xff00 ) - 0xff00;
if ( $newcalcsum == $lastone ) {
print "Success\n";
}
else {
print "Checksum Error\n";
}
WRT->USB->RS232->RS485 or
WRT->USB->RS485 or
WRT->RS232->RS485
And then do you have a second USB for the phone or is it running on a separate PC?
My concern is that a USB to RSxxx adapter would need drivers (and my router doesn't have RS232 unless I open and solder!)?
Thanks for bearing with me, am quite new to Linux so going through a steep learning curve!
something like this
ipkg install kmod-usb-serial-pl2303
I had the usb to serial (rs232) lying around, so just got an rs232 to rs485 adapter
http://www.dealextreme.com/details.dx/sku.6040
so i'm WRT->USB->RS232->RS485
ipkg install kmod-usb-acm
i think (can't access box from here)
and
ipkg install smstools
http://www.heatmiser.co.uk/pclink.htm on a windows pc
I have 2 thermostats and as it is a weekend home I don't really want to leave a PC running 24/7 but happy to leave the router plugged in hence why WRT is my favoured option!
From what I gather you are looping the signal back (127.0.0.1) to a current telnet session on port 2009 (you have selected 2009 rather than the usual 23 for security I assume)- this would also explain why there is no login/password? I connect the typical way using ssh and struggling to enable telnet:
/etc/init.d/telnet start (or enable and reboot - nothing visible after typing "ps")
I have also simply tried telnetd which is loaded but it drops any connection attempt.
I found the following forum post but a little nervous to use it in case I have completely misunderstood the above!
https://forum.openwrt.org/viewtopic.php?id=11910
Is this effectively what you have done? Thanks again!
2009:raw:5:/dev/ttyUSB0:4800
nothing to do with telnetd
From the comfort forums, I have been sent a perl logging script which works with V3 thermostats. The problem is that it uses Device::SerialPort to communicate rather than telnet.pm. I could not get this to work - was this the same problem when you mentioned you struggled get the serial port to behave or which other 'perl to serial' method(s) did you try?
I bought a FTDI USB Serial adapter which has Tx and Rx LEDs so that I know when data is sent which has proven extermely useful. I was also given the tip to use a USB sniffer to get the correct code which was a brilliant idea.
This has brought me back full circle to your script and using Telnet.pm - I know something is being sent thanks to the LED but I get no reply and I'm trying to trace the problem. What I have done is completely cut down your getheatmiser.pl script to the bare essential 'send' element of the code (no listening). The idea being that if the Rx LED flashes back on the cable then I know the thermostat has responded and I can then build from that. I am pretty convinced my script adaptation is correct but I still get no answer. Would you mind if I ask whether I have missed anything out? If you think the script is OK, then the problem must be elsewhere and it will help me narrow down!
use Net::Telnet ();
$t = new Net::Telnet( Timeout => 15 );
# This code Works using Device::SerialPort
my $destination = 0x01;
my $length = 0x0A;
my $source = 0x81;
my $function = 0x00;
my $startl = 0x00;
my $starth = 0x00;
my $rwlengthl = 0xFF;
my $rwlengthh = 0xFF;
my $CRCl = 0x2C;
my $CRCh = 0x09;
# Send Code
$t->open( Host => "127.0.0.1", Port => 2009 );
@lines = $t->print( chr($destination), chr($length), chr($source), chr($function), chr($startl), chr($starth), chr($rwlengthl), chr($rwlengthh), chr($CRCl), chr($CRCh) );
$line = $t->getline;
$t->close;
Rather than use Telnet.pm, his script uses SerialPort - the problem being, as I think you experienced, that I cannot run/compile SerialPort on/from OpenWRT. If there is anyway of getting your script (well, my butchered adaptation of it!) as per my previous post to work that would be amazing!
I have also bought a null modem cable to try and analyse the serial messages being sent in order to debug - just ran out of time recently.
Precious little code available on the web, so it may help someone.