This is an update to https://robertjwallace.com/home-automation-smart-home/.
I am finally beginning to move from the X10 system to a more modern system, despite the cost. My existing system is an hybrid of Philips Hue and X10. To integrate the X10 with Alexa I use the X10 CM19 transceiver with the mochad linux driver, and ha-bridge, a Philips Hue emulator. This allowed me to use Alexa to control the X10 system.
I then added a “real” Hue bridge to the mix. Why the Hue? Well despite the cost of Hue bulbs I decided that it was one of the better products and I found the bridge on sale one day.
But there were a couple of factors that still tie me to the X10 system:
- Motion sensors. I use the X10 motion sensors to turn on lights when I enter a room. These cost about $19.00 where the Hue sensors cost $40.00. The X10 sensors have variable delays for auto off which I like as well.
- Some of my overhead light fixtures have multiple bulbs, making them fairly costly to use with the Hue bulbs.
- Some of my overhead lights are completely enclosed, making them susceptible to the LED bulbs overheating.
Well things were going well until one day Alexa stopped discovering and controlling the devices in the ha-bridge. I think it is likely a software update issue that caused the problem. Searching the web did not discover any solution. And since I had grown accustom to the voice control I decided that it was time to convert more of my rooms to Hue.
The main problem I wanted to overcome was getting the X10 motion sensors to work with the Hue lights. Fortunately there was a solution.
The CM19A and mochad use port 1099. If you watch the port traffic you can see the transmitted and received X10 wireless commands using the “nc” Linux command:
nc localhost 1099
11/15 07:53:20 Tx RF HouseUnit: M15 Func: On
11/15 07:53:22 Unknown RF camera command
11/15 07:53:22 5D 14 27 D8 80
11/15 07:53:22 Rx RF HouseUnit: M15 Func: On
11/15 07:53:22 Tx RF HouseUnit: M15 Func: Off
11/15 07:53:25 Rx RF HouseUnit: M16 Func: Off
11/15 07:53:26 Tx RF HouseUnit: M12 Func: On
The Philips Hue devices can be turned on by using an HTTP protocol command which can be sent to the bridge using the Linux “curl” command:
curl –request PUT –data ‘{“on”:true}’ http://192.168.254.26/api/$apikey/lights/$unit/state
So all I had to do is write a short program with Perl to monitor the port and when the program saw the correct X10 command that was a motion sensor, fire off the “curl” command.
I decide to use Linux piping to input the “nc” data to the Perl program, so the command to start monitoring the port in the background is:
nc localhost 1099 | perl motion.pl &
The Perl program only controls those X10 sensors that are used to control the Hue devices. The other X10 sensors still work normally.
So when it is all put together: Motion.pl monitors the traffic on port 1099 and when it sees a valid X10 command checks to see if the command is for a sensor controlling a Hue light. If it is, then motion.pl makes a system call to a Bash script when then calls huecmd.pl to turn on or off the hue light.
Motion.pl
#!/usr/bin/perl -w
use strict;
use JSON;
use HTTP::Request::Common;
use LWP;
# apikey for communicating with with hue bridge
my $apikey = "********************************";
sub gethuenames{
# send request to hue to return json with light data
my $agent = LWP::UserAgent->new;
my $url = "http://192.168.999.26/api/".$apikey."/lights";
my $response = $agent->get($url);
my $lights = decode_json($response->content);
my %obj;
while ((my $key, my $ele) = each %$lights)
{
my $name = %$ele{'name'};
$obj{"$name"} = "$key";
}
return %obj;
}
#
# get the list of Hue device names and numbers as a hash of "hue name" => "hue number"
my %huenames = gethuenames();
#
# program gets output from "nc localhost 1099" (monitors the X10 traffic through
# mochad) and looks for commands that match motion sensors. When one is found
# it fires off a system command to turn on or off the corresponding Hue device.
#
# hash table of motion sensor unit codes to check for. If a sensor code is changed
# or a new motion sensor added, then this table needs to be updated.
# motionsensor hash is x10 unit => hue light name.
my %motionsensors = (
12 => ['entry light'],
14 => ['spare room 1','spare room 2']
);
#
# infinite loop looking at output from pipe program nc
# When nc line = M3 on, turn on hue lamp number 6
while(1) {
my $line = readline(STDIN); # get the nc input
# look to see if it is a valid command
if ($line =~ /Rx\s*RF\s*HouseUnit:\s*M(\S*)\sFunc:\s*(On|Off)/) {
my $unit = $1;
my $cmd = lc $2;
if (exists $motionsensors{$unit}) # is this a sensor to control a Hue light
{
my @list = @{ $motionsensors{$unit} };
if ($cmd eq "on") { $cmd = "true"; } else { $cmd = "false"; }
foreach (@list)
{
system("perl /home/bob/Home-Automation/mochad-0.1.17/huecmd.pl \"$_\" $cmd");
}
}
}
}
huecmd bash script
echo "do hue commmand: "
echo $1
echo $2
/usr/bin/perl /home/bob/Home-Automation/mochad-0.1.17/huecmd.pl "$1" $2 > log.txt
huecmd Perl program
#!/usr/bin/perl
#use strict;
use JSON;
use HTTP::Request::Common;
use LWP;
#
# need an api key for the hue. See hue developer site:
# https://developers.meethue.com/develop/get-started-2/
#
my $apikey = "**************************";
sub gethuenames{
my $agent = LWP::UserAgent->new;
my $url = "http://192.168.999.26/api/".$apikey."/lights";
my $response = $agent->get($url);
my $lights = decode_json($response->content);
my %obj;
while ((my $key, my $ele) = each %$lights)
{
my $name = %$ele{'name'};
$obj{"$name"} = "$key";
}
return %obj;
}
my %obj = gethuenames();
my $device = @ARGV[0];
my $devnum = $obj{$device};
my $cmd = '{"on":'.@ARGV[1]."}";
my $url = "http://192.168.999.26/api/$apikey/lights/$devnum/state";
my $ua = LWP::UserAgent->new;
# Create a request
my $req = HTTP::Request->new(PUT => $url);
$req->content_type('application/json');
$req->content($cmd);
# Pass request to the user agent and get a response back
my $res = $ua->request($req);
# Check the outcome of the response
if ($res->is_success) {
print $res->content;
} else {
print $res->status_line, "n";
}