File Coverage

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


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-2020 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   1062 use strict;
  1         2  
  1         31  
14 1     1   5 use warnings;
  1         2  
  1         28  
15 1     1   5 use HiPi qw( :rpi :hrf69 :openthings :energenie );
  1         3  
  1         973  
16 1     1   34 use parent qw( HiPi::Class );
  1         3  
  1         6  
17 1     1   91 use Carp;
  1         3  
  1         92  
18 1     1   11 use Time::HiRes qw( usleep );
  1         2  
  1         5  
19 1     1   643 use HiPi::Interface::HopeRF69;
  1         2  
  1         68  
20 1     1   8 use HiPi::GPIO;
  1         3  
  1         34  
21 1     1   34 use HiPi::RF::OpenThings::Message;
  1         2  
  1         1307  
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 rf_high_power ) );
26              
27             our $VERSION ='0.82';
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, 0x42 ], # 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             rf_high_power => 0,
93             );
94            
95 0           foreach my $key (sort keys(%userparams)) {
96 0           $params{$key} = $userparams{$key};
97             }
98            
99 0 0         unless( defined($params{device}) ) {
100             $params{device} = HiPi::Interface::HopeRF69->new(
101             speed => $params{speed},
102             bitsperword => $params{bitsperword},
103             delay => $params{delay},
104             devicename => $params{devicename},
105             reset_gpio => $params{reset_gpio},
106             ook_repeat => $params{ook_repeat},
107             backend => $params{backend},
108             fsk_config => $params{default_config},
109             ook_config => $params{ook_config},
110             high_power_module => $params{rf_high_power},
111 0 0         max_power_on => ( $params{rf_high_power} ) ? 1 : 0,
112             );
113             }
114            
115 0           my $self = $class->SUPER::new(%params);
116 0           $self->init_pins;
117            
118             # setup defaults
119 0           $self->set_red_led( 0 );
120 0           $self->set_green_led( 0 );
121            
122 0           return $self;
123             }
124              
125             sub make_ook_message {
126 0     0 0   my($self, $groupid, $data) = @_;
127            
128             # energenie preamble
129 0           my @msgbytes = ( 0x80, 0x00, 0x00, 0x00 );
130            
131             # encode the group id
132 0           push @msgbytes, ( $self->encode_data( ( $groupid & 0x0f0000 ) >> 16, 4 ) );
133 0           push @msgbytes, ( $self->encode_data( ( $groupid & 0x00ff00 ) >> 8, 8 ) );
134 0           push @msgbytes, ( $self->encode_data( ( $groupid & 0x0000ff ), 8 ) );
135            
136             # encode the databits
137 0           push @msgbytes, ( $self->encode_data( ( $data & 0x00000f ), 4 ) );
138            
139 0           return @msgbytes;
140             }
141              
142             sub send_message {
143 0     0 0   my($self, $bytes) = @_;
144              
145 0 0         return unless(scalar( @$bytes ));
146              
147 0           $self->set_red_led( 1 );
148 0           $self->device->send_message( $bytes );
149 0           $self->set_red_led( 0 );
150            
151 0           return;
152             }
153              
154             sub send_ook_message {
155 0     0 0   my($self, $groupid, $data, $repeat ) = @_;
156            
157 0   0       $repeat ||= $self->ook_repeat;
158            
159 0           $self->set_red_led( 1 );
160            
161             # $groupid = 20 bit controller id for your energenie ENER314-RT - you can vary this
162             # as you wish so you can control multiple groups of 4 devices each.
163             # $address is therefore any number between 0x1 and 0xFFFFF
164             # $data = the 4 bits you want to send as defined in Energenie docs for your switch
165             # order here is d0,d1,d2,d3 as defined in docs for your device
166             # therefore data is a number between 0 and 15
167            
168 0           my @sendbytes = $self->make_ook_message( $groupid, $data );
169            
170 0           $self->device->send_ook_message(\@sendbytes, $repeat );
171            
172 0           $self->set_red_led( 0 );
173             }
174              
175             # mask for bit encoding
176             my @_encoding_mask = ( 0x88, 0x8E, 0xE8, 0xEE );
177              
178             sub encode_data {
179 0     0 0   my($self, $data, $number ) = @_;
180 0           my @encoded = ();
181 0           my $shift = $number - 2;
182 0           while ( $shift >= 0 ) {
183 0           my $encindex = ($data >> $shift) & 0x03;
184 0           push @encoded, $_encoding_mask[$encindex];
185 0           $shift -= 2;
186             }
187 0           return @encoded;
188             }
189              
190             sub init_pins {
191 0     0 0   my $self = shift;
192 0 0         return unless $self->led_on;
193 0 0         if( my $redpin = $self->led_red ) {
194 0           $self->gpiodev->set_pin_mode( $redpin, RPI_MODE_OUTPUT );
195 0           $self->gpiodev->set_pin_level( $redpin, RPI_LOW );
196             }
197 0 0         if( my $greenpin = $self->led_green ) {
198 0           $self->gpiodev->set_pin_mode( $greenpin, RPI_MODE_OUTPUT );
199 0           $self->gpiodev->set_pin_level( $greenpin, RPI_LOW );
200             }
201             }
202              
203             sub set_red_led {
204 0     0 0   my ($self, $value) = @_;
205 0 0         return unless $self->led_on;
206 0 0         if( my $redpin = $self->led_red ) {
207 0           $self->gpiodev->set_pin_level( $redpin, $value );
208             }
209 0           return;
210             }
211              
212             sub set_green_led {
213 0     0 0   my ($self, $value) = @_;
214 0 0         return unless $self->led_on;
215 0 0         if( my $greenpin = $self->led_green ) {
216 0           $self->gpiodev->set_pin_level( $greenpin, $value );
217             }
218 0           return;
219             }
220              
221             sub reset {
222 0     0 0   my $self = shift;
223 0           $self->device->reset;
224             }
225              
226             sub receive_fsk_message {
227 0     0 0   my ($self, $encryptionid) = @_;
228 0 0         if( my $buffer = $self->device->receive_message ) {
229 0           my $msg = HiPi::RF::OpenThings::Message->new(
230             databuffer => $buffer,
231             cryptseed => $encryptionid,
232             );
233 0           $msg->inspect_buffer;
234 0           return $msg;
235             }
236 0           return undef;
237             }
238              
239             sub send_fsk_message {
240 0     0 0   my ($self, $msg) = @_;
241 0 0         $msg->encode_buffer unless $msg->is_encoded;
242 0           $self->send_message( $msg->databuffer );
243             }
244              
245             #-------------------------------------------------------
246             # Common OOK switch handler
247             #-------------------------------------------------------
248              
249             sub switch_ook_socket {
250 0     0 0   my($self, $groupid, $data, $repeat) = @_;
251 0           $self->send_ook_message( $groupid, $data, $repeat );
252             }
253              
254             sub DESTROY {
255 0     0     my $self = shift;
256 0           $self->SUPER::DESTROY;
257 0           $self->device( undef );
258             }
259              
260             1;
261              
262             __END__