File Coverage

blib/lib/Device/Yeelight.pm
Criterion Covered Total %
statement 23 54 42.5
branch 0 14 0.0
condition n/a
subroutine 8 11 72.7
pod 3 3 100.0
total 34 82 41.4


line stmt bran cond sub pod time code
1             package Device::Yeelight;
2              
3 1     1   69863 use 5.026;
  1         3  
4 1     1   671 use utf8;
  1         14  
  1         6  
5 1     1   32 use strict;
  1         2  
  1         20  
6 1     1   5 use warnings;
  1         1  
  1         25  
7              
8 1     1   5 use Carp;
  1         2  
  1         51  
9 1     1   505 use IO::Select;
  1         1706  
  1         50  
10 1     1   529 use IO::Socket::Multicast;
  1         27385  
  1         7  
11 1     1   1076 use Device::Yeelight::Light;
  1         2  
  1         496  
12              
13             =encoding utf8
14             =head1 NAME
15              
16             Device::Yeelight - Controller for Yeelight smart devices
17              
18             =head1 VERSION
19              
20             Version 0.13
21              
22             =cut
23              
24             our $VERSION = '0.13';
25              
26             =head1 SYNOPSIS
27              
28             This Perl module implements local device discovery via Yeeling specific SSDP
29             protocol and sending commands via control protocol in the JSON format.
30              
31             Device::Yeelight module provides base class for detecting Yeelight devices.
32              
33             use Device::Yeelight;
34             use feature 'say';
35              
36             my $yeelight = Device::Yeelight->new();
37             my @devices = @{$yeelight->search()};
38             foreach my $device (@devices) {
39             my %props = %{$device->get_prop(qw/power/)};
40             say "The light is $props{power}";
41             $device->set_power('on', 'smooth', 1000);
42             }
43             ...
44              
45             =head1 SUBROUTINES/METHODS
46              
47             =head2 new
48              
49             Creates new Yeelight controller.
50              
51             =cut
52              
53             sub new {
54 0     0 1   my $class = shift;
55 0           my $data = {
56             address => '239.255.255.250',
57             port => 1982,
58             timeout => 3,
59             devices => [],
60             };
61 0           return bless( $data, $class );
62             }
63              
64             =head2 search
65              
66             Sends search request message and waits for devices response.
67              
68             =cut
69              
70             sub search {
71 0     0 1   my $self = shift;
72              
73             my $socket = IO::Socket::Multicast->new(
74             PeerAddr => $self->{address},
75             PeerPort => $self->{port},
76 0 0         Proto => "udp",
77             ReuseAddr => 1,
78             ) or croak $!;
79 0           $socket->mcast_loopback(0);
80              
81 0 0         my $listen = IO::Socket::INET->new(
82             LocalPort => $socket->sockport,
83             Proto => 'udp',
84             ReuseAddr => 1,
85             ) or croak $!;
86 0           my $sel = IO::Select->new($listen);
87              
88 0           my $query = <
89             M-SEARCH * HTTP/1.1\r
90             HOST: $self->{address}:$self->{port}\r
91             MAN: "ssdp:discover"\r
92             ST: wifi_bulb\r
93             EOQ
94              
95 0           ${*$socket}{'io_socket_mcast_dest'} = sockaddr_in(int($self->{port}),inet_aton($self->{address}));
  0            
96              
97 0 0         $socket->mcast_send( $query ) or croak $!;
98 0           $socket->close;
99              
100 0           my @ready;
101 0           while ( @ready = $sel->can_read( $self->{timeout} ) ) {
102 0 0         break unless @ready;
103 0           foreach my $fh (@ready) {
104 0           my $data;
105 0           $fh->recv( $data, 4096 );
106 0 0         $self->parse_response($data) if $data =~ m#^HTTP/1\.1 200 OK\r\n#;
107             }
108             }
109 0           $listen->close;
110 0           return $self->{devices};
111             }
112              
113             =head2 parse_response
114              
115             Parse response message from Yeelight device.
116              
117             =cut
118              
119             sub parse_response {
120 0     0 1   my $self = shift;
121 0           my ($data) = @_;
122              
123 0           my $device;
124             ( $device->{$_} ) = ( $data =~ /$_: (.*)\r\n/i )
125 0           foreach (
126             qw/location id model fw_ver support power bright color_mode ct rgb hue sat name/
127             );
128             $device->{support} = [ sort split( ' ', $device->{support} ) ]
129 0 0         if defined $device->{support};
130              
131 0           push @{ $self->{devices} }, Device::Yeelight::Light->new(%$device)
132 0 0         unless grep { $device->{id} eq $_->{id} } @{ $self->{devices} };
  0            
  0            
133             }
134              
135             =head1 AUTHOR
136              
137             Jan Baier, C<< >>
138              
139             =head1 SEE ALSO
140              
141             L
142              
143             =head1 BUGS
144              
145             Please report any bugs or feature requests via
146             L
147              
148             =head1 LICENSE AND COPYRIGHT
149              
150             Copyright 2019 Jan Baier.
151              
152             This program is free software; you can redistribute it and/or modify it
153             under the terms of either: the GNU General Public License as published
154             by the Free Software Foundation; or the Artistic License.
155              
156             See L for more information.
157              
158             =cut
159              
160             1; # End of Device::Yeelight