#!/usr/bin/perl use Time::HiRes qw(usleep); use Data::Dumper; use FindBin; # find the script's directory use lib $FindBin::Bin; # add that directory to the library path use xPL::common; ################################################################################ # constants # $vendor_id = 'dspc'; # from xplproject.org $device_id = 'buttons'; # max 8 chars $class_id = 'control'; # max 8 chars $separator = '-' x 80; $indent = ' ' x 2; #------------------------------------------------------------------------------- # global variables # my %configuration; $configuration{'pins'} = [5, 4, 1]; $configuration{'sleep_ms'} = 300; $configuration{'command'} = '/usr/local/bin/gpio'; ################################################################################ # Input arguments # use Getopt::Std; my %opts; getopts('hvp:n:t:w:c:', \%opts); die("\n". "Usage: $0 [options]\n". "\n". "Options:\n". "${indent}-h display this help message\n". "${indent}-v verbose\n". "${indent}-p port the base UDP port\n". "${indent}-n id the instance id (max. 12 chars)\n". "${indent}-t mins the heartbeat interval in minutes\n". "${indent}-w secs the startup sleep interval\n". "${indent}-c cmd the shell executable to control the switches\n". "\n". "Sends button state information.\n". "\n". "More information with: perldoc $0\n". "\n". "" ) if ($opts{h}); my $verbose = $opts{v}; my $client_base_port = $opts{'p'} || 50000; my $instance_id = $opts{'n'} || xpl_build_automatic_instance_id; my $heartbeat_interval = $opts{'t'} || 5; my $startup_sleep_time = $opts{'w'} || 0; $configuration{'command'} = $opts{'c'} || $configuration{'command'}; ################################################################################ # Internal functions # #------------------------------------------------------------------------------- # Build the WiringPi command for a GPIO read # sub build_read_command { my ($button_id, $configuration_ref) = @_; my $command = ''; # build command my $pins_ref = $$configuration_ref{'pins'}; my $pin = $$pins_ref[$button_id-1]; $command .= "$$configuration_ref{'command'} mode $pin up && "; $command .= "$$configuration_ref{'command'} read $pin"; return($command) } #------------------------------------------------------------------------------- # Get button values # sub get_button_values { my ($configuration_ref) = @_; my @controls = (); # read GPIOs my $pins_ref = $$configuration_ref{'pins'}; foreach my $index (1..scalar(@$pins_ref)) { my $command = build_read_command($index, \%configuration); my $value = `$command`; chomp($value); $value =~ s/0/on/; $value =~ s/1/off/; push(@controls, $value); } return(@controls) } #------------------------------------------------------------------------------- # Send button value # sub send_button_value { my ( $id, $value, $client_base_port, $vendor_id, $device_id, $instance_id, $class_id ) = @_; # create socket my ($client_port, $xpl_socket) = xpl_open_socket($xpl_port, $client_base_port); # send message #print "button $id : $value\n"; my $xpl_type = 'xpl-trig'; my $xpl_source = "$vendor_id-$device_id.$instance_id"; my $xpl_target = '*'; my $xpl_class = "$class_id.basic"; my %xpl_body = ('button' => $id, 'value' => $value); xpl_send_message( $xpl_socket, $xpl_port, $xpl_type, $xpl_source, $xpl_target, $xpl_class, %xpl_body ); # close socket close($xpl_socket); } ################################################################################ # Catch control-C interrupt # $SIG{INT} = sub{ $xpl_end++ }; ################################################################################ # Main script # sleep($startup_sleep_time); # xPL parameters my $xpl_id = xpl_build_id($vendor_id, $device_id, $instance_id); my $xpl_ip = xpl_find_ip; # create xPL socket my ($client_port, $xpl_socket) = xpl_open_socket($xpl_port, $client_base_port); # display working parameters if ($verbose == 1) { system("clear"); print("$separator\n"); print("Reading RPi GPIO buttons.\n"); print($indent . "class id : $class_id\n"); print($indent . "instance id: $instance_id\n"); print("\n"); } #------------------------------------------------------------------------------- # Main loop # my @controls; my $pins_ref = $configuration{'pins'}; my @pins = @$pins_ref; while ($xpl_end == 0) { # sleep sampling interval usleep($configuration{'sleep_ms'} * 1E3); # get buttons status my @new_controls = get_button_values(\%configuration); #print join(' ', @controls) . "\n"; if ($controls[0] ne '') { foreach my $index (0..scalar(@$pins_ref)-1) { if ($new_controls[$index] ne $controls[$index]) { if ($verbose == 1) { $button_id = $index + 1; print( $indent . "button $button_id : $controls[$index] -> $new_controls[$index]\n" ); } send_button_value( $index+1, $new_controls[$index], $client_base_port, $vendor_id, $device_id, $instance_id, $class_id ); } } } @controls = @new_controls; } ################################################################################ # Documentation (access it with: perldoc ) # __END__ =head1 NAME xpl-piButtouns.pl - Sends button state information =head1 SYNOPSIS xpl-piButtons.pl [options] =head1 DESCRIPTION This xPL client sends trigger messages from a Raspberry Pi when one of the selected GPIOs change value. =head1 OPTIONS =over 8 =item B<-h> Display a help message. =item B<-v> Be verbose. =item B<-p port> Specify the base port from which the client searches for a free port. If not specified, the client will take a default value. =item B<-n id> Specify the instance id (name). The id is limited to 12 characters. If not specified, it is constructed from the host name. =item B<-t mins> Specify the number of minutes between two heartbeat messages. =item B<-w secs> Specify the number of seconds before sending the first heartbeat. This allows to start the client after the hub, thus eliminating an prospective startup delay of one heartbeat interval. =item B<-c command> Specifies the WiringPi C command. =back =head1 TEST Make sure you have an C running on the machine. Start the button reader: C. Start C in another terminal window. Press a button and check that a message has been sent. =head1 AUTHOR Francois Corthay, DSPC =head1 VERSION 1.0, 2017 =cut