diff --git a/README b/README new file mode 100644 --- /dev/null +++ b/README @@ -0,0 +1,3 @@ +Combine RasperryShake with Hue Lights + +On the RaspberryShake add an UDP Stream to the IP of your Pi. Port 8889 diff --git a/huehuehue-shake.pl b/huehuehue-shake.pl new file mode 100644 --- /dev/null +++ b/huehuehue-shake.pl @@ -0,0 +1,109 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use diagnostics; + +use IO::Socket; +use feature qw(:all); + +use Data::Dumper; +use HTTP::Tiny; +use Term::ANSIColor; +use JSON::Parse qw(:all); +use Net::UPnP::ControlPoint; + +my ($channel, $timestamp, $magnitude, $sleeptimer, $laststate); +my ($bridgeIP, $hueapikey, $http, $UPnP, $name, $device); +my ($socket, $msg, $maxlen, $port, $json, $api_request); +my ($green_hue, $orange_hue, $red_hue); +my @devices; + +$bridgeIP = shift || ""; # IP address as an argument. Not mandatory. +$hueapikey = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'; # The API key/pass you get from the Hue Bridge +$maxlen = 1024; # max length for our UDP server to accept +$port = 8889; # port for our UDP server to listen +$sleeptimer = 2; # set the sleep timer + +($green_hue, $orange_hue, $red_hue) = (3, 1, 2); # Order of the light bulbs by the Hue Bridge +$laststate = ""; # diagnostics - do not modify +$channel = ""; # diagnostics - do not modify + +say "[", color('bold blue'), "+", color('reset'), "] Raspberry shake to Hue Traffic-Light"; +$http = HTTP::Tiny->new; +unless ($bridgeIP =~ /\d+\.\d+\.\d+\.\d+/) { + say "[", color('bold blue'), "~", color('reset'), "] UPnP search for Hue Bridge..."; + + $UPnP = Net::UPnP::ControlPoint->new(); + @devices = $UPnP->search(st =>'urn:schemas-upnp-org:device:Basic:1', + mx => 3); + foreach $device (@devices) { + $name = $device->getfriendlyname(); + $bridgeIP = $1 and last if $name =~ /Philips Hue \((\d+\.\d+\.\d+\.\d+)\)/g; + } +} +say "[", color('bold blue'), "-", color('reset'), "] No Hue Bridge found!" and exit unless $bridgeIP =~ /\d+\.\d+\.\d+\.\d+/; +say "[", color('bold blue'), "+", color('reset'), "] Hue Bridge found under $bridgeIP" if $bridgeIP; + +$socket = IO::Socket::INET->new( LocalPort => $port, + Proto => 'udp') or die "socket: $@"; +say "[", color('bold blue'), "+", color('reset'), "] UDP server runs on port $port"; + +while ($socket->recv($msg, $maxlen)) { + ($channel, $timestamp, $magnitude) = ($1, $2, $3) if $msg =~ /^\{\'(\w{3})\'\, (\d+\.\d+)\, (\d+)/g; + if ($channel eq "ENE") { + sleep $sleeptimer; + $magnitude += 100000; + $api_request = $http->get('http://' . $bridgeIP . '/api/' . $hueapikey); + say "[", color('bold blue'), "-", color('reset'), "] Hue Bridge seems down!" and exit unless $api_request->{success}; + $json = valid_json($api_request->{content}); + say "[", color('bold blue'), "-", color('reset'), "] Hue Bridge responded with malformed json" and exit unless $json; + $json = parse_json($api_request->{content}); + say "[", color('bold blue'), "-", color('reset'), "] Error! Bridge responded with: $json->[0]{error}{description}" and exit if eval { $json->[0]{error}{description} }; + if ($magnitude < 269363) { + say "[", color('bold green'), "!", color('reset'), "] Magnitude: $magnitude"; + unless ($laststate eq "green") { + $api_request = $http->put('http://' . $bridgeIP . '/api/' . $hueapikey . '/lights/' . $green_hue . '/state', + { content => '{"on":true, "sat":254, "bri":254, "hue":25653}' } ); + say "[", color('bold blue'), "-", color('reset'), "] Could not reach Hue Light bulb" and exit unless $api_request->{success}; + $api_request = $http->put('http://' . $bridgeIP . '/api/' . $hueapikey . '/lights/' . $orange_hue . '/state', + { content => '{"on":false}' } ); + say "[", color('bold blue'), "-", color('reset'), "] Could not reach Hue Light bulb" and exit unless $api_request->{success}; + $api_request = $http->put('http://' . $bridgeIP . '/api/' . $hueapikey . '/lights/' . $red_hue . '/state', + { content => '{"on":false}' } ); + say "[", color('bold blue'), "-", color('reset'), "] Could not reach Hue Light bulb" and exit unless $api_request->{success}; + $laststate = "green"; + } + } elsif ($magnitude <= 361343) { + say "[", color('bold yellow'), "!", color('reset'), "] Magnitude: $magnitude"; + unless ($laststate eq "orange") { + $api_request = $http->put('http://' . $bridgeIP . '/api/' . $hueapikey . '/lights/' . $orange_hue . '/state', + { content => '{"on":true, "sat":254, "bri":254, "hue":7038}' } ); + say "[", color('bold blue'), "-", color('reset'), "] Could not reach Hue Light bulb" and exit unless $api_request->{success}; + $api_request = $http->put('http://' . $bridgeIP . '/api/' . $hueapikey . '/lights/' . $green_hue . '/state', + { content => '{"on":false}' } ); + say "[", color('bold blue'), "-", color('reset'), "] Could not reach Hue Light bulb" and exit unless $api_request->{success}; + $api_request = $http->put('http://' . $bridgeIP . '/api/' . $hueapikey . '/lights/' . $red_hue . '/state', + { content => '{"on":false}' } ); + say "[", color('bold blue'), "-", color('reset'), "] Could not reach Hue Light bulb" and exit unless $api_request->{success}; + $laststate = "orange"; + } + } elsif ($magnitude > 361343) { + say "[", color('bold red'), "!", color('reset'), "] Magnitude: $magnitude"; + unless ($laststate eq "red") { + $api_request = $http->put('http://' . $bridgeIP . '/api/' . $hueapikey . '/lights/' . $red_hue . '/state', + { content => '{"on":true, "sat":254, "bri":254, "hue":65527}' } ); + say "[", color('bold blue'), "-", color('reset'), "] Could not reach Hue Light bulb" and exit unless $api_request->{success}; + $api_request = $http->put('http://' . $bridgeIP . '/api/' . $hueapikey . '/lights/' . $orange_hue . '/state', + { content => '{"on":false}' } ); + say "[", color('bold blue'), "-", color('reset'), "] Could not reach Hue Light bulb" and exit unless $api_request->{success}; + $api_request = $http->put('http://' . $bridgeIP . '/api/' . $hueapikey . '/lights/' . $green_hue . '/state', + { content => '{"on":false}' } ); + say "[", color('bold blue'), "-", color('reset'), "] Could not reach Hue Light bulb" and exit unless $api_request->{success}; + $laststate = "red"; + } + } + } +} +die "recv: $!"; +