File Coverage

blib/lib/HiPi/Energenie/ENER314_RT.pm
Criterion Covered Total %
statement 27 99 27.2
branch 0 22 0.0
condition 0 3 0.0
subroutine 9 22 40.9
pod 0 12 0.0
total 36 158 22.7


line stmt bran cond sub pod time code
1             #########################################################################################
2             # Package HiPi::Energenie::ENER314_RT
3             # Description : Control Energenie ENER314-RT board
4             # Copyright : Copyright (c) 2016-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::ENER314_RT;
10              
11             #########################################################################################
12              
13 1     1   1087 use strict;
  1         2  
  1         31  
14 1     1   5 use warnings;
  1         2  
  1         28  
15 1     1   4 use HiPi qw( :rpi :hrf69 :openthings :energenie );
  1         3  
  1         953  
16 1     1   8 use parent qw( HiPi::Class );
  1         2  
  1         7  
17 1     1   54 use Carp;
  1         2  
  1         67  
18 1     1   7 use Time::HiRes qw( usleep );
  1         2  
  1         6  
19 1     1   582 use HiPi::Interface::HopeRF69;
  1         3  
  1         41  
20 1     1   8 use HiPi::GPIO;
  1         2  
  1         30  
21 1     1   6 use HiPi::RF::OpenThings::Message;
  1         1  
  1         1190  
22              
23             __PACKAGE__->create_accessors( qw( device devicename led_green led_red
24             led_on _green_pin _red_pin ook_repeat
25             backend default_config ook_config gpiodev) );
26              
27             our $VERSION ='0.81';
28              
29             sub new {
30 0     0 0   my( $class, %userparams ) = @_;
31            
32 0           my %params = (
33             devicename => '/dev/spidev0.1',
34             backend => 'spi',
35             speed => 9600000, # 9.6 mhz
36             bitsperword => 8,
37             delay => 0,
38             device => undef,
39             led_green => RPI_PIN_13,
40             led_red => RPI_PIN_15,
41             led_on => 1,
42             reset_gpio => RPI_PIN_22,
43             oo_repeat => ENERGENIE_TXOOK_REPEAT_RATE,
44             gpiodev => HiPi::GPIO->new,
45             default_config => [
46             [ RF69_REG_REGDATAMODUL, 0x00 ], # modulation scheme FSK
47             [ RF69_REG_FDEVMSB, 0x01 ], # frequency deviation 5kHz 0x0052 -> 30kHz 0x01EC
48             [ RF69_REG_FDEVLSB, 0xEC ], # frequency deviation 5kHz 0x0052 -> 30kHz 0x01EC
49             [ RF69_REG_FRMSB, 0x6C ], # carrier freq -> 434.3MHz 0x6C9333
50             [ RF69_REG_FRMID, 0x93 ], # carrier freq -> 434.3MHz 0x6C9333
51             [ RF69_REG_FRLSB, 0x33 ], # carrier freq -> 434.3MHz 0x6C9333
52             [ RF69_REG_AFCCTRL, 0x00 ], # standard AFC routine
53             #[ RF69_REG_PREAMBLEMSB, 0x00 ], # 3 byte preamble
54             #[ RF69_REG_PREAMBLELSB, 0x03 ], # 3 byte preamble
55             [ RF69_REG_LNA, 0x08 ], # 200ohms, gain by AGC loop -> 50ohms
56             [ RF69_REG_RXBW, 0x43 ], # channel filter bandwidth 10kHz -> 60kHz page:26
57             [ RF69_REG_BITRATEMSB, 0x1A ], # 4800b/s
58             [ RF69_REG_BITRATELSB, 0x0B ], # 4800b/s
59             [ RF69_REG_SYNCCONFIG, 0x88 ], # Size of the Synch word = 2 (SyncSize + 1)
60             [ RF69_REG_SYNCVALUE1, 0x2D ], # 1st byte of Sync word
61             [ RF69_REG_SYNCVALUE2, 0xD4 ], # 2nd byte of Sync word
62             [ RF69_REG_PACKETCONFIG1, 0xA0 ], # Variable length, Manchester coding
63             [ RF69_REG_PAYLOADLEN, 66 ], # max Length in RX, not used in Tx
64             [ RF69_REG_NODEADDRESS, 0x06 ], # Node address used in address filtering ( not used in this config )
65             [ RF69_REG_FIFOTHRESH, 0x81 ], # Condition to start packet transmission: at least one byte in FIFO
66             [ RF69_REG_OPMODE, RF69_MASK_OPMODE_RX ], # Operating mode to Receive
67             ],
68            
69             ook_config => [
70             [ RF69_REG_REGDATAMODUL, 0x08 ], # modulation scheme OOK
71             [ RF69_REG_FDEVMSB, 0 ], # frequency deviation -> 0kHz
72             [ RF69_REG_FDEVLSB, 0 ], # frequency deviation -> 0kHz
73             [ RF69_REG_FRMSB, 0x6C ], # carrier freq -> 433.92MHz 0x6C7AE1
74             [ RF69_REG_FRMID, 0x7A ], # carrier freq -> 433.92MHz 0x6C7AE1
75             [ RF69_REG_FRLSB, 0xE1 ], # carrier freq -> 433.92MHz 0x6C7AE1
76             [ RF69_REG_RXBW, 0x41 ], # channel filter bandwidth 120kHz
77             [ RF69_REG_BITRATEMSB, 0x40 ], # 1938b/s
78             [ RF69_REG_BITRATELSB, 0x80 ], # 1938b/s
79             [ RF69_REG_PREAMBLEMSB, 0 ], # no preamble
80             [ RF69_REG_PREAMBLELSB, 0 ], # no preamble
81             [ RF69_REG_SYNCCONFIG, 0x98 ], # Size of the Synch word = 4 (SyncSize + 1)
82             [ RF69_REG_SYNCVALUE1, 0x80 ], # sync value 1
83             [ RF69_REG_SYNCVALUE2, 0 ], # sync value 2
84             [ RF69_REG_SYNCVALUE3, 0 ], # sync value 3
85             [ RF69_REG_SYNCVALUE4, 0 ], # sync value 4
86             [ RF69_REG_PACKETCONFIG1, 0 ], # Fixed length, no Manchester coding, OOK
87             [ RF69_REG_PAYLOADLEN, 13 + 8 * 17 ], # Fixed OOK Payload Length
88             [ RF69_REG_FIFOTHRESH, 0x1E ], # Condition to start packet transmission: wait for 30 bytes in FIFO
89             [ RF69_REG_OPMODE, RF69_MASK_OPMODE_TX ], # Transmitter mode
90             ],
91             );
92            
93 0           foreach my $key (sort keys(%userparams)) {
94 0           $params{$key} = $userparams{$key};
95             }
96            
97 0 0         unless( defined($params{device}) ) {
98             $params{device} = HiPi::Interface::HopeRF69->new(
99             speed => $params{speed},
100             bitsperword => $params{bitsperword},
101             delay => $params{delay},
102             devicename => $params{devicename},
103             reset_gpio => $params{reset_gpio},
104             ook_repeat => $params{ook_repeat},
105             backend => $params{backend},
106             fsk_config => $params{default_config},
107             ook_config => $params{ook_config},
108 0           );
109             }
110            
111 0           my $self = $class->SUPER::new(%params);
112 0           $self->init_pins;
113            
114             # setup defaults
115 0           $self->set_red_led( 0 );
116 0           $self->set_green_led( 0 );
117            
118 0           return $self;
119             }
120              
121             sub make_ook_message {
122 0     0 0   my($self, $groupid, $data) = @_;
123            
124             # energenie preamble
125 0           my @msgbytes = ( 0x80, 0x00, 0x00, 0x00 );
126            
127             # encode the group id
128 0           push @msgbytes, ( $self->encode_data( ( $groupid & 0x0f0000 ) >> 16, 4 ) );
129 0           push @msgbytes, ( $self->encode_data( ( $groupid & 0x00ff00 ) >> 8, 8 ) );
130 0           push @msgbytes, ( $self->encode_data( ( $groupid & 0x0000ff ), 8 ) );
131            
132             # encode the databits
133 0           push @msgbytes, ( $self->encode_data( ( $data & 0x00000f ), 4 ) );
134            
135 0           return @msgbytes;
136             }
137              
138             sub send_message {
139 0     0 0   my($self, $bytes) = @_;
140              
141 0 0         return unless(scalar( @$bytes ));
142              
143 0           $self->set_red_led( 1 );
144 0           $self->device->send_message( $bytes );
145 0           $self->set_red_led( 0 );
146            
147 0           return;
148             }
149              
150             sub send_ook_message {
151 0     0 0   my($self, $groupid, $data, $repeat ) = @_;
152            
153 0   0       $repeat ||= $self->ook_repeat;
154            
155 0           $self->set_red_led( 1 );
156            
157             # $groupid = 20 bit controller id for your energenie ENER314-RT - you can vary this
158             # as you wish so you can control multiple groups of 4 devices each.
159             # $address is therefore any number between 0x1 and 0xFFFFF
160             # $data = the 4 bits you want to send as defined in Energenie docs for your switch
161             # order here is d0,d1,d2,d3 as defined in docs for your device
162             # therefore data is a number between 0 and 15
163            
164 0           my @sendbytes = $self->make_ook_message( $groupid, $data );
165            
166 0           $self->device->send_ook_message(\@sendbytes, $repeat );
167            
168 0           $self->set_red_led( 0 );
169             }
170              
171             # mask for bit encoding
172             my @_encoding_mask = ( 0x88, 0x8E, 0xE8, 0xEE );
173              
174             sub encode_data {
175 0     0 0   my($self, $data, $number ) = @_;
176 0           my @encoded = ();
177 0           my $shift = $number - 2;
178 0           while ( $shift >= 0 ) {
179 0           my $encindex = ($data >> $shift) & 0x03;
180 0           push @encoded, $_encoding_mask[$encindex];
181 0           $shift -= 2;
182             }
183 0           return @encoded;
184             }
185              
186             sub init_pins {
187 0     0 0   my $self = shift;
188 0 0         return unless $self->led_on;
189 0 0         if( my $redpin = $self->led_red ) {
190 0           $self->gpiodev->set_pin_mode( $redpin, RPI_MODE_OUTPUT );
191 0           $self->gpiodev->set_pin_level( $redpin, RPI_LOW );
192             }
193 0 0         if( my $greenpin = $self->led_green ) {
194 0           $self->gpiodev->set_pin_mode( $greenpin, RPI_MODE_OUTPUT );
195 0           $self->gpiodev->set_pin_level( $greenpin, RPI_LOW );
196             }
197             }
198              
199             sub set_red_led {
200 0     0 0   my ($self, $value) = @_;
201 0 0         return unless $self->led_on;
202 0 0         if( my $redpin = $self->led_red ) {
203 0           $self->gpiodev->set_pin_level( $redpin, $value );
204             }
205 0           return;
206             }
207              
208             sub set_green_led {
209 0     0 0   my ($self, $value) = @_;
210 0 0         return unless $self->led_on;
211 0 0         if( my $greenpin = $self->led_green ) {
212 0           $self->gpiodev->set_pin_level( $greenpin, $value );
213             }
214 0           return;
215             }
216              
217             sub reset {
218 0     0 0   my $self = shift;
219 0           $self->device->reset;
220             }
221              
222             sub receive_fsk_message {
223 0     0 0   my ($self, $encryptionid) = @_;
224 0 0         if( my $buffer = $self->device->receive_message ) {
225 0           my $msg = HiPi::RF::OpenThings::Message->new(
226             databuffer => $buffer,
227             cryptseed => $encryptionid,
228             );
229 0           $msg->inspect_buffer;
230 0           return $msg;
231             }
232 0           return undef;
233             }
234              
235             sub send_fsk_message {
236 0     0 0   my ($self, $msg) = @_;
237 0 0         $msg->encode_buffer unless $msg->is_encoded;
238 0           $self->send_message( $msg->databuffer );
239             }
240              
241             #-------------------------------------------------------
242             # Common OOK switch handler
243             #-------------------------------------------------------
244              
245             sub switch_ook_socket {
246 0     0 0   my($self, $groupid, $data, $repeat) = @_;
247 0           $self->send_ook_message( $groupid, $data, $repeat );
248             }
249              
250             sub DESTROY {
251 0     0     my $self = shift;
252 0           $self->SUPER::DESTROY;
253 0           $self->device( undef );
254             }
255              
256             1;
257              
258             __END__