File Coverage

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


line stmt bran cond sub pod time code
1             package Device::Yeelight;
2              
3 1     1   66076 use 5.026;
  1         4  
4 1     1   668 use utf8;
  1         15  
  1         5  
5 1     1   31 use strict;
  1         3  
  1         18  
6 1     1   4 use warnings;
  1         2  
  1         24  
7              
8 1     1   6 use Carp;
  1         1  
  1         51  
9 1     1   422 use IO::Select;
  1         1577  
  1         47  
10 1     1   451 use IO::Socket::Multicast;
  1         26397  
  1         5  
11 1     1   1008 use Device::Yeelight::Light;
  1         2  
  1         455  
12              
13             =encoding utf8
14             =head1 NAME
15              
16             Device::Yeelight - Controller for Yeelight smart devices
17              
18             =head1 VERSION
19              
20             Version 0.11
21              
22             =cut
23              
24             our $VERSION = '0.11';
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 0 0         $socket->mcast_send( $query, "$self->{address}:$self->{port}" ) or croak $!;
94 0           $socket->close;
95              
96 0           my @ready;
97 0           while ( @ready = $sel->can_read( $self->{timeout} ) ) {
98 0 0         break unless @ready;
99 0           foreach my $fh (@ready) {
100 0           my $data;
101 0           $fh->recv( $data, 4096 );
102 0 0         $self->parse_response($data) if $data =~ m#^HTTP/1\.1 200 OK\r\n#;
103             }
104             }
105 0           $listen->close;
106 0           return $self->{devices};
107             }
108              
109             =head2 parse_response
110              
111             Parse response message from Yeelight device.
112              
113             =cut
114              
115             sub parse_response {
116 0     0 1   my $self = shift;
117 0           my ($data) = @_;
118              
119 0           my $device;
120             ( $device->{$_} ) = ( $data =~ /$_: (.*)\r\n/i )
121 0           foreach (
122             qw/location id model fw_ver support power bright color_mode ct rgb hue sat name/
123             );
124             $device->{support} = [ split( ' ', $device->{support} ) ]
125 0 0         if defined $device->{support};
126              
127 0           push @{ $self->{devices} }, Device::Yeelight::Light->new(%$device)
128 0 0         unless grep { $device->{id} eq $_->{id} } @{ $self->{devices} };
  0            
  0            
129             }
130              
131             =head1 AUTHOR
132              
133             Jan Baier, C<< >>
134              
135             =head1 SEE ALSO
136              
137             L
138              
139             =head1 BUGS
140              
141             Please report any bugs or feature requests via
142             L
143              
144             =head1 LICENSE AND COPYRIGHT
145              
146             Copyright 2019 Jan Baier.
147              
148             This program is free software; you can redistribute it and/or modify it
149             under the terms of either: the GNU General Public License as published
150             by the Free Software Foundation; or the Artistic License.
151              
152             See L for more information.
153              
154             =cut
155              
156             1; # End of Device::Yeelight