File Coverage

blib/lib/Device/Nest.pm
Criterion Covered Total %
statement 28 308 9.0
branch 1 96 1.0
condition 0 9 0.0
subroutine 10 45 22.2
pod 33 33 100.0
total 72 491 14.6


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