File Coverage

blib/lib/Device/Nest.pm
Criterion Covered Total %
statement 34 321 10.5
branch 1 96 1.0
condition 0 9 0.0
subroutine 12 48 25.0
pod 33 34 97.0
total 80 508 15.7


line stmt bran cond sub pod time code
1             package Device::Nest;
2              
3 1     1   15288 use warnings;
  1         2  
  1         45  
4 1     1   6 use strict;
  1         2  
  1         38  
5 1     1   22 use 5.006_001;
  1         13  
  1         190  
6              
7             require Exporter;
8              
9             our @ISA = qw(Exporter);
10              
11             # Items to export into callers namespace by default. Note: do not export
12             # names by default without a very good reason. Use EXPORT_OK instead.
13             # Do not simply export all your public functions/methods/constants.
14              
15             # This allows declaration use Device::Nest ':all';
16             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
17             # will save memory.
18              
19             our %EXPORT_TAGS = ( 'all' => [ qw( new
20             fetch_Auth_Token fetch_Thermostat_Designation fetch_Ambient_Temperature_C
21             fetch_Target_Temperature_C fetch_Target_Temperature_high_C fetch_Target_Temperature_low_C
22             fetch_Away_Temperature_low_C fetch_Ambient_Temperature_F fetch_Away_Temperature_low_F
23             fetch_Away_Temperature_high_F fetch_Target_Temperature_low_F fetch_Target_Temperature_F
24             fetch_Target_Temperature_high_F fetch_Temperature_Scale fetch_Locale fetch_Name
25             fetch_Long_Name fetch_HVAC_Mode fetch_SW_Version fetch_Away_State
26             fetch_Country_Code
27             set_Target_Temperature_C set_Target_Temperature_F set_Target_Temperature_high_C
28             set_Target_Temperature_low_C set_Target_Temperature_high_F set_Target_Temperature_low_F
29             set_Away_State
30             ) ] );
31              
32             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
33             our @EXPORT = qw( $EXPORT_TAGS{'all'});
34              
35             BEGIN
36             {
37 1 50   1   2594 if ($^O eq "MSWin32"){
38 1     1   825 use LWP::UserAgent;
  1         51226  
  1         47  
39 1     1   919 use JSON qw(decode_json encode_json);
  1         9714  
  1         6  
40 1     1   697 use Time::HiRes qw/gettimeofday/;
  1         1204  
  1         3  
41 1     1   686 use Data::Dumper;
  1         5169  
  1         69  
42             } else {
43 1     1   6 use LWP::UserAgent;
  1         1  
  1         21  
44 1     1   3 use JSON qw(decode_json encode_json);
  1         1  
  1         7  
45 1     1   109 use Time::HiRes qw/gettimeofday/;
  1         1  
  1         7  
46 1     1   74 use Data::Dumper;
  1         1  
  1         30  
47             }
48             }
49              
50              
51             =head1 NAME
52              
53             Device::Nest - Methods for wrapping the Nest API calls so that they are
54             accessible via Perl
55              
56             =head1 VERSION
57              
58             Version 0.08
59              
60             =cut
61              
62             our $VERSION = '0.08';
63              
64             #*****************************************************************
65              
66             =head1 SYNOPSIS
67              
68             This module provides a Perl interface to a Nest Thermostat via the following
69             methods:
70             - new
71             - connect
72             - fetch_Ambient_Temperature
73             - fetch_Designation
74              
75             In order to use this module, you will require a Nest thermostat installed in
76             your home as well. You will also need your ClientID and ClientSecret provided
77             by Nest when you register as a developper at https://developer.nest.com.
78             You will aos need an access code which can be obtained at
79             https://home.nest.com/login/oauth2?client_id=CLIENT_ID&state=FOO
80             Your authorization code will be obtained and stored in this module when you
81             call it.
82              
83             The module is written entirely in Perl and has been developped on Raspbian Linux.
84              
85             =head1 SAMPLE CODE
86              
87             use Device::Nest;
88              
89             $my_Nest = Device::Nest->new($ClientID,$ClientSecret,$code,$phrase,$debug);
90              
91             $my_Nest->connect();
92            
93             undef $my_Nest;
94              
95              
96             You need to get an authorization code by going to https://home.nest.com/login/oauth2?client_id=CLIENT_ID&state=FOO
97             and specifying your client ID in the URL along with a random string for state
98            
99             Use this code, along with your ClientID and ClientSecret to get an authorization code
100             by using the 'connect' function below.
101            
102             From now on, all you need is your auth_token
103            
104              
105              
106             =head2 EXPORT
107              
108             All by default.
109              
110              
111             =head1 SUBROUTINES/METHODS
112              
113             =head2 new - the constructor for a Nest object
114              
115             Creates a new instance which will be able to fetch data from a unique Nest
116             sensor.
117              
118             my $Nest = Device::Nest->new($ClientID, $ClientSecret, $phrase, $debug);
119              
120             This method accepts the following parameters:
121             - $ClientID : Client ID for the account - Required
122             - $ClientSecret : Secret key for the account - Required
123             - $auth_token : authentication token to access the account - Required
124             - $debug : enable or disable debug messages (disabled by default - Optional)
125              
126             Returns a Nest object if successful.
127             Returns 0 on failure
128             =cut
129             sub new {
130 0     0 1   my $class = shift;
131 0           my $self;
132            
133 0           $self->{'ua'} = LWP::UserAgent->new(max_redirect=>3,requests_redirectable=>['GET','HEAD','PUT']);
134 0           $self->{'ClientID'} = shift;
135 0           $self->{'ClientSecret'} = shift;
136 0           $self->{'PIN_code'} = shift;
137 0           $self->{'auth_token'} = shift;
138 0           $self->{'debug'} = shift;
139 0           $self->{'last_code'} = '';
140 0           $self->{'last_reason'} = '';
141 0           $self->{'device_url'} = "https://developer-api.nest.com/devices.json?auth=".$self->{'auth_token'};
142 0           $self->{'last_exec_time'} = 0;
143            
144 0 0         if (!defined $self->{'debug'}) {
145 0           $self->{'debug'} = 0;
146             }
147            
148 0 0 0       if ((!defined $self->{'ClientID'}) || (!defined $self->{'ClientSecret'}) || (!defined $self->{'PIN_code'}) || (!defined $self->{'auth_token'})) {
      0        
      0        
149 0           print "Nest->new(): ClientID, ClientSecret, PIN_code and auth_token are REQUIRED parameters.\n";
150 0           return 0;
151             }
152            
153 0           bless $self, $class;
154            
155 0           return $self;
156             }
157              
158              
159             #*****************************************************************
160              
161             =head2 fetch_Auth_Token - generates and displays the auth_token
162              
163             This function will display the authenticaton token for the PIN code
164             provided. This can only be done once per PIN code. Pleas make sure
165             to note and store your auth code since it will be the only thing requiired
166             for all other API calls.
167              
168             $Nest->fetch_Auth_Token();
169            
170             This method accepts no parameters
171            
172             Returns 1 on success and prints auth_token
173             Returns 0 on failure
174             =cut
175             sub fetch_Auth_Token {
176 0     0 1   my $self = shift;
177 0           my $auth_token = '';
178            
179             # Submit request for authentiaction token.
180 0           my $response = $self->{'ua'}->post('https://api.home.nest.com/oauth2/access_token',
181             { code => $self->{'PIN_code'},
182             grant_type => 'authorization_code',
183             client_id => $self->{'ClientID'},
184             client_secret => $self->{'ClientSecret'},
185             }
186             );
187            
188 0           $self->{'last_code'} = $response->code;
189            
190 0 0         if($response->is_success) {
191 0 0         if ($response->content =~ /\"access_token\":\"(.*?)\"/) {
192 0           print "Found authentication code. Please use it when calling functions\n";
193 0           print "Authentication code: $1\n";
194 0           return 1;
195             } else {
196 0           print "No authentication token found.\n";
197 0           print "Make sure your PIN is correct.\n";
198 0           print "You may need to request a new PIN\n";
199 0           return 0;
200             }
201             } else {
202 0           print "No authentication token found.\n";
203 0           print "Make sure your PIN is correct.\n";
204 0           print "You may need to request a new PIN\n";
205 0           return 0;
206             }
207             }
208              
209              
210             #*****************************************************************
211              
212             =head2 fetch_Thermostat_Designation - fetch the designation for your thermostat
213              
214             Retrieves the code designating your thermostat and stores it in $self
215              
216             $Nest->fetch_Thermostat_Designation();
217              
218             This method accepts no parameters
219            
220             Returns 1 on success
221             Returns 0 on failure
222            
223             =cut
224             sub fetch_Thermostat_Designation {
225 0     0 1   my $self = shift;
226 0           my $response = $self->{'ua'}->get($self->{'device_url'});
227            
228 0           $self->{'last_code'} = $response->code;
229            
230 0 0         if ($response->is_success) {
231 0           my $decoded_response = decode_json($response->content);
232 0           my $designation = ($decoded_response->{'thermostats'});
233 0           my @designation2 = keys(%$designation);
234 0           $self->{'thermostat'} = $designation2[0];
235 0           $self->{'thermostat_url'} = "https://developer-api.nest.com/devices/thermostats/".$self->{'thermostat'};
236 0 0         print "Thermostat designation: ".$self->{'thermostat'}."\n" if ($self->{'debug'});
237              
238 0           my $response = $self->{'ua'}->get("https://developer-api.nest.com/structures?auth=".$self->{'auth_token'});
239              
240 0           $self->{'last_code'} = $response->code;
241            
242 0 0         if ($response->is_success) {
243 0           my $decoded_response = decode_json($response->content);
244 0           my @designation = keys(%$decoded_response);
245 0           $self->{'structure'} = $designation[0];
246 0           $self->{'struct_url'} = "https://developer-api.nest.com/structures/".$self->{'structure'}."?auth=".$self->{'auth_token'};
247 0 0         print "Structure Designation: ".$self->{'structure'}."\n" if ($self->{'debug'});
248 0           return 1;
249             } else {
250 0           print "Nest->fetch_Thermostat_Designation(): Response from server for structure URL is not valid\n";
251 0           print " \"".$response->content."\"\n\n";
252 0           return 0;
253             }
254             } else {
255 0           print "Nest->fetch_Thermostat_Designation(): Failed with return code ".$self->get_last_code()."\n";
256 0           return 0;
257             }
258             }
259              
260              
261             #*****************************************************************
262              
263             =head2 fetch_Ambient_Temperature_C - Fetch the ambient temperature reported by Nest in Celcius
264              
265             Retrieves the ambient temperature reported by the Nest in Celcius
266              
267             $Nest->fetch_Ambient_Temperature_C();
268              
269             This method accepts no parameters
270            
271             Returns the ambient temperature in Celcius
272             Returns 0 on failure
273            
274             =cut
275             sub fetch_Ambient_Temperature_C {
276 0     0 1   my $self = shift;
277            
278 0 0         if (!defined $self->{'thermostat'}) {
279 0           print "Nest->fetch_Ambient_Temperature_C(): No thermostat designation found\n";
280 0           return 0;
281             }
282              
283 0           return $self->__process_get($self->{'device_url'},'ambient_temperature_c');
284             }
285              
286             #*****************************************************************
287              
288             =head2 fetch_Target_Temperature_C - Fetch the target temperature reported by Nest in Celcius
289              
290             Retrieves the target temperature reported by the Nest in Celcius
291              
292             $Nest->fetch_Target_Temperature_C();
293              
294             This method accepts no parameters
295            
296             Returns the target temperature in Celcius
297             Returns 0 on failure
298            
299             =cut
300             sub fetch_Target_Temperature_C {
301 0     0 1   my $self = shift;
302            
303 0 0         if (!defined $self->{'thermostat'}) {
304 0           print "Nest->fetch_Target_Temperature_C(): No thermostat designation found\n";
305 0           return 0;
306             }
307            
308 0           return $self->__process_get($self->{'device_url'},'target_temperature_c');
309             }
310              
311             #*****************************************************************
312              
313             =head2 fetch_Target_Temperature_high_C - Fetch the higher target temperature reported by Nest in Celcius
314              
315             Retrieves the high target temperature reported by the Nest in Celcius
316              
317             $Nest->fetch_Target_Temperature_high_C();
318              
319             This method accepts no parameters
320            
321             Returns the high target temperature in Celcius
322             Returns 0 on failure
323            
324             =cut
325             sub fetch_Target_Temperature_high_C {
326 0     0 1   my $self = shift;
327            
328 0 0         if (!defined $self->{'thermostat'}) {
329 0           print "Nest->fetch_Target_Temperature_high_C(): No thermostat designation found\n";
330 0           return 0;
331             }
332            
333 0           return $self->__process_get($self->{'device_url'},'target_temperature_high_c');
334             }
335              
336             #*****************************************************************
337              
338             =head2 fetch_Target_Temperature_low_C - Fetch the lower target temperature reported by Nest in Celcius
339              
340             Retrieves the lower target temperature reported by the Nest in Celcius
341              
342             $Nest->fetch_Target_Temperature_low_C();
343              
344             This method accepts no parameters
345            
346             Returns the lower target temperature in Celcius
347             Returns 0 on failure
348            
349             =cut
350             sub fetch_Target_Temperature_low_C {
351 0     0 1   my $self = shift;
352            
353 0 0         if (!defined $self->{'thermostat'}) {
354 0           print "Nest->fetch_Target_Temperature_low_C(): No thermostat designation found\n";
355 0           return 0;
356             }
357            
358 0           return $self->__process_get($self->{'device_url'},'target_temperature_low_c');
359             }
360              
361             #*****************************************************************
362              
363             =head2 fetch_Away_Temperature_low_C - Fetch the lower away temperature reported by Nest in Celcius
364              
365             Retrieves the lower away temperature reported by the Nest in Celcius
366              
367             $Nest->fetch_Away_Temperature_low_C();
368              
369             This method accepts no parameters
370            
371             Returns the lower away temperature in Celcius
372             Returns 0 on failure
373            
374             =cut
375             sub fetch_Away_Temperature_low_C {
376 0     0 1   my $self = shift;
377            
378 0 0         if (!defined $self->{'thermostat'}) {
379 0           print "Nest->fetch_Away_Temperature_low_C(): No thermostat designation found\n";
380 0           return 0;
381             }
382            
383 0           return $self->__process_get($self->{'device_url'},'away_temperature_low_c');
384             }
385              
386             #*****************************************************************
387              
388             =head2 fetch_Away_Temperature_high_C - Fetch the high away temperature reported by Nest in Celcius
389              
390             Retrieves the high away temperature reported by the Nest in Celcius
391              
392             $Nest->fetch_Away_Temperature_high_C();
393              
394             This method accepts no parameters
395            
396             Returns the high away temperature in Celcius
397             Returns 0 on failure
398            
399             =cut
400             sub fetch_Away_Temperature_high_C {
401 0     0 1   my $self = shift;
402            
403 0 0         if (!defined $self->{'thermostat'}) {
404 0           print "Nest->fetch_Away_Temperature_high_C(): No thermostat designation found\n";
405 0           return 0;
406             }
407            
408 0           return $self->__process_get($self->{'device_url'},'away_temperature_high_c');
409             }
410              
411             #*****************************************************************
412              
413             =head2 fetch_Ambient_Temperature_F - Fetch the ambient temperature reported by Nest in Fahrenheit
414              
415             Retrieves the ambient temperature reported by the Nest in Fahrenheit
416              
417             $Nest->fetch_Ambient_Temperature_F();
418              
419             This method accepts no parameters
420            
421             Returns the ambient temperature in Fahrenheit
422             Returns 0 on failure
423            
424             =cut
425             sub fetch_Ambient_Temperature_F {
426 0     0 1   my $self = shift;
427            
428 0 0         if (!defined $self->{'thermostat'}) {
429 0           print "Nest->fetch_Ambient_Temperature_F(): No thermostat designation found\n";
430 0           return 0;
431             }
432            
433 0           return $self->__process_get($self->{'device_url'},'ambient_temperature_f');
434             }
435              
436             #*****************************************************************
437              
438             =head2 fetch_Away_Temperature_low_F - Fetch the lower away temperature reported by Nest in Fahrenheit
439              
440             Retrieves the lower away temperature reported by the Nest in Fahrenheit
441              
442             $Nest->fetch_Away_Temperature_low_F();
443              
444             This method accepts no parameters
445            
446             Returns the lower away temperature in Fahrenheit
447             Returns 0 on failure
448            
449             =cut
450             sub fetch_Away_Temperature_low_F {
451 0     0 1   my $self = shift;
452            
453 0 0         if (!defined $self->{'thermostat'}) {
454 0           print "Nest->fetch_Away_Temperature_low_F(): No thermostat designation found\n";
455 0           return 0;
456             }
457            
458 0           return $self->__process_get($self->{'device_url'},'away_temperature_low_f');
459             }
460              
461             #*****************************************************************
462              
463             =head2 fetch_Away_Temperature_high_F - Fetch the higher away temperature reported by Nest in Fahrenheit
464              
465             Retrieves the higher away temperature reported by the Nest in Fahrenheit
466              
467             $Nest->fetch_Away_Temperature_high_F();
468              
469             This method accepts no parameters
470            
471             Returns the higher away temperature in Fahrenheit
472             Returns 0 on failure
473            
474             =cut
475             sub fetch_Away_Temperature_high_F {
476 0     0 1   my $self = shift;
477            
478 0 0         if (!defined $self->{'thermostat'}) {
479 0           print "Nest->fetch_Away_Temperature_high_F(): No thermostat designation found\n";
480 0           return 0;
481             }
482            
483 0           return $self->__process_get($self->{'device_url'},'away_temperature_high_f');
484             }
485              
486             #*****************************************************************
487              
488             =head2 fetch_Target_Temperature_low_F - Fetch the lower target temperature reported by Nest in Fahrenheit
489              
490             Retrieves the lower target temperature reported by the Nest in Fahrenheit
491              
492             $Nest->fetch_Target_Temperature_low_F();
493              
494             This method accepts no parameters
495            
496             Returns the lower target temperature in Fahrenheit
497             Returns 0 on failure
498            
499             =cut
500             sub fetch_Target_Temperature_low_F {
501 0     0 1   my $self = shift;
502            
503 0 0         if (!defined $self->{'thermostat'}) {
504 0           print "Nest->fetch_Target_Temperature_low_F(): No thermostat designation found\n";
505 0           return 0;
506             }
507            
508 0           return $self->__process_get($self->{'device_url'},'target_temperature_low_f');
509             }
510              
511             #*****************************************************************
512              
513             =head2 fetch_Target_Temperature_F - Fetch the target temperature reported by Nest in Fahrenheit
514              
515             Retrieves the target temperature reported by the Nest in Fahrenheit
516              
517             $Nest->fetch_Target_Temperature_F();
518              
519             This method accepts no parameters
520            
521             Returns the target temperature in Fahrenheit
522             Returns 0 on failure
523            
524             =cut
525             sub fetch_Target_Temperature_F {
526 0     0 1   my $self = shift;
527            
528 0 0         if (!defined $self->{'thermostat'}) {
529 0           print "Nest->fetch_Target_Temperature_F(): No thermostat designation found\n";
530 0           return 0;
531             }
532            
533 0           return $self->__process_get($self->{'device_url'},'target_temperature_f');
534             }
535              
536             #*****************************************************************
537              
538             =head2 fetch_Target_Temperature_high_F - Fetch the higher target temperature reported by Nest in Fahrenheit
539              
540             Retrieves the higher target temperature reported by the Nest in Fahrenheit
541              
542             $Nest->fetch_Target_Temperature_high_F();
543              
544             This method accepts no parameters
545            
546             Returns the target temperature in Fahrenheit
547             Returns 0 on failure
548            
549             =cut
550             sub fetch_Target_Temperature_high_F {
551 0     0 1   my $self = shift;
552            
553 0 0         if (!defined $self->{'thermostat'}) {
554 0           print "Nest->fetch_Target_Temperature_high_F(): No thermostat designation found\n";
555 0           return 0;
556             }
557            
558 0           return $self->__process_get($self->{'device_url'},'target_temperature_high_f');
559             }
560              
561             #*****************************************************************
562              
563             =head2 fetch_Temperature_Scale - Fetch the temperature scale reported by Nest
564              
565             Retrieves the temperature scale reported by the Nest as either F (Fahrenheit)
566             or C (Celcius)
567              
568             $Nest->fetch_Temperature_Scale();
569              
570             This method accepts no parameters
571            
572             Returns the temperature scale
573             Returns 0 on failure
574            
575             =cut
576             sub fetch_Temperature_Scale {
577 0     0 1   my $self = shift;
578            
579 0 0         if (!defined $self->{'thermostat'}) {
580 0           print "Nest->fetch_Temperature_Scale(): No thermostat designation found\n";
581 0           return 0;
582             }
583            
584 0           return $self->__process_get($self->{'device_url'},'temperature_scale');
585             }
586              
587              
588             ##*****************************************************************
589             #
590             #=head2 fetch_Relative_Humidity - Fetch the relative humidity reported by Nest
591             #
592             # Retrieves the relative humidity reported by the Nest
593             #
594             # $Nest->fetch_Relative_Humidity();
595             #
596             # This method accepts no parameters
597             #
598             # Returns the temperature scale
599             # Returns 0 on failure
600             #
601             #=cut
602             #sub fetch_Relative_Humidity {
603             # my $self = shift;
604             #
605             # if (!defined $self->{'thermostat'}) {
606             # print "Nest->fetch_Relative_Humidity(): No thermostat designation found\n";
607             # return 0;
608             # }
609             #
610             # return $self->__process_get($self->{'device_url'},'relative_humidity');
611             #}
612             #
613              
614             #*****************************************************************
615              
616             =head2 fetch_Away_State - Fetch the away state reported by Nest
617              
618             Retrieves the away state reported by the Nest
619              
620             $Nest->fetch_Away_State();
621              
622             This method accepts no parameters
623            
624             Returns the away state
625             Returns 0 on failure
626            
627             =cut
628             sub fetch_Away_State {
629 0     0 1   my $self = shift;
630            
631 0 0         if (!defined $self->{'thermostat'}) {
632 0           print "Nest->fetch_Away_State(): No thermostat designation found\n";
633 0           return 0;
634             }
635            
636 0           my $response = $self->{'ua'}->get($self->{'struct_url'});
637              
638 0           $self->{'last_code'} = $response->code;
639            
640 0 0         if ($response->is_success) {
641 0           my $decoded_response = decode_json($response->content);
642 0           return $decoded_response->{'away'};
643             } else {
644 0           print "Nest->fetch_Away_State(): Failed with return code ".$self->get_last_code()."\n";
645 0           return 0;
646             }
647             }
648              
649              
650             #*****************************************************************
651              
652             =head2 fetch_Country_Code - Fetch the country code reported by Nest
653              
654             Retrieves the country code reported by the Nest
655              
656             $Nest->fetch_Country_Code();
657              
658             This method accepts no parameters
659            
660             Returns the away state
661             Returns 0 on failure
662            
663             =cut
664             sub fetch_Country_Code {
665 0     0 1   my $self = shift;
666            
667 0 0         if (!defined $self->{'thermostat'}) {
668 0           print "Nest->fetch_Country_Code(): No thermostat designation found\n";
669 0           return 0;
670             }
671            
672 0           my $response = $self->{'ua'}->get($self->{'struct_url'});
673            
674 0           $self->{'last_code'} = $response->code;
675            
676 0 0         if ($response->is_success) {
677 0           my $decoded_response = decode_json($response->content);
678 0           return $decoded_response->{$self->{'structure'}}->{'country_code'};
679             } else {
680 0           print "Nest->fetch_Country_Code(): Failed with return code ".$self->get_last_code()."\n";
681 0           return 0;
682             }
683             }
684              
685              
686             #*****************************************************************
687              
688             =head2 fetch_Locale - Fetch the locale reported by Nest
689              
690             Retrieves the locale reported by the Nest
691              
692             $Nest->fetch_Locale();
693              
694             This method accepts no parameters
695            
696             Returns the locale
697             Returns 0 on failure
698            
699             =cut
700             sub fetch_Locale {
701 0     0 1   my $self = shift;
702            
703 0 0         if (!defined $self->{'thermostat'}) {
704 0           print "Nest->fetch_Locale(): No thermostat designation found\n";
705 0           return 0;
706             }
707            
708 0           return $self->__process_get($self->{'device_url'},'locale');
709             }
710              
711             #*****************************************************************
712              
713             =head2 fetch_Name - Fetch the name reported by Nest
714              
715             Retrieves the name reported by the Nest
716              
717             $Nest->fetch_Name();
718              
719             This method accepts no parameters
720            
721             Returns the name of the thermostat
722             Returns 0 on failure
723            
724             =cut
725             sub fetch_Name {
726 0     0 1   my $self = shift;
727            
728 0 0         if (!defined $self->{'thermostat'}) {
729 0           print "Nest->fetch_Name(): No thermostat designation found\n";
730 0           return 0;
731             }
732            
733 0           return $self->__process_get($self->{'device_url'},'name');
734             }
735              
736              
737             #*****************************************************************
738              
739             =head2 fetch_Long_Name - Fetch the long name reported by Nest
740              
741             Retrieves the long name reported by the Nest
742              
743             $Nest->fetch_Long_Name();
744              
745             This method accepts no parameters
746            
747             Returns the long name of the thermostat
748             Returns 0 on failure
749            
750             =cut
751             sub fetch_Long_Name {
752 0     0 1   my $self = shift;
753            
754 0 0         if (!defined $self->{'thermostat'}) {
755 0           print "Nest->fetch_Long_Name(): No thermostat designation found\n";
756 0           return 0;
757             }
758            
759 0           return $self->__process_get($self->{'device_url'},'name_long');
760             }
761              
762              
763             #*****************************************************************
764              
765             =head2 fetch_HVAC_Mode - Fetch the HVAC Mode reported by Nest
766              
767             Retrieves the HVAC Mode reported by the Nest as either 'heat' or 'cool'
768              
769             $Nest->fetch_HVAC_Mode();
770              
771             This method accepts no parameters
772            
773             Returns the HVAC mode
774             Returns 0 on failure
775            
776             =cut
777             sub fetch_HVAC_Mode {
778 0     0 1   my $self = shift;
779            
780 0 0         if (!defined $self->{'thermostat'}) {
781 0           print "Nest->fetch_HVAC_Mode(): No thermostat designation found\n";
782 0           return 0;
783             }
784            
785 0           return $self->__process_get($self->{'device_url'},'hvac_mode');
786             }
787              
788              
789             #*****************************************************************
790              
791             =head2 fetch_SW_Version - Fetch the software version reported by Nest
792              
793             Retrieves the software version reported by the Nest
794              
795             $Nest->fetch_SW_Version();
796              
797             This method accepts no parameters
798            
799             Returns the software version
800             Returns 0 on failure
801            
802             =cut
803             sub fetch_SW_Version {
804 0     0 1   my $self = shift;
805            
806 0 0         if (!defined $self->{'thermostat'}) {
807 0           print "Nest->fetch_SW_Version(): No thermostat designation found\n";
808 0           return 0;
809             }
810            
811 0           return $self->__process_get($self->{'device_url'},'software_version');
812             }
813              
814              
815             #*****************************************************************
816              
817             =head2 set_Target_Temperature_C - Set the target temperature in Celcius
818              
819             Set the target temperature in Celcius
820              
821             $Nest->set_Target_Temperature_C($temperature);
822              
823             This method accepts the following parameters:
824             - $temperature : target temperature in Celcius - Required
825            
826             Returns 1 on success
827             Returns 0 on failure
828            
829             =cut
830             sub set_Target_Temperature_C {
831 0     0 1   my $self = shift;
832 0           my $temperature = shift;
833            
834 0 0         if (!defined $self->{'thermostat'}) {
835 0           print "Nest->set_Target_Temperature_C(): No thermostat designation found\n";
836 0           return 0;
837             }
838 0 0         if (!defined $temperature) {
839 0           print "Nest->set_Target_Temperature_C(): Temperature is a required perameter\n";
840 0           return 0;
841             }
842              
843 0           return $self->__process_set($self->{'thermostat_url'},'target_temperature_C',$temperature);
844             }
845              
846              
847             #*****************************************************************
848              
849             =head2 set_Target_Temperature_high_C - Set the high target temperature in Celcius
850              
851             Set the high target temperature in Celcius
852              
853             $Nest->set_Target_Temperature_high_C($temperature);
854              
855             This method accepts the following parameters:
856             - $temperature : high target temperature in Celcius - Required
857            
858             Returns 1 on success
859             Returns 0 on failure
860            
861             =cut
862             sub set_Target_Temperature_high_C {
863 0     0 1   my $self = shift;
864 0           my $temperature = shift;
865            
866 0 0         if (!defined $self->{'thermostat'}) {
867 0           print "Nest->set_Target_Temperature_high_C(): No thermostat designation found\n";
868 0           return 0;
869             }
870 0 0         if (!defined $temperature) {
871 0           print "Nest->set_Target_Temperature_high_C(): Temperature is a required perameter\n";
872 0           return 0;
873             }
874            
875 0           return $self->__process_set($self->{'thermostat_url'},'target_temperature_high_C',$temperature);
876             }
877              
878              
879             #*****************************************************************
880              
881             =head2 set_Target_Temperature_low_C - Set the low target temperature in Celcius
882              
883             Set the low target temperature in Celcius
884              
885             $Nest->set_Target_Temperature_low_C($temperature);
886              
887             This method accepts the following parameters:
888             - $temperature : low target temperature in Celcius - Required
889            
890             Returns 1 on success
891             Returns 0 on failure
892            
893             =cut
894             sub set_Target_Temperature_low_C {
895 0     0 1   my $self = shift;
896 0           my $temperature = shift;
897            
898 0 0         if (!defined $self->{'thermostat'}) {
899 0           print "Nest->set_Target_Temperature_low_C(): No thermostat designation found\n";
900 0           return 0;
901             }
902 0 0         if (!defined $temperature) {
903 0           print "Nest->set_Target_Temperature_low_C(): Temperature is a required perameter\n";
904 0           return 0;
905             }
906            
907 0           return $self->__process_set($self->{'thermostat_url'},'target_temperature_low_C',$temperature);
908             }
909              
910              
911             #*****************************************************************
912              
913             =head2 set_Target_Temperature_F - Set the target temperature in Fahrenheit
914              
915             Set the target temperature in Fahrenheit
916              
917             $Nest->set_Target_Temperature_F($temperature);
918              
919             This method accepts the following parameters:
920             - $temperature : target temperature in Fahrenheit - Required
921            
922             Returns 1 on success
923             Returns 0 on failure
924            
925             =cut
926             sub set_Target_Temperature_F {
927 0     0 1   my $self = shift;
928 0           my $temperature = shift;
929            
930 0 0         if (!defined $self->{'thermostat'}) {
931 0           print "Nest->set_Target_Temperature_F(): No thermostat designation found\n";
932 0           return 0;
933             }
934 0 0         if (!defined $temperature) {
935 0           print "Nest->set_Target_Temperature_F(): Temperature is a required perameter\n";
936 0           return 0;
937             }
938            
939 0           return $self->__process_set($self->{'thermostat_url'},'target_temperature_F',$temperature);
940             }
941              
942              
943             #*****************************************************************
944              
945             =head2 set_Target_Temperature_high_F - Set the high target temperature in Fahrenheit
946              
947             Set the high target temperature in Fahrenheit
948              
949             $Nest->set_Target_Temperature_high_F($temperature);
950              
951             This method accepts the following parameters:
952             - $temperature : high target temperature in Fahrenheit - Required
953            
954             Returns 1 on success
955             Returns 0 on failure
956            
957             =cut
958             sub set_Target_Temperature_high_F {
959 0     0 1   my $self = shift;
960 0           my $temperature = shift;
961            
962 0 0         if (!defined $self->{'thermostat'}) {
963 0           print "Nest->set_Target_Temperature_high_F(): No thermostat designation found\n";
964 0           return 0;
965             }
966 0 0         if (!defined $temperature) {
967 0           print "Nest->set_Target_Temperature_high_F(): Temperature is a required perameter\n";
968 0           return 0;
969             }
970            
971 0           return $self->__process_set($self->{'thermostat_url'},'target_temperature_high_F',$temperature);
972             }
973              
974              
975             #*****************************************************************
976              
977             =head2 set_Target_Temperature_low_F - Set the low target temperature in Fahrenheit
978              
979             Set the low target temperature in Fahrenheit
980              
981             $Nest->set_Target_Temperature_low_F($temperature);
982              
983             This method accepts the following parameters:
984             - $temperature : low target temperature in Fahrenheit - Required
985              
986             Returns 1 on success
987             Returns 0 on failure
988            
989             =cut
990             sub set_Target_Temperature_low_F {
991 0     0 1   my $self = shift;
992 0           my $temperature = shift;
993            
994 0 0         if (!defined $self->{'thermostat'}) {
995 0           print "Nest->set_Target_Temperature_low_F(): No thermostat designation found\n";
996 0           return 0;
997             }
998 0 0         if (!defined $temperature) {
999 0           print "Nest->set_Target_Temperature_low_F(): Temperature is a required perameter\n";
1000 0           return 0;
1001             }
1002            
1003 0           return $self->__process_set($self->{'thermostat_url'},'target_temperature_low_F',$temperature);
1004             }
1005              
1006              
1007             #*****************************************************************
1008              
1009             =head2 set_Away_State - Set the away state of the Nest
1010              
1011             Set the away state of the Nest to either 'home' or 'away'
1012              
1013             $Nest->set_Away_State($state);
1014              
1015             This method accepts the following parameters:
1016             - $state : away state either 'home' or 'away' - Required
1017              
1018             Returns 1 on success
1019             Returns 0 on failure
1020            
1021             =cut
1022             sub set_Away_State {
1023 0     0 1   my $self = shift;
1024 0           my $state = shift;
1025            
1026 0 0         if (!defined $self->{'thermostat'}) {
1027 0           print "Nest->set_Away_State(): No thermostat designation found\n";
1028 0           return 0;
1029             }
1030 0 0         if (!defined $state) {
1031 0           print "Nest->set_Away_State(): State is a required perameter\n";
1032 0           return 0;
1033             }
1034            
1035 0           my %state = ('away' => $state);
1036 0           my $json = encode_json(\%state);
1037              
1038 0           my $response = $self->{'ua'}->put($self->{'struct_url'},
1039             Content_Type => 'application/json',
1040             content => $json);
1041              
1042 0           $self->{'last_code'} = $response->code;
1043            
1044 0 0         if ($response->is_success) {
1045 0           return $response->content;
1046             } else {
1047 0           print "Nest->set_Away_State(): Failed with return code ".$self->get_last_code()."\n";
1048 0           return 0;
1049             }
1050             }
1051              
1052              
1053             ##*****************************************************************
1054             #
1055             #=head2 set_Temperature_Scale - Set the temperature scale
1056             #
1057             # Set the temperature as either F (Fahrenheit) or C (Celcius)
1058             #
1059             # $Nest->set_Temperature_Scale($scale);
1060             #
1061             # This method accepts the following parameters:
1062             # - $scale : F (Fahrenheit) or C (Celcius) - Required
1063             #
1064             # Returns 1 on success
1065             # Returns 0 on failure
1066             #
1067             #=cut
1068             #
1069             #sub set_Temperature_Scale {
1070             # my $self = shift;
1071             # my $scale = shift;
1072             #
1073             # if (!defined $self->{'thermostat'}) {
1074             # print "Nest->set_Temperature_Scale(): No thermostat designation found\n";
1075             # return 0;
1076             # }
1077             # if (!defined $scale) {
1078             # print "Nest->set_Temperature_Scale(): Scale is a required perameter\n";
1079             # return 0;
1080             # }
1081             #
1082             # return $self->__process_set($self->{'thermostat_url'},'temperature_scale');
1083             #}
1084             #
1085              
1086              
1087             #*****************************************************************
1088              
1089             =head2 dump_Object - shows the contents of the local Nest object
1090              
1091             shows the contents of the local Nest object in human readable form
1092              
1093             $Nest->dump_Object();
1094              
1095             This method accepts no parameters
1096            
1097             Returns nothing
1098            
1099             =cut
1100             sub dump_Object {
1101 0     0 1   my $self = shift;
1102            
1103 0           print "ClientID : ".substr($self->{'ClientID'}, 0,120)."\n";
1104 0           print "ClientSecret : ".substr($self->{'ClientSecret'}, 0,120)."\n";
1105 0           print "auth_token : ".substr($self->{'auth_token'}, 0,120)."\n";
1106 0           print "PIN_code : ".substr($self->{'PIN_code'}, 0,120)."\n";
1107 0           print "device_url : ".substr($self->{'device_url'}, 0,120)."\n";
1108 0           print "struct_url : ".substr($self->{'struct_url'}, 0,120)."\n";
1109 0           print "structure : ".substr($self->{'structure'}, 0,120)."\n";
1110 0           print "thermostat_url : ".substr($self->{'thermostat_url'},0,120)."\n";
1111 0           print "thermostat : ".substr($self->{'thermostat'}, 0,120)."\n";
1112 0           print "debug : ".substr($self->{'debug'}, 0,120)."\n";
1113 0           print "last_code : ".substr($self->{'last_code'}, 0,120)."\n";
1114 0           print "last_reason : ".substr($self->{'last_reason'}, 0,120)."\n";
1115 0           print "\n";
1116             }
1117              
1118              
1119             #*****************************************************************
1120              
1121             =head2 get_last_code - returns the code generated by the most recent fetch
1122              
1123             Returns the HTTP Header code for the most recent fetch command
1124              
1125             $Nest->get_last_code();
1126              
1127             This method accepts no parameters
1128            
1129             Returns the numeric code
1130            
1131             =cut
1132              
1133             sub get_last_code {
1134 0     0 1   my $self = shift;
1135 0           return $self->{'last_code'};
1136             }
1137              
1138             #*****************************************************************
1139              
1140             =head2 get_last_reason - returns the text generated by the most recent fetch
1141              
1142             Returns the HTTP Header reason for the most recent fetch command
1143              
1144             $Nest->get_last_reason();
1145              
1146             This method accepts no parameters
1147            
1148             Returns the textual reason
1149            
1150             =cut
1151              
1152             sub get_last_reason {
1153 0     0 1   my $self = shift;
1154 0           return $self->{'last_reason'};
1155             }
1156              
1157             #******************************************************************************
1158             =head2 get_last_exec_time - returns the execution time for the last fetch
1159              
1160             Returns the number of milliseconds it took for the last fetch call
1161              
1162             $Nest->get_last_exec_time();
1163              
1164             This method accepts no parameters
1165            
1166             Returns the number of milliseconds
1167            
1168             =cut
1169              
1170             sub get_last_exec_time {
1171 0     0 0   my $self = shift;
1172 0           return $self->{'last_exec_time'};
1173             }
1174              
1175             #*****************************************************************
1176              
1177             sub __process_get {
1178 0     0     my $self = shift;
1179 0           my $url = shift;
1180 0           my $tag = shift;
1181 0           my $time_before = gettimeofday;
1182 0           my $response = $self->{'ua'}->get($url);
1183 0           my $time_after = gettimeofday;
1184            
1185 0           $self->{'last_exec_time'} = eval{($time_after-$time_before)*1000};
  0            
1186 0           $self->{'last_code'} = $response->code;
1187            
1188 0 0         if ($response->is_success) {
1189 0           my $decoded_response = decode_json($response->content);
1190 0           return $decoded_response->{'thermostats'}->{$self->{'thermostat'}}->{$tag};
1191             } else {
1192 0           print "\n".(caller(1))[3]."(): Failed with return code ".$self->get_last_code()."\n";
1193 0           return 0;
1194             }
1195             }
1196              
1197             #*****************************************************************
1198              
1199             sub __process_set {
1200 0     0     my $self = shift;
1201 0           my $url = shift;
1202 0           my $tag = shift;
1203 0           my $value = shift;
1204              
1205 0           my $response = $self->{'ua'}->put($url."/".$tag."?auth=".$self->{'auth_token'},
1206             Content_Type => 'application/json',
1207             content => $value );
1208 0           $self->{'last_code'} = $response->code;
1209 0           $self->{'last_reason'} = decode_json($response->content)->{'error'};
1210              
1211 0 0         if ($response->is_success) {
1212 0           return $response->content;
1213             } else {
1214 0           print "\n".(caller(1))[3]."(): Failed with return code ".$self->get_last_code()." - ".$self->get_last_reason()."\n";
1215 0           return 0;
1216             }
1217             }
1218              
1219              
1220             #*****************************************************************
1221              
1222             =head1 AUTHOR
1223              
1224             Kedar Warriner, C
1225              
1226             =head1 BUGS
1227              
1228             Please report any bugs or feature requests to C
1229             or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Device-Nest
1230             I will be notified, and then you'll automatically be notified of progress on
1231             your bug as I make changes.
1232              
1233             =head1 SUPPORT
1234              
1235             You can find documentation for this module with the perldoc command.
1236              
1237             perldoc Device::Nest
1238              
1239             You can also look for information at:
1240              
1241             =over 5
1242              
1243             =item * RT: CPAN's request tracker
1244              
1245             L
1246              
1247             =item * AnnoCPAN: Annotated CPAN documentation
1248              
1249             L
1250              
1251             =item * CPAN Ratings
1252              
1253             L
1254              
1255             =item * Search CPAN
1256              
1257             L
1258              
1259             =back
1260              
1261             =head1 ACKNOWLEDGEMENTS
1262              
1263             Many thanks to:
1264             The guys at Nest for creating the Nest Thermostat sensor and
1265             developping the API.
1266             Everyone involved with CPAN.
1267              
1268             =head1 LICENSE AND COPYRIGHT
1269              
1270             Copyright 2014 Kedar Warriner .
1271              
1272             This program is free software; you can redistribute it and/or modify it
1273             under the terms of either: the GNU General Public License as published
1274             by the Free Software Foundation; or the Artistic License.
1275              
1276             See http://dev.perl.org/licenses/ for more information.
1277              
1278             =cut
1279              
1280             #********************************************************************
1281             1; # End of Device::Nest - Return success to require/use statement
1282             #********************************************************************
1283              
1284