File Coverage

blib/lib/Device/Osram/Lightify/Light.pm
Criterion Covered Total %
statement 9 148 6.0
branch 0 12 0.0
condition 0 7 0.0
subroutine 3 18 16.6
pod 14 14 100.0
total 26 199 13.0


line stmt bran cond sub pod time code
1              
2             =head1 NAME
3            
4             Device::Osram::Lightify::Light - The interface to a single light
5            
6             =head1 DESCRIPTION
7            
8             This module allows a single Osram lightify light to be manipulated.
9            
10             Objects are not expected to be constructed manually, instead
11             they are discovered dynmically via communication with the hub.
12            
13             =cut
14              
15             =head1 SYNOPSIS
16            
17             use Device::Osram::Lightify;
18            
19             my $tmp = Device::Osram::Lightify::Hub->new( host => "1.2.3.4" );
20            
21             # Show all nodes we found
22             # (Stringification means we dump all the state here.)
23             foreach my $light ( $tmp->lights() ) {
24             print $light;
25             }
26            
27             =cut
28              
29             =head1 DESCRIPTION
30            
31             This module allows basic control of an Osram Lightify light.
32            
33             =cut
34              
35             =head1 METHODS
36            
37             =cut
38              
39 1     1   5 use strict;
  1         2  
  1         23  
40 1     1   5 use warnings;
  1         2  
  1         45  
41              
42             package Device::Osram::Lightify::Light;
43              
44             #
45             # Allow our object to treated as a string.
46             #
47 1     1   5 use overload '""' => 'stringify';
  1         2  
  1         7  
48              
49              
50             =head2 new
51            
52             Create a new light-object.
53            
54             This is invoked by C<Hub:lights()> method, which will read a binary
55             string containing all the details of the light - we must then parse
56             it according to L<Device::Osram::Lightify::API>.
57            
58             =cut
59              
60             sub new
61             {
62 0     0 1       my ( $proto, %supplied ) = (@_);
63 0   0           my $class = ref($proto) || $proto;
64              
65 0               my $self = {};
66 0               bless( $self, $class );
67              
68              
69 0   0           $self->{ 'hub' } = $supplied{ 'hub' } || die "Missing 'hub' parameter";
70 0   0           $self->{ 'binary' } = $supplied{ 'binary' } ||
71                   die "Missing 'binary' parameter";
72              
73 0               $self->_decode_binary();
74 0               return $self;
75             }
76              
77              
78             =begin doc
79            
80             Internal method, parse the status of a light.
81            
82             =end doc
83            
84             =cut
85              
86             sub _decode_binary
87             {
88 0     0         my ($self) = (@_);
89              
90 0               my $buffer = $self->{ 'binary' };
91              
92             #
93             # my $str = $buffer;
94             # $str =~ s/(.)/sprintf("0x%x ",ord($1))/megs;
95             # print "HEX:" . $str . "\n";
96             #
97              
98             # Get the MAC
99 0               my $mac = substr( $buffer, 2, 8 );
100 0               foreach my $c ( reverse( split( //, $mac ) ) )
101                 {
102 0                   $self->{ 'mac' } .= sprintf( "%02x", ord($c) );
103 0                   $self->{ 'maddr' } .= $c;
104                 }
105 0               $self->{ 'maddr' } = reverse( $self->{ 'maddr' } );
106              
107             # Get the firmware-version
108 0               my $ver = substr( $buffer, 11, 4 );
109 0               foreach my $c ( split( //, $ver ) )
110                 {
111 0 0                 $self->{ 'version' } .= "." if ( $self->{ 'version' } );
112 0                   $self->{ 'version' } .= sprintf( "%x", ord($c) );
113                 }
114              
115 0 0             if ( ord( substr( $buffer, 18, 1 ) ) eq 1 )
116                 {
117 0                   $self->{ 'status' } = "on";
118                 }
119                 else
120                 {
121 0                   $self->{ 'status' } = "off";
122                 }
123              
124             # Brightness
125 0               $self->{ 'brightness' } = ord( substr( $buffer, 19, 1 ) );
126              
127             # Temperature in kelvins
128 0               my $k1 = ord( substr( $buffer, 20, 1 ) );
129 0               my $k2 = ord( substr( $buffer, 21, 1 ) );
130 0               $self->{ 'temperature' } = ( $k1 + ( 256 * $k2 ) );
131              
132             # R,G,B,W
133 0               $self->{ 'r' } = ord( substr( $buffer, 22, 1 ) );
134 0               $self->{ 'g' } = ord( substr( $buffer, 23, 1 ) );
135 0               $self->{ 'b' } = ord( substr( $buffer, 24, 1 ) );
136 0               $self->{ 'w' } = ord( substr( $buffer, 25, 1 ) );
137              
138             # The name of the bulb.
139 0               $self->{ 'name' } = substr( $buffer, 26, 15 );
140 0               $self->{ 'name' } =~ s/\0//g;
141             }
142              
143              
144              
145             =head2 brightness
146            
147             Get the brightness value of this light (0-100).
148            
149             =cut
150              
151             sub brightness
152             {
153 0     0 1       my ($self) = (@_);
154              
155 0               return ( $self->{ 'brightness' } );
156             }
157              
158              
159             =head2 mac
160            
161             Get the MAC address of this light.
162            
163             =cut
164              
165             sub mac
166             {
167 0     0 1       my ($self) = (@_);
168              
169 0               return ( $self->{ 'mac' } );
170             }
171              
172              
173             =head2 name
174            
175             Return the name of this light.
176            
177             =cut
178              
179             sub name
180             {
181 0     0 1       my ($self) = (@_);
182              
183 0               return ( $self->{ 'name' } );
184             }
185              
186              
187              
188             =head2 rgbw
189            
190             Return the current RGBW value of this light.
191            
192             =cut
193              
194             sub rgbw
195             {
196 0     0 1       my ($self) = (@_);
197              
198 0               my $x = "";
199 0               $x .= $self->{ 'r' };
200 0               $x .= ",";
201 0               $x .= $self->{ 'g' };
202 0               $x .= ",";
203 0               $x .= $self->{ 'b' };
204 0               $x .= ",";
205 0               $x .= $self->{ 'w' };
206              
207 0               return ($x);
208             }
209              
210              
211             =head2 status
212            
213             Is the light C<on> or C<off> ?
214            
215             =cut
216              
217             sub status
218             {
219 0     0 1       my ($self) = (@_);
220              
221 0               return ( $self->{ 'status' } );
222             }
223              
224              
225             =head2 temperature
226            
227             Get the temperature value of this light (2200-6500).
228            
229             =cut
230              
231             sub temperature
232             {
233 0     0 1       my ($self) = (@_);
234              
235 0               return ( $self->{ 'temperature' } );
236             }
237              
238              
239             =head2 version
240            
241             Get the firmware version of this light.
242            
243             =cut
244              
245             sub version
246             {
247 0     0 1       my ($self) = (@_);
248              
249 0               return ( $self->{ 'version' } );
250             }
251              
252              
253              
254             =head2 set_on
255            
256             Set this light to be "on".
257            
258             =cut
259              
260             sub set_on
261             {
262 0     0 1       my ($self) = (@_);
263              
264 0               my $parent = $self->{ 'hub' };
265 0               my $socket = $parent->{ '_socket' };
266              
267             # Prefix for sending a light on
268 0               my $x = "";
269 0               foreach my $char (qw! 0x0f 0x00 0x00 0x32 !)
270                 {
271 0                   $x .= chr( hex($char) );
272                 }
273              
274             # Add a time/session-token
275 0               $x .= $parent->_session_token();
276              
277             # MAC address - binary - in reverse
278 0               $x .= $self->{ 'maddr' };
279              
280             # Desired state: 1
281 0               $x .= chr( hex("0x01") );
282              
283 0               syswrite( $socket, $x, length($x) );
284              
285             # Read 8-byte header + 12-byte reply
286 0               my $buffer = $parent->_read(20);
287             }
288              
289              
290             =head2 set_off
291            
292             Set this light to be "off".
293            
294             =cut
295              
296             sub set_off
297             {
298 0     0 1       my ($self) = (@_);
299              
300 0               my $parent = $self->{ 'hub' };
301 0               my $socket = $parent->{ '_socket' };
302              
303             # Prefix for sending a light off
304 0               my $x = "";
305 0               foreach my $char (qw! 0x0f 0x00 0x00 0x32 !)
306                 {
307 0                   $x .= chr( hex($char) );
308                 }
309              
310             # Add a time/session-token
311 0               $x .= $parent->_session_token();
312              
313             # MAC address - binary - in reverse
314 0               $x .= $self->{ 'maddr' };
315              
316              
317             # Desired state: 0
318 0               $x .= chr( hex("0x00") );
319              
320 0               syswrite( $socket, $x, length($x) );
321              
322             # Read 8-byte header + 12-byte reply
323 0               my $buffer = $parent->_read(20);
324              
325             }
326              
327              
328             =head2 set_brightness
329            
330             Set the brightness value of this light - valid values are 0-100.
331            
332             =cut
333              
334             sub set_brightness
335             {
336 0     0 1       my ( $self, $brightness ) = (@_);
337              
338 0 0             if ( $brightness < 0 )
339                 {
340 0                   $brightness = 0;
341                 }
342 0 0             if ( $brightness > 100 )
343                 {
344 0                   $brightness = 100;
345                 }
346              
347 0               my $parent = $self->{ 'hub' };
348 0               my $socket = $parent->{ '_socket' };
349              
350             # Prefix for changing the brightness.
351 0               my $x = "";
352 0               foreach my $char (qw! 11 00 00 31 !)
353                 {
354 0                   $x .= chr( hex($char) );
355                 }
356              
357             # Add a time/session-token
358 0               $x .= $parent->_session_token();
359              
360             # MAC address - binary - in reverse
361 0               $x .= $self->{ 'maddr' };
362              
363             # Desired brightness 0-100.
364 0               $x .= chr($brightness);
365              
366 0               $x .= chr( hex("0x00") );
367 0               $x .= chr( hex("0x00") );
368              
369 0               syswrite( $socket, $x, length($x) );
370              
371             # Read 8-byte header + 12-byte reply
372 0               my $buffer = $parent->_read(20);
373             }
374              
375              
376             =head2 set_rgbw
377            
378             Set the specified RGBW values of this light.
379            
380             =cut
381              
382             sub set_rgbw
383             {
384 0     0 1       my ( $self, $r, $g, $b, $w ) = (@_);
385              
386 0               my $parent = $self->{ 'hub' };
387 0               my $socket = $parent->{ '_socket' };
388              
389             # Prefix for changing the RGBW values.
390 0               my $x = "";
391 0               foreach my $char (qw! 0x14 0x00 0x00 0x36 !)
392                 {
393 0                   $x .= chr( hex($char) );
394                 }
395              
396              
397             # Add a time/session-token
398 0               $x .= $parent->_session_token();
399              
400             # MAC address - binary - in reverse
401 0               $x .= $self->{ 'maddr' };
402              
403             # The colours.
404 0               $x .= chr($r);
405 0               $x .= chr($g);
406 0               $x .= chr($b);
407 0               $x .= chr($w);
408              
409             # Two more bytes
410 0               $x .= chr( hex("0x00") );
411 0               $x .= chr( hex("0x00") );
412              
413 0               syswrite( $socket, $x, length($x) );
414              
415             # Read 8-byte header + 12-byte reply
416 0               my $buffer = $parent->_read(20);
417              
418             }
419              
420              
421             =head2 set_temperature
422            
423             Set the specified temperature value for this light, in the range 2200-6500.
424            
425             =cut
426              
427             sub set_temperature
428             {
429 0     0 1       my ( $self, $temp ) = (@_);
430              
431 0               my $parent = $self->{ 'hub' };
432 0               my $socket = $parent->{ '_socket' };
433              
434 0 0             if ( $temp < 2200 )
435                 {
436 0                   $temp = 2200;
437                 }
438 0 0             if ( $temp > 6500 )
439                 {
440 0                   $temp = 6500;
441                 }
442              
443 0               my $t1 = $temp % 256;
444 0               my $t2 = ( $temp - $t1 ) / 256;
445              
446 0               my $x = "";
447 0               foreach my $char (qw! 0x12 0x00 0x00 0x33 !)
448                 {
449 0                   $x .= chr( hex($char) );
450                 }
451              
452             # Add a time/session-token
453 0               $x .= $parent->_session_token();
454              
455             # MAC address - binary - in reverse
456 0               $x .= $self->{ 'maddr' };
457              
458             # The temperature.
459 0               $x .= chr($t1);
460 0               $x .= chr($t2);
461              
462             # Two more bytes
463 0               $x .= chr( hex("0x00") );
464 0               $x .= chr( hex("0x00") );
465              
466 0               syswrite( $socket, $x, length($x) );
467              
468             # Read 8-byte header + 12-byte reply
469 0               my $buffer = $parent->_read(20);
470              
471             }
472              
473              
474              
475             =head2 stringify
476            
477             Convert the record to a string, suitable for printing.
478            
479             =cut
480              
481             sub stringify
482             {
483 0     0 1       my ($self) = (@_);
484 0               my $txt = "";
485              
486 0               $txt .= "Name: " . $self->name() . "\n";
487 0               $txt .= "\tMAC:" . $self->mac() . "\n";
488 0               $txt .= "\tversion:" . $self->version() . "\n";
489 0               $txt .= "\tBrightness:" . $self->brightness() . "\n";
490 0               $txt .= "\tRGBW:" . $self->rgbw() . "\n";
491 0               $txt .= "\tTemperature:" . $self->temperature() . "\n";
492 0               $txt .= "\tStatus:" . $self->{ 'status' } . "\n";
493              
494 0               $txt;
495             }
496              
497             1;
498              
499              
500              
501             =head1 AUTHOR
502            
503             Steve Kemp <steve@steve.org.uk>
504            
505             =cut
506              
507             =head1 COPYRIGHT AND LICENSE
508            
509             Copyright (C) 2016 Steve Kemp <steve@steve.org.uk>.
510            
511             This library is free software. You can modify and or distribute it under
512             the same terms as Perl itself.
513            
514             =cut
515