File Coverage

blib/lib/HiPi/Energenie/Command.pm
Criterion Covered Total %
statement 36 635 5.6
branch 0 284 0.0
condition 0 93 0.0
subroutine 12 53 22.6
pod 0 29 0.0
total 48 1094 4.3


line stmt bran cond sub pod time code
1             #########################################################################################
2             # Package HiPi::Energenie::Command
3             # Description : Energenie Command Wrapper
4             # Copyright : Copyright (c) 2017 Mark Dootson
5             # License : This is free software; you can redistribute it and/or modify it under
6             # the same terms as the Perl 5 programming language system itself.
7             #########################################################################################
8              
9             package HiPi::Energenie::Command;
10              
11             #########################################################################################
12              
13 1     1   1278 use strict;
  1         4  
  1         31  
14 1     1   5 use warnings;
  1         2  
  1         26  
15 1     1   6 use feature 'say';
  1         1  
  1         156  
16 1     1   7 use parent qw( HiPi::Class );
  1         2  
  1         5  
17 1     1   74 use HiPi qw( :openthings :energenie :rpi );
  1         3  
  1         588  
18 1     1   9 use HiPi::Energenie;
  1         2  
  1         56  
19 1     1   464 use HiPi::Utils::Config;
  1         4  
  1         54  
20 1     1   852 use Getopt::Long qw( GetOptionsFromArray );
  1         10986  
  1         6  
21 1     1   239 use JSON;
  1         3  
  1         16  
22 1     1   119 use Try::Tiny;
  1         2  
  1         58  
23 1     1   9 use HiPi::RF::OpenThings::Message;
  1         3  
  1         152  
24              
25             our $VERSION ='0.81';
26              
27             __PACKAGE__->create_accessors( qw( config result mode display options pretty user console_display_message) );
28              
29             use constant {
30 1         9636 ERROR_SUCCESS => 'ERROR_SUCCESS',
31             ERROR_UNKNOWN => 'ERROR_UNKNOWN',
32             ERROR_MISSING_COMMAND => 'ERROR_MISSING_COMMAND',
33             ERROR_BAD_COMMAND => 'ERROR_BAD_COMMAND',
34             ERROR_BAD_OPTIONS => 'ERROR_BAD_OPTIONS',
35            
36             ERROR_SYSTEM => 'ERROR_SYSTEM',
37            
38             ERROR_CONFIG_INVALID_BOARD => 'ERROR_CONFIG_INVALID_BOARD',
39             ERROR_CONFIG_INVALID_DEVICE => 'ERROR_CONFIG_INVALID_DEVICE',
40             ERROR_CONFIG_INVALID_GPIO => 'ERROR_CONFIG_INVALID_GPIO',
41            
42             ERROR_GROUP_INVALID_OPTIONS => 'ERROR_GROUP_INVALID_OPTIONS',
43             ERROR_GROUP_EXISTING_GROUP => 'ERROR_GROUP_EXISTING_GROUP',
44             ERROR_GROUP_EXISTING_NAME => 'ERROR_GROUP_EXISTING_NAME',
45             ERROR_GROUP_NAME_NOT_FOUND => 'ERROR_GROUP_NAME_NOT_FOUND',
46             ERROR_GROUP_ID_NOT_FOUND => 'ERROR_GROUP_ID_NOT_FOUND',
47            
48             ERROR_PAIR_INVALID_OPTIONS => 'ERROR_PAIR_INVALID_OPTIONS',
49             ERROR_PAIR_GROUP_NOT_FOUND => 'ERROR_PAIR_GROUP_NOT_FOUND',
50             ERROR_PAIR_INVALID_SWITCH => 'ERROR_PAIR_INVALID_SWITCH',
51             ERROR_PAIR_NAME_NOT_FOUND => 'ERROR_PAIR_NAME_NOT_FOUND',
52             ERROR_PAIR_EXISTING_SWITCH => 'ERROR_PAIR_EXISTING_SWITCH',
53            
54             ERROR_SWITCH_INVALID_OPTIONS => 'ERROR_SWITCH_INVALID_OPTIONS',
55             ERROR_SWITCH_GROUP_NOT_FOUND => 'ERROR_SWITCH_GROUP_NOT_FOUND',
56             ERROR_SWITCH_INVALID_SWITCH => 'ERROR_SWITCH_INVALID_SWITCH',
57             ERROR_SWITCH_NAME_NOT_FOUND => 'ERROR_SWITCH_NAME_NOT_FOUND',
58            
59             ERROR_ALIAS_INVALID_OPTIONS => 'ERROR_ALIAS_INVALID_OPTIONS',
60             ERROR_ALIAS_GROUP_NOT_FOUND => 'ERROR_ALIAS_GROUP_NOT_FOUND',
61             ERROR_ALIAS_INVALID_SWITCH => 'ERROR_ALIAS_INVALID_SWITCH',
62            
63             ERROR_USUPPORTED_RX_COMMAND => 'ERROR_USUPPORTED_RX_COMMAND',
64            
65             ERROR_JOIN_INVALID_OPTIONS => 'ERROR_JOIN_INVALID_OPTIONS',
66             ERROR_JOIN_EXISTING_ADAPTER => 'ERROR_JOIN_EXISTING_ADAPTER',
67             ERROR_JOIN_EXISTING_MONITOR => 'ERROR_JOIN_EXISTING_MONITOR',
68             ERROR_JOIN_DEVICE_NOT_FOUND => 'ERROR_JOIN_DEVICE_NOT_FOUND',
69             ERROR_JOIN_FAILED => 'ERROR_JOIN_FAILED',
70            
71             ERROR_ADAPTER_INVALID_OPTIONS => 'ERROR_ADAPTER_INVALID_OPTIONS',
72             ERROR_ADAPTER_NAME_NOT_FOUND => 'ERROR_ADAPTER_NAME_NOT_FOUND',
73             ERROR_ADAPTER_FAILED => 'ERROR_ADAPTER_FAILED',
74            
75             ERROR_MONITOR_INVALID_OPTIONS => 'ERROR_MONITOR_INVALID_OPTIONS',
76             ERROR_MONITOR_NAME_NOT_FOUND => 'ERROR_MONITOR_NAME_NOT_FOUND',
77             ERROR_MONITOR_FAILED => 'ERROR_MONITOR_FAILED',
78            
79 1     1   11 };
  1         2  
80              
81             my $commandopts = {
82             help => {
83             template => undef,
84             defaults => {},
85             },
86             version => {
87             template => undef,
88             defaults => {},
89             },
90             config => {
91             template => [ 'help|h!', 'list|l!', 'device|d:s', 'board|b:s', 'reset|r:s' ],
92             defaults => { help => 0, list => 0, device => undef, board => undef, reset => undef },
93             },
94             group => {
95             template => [ 'help|h!', 'create|c:s', 'delete|d:s', 'rename|r:s', 'group|g:o', 'newname|n:s', 'list|l!',],
96             defaults => { },
97             },
98             pair => {
99             template => [ 'help|h!', 'list|l', 'groupname|g:s', 'switch|s:i', 'name|n:s', ],
100             defaults => { groupname => undef, switch => 0, },
101             },
102             switch => {
103             template => [ 'help|h!', 'list|l!', 'groupname|g:s', 'switch|s:i', 'name|n:s', 'on|1!', 'off|0!', 'all!' ],
104             defaults => { help => 0, list => 0, groupname => undef, switch => undef, on => 0, off => 0, all => 0, } ,
105             },
106             alias => {
107             template => [ 'help|h!', 'list|l!', 'groupname|g:s', 'switch|s:i', 'name|n:s', ],
108             defaults => { help => 0, list => 0, } ,
109             },
110             join => {
111             template => [ 'help|h!', 'list|l!', 'name|n:s', 'delete|d:s', 'rename|r:s' ],
112             defaults => { help => 0, list => 0, name => '', delete => '', rename => '' },
113             },
114             adapter => {
115             template => [ 'help|h!', 'list|l!', 'name|n:s', 'query|q!', 'on|1!', 'off|0!', ],
116             defaults => { name => undef, query => 0, on => 0, off => 0, list => 0, help => 0, },
117             },
118             monitor => {
119             template => [ 'help|h!', 'list|l!', 'name|n:s', ],
120             defaults => { name => undef, list => 0, help => 0, } ,
121             },
122             };
123              
124              
125             sub new {
126 0     0 0   my($class, %userparams ) = @_;
127            
128 0           my %params = (
129             display => 'usage',
130             mode => 'console',
131             pretty => 0,
132             user => getpwuid($>),
133             console_display_message => '',
134             result => {
135             success => 0,
136             command => 'unknown',
137             option => '',
138             error => 'unknown error',
139             errorcode => ERROR_UNKNOWN,
140             data => {},
141             },
142             );
143            
144 0           foreach my $key (sort keys(%userparams)) {
145 0           $params{$key} = $userparams{$key};
146             }
147            
148 0           $params{config} = HiPi::Utils::Config->new(
149             configclass => 'scripts/energenie',
150             default => {
151             version => $VERSION,
152             board => 'ENER314_RT',
153             spi_device => '/dev/spidev0.1',
154             reset_gpio => RPI_PIN_22,
155             led_red_gpio => 0,
156             led_green_gpio => 0,
157             groups => {},
158             adapters => {},
159             monitors => {},
160             switches => {},
161             },
162             );
163            
164 0           my $self = $class->SUPER::new( %params );
165 0           return $self;
166             }
167              
168 0     0 0   sub conf { $_[0]->config->config(); }
169              
170             sub valid_command {
171 0     0 0   my( $self, $command) = @_;
172 0 0 0       return 0 if( length($command) > 40 || $command !~ /^[a-z]+$/ );
173 0 0         return ( exists($commandopts->{$command}) ) ? 1 : 0;
174             }
175            
176             sub handle_command {
177 0     0 0   my $self = shift;
178 0           my @commandargs = @ARGV;
179            
180 0           $self->handle_command_arguments( @commandargs );
181             }
182              
183             sub handle_command_arguments {
184 0     0 0   my ($self, @inputargs) = @_;
185            
186 0           my @commandargs = ();
187            
188             my $result = try {
189            
190 0     0     for my $arg ( @inputargs ) {
191 0 0         if( lc($arg) eq '--json' ) {
    0          
192 0           $self->mode('json');
193             } elsif( lc($arg) eq '--pretty' ) {
194 0           $self->mode('json');
195 0           $self->pretty(1);
196             } else {
197 0           push @commandargs, $arg;
198             }
199             }
200            
201 0 0         $commandargs[0] = 'missing' unless @commandargs;
202            
203 0           my $command = shift @commandargs;
204            
205 0 0         if ( $self->valid_command($command) ) {
206 0           $self->result->{command} = $command;
207 0           my $opt = $commandopts->{$command}->{defaults};
208 0           my $opttemplate = $commandopts->{$command}->{template};
209 0 0         if( $opttemplate ) {
210 0           GetOptionsFromArray(\@commandargs, $opt, @$opttemplate )
211             }
212 0           $self->options( $opt );
213 0           my $commandsub = qq(command_$command);
214 0           $self->$commandsub();
215             } else {
216 0           $self->result->{command} = $command;
217 0 0         my $errorcode = ( $command eq 'missing' ) ? ERROR_MISSING_COMMAND : ERROR_BAD_COMMAND;
218 0           $self->set_result_error( $errorcode, qq(bad or missing command provided : $command ))
219             }
220            
221 0           $self->return_result();
222             } catch {
223 0     0     my $error = $_;
224 0           $error =~ s/["\n]/ /g;
225 0           return qq({"success":0,"errorcode":"ERROR_SYSTEM","error":"$error"});
226 0           };
227            
228 0           return $result;
229             }
230              
231             sub return_result {
232 0     0 0   my $self = shift;
233            
234 0 0         if($self->mode eq 'json') {
235 0 0 0       if( exists( $self->result->{data}) && ref($self->result->{data})->isa('HiPi::RF::OpenThings::Message') ) {
236 0           $self->result->{data} = $self->result->{data}->value_hash;
237             }
238 0           my $j = JSON->new;
239 0 0         my $output = ( $self->pretty ) ? $j->pretty->canonical->encode( $self->result ) : $j->encode( $self->result );
240 0           return $output;
241             }
242            
243 0 0         if( $self->display eq 'usage' ) {
244            
245 0           my $output = '';
246 0 0         if( $self->result->{errorcode} ne 'ERROR_SUCCESS' ) {
247 0           $output .= sprintf(qq(\nERROR : %s : %s\n), $self->result->{errorcode}, $self->result->{error});
248             }
249 0           $output .= $self->get_command_usage($self->result->{command});
250            
251 0           return $output;
252             }
253            
254             # display the command result
255 0 0 0       if( $self->result->{errorcode} ne 'ERROR_SUCCESS' || !$self->result->{success} ) {
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0          
256 0           return sprintf(qq(Command : %s : ERROR : %s : %s), $self->result->{command}, $self->result->{errorcode}, $self->result->{error});
257            
258             # CONFIG
259            
260             } elsif( $self->result->{command} eq 'config') {
261            
262 0           my $output = qq(\nCONFIGURATION\n);
263 0           $output .= qq(-----------------------------------------\n);
264            
265 0 0         if( my $data = $self->result->{data} ) {
266            
267 0           my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime( $data->{epoch} );
268 0           my $timestamp = sprintf('%u-%02u-%02u %02u:%02u:%02u',
269             $year + 1900, $mon + 1, $mday, $hour, $min, $sec
270             );
271            
272 0 0         $output .= qq( Config Version : $data->{version}\n) if $data->{version};
273 0 0         $output .= qq( Energenie Board : $data->{board}\n) if $data->{board};
274 0 0         $output .= qq( Receiver : $data->{can_rx}\n) if $data->{can_rx};
275 0 0         $output .= qq( Uses SPI : $data->{uses_spi}\n) if $data->{uses_spi};
276 0 0 0       $output .= qq( SPI Device : $data->{spi_device}\n) if $data->{spi_device} && $data->{can_rx} eq 'YES';
277 0 0 0       $output .= qq( Reset GPIO : $data->{reset_gpio}\n) if $data->{spi_device} && $data->{can_rx} eq 'YES';
278 0           $output .= qq( Config Saved : $timestamp\n);
279             }
280 0           return $output;
281            
282             # VERSION
283            
284             } elsif( $self->result->{command} eq 'version') {
285 0           return $self->result->{data}->{versiontext};
286            
287             # GROUP
288            
289             } elsif( $self->result->{command} eq 'group') {
290 0           my $output = qq(\nGROUPS\n);
291 0           $output .= qq(-----------------------------------------\n);
292             # $output .= qq(NAME ID\n);
293 0           for my $gname ( sort keys %{ $self->result->{data}->{groups} } ) {
  0            
294 0           my $gid = $self->result->{data}->{groups}->{$gname};
295 0           $output .= sprintf(qq( %-30s %s\n), $gname, $gid);
296             }
297 0           return $output;
298            
299             # SWITCH LIST
300            
301             } elsif( $self->result->{command} =~ /^pair|alias$/
302             || ( $self->result->{command} eq 'switch' && $self->result->{option} eq 'list') ) {
303            
304 0           my $output = qq(\nSWITCHES & SOCKETS\n);
305 0           $output .= qq(------------------------------------------\n);
306 0           $output .= qq( NAME GROUP SWITCH\n);
307 0           for my $switch( sort keys %{ $self->result->{data}->{switches} } ) {
  0            
308 0           my $group = $self->result->{data}->{switches}->{$switch}->{group};
309 0           my $sno = $self->result->{data}->{switches}->{$switch}->{switch};
310 0           $output .= sprintf(qq( %-18s %-18s %s\n), $switch, $group, $sno);
311             }
312 0           return $output;
313            
314             # SWITCH BROADCAST
315            
316            
317             } elsif( $self->result->{command} eq 'switch' && $self->result->{option} ne 'list' ) {
318            
319            
320 0           my $output = sprintf(qq(\nSWITCH BROADCAST STATUS - %s\n), $self->result->{data}->{status});
321 0           $output .= qq(-------------------------------\n);
322            
323 0 0         my @snums = ( $self->result->{data}->{switch} ) ? ( $self->result->{data}->{switch} ) : (1,2,3,4);
324 0           my $group = $self->result->{data}->{groupname};
325 0           $output .= qq( GROUP SWITCH\n);
326 0           for my $switch( @snums ) {
327 0           $output .= sprintf(qq( %-25s %s\n), $group, $switch);
328             }
329            
330 0           return $output;
331            
332             } elsif( $self->result->{command} eq 'join' || ( $self->result->{command} =~ /^adapter|monitor$/ && $self->result->{option} eq 'list' ) ) {
333            
334 0           my $output = qq(\nMONITORS AND ADAPTERS\n);
335 0           $output .= qq(---------------------------------------------------------------------\n);
336 0           $output .= (qq( NAME PRODUCT SENSORID SWITCH\n));
337            
338 0 0         my $listname = ( $self->result->{command} eq 'adapter' ) ? 'adapters' : 'monitors';
339            
340 0           for my $monitor ( sort keys %{ $self->result->{data}->{$listname} } ) {
  0            
341 0           my $data = $self->result->{data}->{$listname}->{$monitor};
342 0 0         my $switch = HiPi::RF::OpenThings->product_can_switch( $data->{manufacturer_id}, $data->{product_id} ) ? 'YES' : ' NO';
343             # my $switch = ( exists( $self->result->{data}->{adapters}->{$monitor}) ) ? 'YES' : ' NO';
344             $output .= sprintf(qq( %-20s %-28s 0x%06X %s\n),
345 0           $monitor, $data->{product_name}, $data->{sensor_id}, $switch
346             );
347             }
348            
349            
350 0           return $output;
351            
352             } elsif( $self->result->{command} =~ /^adapter|monitor$/ && $self->result->{option} ne 'list' ) {
353            
354 0           my $data = $self->result->{data}->value_hash;
355            
356 0           my $output = sprintf(qq(\n%s STATUS REPORT FOR "%s"\n), uc($self->result->{command}), $data->{'configured_name'});
357 0           $output .= qq(---------------------------------------------\n);
358 0           $output .= qq( Sensor Type $data->{product_name}\n);
359 0           $output .= qq( Sensor Key $data->{sensor_key}\n);
360 0           $output .= qq( Timestamp $data->{timestamp}\n);
361 0           $output .= qq( -------------------------------------------\n);
362 0           for my $record ( @{ $data->{records} } ) {
  0            
363 0           my $value = $record->{value};
364 0 0         if( $record->{id} == OPENTHINGS_PARAM_SWITCH_STATE ) {
365 0 0         $value = ( $value ) ? 'ON' : 'OFF';
366             }
367 0 0         my $unitpart = ($record->{units}) ? qq( $record->{units}) : '';
368 0           $output .= sprintf(qq( %-20s %s%s\n), $record->{name}, $value, $unitpart);
369            
370             }
371            
372 0           return $output;
373             # other ?
374             } else {
375 0 0 0       if( exists( $self->result->{data}) && ref($self->result->{data})->isa('HiPi::RF::OpenThings::Message') ) {
376 0           $self->result->{data} = $self->result->{data}->value_hash;
377             }
378 0           my $j = JSON->new;
379 0           my $output = $j->pretty->canonical->encode( $self->result );
380 0           return $output;
381             }
382             }
383              
384             sub set_result_success {
385 0     0 0   my( $self, $data, $option ) = @_;
386 0 0         if( $data ) {
387 0           $self->display('data');
388 0           $self->result->{data} = $data;
389             }
390 0           $self->result->{success} = 1;
391 0           $self->result->{error} = '';
392 0           $self->result->{errorcode} = ERROR_SUCCESS;
393 0 0         $self->result->{option} = $option if $option;
394 0           return;
395             }
396              
397             sub set_result_error {
398 0     0 0   my ($self, $errorcode, $error, $option) = @_;
399 0   0       $error //= $errorcode;
400 0           $self->display('error');
401 0           $self->result->{success} = 0;
402 0           $self->result->{error} = $error;
403 0           $self->result->{errorcode} = $errorcode;
404 0 0         $self->result->{option} = $option if $option;
405 0           return;
406             }
407              
408             sub set_result_options_error {
409 0     0 0   my ($self, $errorcode, $error, $option) = @_;
410 0   0       $error //= $errorcode;
411 0           $self->display('options');
412 0           $self->result->{success} = 0;
413 0           $self->result->{error} = $error;
414 0           $self->result->{errorcode} = $errorcode;
415 0 0         $self->result->{option} = $option if $option;
416 0           return;
417             }
418              
419             sub command_help {
420 0     0 0   my $self = shift;
421 0           $self->set_result_success();
422 0           return;
423             }
424              
425             sub command_version {
426 0     0 0   my $self = shift;
427 0           $self->set_result_success(
428             {
429             version => $VERSION,
430             versiontext => qq(HiPi Energenie Version $VERSION),
431             }
432             );
433 0           return;
434             }
435              
436             sub command_config {
437 0     0 0   my( $self ) = @_;
438            
439 0 0         if( $self->options->{help} ) {
    0          
440 0           $self->set_result_success(undef, 'help');
441 0           return;
442             } elsif( $self->options->{list} ) {
443 0           $self->list_configuration('list');
444 0           return;
445             } else {
446 0           my( $newdevice, $newboard, $newreset );
447            
448 0 0         if ( $self->options->{device} ) {
449 0 0         if( my ($devicename) = ( $self->options->{device} =~ /^(\/dev\/spidev\d\.\d)$/i ) ) {
450 0           $newdevice = $devicename;
451             } else {
452             $self->set_result_error(
453             ERROR_CONFIG_INVALID_DEVICE,
454 0           sprintf(q(Invalid device %s specified), $self->options->{device}),
455             'update',
456             );
457 0           return;
458             }
459             }
460            
461 0 0         if( $self->options->{board} ) {
462 0 0         if( my ($board) = ( $self->options->{board} =~ /^(ENER314|ENER314_RT)$/i ) ) {
463 0           $newboard = uc($board);
464             } else {
465             $self->set_result_error(
466             ERROR_CONFIG_INVALID_BOARD,
467 0           sprintf(q(Invalid board %s specified), $self->options->{board}),
468             'update',
469             );
470 0           return;
471             }
472             }
473            
474 0 0         if( defined($self->options->{reset}) ) {
475             # reset should be a number greater than 0
476 0 0 0       if( $self->options->{reset} && $self->options->{reset} =~ /^\d+$/ ) {
477 0           $newreset = $self->options->{reset};
478             } else {
479             $self->set_result_error(
480             ERROR_CONFIG_INVALID_GPIO,
481 0           sprintf(q(Invalid Reset GPIO %s specified), $self->options->{reset}),
482             'update',
483             );
484 0           return;
485             }
486             }
487            
488 0           my $coption = 'update';
489            
490 0 0         if( $newdevice ) {
491 0           $self->conf->{spi_device} = $newdevice;
492 0           $coption = 'refresh';
493             }
494            
495 0 0         if( $newboard ) {
496 0           $self->conf->{board} = $newboard;
497 0           $coption = 'refresh';
498             }
499            
500 0 0         if( $newreset ) {
501 0           $self->conf->{reset_gpio} = $newreset;
502 0           $coption = 'refresh';
503             }
504            
505             # so put config info in data
506 0           $self->list_configuration($coption);
507             }
508 0           return;
509             }
510              
511             sub command_group {
512 0     0 0   my $self = shift;
513            
514 0           my $create = $self->options->{create};
515 0           my $delete = $self->options->{delete};
516 0           my $rename = $self->options->{rename};
517            
518            
519 0 0         if( $self->options->{help} ) {
    0          
    0          
    0          
    0          
520 0           $self->set_result_success(undef, 'help');
521 0           return;
522             } elsif( $self->options->{list} ) {
523 0           $self->list_groups('list');
524 0           return;
525             } elsif ( $create ) {
526            
527 0 0 0       if( $delete || $rename ) {
528 0           $self->set_result_options_error(
529             ERROR_GROUP_INVALID_OPTIONS,
530             'You must specify only one of --create, --delete, --rename, --list, or --help',
531             'missing',
532             );
533 0           return;
534             }
535            
536 0           for my $existing( keys %{ $self->conf->{groups} } ) {
  0            
537 0 0         if(lc($self->conf->{groups}->{$existing}) eq lc($create) ) {
538 0           $self->set_result_error(
539             ERROR_GROUP_EXISTING_NAME,
540             sprintf('The name %s is already in use for group 0x%05x', $create, $existing),
541             'create'
542             );
543 0           return;
544             }
545             }
546            
547 0           my $group = $self->options->{group};
548            
549 0 0         if( $group ) {
550 0 0         if(exists($self->conf->{groups}->{$group})) {
551 0           $self->set_result_error(
552             ERROR_GROUP_EXISTING_GROUP,
553             sprintf('The group id 0x%05x already exists', $group),
554             'create'
555             );
556 0           return;
557             }
558             }
559            
560 0           my $newgroup = $group;
561            
562 0           while(! $newgroup ) {
563 0           $group = $self->generate_switch_group();
564 0 0         unless(exists($self->conf->{groups}->{$group})) {
565 0           $newgroup = $group;
566             }
567             }
568            
569 0           $self->conf->{groups}->{$newgroup} = $create;
570 0           $self->list_groups('create');
571 0           return;
572             } elsif ( $delete ) {
573              
574 0 0 0       if( $create || $rename ) {
575 0           $self->set_result_options_error(
576             ERROR_GROUP_INVALID_OPTIONS,
577             'You must specify only one of --create, --delete, --rename, --list, or --help',
578             'missing',
579             );
580 0           return;
581             }
582            
583 0           for my $group( keys %{ $self->conf->{groups} } ) {
  0            
584 0 0         if(lc($self->conf->{groups}->{$group}) eq lc($delete) ) {
585             # delete any grouped switches first
586 0           for my $switchname ( keys %{ $self->conf->{switches} } ) {
  0            
587 0 0         if( $self->conf->{switches}->{$switchname}->{group} == $group ) {
588 0           delete($self->conf->{switches}->{$switchname});
589             }
590             }
591 0           delete($self->conf->{groups}->{$group});
592 0           $self->list_groups('delete');
593 0           return;
594             }
595             }
596            
597             $self->set_result_error(
598 0           ERROR_GROUP_NAME_NOT_FOUND,
599             qq(A group with name $delete was not found),
600             'delete'
601             );
602 0           return;
603            
604             } elsif( $rename ) {
605            
606 0 0 0       if( $delete || $create ) {
607 0           $self->set_result_options_error(
608             ERROR_GROUP_INVALID_OPTIONS,
609             'You must specify only one of --create, --delete, --rename, --list, or --help',
610             'missing',
611             );
612 0           return;
613             }
614            
615 0           my $newname = $self->options->{newname};
616 0 0         unless( $newname ) {
617 0           $self->set_result_options_error(
618             ERROR_GROUP_INVALID_OPTIONS,
619             'You must provide both options --rename and --newname to rename an existing group',
620             'rename'
621             );
622 0           return;
623             }
624            
625 0           for my $existing( keys %{ $self->conf->{groups} } ) {
  0            
626 0 0         if(lc($self->conf->{groups}->{$existing}) eq lc($newname) ) {
627 0           $self->set_result_error(
628             ERROR_GROUP_EXISTING_NAME,
629             sprintf('The name %s is already in use for group 0x%05x', $newname, $existing),
630             'rename'
631             );
632 0           return;
633             }
634             }
635            
636 0           for my $existing( keys %{ $self->conf->{groups} } ) {
  0            
637 0 0         if(lc($self->conf->{groups}->{$existing}) eq lc($rename) ) {
638 0           $self->conf->{groups}->{$existing} = $newname;
639 0           $self->list_groups('rename');
640 0           return;
641             }
642             }
643            
644             $self->set_result_error(
645 0           ERROR_GROUP_NAME_NOT_FOUND,
646             qq(A group with name $rename was not found),
647             'delete'
648             );
649            
650 0           return;
651             }
652            
653             $self->set_result_options_error(
654 0           ERROR_GROUP_INVALID_OPTIONS,
655             'You must specify one of --create --delete --rename --list --help',
656             'missing',
657             );
658 0           return;
659             }
660              
661             sub command_pair {
662 0     0 0   my $self = shift;
663            
664 0 0         if( $self->options->{help} ) {
665 0           $self->set_result_success(undef, 'help');
666 0           return;
667             }
668            
669 0 0         if( $self->options->{list} ) {
670 0           $self->list_switches('list');
671 0           return;
672             }
673            
674 0           my $group = 0;
675 0           my $groupname = $self->options->{groupname};
676 0           my $name = $self->options->{name};
677            
678 0 0         if( $self->receiver ) {
679             # we care about group name
680 0 0         unless($groupname) {
681 0           $self->set_result_options_error(
682             ERROR_PAIR_INVALID_OPTIONS,
683             'You must provide a --groupname to pair a socket or switch when using tx/rx board ENER314_RT',
684             'pair'
685             );
686 0           return;
687             }
688            
689             # get the group
690 0           for my $checkgroup( keys %{ $self->conf->{groups} } ) {
  0            
691 0 0         if(lc($self->conf->{groups}->{$checkgroup}) eq lc($groupname) ) {
692 0           $group = $checkgroup;
693 0           last;
694             }
695             }
696            
697 0 0         unless( $group ) {
698 0           $self->set_result_error(
699             ERROR_PAIR_GROUP_NOT_FOUND,
700             qq(Could not find a configured group named $groupname),
701             'pair'
702             );
703 0           return;
704             }
705             } else {
706 0           $group = ENERGENIE_ENER314_DUMMY_GROUP;
707 0           $groupname = 'energenie_single_group';
708             }
709              
710 0           my $switch = $self->options->{switch};
711            
712 0 0 0       unless( $switch && $switch =~ /^1|2|3|4$/) {
713 0           $self->set_result_error(
714             ERROR_PAIR_INVALID_SWITCH,
715             q(You must provide a valid switch number --switch 1|2|3|4),
716             'pair'
717             );
718 0           return;
719             }
720            
721             # pair the switch
722            
723             my $error = try {
724             my $handler = HiPi::Energenie->new(
725             board => $self->conf->{board},
726             devicename => $self->conf->{spi_device},
727             reset_gpio => $self->conf->{reset_gpio},
728 0     0     );
729            
730 0           $handler->pair_socket( $group, $switch, 5 );
731 0           return '';
732             } catch {
733 0     0     my $err = $_;
734 0           $err =~ s/\n/ /g;
735 0           return $err;
736 0           };
737            
738 0 0         if( $error ) {
739 0           $self->set_result_error( ERROR_SYSTEM, $error, 'pair' );
740 0           return;
741             }
742            
743 0   0       $name ||= qq(${groupname}_switch_${switch});
744            
745 0           $self->conf->{switches}->{$name} = { group => $group, switch => $switch };
746            
747 0           $self->list_switches('pair');
748             }
749              
750             sub command_switch {
751 0     0 0   my $self = shift;
752            
753 0 0         if( $self->options->{help} ) {
754 0           $self->set_result_success(undef, 'help');
755 0           return;
756             }
757            
758 0 0         if( $self->options->{list} ) {
759 0           $self->list_switches('list');
760 0           return;
761             }
762            
763 0           my $group = 0;
764 0           my $groupname = $self->options->{groupname};
765 0 0         my $switch = ( $self->options->{all} ) ? 0 : $self->options->{switch};
766            
767 0           my $name = $self->options->{name};
768            
769 0 0         if($name) {
770 0 0         if(exists($self->conf->{switches}->{$name})) {
771 0           $group = $self->conf->{switches}->{$name}->{group};
772 0           $switch = $self->conf->{switches}->{$name}->{switch};
773 0           $groupname = $self->conf->{groups}->{$group};
774             } else {
775 0           $self->set_result_error(
776             ERROR_SWITCH_NAME_NOT_FOUND,
777             qq(Could not find a configured switch named $name),
778             'switch'
779             );
780 0           return;
781             }
782             }
783            
784            
785 0 0 0       if( $self->receiver && !$group ) {
    0          
786             # we care about group name
787 0 0         unless($groupname) {
788 0           $self->set_result_options_error(
789             ERROR_SWITCH_INVALID_OPTIONS,
790             'You must provide a --groupname to turn on/off a socket or switch',
791             'switch'
792             );
793 0           return;
794             }
795            
796             # get the group
797 0           for my $checkgroup( keys %{ $self->conf->{groups} } ) {
  0            
798 0 0         if(lc($self->conf->{groups}->{$checkgroup}) eq lc($groupname) ) {
799 0           $group = $checkgroup;
800 0           last;
801             }
802             }
803            
804 0 0         unless( $group ) {
805 0           $self->set_result_error(
806             ERROR_SWITCH_GROUP_NOT_FOUND,
807             qq(Could not find a configured group named $groupname),
808             'switch'
809             );
810 0           return;
811             }
812             } elsif( !$self->receiver ) {
813 0           $group = ENERGENIE_ENER314_DUMMY_GROUP;
814 0           $groupname = 'energenie_single_group';
815             }
816            
817 0 0 0       unless( defined($switch) && $switch =~ /^0|1|2|3|4$/) {
818 0           $self->set_result_error(
819             ERROR_SWITCH_INVALID_SWITCH,
820             q(You must provide a valid switch number --switch 0|1|2|3|4 ( 0 switches all switches in the group )),
821             'switch'
822             );
823 0           return;
824             }
825            
826 0 0 0       if(!$self->options->{on} && !$self->options->{off}) {
827 0           $self->set_result_options_error(
828             ERROR_SWITCH_INVALID_OPTIONS,
829             'You must specify either --on or --off',
830             'switch'
831             );
832 0           return;
833             }
834            
835 0 0 0       if($self->options->{on} && $self->options->{off}) {
836 0           $self->set_result_options_error(
837             ERROR_SWITCH_INVALID_OPTIONS,
838             'You must specify either --on or --off - not both',
839             'switch'
840             );
841 0           return;
842             }
843            
844 0 0         my $state = ( $self->options->{on} ) ? 1 : 0;
845            
846             # Set the switch on / off
847            
848             my $error = try {
849             my $handler = HiPi::Energenie->new(
850             board => $self->conf->{board},
851             devicename => $self->conf->{spi_device},
852             reset_gpio => $self->conf->{reset_gpio},
853 0     0     );
854            
855 0           $handler->switch_socket( $group, $switch, $state );
856 0           return '';
857             } catch {
858 0     0     my $err = $_;
859 0           $err =~ s/\n/ /g;
860 0           return $err;
861 0           };
862            
863 0 0         if( $error ) {
864 0           $self->set_result_error( ERROR_SYSTEM, $error, 'switch' );
865 0           return;
866             }
867            
868 0 0         my $groupid = ( $self->receiver ) ? $self->format_group($group) : '';
869            
870 0 0         my $statename = ( $state ) ? 'ON' : 'OFF';
871            
872 0           my $resultdata = { switch => $switch, status => $statename };
873            
874 0           $resultdata->{group} = $self->format_group($group);
875 0           $resultdata->{groupname} = $groupname;
876            
877 0           $self->set_result_success( $resultdata, 'switch' );
878            
879             }
880              
881             sub command_alias {
882 0     0 0   my $self = shift;
883            
884 0 0         if( $self->options->{help} ) {
885 0           $self->set_result_success(undef, 'help');
886 0           return;
887             }
888            
889 0 0         if( $self->options->{list} ) {
890 0           $self->list_switches('list');
891 0           return;
892             }
893            
894 0           my $groupname = $self->options->{groupname};
895 0           my $switch = $self->options->{switch};
896 0           my $name = $self->options->{name};
897 0           my $group = 0;
898            
899 0 0 0       unless( $switch && $switch =~ /^|1|2|3|4$/) {
900 0           $self->set_result_error(
901             ERROR_ALIAS_INVALID_SWITCH,
902             q(You must provide a valid switch number --switch 0|1|2|3|4 ( 0 switches all switches in the group )),
903             'alias'
904             );
905 0           return;
906             }
907            
908 0 0         unless( $name ) {
909 0           $self->set_result_error(
910             ERROR_ALIAS_INVALID_OPTIONS,
911             q(You must provide at least --switch and --name to alias a switch),
912             'alias'
913             );
914 0           return;
915             }
916            
917 0 0         if( $self->receiver ) {
918             # we care about group name
919 0 0         unless($groupname) {
920 0           $self->set_result_options_error(
921             ERROR_ALIAS_INVALID_OPTIONS,
922             'You must provide --groupname, --switch and --name to alias a switch when using the txrx ENER314_RT board',
923             'alias'
924             );
925 0           return;
926             }
927            
928             # get the group
929 0           for my $checkgroup( keys %{ $self->conf->{groups} } ) {
  0            
930 0 0         if(lc($self->conf->{groups}->{$checkgroup}) eq lc($groupname) ) {
931 0           $group = $checkgroup;
932 0           last;
933             }
934             }
935            
936 0 0         unless( $group ) {
937 0           $self->set_result_error(
938             ERROR_ALIAS_GROUP_NOT_FOUND,
939             qq(Could not find a configured group named $groupname),
940             'alias'
941             );
942 0           return;
943             }
944             } else {
945 0           $group = ENERGENIE_ENER314_DUMMY_GROUP;
946 0           $groupname = 'energenie_single_group';
947             }
948            
949             # do we have an alias for this group already
950            
951 0           for my $switchname ( keys %{ $self->conf->{switches} } ) {
  0            
952 0 0 0       if( $self->conf->{switches}->{$switchname}->{switch} == $switch
953             && $self->conf->{switches}->{$switchname}->{group} == $group )
954             {
955 0           delete($self->conf->{switches}->{$switchname});
956             }
957             }
958            
959 0           $self->conf->{switches}->{$name} = { group => $group, switch => $switch };
960 0           $self->list_switches('alias');
961 0           return;
962             }
963              
964              
965             sub command_join {
966 0     0 0   my $self = shift;
967            
968 0 0         if( $self->options->{help} ) {
969 0           $self->set_result_success(undef, 'help');
970 0           return;
971             }
972            
973 0 0         if( $self->options->{list} ) {
974 0           $self->list_adapters_monitors('list', 'both');
975 0           return;
976             }
977            
978 0 0         unless( $self->receiver ) {
979 0           $self->set_result_error(
980             ERROR_USUPPORTED_RX_COMMAND,
981             q(You must be using board ENER314_RT to use join command),
982             'join'
983             );
984 0           return;
985             }
986            
987 0           my $name = $self->options->{name};
988 0           my $delete = $self->options->{delete};
989 0           my $rename = $self->options->{rename};
990            
991 0 0         if( $delete ) {
    0          
992 0           my $deleted;
993 0 0         if(exists($self->conf->{adapters}->{$delete})) {
994 0           delete($self->conf->{adapters}->{$delete});
995 0           $deleted = 1;
996             }
997 0 0         if(exists($self->conf->{monitors}->{$delete})) {
998 0           delete($self->conf->{monitors}->{$delete});
999 0           $deleted = 1;
1000             }
1001 0 0         if( $deleted ) {
1002 0           $self->list_adapters_monitors('delete', 'both' );
1003 0           return;
1004             } else {
1005 0           $self->set_result_error(
1006             ERROR_JOIN_DEVICE_NOT_FOUND,
1007             qq(The adaptor or monitor named $delete was not found in configuration),
1008             'delete'
1009             );
1010 0           return;
1011             }
1012             } elsif( $rename ) {
1013 0 0         unless( $name ) {
1014 0           $self->set_result_options_error(
1015             ERROR_JOIN_INVALID_OPTIONS,
1016             q(You must provide a --name option together with iption --rename),
1017             'rename'
1018             );
1019 0           return;
1020             }
1021            
1022             # does name already exist
1023 0 0         if(exists($self->conf->{monitors}->{$name})) {
1024 0           $self->set_result_error(
1025             ERROR_JOIN_EXISTING_ADAPTER,
1026             qq(An adapter or monitor named $name already exists in your configuration ),
1027             'rename'
1028             );
1029 0           return;
1030             }
1031             # does rename exist
1032            
1033 0 0         unless(exists($self->conf->{monitors}->{$rename})) {
1034 0           $self->set_result_error(
1035             ERROR_JOIN_DEVICE_NOT_FOUND,
1036             qq(The adaptor or monitor named $rename was not found in configuration),
1037             'rename'
1038             );
1039 0           return;
1040             }
1041            
1042 0           $self->conf->{monitors}->{$name} = $self->conf->{monitors}->{$rename};
1043 0           delete( $self->conf->{monitors}->{$rename} );
1044            
1045 0 0         if(exists($self->conf->{adapters}->{$rename})) {
1046 0           $self->conf->{adapters}->{$name} = $self->conf->{adapters}->{$rename};
1047 0           delete( $self->conf->{adapters}->{$rename} );
1048             }
1049            
1050 0           $self->list_adapters_monitors('rename', 'both');
1051 0           return;
1052             }
1053            
1054             # does name already exist
1055 0 0         if(exists($self->conf->{adapters}->{$name})) {
1056 0           $self->set_result_error(
1057             ERROR_JOIN_EXISTING_ADAPTER,
1058             qq(An adapter or monitor named $name already exists in your configuration),
1059             'rename'
1060             );
1061 0           return;
1062             }
1063            
1064             # only show on console
1065 0           print STDERR qq(\nListening for join messages from adapters and monitors. Set your device mode to join ....\n\n);
1066            
1067             my $result = try {
1068             my $handler = HiPi::Energenie->new(
1069             board => $self->conf->{board},
1070             devicename => $self->conf->{spi_device},
1071             reset_gpio => $self->conf->{reset_gpio},
1072 0     0     );
1073            
1074 0           return $handler->process_request(
1075             command => 'join',
1076             );
1077             } catch {
1078 0     0     return { success => 0, error => $_ , catch_errorcode => ERROR_SYSTEM };
1079 0           };
1080            
1081 0 0         if( $result->{success} ) {
1082            
1083 0           my $joinmsg = $result->{data};
1084            
1085             # check if we know this sensor key
1086 0 0         if(my $registered_name = $self->registered_sensor( $joinmsg->sensor_key ) ) {
1087 0           my $sensorkey = $joinmsg->sensor_key;
1088 0           $self->set_result_error( ERROR_JOIN_FAILED, qq(Device $sensorkey is already registered as $registered_name), 'join' );
1089 0           return;
1090             }
1091            
1092 0           $self->conf->{monitors}->{$name} = {
1093             manufacturer_id => $joinmsg->manufacturer_id,
1094             product_id => $joinmsg->product_id,
1095             product_name => $joinmsg->product_name,
1096             sensor_id => $joinmsg->sensor_id,
1097             sensor_key => $joinmsg->sensor_key,
1098             };
1099            
1100 0 0         if( HiPi::RF::OpenThings->product_can_switch( $joinmsg->manufacturer_id, $joinmsg->product_id ) ) {
1101 0           $self->conf->{adapters}->{$name} = {
1102             manufacturer_id => $joinmsg->manufacturer_id,
1103             product_id => $joinmsg->product_id,
1104             product_name => $joinmsg->product_name,
1105             sensor_id => $joinmsg->sensor_id,
1106             sensor_key => $joinmsg->sensor_key,
1107             };
1108             }
1109            
1110 0           $self->list_adapters_monitors('join', 'both' );
1111             } else {
1112 0           my $error = $result->{error};
1113 0           $error =~ s/\n/ /g;
1114 0   0       my $errorcode = $result->{catch_errorcode} || ERROR_JOIN_FAILED;
1115 0           $self->set_result_error( $errorcode, $error, 'join' );
1116             }
1117             }
1118              
1119             sub command_adapter {
1120 0     0 0   my $self = shift;
1121            
1122 0 0         if( $self->options->{help} ) {
1123 0           $self->set_result_success(undef, 'help');
1124 0           return;
1125             }
1126            
1127 0 0         if( $self->options->{list} ) {
1128 0           $self->list_adapters_monitors('list', 'adapters');
1129 0           return;
1130             }
1131            
1132 0 0         unless( $self->receiver ) {
1133 0           $self->set_result_error(
1134             ERROR_USUPPORTED_RX_COMMAND,
1135             q(You must be using board ENER314_RT to use the adapter command),
1136             'switch'
1137             );
1138 0           return;
1139             }
1140            
1141 0           my $name = $self->options->{name};
1142            
1143 0 0         unless($name) {
1144 0           $self->set_result_options_error(
1145             ERROR_ADAPTER_INVALID_OPTIONS,
1146             q(You must provide an adapter --name for the adapter command),
1147              
1148             );
1149 0           return;
1150             }
1151            
1152 0           my $nameconfig;
1153            
1154             # get the name
1155 0           for my $checkname( keys %{ $self->conf->{adapters} } ) {
  0            
1156 0 0         if(lc($checkname) eq lc($name) ) {
1157 0           $nameconfig = $self->conf->{adapters}->{$checkname};
1158 0           last;
1159             }
1160             }
1161            
1162 0 0         unless( $nameconfig ) {
1163 0           $self->set_result_error(
1164             ERROR_ADAPTER_NAME_NOT_FOUND,
1165             qq(Could not find a configured adapter named $name)
1166             );
1167 0           return;
1168             }
1169            
1170 0 0         if( $self->options->{query} ) {
1171 0           $self->do_monitor_query( $nameconfig, 'adapter', $name );
1172 0           return;
1173             }
1174            
1175             # in switch mode
1176            
1177 0 0 0       if(!$self->options->{on} && !$self->options->{off}) {
1178 0           $self->set_result_options_error(
1179             ERROR_ADAPTER_INVALID_OPTIONS,
1180             q(You must specify either --on or --off to switch an adapter),
1181             'switch',
1182             );
1183 0           return;
1184             }
1185            
1186 0 0 0       if($self->options->{on} && $self->options->{off}) {
1187 0           $self->set_result_options_error(
1188             ERROR_ADAPTER_INVALID_OPTIONS,
1189             q(You must specify either --on or --off - not both to switch an adapter),
1190             'switch',
1191             );
1192 0           return;
1193             }
1194            
1195 0 0         my $state = ( $self->options->{on} ) ? 1 : 0;
1196            
1197             # do switch
1198            
1199             my $result = try {
1200             my $handler = HiPi::Energenie->new(
1201             board => $self->conf->{board},
1202             devicename => $self->conf->{spi_device},
1203             reset_gpio => $self->conf->{reset_gpio},
1204 0     0     );
1205            
1206             my $val = $handler->process_request(
1207             command => 'switch',
1208             sensor_key => $nameconfig->{sensor_key},
1209 0           switch_state => $state,
1210             );
1211            
1212 0           return $val;
1213             } catch {
1214 0     0     return { success => 0, error => $_ , catch_errorcode => ERROR_SYSTEM };
1215 0           };
1216            
1217 0 0         if( !$result->{success} ) {
1218 0           my $error = $result->{error};
1219 0           $error =~ s/\n/ /g;
1220 0   0       my $errorcode = $result->{catch_errorcode} || ERROR_ADAPTER_FAILED;
1221 0           $self->set_result_error( $errorcode, $error, 'switch' );
1222 0           return;
1223             }
1224            
1225 0           my $data = $result->{data};
1226 0           $data->configured_name( $name );
1227            
1228 0           $self->set_result_success($data, 'switch');
1229             }
1230              
1231             sub command_monitor {
1232 0     0 0   my $self = shift;
1233            
1234 0 0         if( $self->options->{help} ) {
1235 0           $self->set_result_success(undef, 'help');
1236 0           return;
1237             }
1238            
1239 0 0         if( $self->options->{list} ) {
1240 0           $self->list_adapters_monitors('list', 'monitors');
1241 0           return;
1242             }
1243            
1244 0 0         unless( $self->receiver ) {
1245 0           $self->set_result_error(
1246             ERROR_USUPPORTED_RX_COMMAND,
1247             q(You must be using board ENER314_RT to use the monitor command),
1248             'switch'
1249             );
1250 0           return;
1251             }
1252            
1253 0           my $name = $self->options->{name};
1254            
1255 0 0         unless($name) {
1256 0           $self->set_result_options_error(
1257             ERROR_MONITOR_INVALID_OPTIONS,
1258             q(You must provide a monitor --name for the monitor command),
1259              
1260             );
1261 0           return;
1262             }
1263            
1264 0           my $nameconfig;
1265            
1266             # get the name
1267 0           for my $checkname( keys %{ $self->conf->{monitors} } ) {
  0            
1268 0 0         if(lc($checkname) eq lc($name) ) {
1269 0           $nameconfig = $self->conf->{monitors}->{$checkname};
1270 0           last;
1271             }
1272             }
1273            
1274 0 0         unless( $nameconfig ) {
1275 0           $self->set_result_error(
1276             ERROR_MONITOR_NAME_NOT_FOUND,
1277             qq(Could not find a configured monitor named $name)
1278             );
1279 0           return;
1280             }
1281            
1282 0           $self->do_monitor_query( $nameconfig, 'monitor', $name );
1283             }
1284              
1285             sub do_monitor_query {
1286 0     0 0   my ( $self, $nameconfig, $type, $configname ) = @_;
1287              
1288             my $result = try {
1289             my $handler = HiPi::Energenie->new(
1290             board => $self->conf->{board},
1291             devicename => $self->conf->{spi_device},
1292             reset_gpio => $self->conf->{reset_gpio},
1293 0     0     );
1294            
1295             my $val = $handler->process_request(
1296             command => 'query',
1297             sensor_key => $nameconfig->{sensor_key},
1298 0           );
1299            
1300 0           return $val;
1301             } catch {
1302 0     0     return { success => 0, error => $_ , catch_errorcode => ERROR_SYSTEM };
1303 0           };
1304            
1305 0 0         if( !$result->{success} ) {
1306 0           my $error = $result->{error};
1307 0           $error =~ s/\n/ /g;
1308 0 0         my $alterror = ( $type eq 'adapter ') ? ERROR_ADAPTER_FAILED : ERROR_MONITOR_FAILED;
1309 0   0       my $errorcode = $result->{catch_errorcode} || $alterror;
1310 0           $self->set_result_error( $errorcode, $error, 'query' );
1311 0           return;
1312             }
1313            
1314 0           my $data = $result->{data};
1315            
1316 0           $data->configured_name( $configname );
1317            
1318 0           $self->set_result_success($data, 'query');
1319            
1320 0           return;
1321             }
1322              
1323             sub list_configuration {
1324 0     0 0   my ($self, $option ) = @_;
1325 0           $self->config->write_config;
1326             $self->set_result_success( {
1327             'version' => $self->conf->{version},
1328             'board' => $self->conf->{board},
1329             'spi_device' => $self->conf->{spi_device},
1330             'reset_gpio' => $self->conf->{reset_gpio},
1331             'uses_spi' => ( $self->receiver ) ? 'YES' : 'NO',
1332             'can_rx' => ( $self->receiver ) ? 'YES' : 'NO',
1333 0 0 0       'epoch' => $self->conf->{epoch} || 1,
    0          
1334             }, $option );
1335 0           return;
1336             }
1337              
1338             sub list_groups {
1339 0     0 0   my ($self, $option ) = @_;
1340            
1341 0           my $groups = {};
1342            
1343 0           for my $group ( keys %{ $self->conf->{groups} } ) {
  0            
1344 0           my $groupname = $self->conf->{groups}->{$group};
1345 0           $groups->{$groupname} = $self->format_group( $group );
1346             }
1347            
1348 0           $self->set_result_success( { groups => $groups }, $option );
1349 0           return;
1350             }
1351              
1352             sub list_adapters_monitors {
1353 0     0 0   my ($self, $option, $type) = @_;
1354            
1355 0 0         my @todolist = ( $type eq 'both' ) ? ( qw( adapters monitors ) ) : ( $type );
1356            
1357 0           my $resdata = {};
1358            
1359 0           for my $item ( @todolist ) {
1360 0           my $data = {};
1361 0           my $conf = $self->conf->{$item};
1362 0           for my $member ( keys %$conf ) {
1363 0           for my $element ( keys %{ $conf->{$member} } ) {
  0            
1364 0           $data->{$member}->{$element} = $conf->{$member}->{$element};
1365             }
1366             }
1367 0           $resdata->{$item} = $data;
1368             }
1369            
1370 0           $self->set_result_success( $resdata, $option );
1371            
1372 0           return;
1373             }
1374              
1375             sub list_switches {
1376 0     0 0   my ($self, $option) = @_;
1377            
1378 0           my $data = {};
1379 0           my $conf = $self->conf->{switches};
1380 0           for my $member ( keys %$conf ) {
1381            
1382 0           $data->{switches}->{$member}->{switch} = $conf->{$member}->{switch};
1383 0           $data->{switches}->{$member}->{group} = $self->conf->{groups}->{$conf->{$member}->{group}};
1384             }
1385            
1386 0           $self->set_result_success( $data, $option );
1387            
1388 0           return;
1389             }
1390              
1391             sub registered_sensor {
1392 0     0 0   my( $self, $sensorkey ) = @_;
1393 0           $sensorkey = lc($sensorkey);
1394 0           for my $item ( qw( adapters monitors ) ) {
1395 0           my $conf = $self->conf->{$item};
1396 0           for my $member ( keys %$conf ) {
1397 0 0         if( lc($conf->{$member}->{sensor_key}) eq $sensorkey ) {
1398 0           return $member;
1399             }
1400             }
1401             }
1402 0           return undef;
1403             }
1404              
1405             sub generate_switch_group {
1406 0     0 0   my $self = shift;
1407             # a number between 0x1 and 0xFFFFF
1408 0           my $group = 1 + int(rand(0xFFFFE));
1409 0           return $group;
1410             }
1411              
1412             sub format_group {
1413 0     0 0   my ($self, $id) = @_;
1414 0           return sprintf('0x%06X', $id);
1415             }
1416              
1417             sub receiver {
1418 0     0 0   my $self = shift;
1419 0 0         return ( $self->conf->{board} eq 'ENER314_RT' ) ? 1 : 0;
1420             }
1421              
1422             sub get_command_usage {
1423 0     0 0   my($self, $command) = @_;
1424            
1425 0           my $usagetext = {
1426            
1427             #### GENERAL USAGE ################################
1428            
1429             unknown => q(
1430             usage : hipi-energenie [options]
1431            
1432             command :
1433             help Print this message
1434             version Print the version
1435             config Configure the board type ( ENER314_RT or ENER314 )
1436             group Manage groups for use with sockets
1437             pair Pair a socket or switch
1438             alias Rename or name a socket or switch
1439             switch Switch a socket or switch on or off
1440             join Configure a monitor or adaptor
1441             adapter Switch an adapter device on or off
1442             monitor Query a monitoring device for values
1443              
1444             For help on each command use:
1445             hipi-energenie -h
1446             ),
1447              
1448             #### CONFIG USAGE ################################
1449            
1450             config => q(
1451             usage : hipi-energenie config
1452            
1453             options :
1454              
1455             --help -h Display this message
1456              
1457             --list -l List the current config
1458              
1459             --board -b < ENER314 | ENER314_RT > Set the board type that
1460             you have connected to the Raspberry Pi.
1461             Default is 'ENER314_RT'
1462              
1463             --device -d < devicename > Set the SPI device used by the
1464             ENER314_RT board. Default is '/dev/spidev0.1'
1465            
1466             --reset -r < gpio > Specify the GPIO pin connected to
1467             the reset pin on the ENER314_RT board.
1468             Default is 25 ( RPI_PIN_22 )
1469            
1470             --json The command results will be output as a JSON
1471             string. This can be used when you want to parse
1472             the command output from external code.
1473              
1474             --pretty The command results will be output as formatted JSON
1475             with line breaks and indentation.
1476              
1477             ),
1478             #### GROUP USAGE ################################
1479              
1480             group => q(
1481             usage : hipi-energenie group
1482              
1483             description: Set up groups for use with ENER314_RT board to control
1484             multiple sets of simple switches or sockets.
1485              
1486             options :
1487              
1488             --help -h Display this message
1489              
1490             --list -l List the currently configured groups
1491              
1492             --create -c Create a new group. The system will create a new
1493             unused group id and associate the supplied name with it.
1494             e.g. hipi-energenie group -c newname
1495             Provide option --groupid to name an existing group.
1496            
1497             --delete -d Delete an existing group.
1498             e.g. hipi-energenie group -d 'my group 1'
1499            
1500             --rename -r Rename an existing group. Must be accompanied
1501             by option for --newname.
1502             e.g. hipi-energenie group -r oldname -n newname
1503            
1504             --newname -n The new name for a group. (used with --rename)
1505              
1506             --groupid The group id identifier that is used
1507             to control a group of four switches or sockets,
1508             or one 4 way gang extension. This is a number
1509             between 0x01 and 0xFFFFF. The parameter can be
1510             passed in decimal, hexadecimal or binary
1511             notation. It is parsed by the Perl 'oct'
1512             function.
1513              
1514             --json The command results will be output as a JSON
1515             string. This can be used when you want to parse
1516             the command output from external code.
1517              
1518             --pretty The command results will be output as formatted JSON
1519             with line breaks and indentation.
1520              
1521             ),
1522              
1523             #### PAIR USAGE ################################
1524            
1525             pair => q(
1526             usage : hipi-energenie pair
1527            
1528             description: pair with a simple socket or switch such as an ENER002 switch
1529             socket; an ENER010 4 way extension; a Mi|Home MIHO002 adapter.
1530             Set the adapter to pairing mode and run this command.
1531              
1532             options :
1533              
1534             --help -h Display this message
1535              
1536             --list -l list paired switches
1537            
1538             --groupname -g A groupname you have configured using the
1539             group command. If you are using the transmit
1540             only ENER314 board, this option is ignored.
1541              
1542             --switch -s < 1 | 2 | 3 | 4 > The number of the switch or socket
1543             you want to pair. Each groupname can control a
1544             maximum of 4 switches. If you are pairing an
1545             ENER010 4 gang extension, use '1'
1546            
1547             --name -n A name for the paired switch
1548             that you may use in the future to command the switch
1549             rather than specifying both group and switch
1550             number.
1551              
1552             --json The command results will be output as a JSON
1553             string. This can be used when you want to parse
1554             the command output from external code.
1555              
1556             --pretty The command results will be output as formatted JSON
1557             with line breaks and indentation.
1558            
1559             ( to rename a switch / group pair use the 'alias' command )
1560              
1561             ),
1562             #### SWITCH USAGE ################################
1563            
1564             switch => q(
1565             usage : hipi-energenie switch
1566            
1567             description: Turn a paired socket or switch on or off
1568              
1569             options :
1570             --help -h Display this message
1571              
1572             --list -l List the currently configured switches
1573              
1574             --name -n An alias for the groupname / switch pair
1575            
1576             --groupname -g If you don't provide a name you can specify
1577             groupname and switch number instead. This is the
1578             groupname you paired the switch with.
1579             If you are using the transmit only ENER314 board,
1580             this option is ignored.
1581              
1582             --switch -s < 0 | 1 | 2 | 3 | 4 > If you don't provide a name you can
1583             specify groupname and switch number instead. This is the
1584             number of the switch or socket you want to switch.
1585             Specifying 0 switches all members of the group.
1586            
1587             --on -1 Switch the socket on
1588              
1589             --off -0 Switch the socket off
1590            
1591             --all Switch all sockets in the group. The same as specifying
1592             --switch 0
1593              
1594             --json The command results will be output as a JSON
1595             string. This can be used when you want to parse
1596             the command output from external code.
1597              
1598             --pretty The command results will be output as formatted JSON
1599             with line breaks and indentation.
1600              
1601             ),
1602              
1603             #### ALAIS USAGE ################################
1604            
1605             alias => q(
1606             usage : hipi-energenie alias
1607            
1608             description: Give a name to a groupname / switch number pair
1609              
1610             options :
1611             --help -h Display this message
1612            
1613             --list -l List configured aliases
1614            
1615             --name -n The alias you want to use
1616            
1617             --groupname -g The group for the alias
1618              
1619             --switch -s < 1 | 2 | 3 | 4 > The switch number for the alias
1620            
1621             --json The command results will be output as a JSON
1622             string. This can be used when you want to parse
1623             the command output from external code.
1624              
1625             --pretty The command results will be output as formatted JSON
1626             with line breaks and indentation.
1627              
1628             ),
1629             #### JOIN USAGE ################################
1630            
1631             join => q(
1632             usage : hipi-energenie join
1633            
1634             description: Join a Mi|Home monitor or adapter. Run this command first and
1635             then switch your adapter or monitor to join mode.
1636              
1637             options :
1638            
1639             --help -h Display this message
1640            
1641             --list -l List the adapters and monitors already joined
1642              
1643             --name -n A name for the adapter or monitor. This
1644             is required.
1645              
1646             --rename -r You can rename an adapter. If --rename is specified
1647             then --rename contains the existing name and --name contains the
1648             new name.
1649            
1650             --delete -d Remove the named monitor or adapter from configuration
1651              
1652             --json The command results will be output as a JSON
1653             string. This can be used when you want to parse
1654             the command output from external code.
1655              
1656             --pretty The command results will be output as formatted JSON
1657             with line breaks and indentation.
1658              
1659             ),
1660             #### ADAPTER USAGE ################################
1661            
1662             adapter => q(
1663             usage : hipi-energenie adapter
1664            
1665             description: Switch a Mi|Home Adapter Plus on and off or query its switch state
1666              
1667             options :
1668            
1669             --help -h Display this message
1670            
1671             --list -l List all the adapters registered
1672              
1673             --name -n The name registered for the adapter. This
1674             is required.
1675              
1676             --query -q Get the switch state for the adapter
1677            
1678             --on -1 Switch the adapter on
1679            
1680             --off -0 Switch the adapter off
1681              
1682             --json The command results will be output as a JSON
1683             string. This can be used when you want to parse
1684             the command output from external code.
1685              
1686             --pretty The command results will be output as formatted JSON
1687             with line breaks and indentation.
1688              
1689             ),
1690             #### MONITOR USAGE ################################
1691            
1692             monitor => q(
1693             usage : hipi-energenie monitor
1694            
1695             description: Query status from a Mi|Home adapter or monitor
1696              
1697             options :
1698            
1699             --help -h Display this message
1700            
1701             --list -l List all the monitors registered
1702              
1703             --name -n The name registered for the montitor. This
1704             is required.
1705              
1706             --json The command results will be output as a JSON
1707             string. This can be used when you want to parse
1708             the command output from external code.
1709              
1710             --pretty The command results will be output as formatted JSON
1711             with line breaks and indentation.
1712              
1713             ),
1714             };
1715            
1716            
1717 0 0         if(exists($usagetext->{$command})) {
1718 0           return $usagetext->{$command};
1719             } else {
1720 0           return $usagetext->{unknown};
1721             }
1722             }
1723              
1724             1;
1725              
1726             __END__