File Coverage

blib/lib/Power/Outlet/Tasmota.pm
Criterion Covered Total %
statement 9 65 13.8
branch 0 34 0.0
condition 0 6 0.0
subroutine 3 20 15.0
pod 8 8 100.0
total 20 133 15.0


line stmt bran cond sub pod time code
1             package Power::Outlet::Tasmota;
2 2     2   110018 use strict;
  2         13  
  2         63  
3 2     2   13 use warnings;
  2         4  
  2         60  
4 2     2   10 use base qw{Power::Outlet::Common::IP::HTTP::JSON};
  2         4  
  2         1521  
5              
6             our $VERSION = '0.47';
7              
8             =head1 NAME
9              
10             Power::Outlet::Tasmota - Control and query a Tasmota GIPO configured as a Relay (Switch or Button)
11              
12             =head1 SYNOPSIS
13              
14             my $outlet = Power::Outlet::Tasmota->new(host => "tasmota", relay => "POWER1");
15             print $outlet->query, "\n";
16             print $outlet->on, "\n";
17             print $outlet->off, "\n";
18              
19             =head1 DESCRIPTION
20              
21             Power::Outlet::Tasmota is a package for controlling and querying a relay on Tasmota ESP8266 hardware.
22              
23             From: L
24              
25             Commands can be executed via web (HTTP) requests, for example:
26              
27             http:///cm?cmnd=Power%20TOGGLE
28             http:///cm?cmnd=Power%20On
29             http:///cm?cmnd=Power%20off
30             http:///cm?user=admin&password=joker&cmnd=Power%20Toggle
31              
32             Examples:
33              
34              
35             Query default relay
36              
37             $ curl http://tasmota/cm?cmnd=POWER1
38             {"POWER1":"ON"}
39              
40             Toggle (Switch) relay 4
41              
42             $ curl http://tasmota/cm?user=foo;password=bar;cmnd=POWER4+TOGGLE
43             {"POWER4":"OFF"}
44              
45             Turn ON relay 2
46              
47             $ curl http://tasmota/cm?user=foo;password=bar;cmnd=POWER2+ON
48             {"POWER2":"ON"}
49              
50             =head1 USAGE
51              
52             use Power::Outlet::Tasmota;
53             my $relay = Power::Outlet::Tasmota->new(host=>"tasmota", relay=>"POWER2");
54             print $relay->on, "\n";
55              
56             =head1 CONSTRUCTOR
57              
58             =head2 new
59              
60             my $outlet = Power::Outlet->new(type=>"Tasmota", host=>"tasmota", relay=>"POWER2");
61             my $outlet = Power::Outlet::Tasmota->new(host=>"tasmota", relay=>"POWER2");
62              
63             =head1 PROPERTIES
64              
65             =head2 relay
66              
67             Tasmota version 8.1.0 supports up to 8 relays. These 8 relays map to the relay tokens "POWER1", "POWER2", ... "POWER8". With "POWER" being the default relay name for the first relay defined in the configuration.
68              
69             Default: POWER1
70              
71             =cut
72              
73             sub relay {
74 0     0 1   my $self = shift;
75 0 0         $self->{'relay'} = shift if @_;
76 0 0         $self->{'relay'} = $self->_relay_default unless defined $self->{'relay'};
77 0           return $self->{'relay'};
78             }
79              
80             sub _relay {
81 0     0     my $self = shift;
82 0           my $relay = uc($self->relay); #upper case
83             #Added suport for ID only relay
84 0 0         $relay = "POWER$relay" if $relay =~ m/\A[0-9]\Z/;
85             #support SetOption26 on and off
86 0 0         $relay .= '1' if $relay eq "POWER"; #see SetOption26
87 0 0         die unless $relay =~ m/\APOWER[0-9]\Z/; #0-8???
88 0           return $relay;
89             }
90              
91 0     0     sub _relay_default {'POWER1'};
92              
93             =head2 host
94              
95             Sets and returns the hostname or IP address.
96              
97             Default: tasmota
98              
99             =cut
100              
101 0     0     sub _host_default {'tasmota'};
102              
103             =head2 port
104              
105             Sets and returns the port number.
106              
107             Default: 80
108              
109             =cut
110              
111 0     0     sub _port_default {'80'};
112              
113             =head2 http_path
114              
115             Sets and returns the http_path.
116              
117             Default: /cm
118              
119             =cut
120              
121 0     0     sub _http_path_default {'/cm'};
122              
123              
124             =head2 user
125              
126             Sets and returns the user used for authentication with the Tasmota hardware
127              
128             my $outlet = Power::Outlet::Tasmota->new(host=>"tasmota", relay=>"POWER1", user=>"mylogin", password=>"mypassword");
129             print $outlet->query, "\n";
130              
131             Default: undef() #which is only passed on the url when defined
132              
133             =cut
134              
135             sub user {
136 0     0 1   my $self = shift;
137 0 0         $self->{'user'} = shift if @_;
138 0 0         $self->{'user'} = $self->_user_default unless defined $self->{'user'};
139 0           return $self->{'user'};
140             }
141              
142 0     0     sub _user_default {undef};
143              
144             =head2 password
145              
146             Sets and returns the password used for authentication with the Tasmota hardware
147              
148             Default: "" #which is only passed on the url when user property is defined
149              
150             =cut
151              
152             sub password {
153 0     0 1   my $self = shift;
154 0 0         $self->{'password'} = shift if @_;
155 0 0         $self->{'password'} = $self->_password_default unless defined $self->{'password'};
156 0           return $self->{'password'};
157             }
158              
159 0     0     sub _password_default {''};
160              
161              
162             =head1 METHODS
163              
164             =head2 name
165              
166             Returns the FriendlyName from the Tasmota hardware.
167              
168             Note: The FriendlyName is cached for the life of the object.
169              
170             =cut
171              
172             sub name {
173 0     0 1   my $self = shift;
174 0 0         unless ($self->{'name'}) {
175 0           my $relay = $self->_relay;
176 0 0         if ($relay eq "POWER0") {
177 0           $self->{'name'} = "All";
178             } else {
179 0           $relay =~ s/POWER/FriendlyName/i;
180 0   0       $self->{'name'} = $self->_get(cmnd=>"FriendlyName")->{$relay} || $relay;
181             }
182             }
183 0           return $self->{'name'};
184             }
185              
186             =head2 query
187              
188             Sends an HTTP message to the device to query the current state
189              
190             =cut
191              
192             sub query {
193 0     0 1   my $self = shift;
194 0           return $self->_call('');
195             }
196              
197             =head2 on
198              
199             Sends a message to the device to Turn Power ON
200              
201             =cut
202              
203             sub on {
204 0     0 1   my $self = shift;
205 0           return $self->_call('ON');
206             }
207              
208             =head2 off
209              
210             Sends a message to the device to Turn Power OFF
211              
212             =cut
213              
214             sub off {
215 0     0 1   my $self = shift;
216 0           return $self->_call('OFF');
217             }
218              
219             =head2 switch
220              
221             Sends a message to the device to toggle the power
222              
223             =cut
224              
225             sub switch {
226 0     0 1   my $self = shift;
227 0           return $self->_call('TOGGLE');
228             }
229              
230             =head2 cycle
231              
232             Sends messages to the device to Cycle Power (ON-OFF-ON or OFF-ON-OFF).
233              
234             =cut
235              
236             #see Power::Outlet::Common->cycle
237              
238             sub _call {
239 0     0     my $self = shift;
240 0           my $arg = shift; #e.g. "" || ON || OFF || TOGGLE
241 0           my $relay = $self->_relay; #e.g. POWER0 || POWER1 || POWER2 ... (not POWER, not FriendlyName)
242 0 0         my $cmnd = $arg ? "$relay $arg" : $relay;
243 0           my $hash = $self->_get(cmnd=>$cmnd);
244             #use Data::Dumper qw{Dumper};
245             #print Dumper($hash);
246             my $return = $relay eq 'POWER1' ? $hash->{'POWER'} || $hash->{'POWER1'} #SetOption26 on|off
247 0           : $relay eq 'POWER0' ? ((grep {$_ eq 'ON'} values %$hash) ? 'ON' : 'OFF') #any on = on
248 0 0 0       : $hash->{$relay};
    0          
    0          
249 0           return $return;
250             }
251              
252             sub _get {
253 0     0     my $self = shift;
254 0           my @param = @_;
255             #http:///cm?user=admin&password=joker&cmnd=Power%20Toggle
256 0           my $url = $self->url; #isa URI from Power::Outlet::Common::IP::HTTP
257 0 0         my @auth = $self->user ? (user => $self->user, password => $self->password) : ();
258 0           $url->query_form(@auth, @param);
259             #print "$url\n";
260 0           my $hash = $self->json_request(GET => $url); #isa HASH
261             #{"POWER1":"OFF"}
262             #{"Command":"Unknown"}
263             #{"WARNING":"Enter command cmnd="}
264 0 0         die("Error: Method _get failed to return expected JSON object") unless ref($hash) eq "HASH";
265 0           return $hash;
266             }
267              
268             =head1 BUGS
269              
270             Please log on RT and send an email to the author.
271              
272             =head1 SUPPORT
273              
274             DavisNetworks.com supports all Perl applications including this package.
275              
276             =head1 AUTHOR
277              
278             Michael R. Davis
279             CPAN ID: MRDVT
280             DavisNetworks.com
281              
282             =head1 COPYRIGHT
283              
284             Copyright (c) 2020 Michael R. Davis
285              
286             This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
287              
288             The full text of the license can be found in the LICENSE file included with this module.
289              
290             =head1 SEE ALSO
291              
292             L
293              
294             =cut
295              
296             1;