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