File Coverage

blib/lib/Tesla/Vehicle.pm
Criterion Covered Total %
statement 18 282 6.3
branch 0 70 0.0
condition 0 65 0.0
subroutine 6 87 6.9
pod 78 78 100.0
total 102 582 17.5


line stmt bran cond sub pod time code
1             package Tesla::Vehicle;
2              
3 1     1   57798 use warnings;
  1         2  
  1         27  
4 1     1   4 use strict;
  1         2  
  1         18  
5              
6 1     1   387 use parent 'Tesla::API';
  1         280  
  1         7  
7              
8 1     1   189897 use Carp qw(croak confess);
  1         2  
  1         53  
9 1     1   7 use Data::Dumper;
  1         2  
  1         86  
10              
11             our $VERSION = '0.07';
12              
13             use constant {
14             DEBUG_ONLINE => $ENV{TESLA_DEBUG_ONLINE},
15             DEBUG_API_RETRY => $ENV{TESLA_DEBUG_API_RETRY},
16 1         3571 API_RETRIES => 5,
17             WAKE_TIMEOUT => 30,
18             WAKE_INTERVAL => 2,
19             WAKE_BACKOFF => 1.15
20 1     1   7 };
  1         1  
21              
22             # Object Related
23              
24             sub new {
25 0     0 1   my ($class, %params) = @_;
26              
27             # See Tesla::API new() for params the parent handles
28 0           my $self = $class->SUPER::new(%params);
29              
30 0           $self->warn($params{warn});
31 0           $self->_id($params{id});
32 0           $self->auto_wake($params{auto_wake});
33              
34 0           return $self;
35             }
36             sub auto_wake {
37 0     0 1   my ($self, $auto_wake) = @_;
38              
39 0 0         if (defined $auto_wake) {
40 0           $self->{auto_wake} = $auto_wake;
41             }
42              
43 0   0       return $self->{auto_wake} // 0;
44             }
45             sub warn {
46 0     0 1   my ($self, $warn) = @_;
47 0 0         $self->{warn} = $warn if defined $warn;
48 0   0       return $self->{warn} // 1;
49             }
50              
51             # Vehicle Summary Methods
52              
53             sub in_service {
54 0     0 1   return $_[0]->summary->{in_service};
55             }
56             sub options {
57 0     0 1   my ($self) = @_;
58 0           my $vehicle_options = $self->summary->{option_codes};
59              
60 0           my $option_codes = $self->option_codes;
61              
62 0           my %option_definitions;
63              
64 0           for (split /,/, $vehicle_options) {
65 0           $option_definitions{$_} = $option_codes->{$_};
66             }
67              
68 0           return \%option_definitions;
69             }
70             sub vehicle_id {
71 0     0 1   return $_[0]->summary->{vehicle_id};
72             }
73             sub vin {
74 0     0 1   return $_[0]->summary->{vin};
75             }
76              
77             # Vehicle Identification Methods
78              
79             sub id {
80             # Tries to figure out the ID to use in API calls
81 0     0 1   my ($self, $id) = @_;
82              
83 0 0         if (! defined $id) {
84 0           $id = $self->_id;
85             }
86              
87 0 0         if (! $id) {
88 0           confess "Method called that requires an \$id param, but it wasn't sent in";
89             }
90              
91 0           return $id;
92             }
93             sub list {
94 0     0 1   my ($self) = @_;
95              
96 0 0         return $self->{vehicles} if $self->{vehicles};
97              
98 0           my $vehicles = $self->api(endpoint => 'VEHICLE_LIST');
99              
100 0           for (@$vehicles) {
101 0           $self->{data}{vehicles}{$_->{id}} = $_->{display_name};
102             }
103              
104 0           return $self->{data}{vehicles};
105             }
106             sub name {
107 0     0 1   my ($self) = @_;
108 0           return $self->list->{$self->id};
109             }
110              
111             # Top Level Data Structure Methods
112              
113             sub data {
114 0     0 1   my ($self) = @_;
115 0           $self->_online_check;
116              
117 0           my $data = $self->api(endpoint => 'VEHICLE_DATA', id => $self->id);
118              
119 0 0         if (ref $data ne 'HASH') {
120 0           CORE::warn "Tesla API timed out. Please retry the call\n";
121 0           return {};
122             }
123              
124 0 0         if (! defined $data->{drive_state}{shift_state}) {
125              
126 0           for (1 .. API_RETRIES) {
127 0           print "API retry attempt $_\n" if DEBUG_API_RETRY;
128              
129 0           $self->api_cache_clear;
130              
131 0           $data = $self->api(endpoint => 'VEHICLE_DATA', id => $self->id);
132              
133 0 0         if (defined $data->{drive_state}{shift_state}) {
134 0           last;
135             }
136             }
137              
138 0 0         if (! defined $data->{drive_state}{shift_state}) {
139 0           $data->{drive_state}{shift_state} = 'U';
140             }
141             }
142              
143 0           return $data;
144             }
145             sub state {
146 0     0 1   my ($self) = @_;
147 0           $self->_online_check;
148 0           return $self->data->{vehicle_state};
149             }
150             sub summary {
151 0     0 1   return $_[0]->api(endpoint => 'VEHICLE_SUMMARY', id => $_[0]->id);
152             }
153             sub charge_state {
154 0     0 1   my ($self) = @_;
155 0           $self->_online_check;
156 0           return $self->data->{charge_state};
157             }
158             sub climate_state {
159 0     0 1   my ($self) = @_;
160 0           $self->_online_check;
161 0           return $self->data->{climate_state};
162             }
163             sub drive_state {
164 0     0 1   my ($self) = @_;
165 0           $self->_online_check;
166 0           return $self->data->{drive_state};
167             }
168             sub vehicle_config {
169 0     0 1   my ($self) = @_;
170 0           $self->_online_check;
171 0           return $self->data->{vehicle_config};
172             }
173              
174             # Vehicle State Methods
175              
176             sub dashcam {
177 0     0 1   return $_[0]->data->{vehicle_state}{dashcam_state};
178             }
179             sub locked {
180 0     0 1   return $_[0]->data->{vehicle_state}{locked};
181             }
182             sub online {
183 0     0 1   my $status = $_[0]->summary->{state};
184 0 0         return $status eq 'online' ? 1 : 0;
185             }
186             sub odometer {
187 0     0 1   return $_[0]->data->{vehicle_state}{odometer};
188             }
189             sub sentry_mode {
190 0     0 1   return $_[0]->data->{vehicle_state}{sentry_mode};
191             }
192             sub santa_mode {
193 0     0 1   return $_[0]->data->{vehicle_state}{santa_mode};
194             }
195             sub trunk_front {
196 0     0 1   return $_[0]->data->{vehicle_state}{rt};
197             }
198             sub trunk_rear {
199 0     0 1   return $_[0]->data->{vehicle_state}{rt};
200             }
201             sub user_present {
202 0     0 1   return $_[0]->data->{vehicle_state}{is_user_present};
203             }
204              
205             # Drive State Methods
206              
207             sub gear {
208 0     0 1   return $_[0]->data->{drive_state}{shift_state};
209             }
210             sub gps_as_of {
211 0     0 1   return $_[0]->data->{drive_state}{gps_as_of};
212             }
213             sub heading {
214 0     0 1   return $_[0]->data->{drive_state}{heading};
215             }
216             sub latitude {
217 0     0 1   return $_[0]->data->{drive_state}{latitude};
218             }
219             sub longitude {
220 0     0 1   return $_[0]->data->{drive_state}{longitude};
221             }
222             sub power {
223 0     0 1   return $_[0]->data->{drive_state}{power};
224             }
225             sub speed {
226 0   0 0 1   return $_[0]->data->{drive_state}{speed} // 0;
227             }
228              
229             # Charge State Methods
230              
231             sub battery_level {
232 0     0 1   return $_[0]->data->{charge_state}{battery_level};
233             }
234             sub charge_amps {
235 0     0 1   return $_[0]->data->{charge_state}{charge_amps};
236             }
237             sub charge_actual_current {
238 0     0 1   return $_[0]->data->{charge_state}{charge_actual_current};
239             }
240             sub charge_limit_soc {
241 0     0 1   return $_[0]->data->{charge_state}{charge_limit_soc};
242             }
243             sub charge_limit_soc_std {
244 0     0 1   return $_[0]->data->{charge_state}{charge_limit_soc_std};
245             }
246             sub charge_limit_soc_min {
247 0     0 1   return $_[0]->data->{charge_state}{charge_limit_soc_min};
248             }
249             sub charge_limit_soc_max {
250 0     0 1   return $_[0]->data->{charge_state}{charge_limit_soc_max};
251             }
252             sub charge_port_color {
253 0     0 1   return $_[0]->data->{charge_state}{charge_port_color};
254             }
255             sub charger_voltage {
256 0     0 1   return $_[0]->data->{charge_state}{charger_voltage};
257             }
258             sub charging_sites_nearby {
259 0     0 1   my ($self) = @_;
260 0           $self->_online_check;
261 0           my $sites = $self->api(endpoint => 'NEARBY_CHARGING_SITES', id => $self->id);
262              
263 0           my $super_chargers = $sites->{superchargers};
264 0           my $destination_chargers = $sites->{destination_charging};
265              
266 0           my %stations;
267              
268 0           my $cmp = 'distance_miles';
269              
270 0           for (sort { $a->{$cmp} <=> $b->{$cmp} } @$super_chargers) {
  0            
271 0 0         next if $_->{available_stalls} == 0;
272 0           push @{ $stations{super_chargers} }, $_;
  0            
273             }
274              
275 0           for (sort { $a->{$cmp} <=> $b->{$cmp} } @$destination_chargers) {
  0            
276 0 0         next if $_->{available_stalls} == 0;
277 0           push @{ $stations{destination_chargers} }, $_;
  0            
278             }
279              
280 0           return \%stations;
281             }
282             sub charging_state {
283 0     0 1   return $_[0]->data->{charge_state}{charging_state};
284             }
285             sub minutes_to_full_charge {
286 0     0 1   return $_[0]->data->{charge_state}{minutes_to_full_charge};
287             }
288              
289             # Climate State Methods
290              
291             sub bioweapon_mode {
292 0     0 1   return $_[0]->data->{climate_state}{bioweapon_mode};
293             }
294              
295             sub defroster_front {
296 0     0 1   return $_[0]->data->{climate_state}{front_defroster};
297             }
298             sub defroster_rear {
299 0     0 1   return $_[0]->data->{climate_state}{rear_defroster};
300             }
301              
302             sub fan_status {
303 0     0 1   return $_[0]->data->{climate_state}{fan_status};
304             }
305              
306             sub heater_battery {
307 0     0 1   return $_[0]->data->{climate_state}{battery_heater};
308             }
309             sub heater_seat_driver {
310 0     0 1   return $_[0]->data->{climate_state}{seat_heater_left};
311             }
312             sub heater_seat_passenger {
313 0     0 1   return $_[0]->data->{climate_state}{seat_heater_right};
314             }
315             sub heater_side_mirrors {
316 0     0 1   return $_[0]->data->{climate_state}{side_mirror_heaters};
317             }
318             sub heater_steering_wheel{
319 0     0 1   return $_[0]->data->{climate_state}{steering_wheel_heater};
320             }
321             sub heater_wipers {
322 0     0 1   return $_[0]->data->{climate_state}{outside_temp};
323             }
324              
325             sub is_climate_on {
326 0     0 1   return $_[0]->data->{climate_state}{is_climate_on};
327             }
328             sub is_air_conditioning_on {
329 0     0 1   return $_[0]->data->{climate_state}{is_air_conditioning_on};
330             }
331              
332             sub temperature_inside {
333 0     0 1   return $_[0]->data->{climate_state}{inside_temp};
334             }
335             sub temperature_outside {
336 0     0 1   return $_[0]->data->{climate_state}{outside_temp};
337             }
338             sub temperature_setting_driver {
339 0     0 1   return $_[0]->data->{climate_state}{driver_temp_setting};
340             }
341             sub temperature_setting_passenger {
342 0     0 1   return $_[0]->data->{climate_state}{passenger_temp_setting};
343             }
344              
345             # Command Related Methods
346              
347             sub charge_limit_set {
348 0     0 1   my ($self, $percent) = @_;
349              
350 0 0 0       if (! defined $percent || $percent !~ /^\d+$/ || $percent > 100 || $percent < 1) {
      0        
      0        
351 0           croak "charge_limit_set() requires a percent integer between 1 and 100";
352             }
353              
354 0           $self->_online_check;
355              
356 0           my $return = $self->api(
357             endpoint => 'CHANGE_CHARGE_LIMIT',
358             id => $self->id,
359             api_params => { percent => $percent }
360             );
361              
362 0           $self->api_cache_clear;
363              
364 0 0 0       if (! $return->{result} && $self->warn) {
365 0           print "Couldn't set charge limit: '$return->{reason}'\n";
366             }
367              
368 0           return $return->{result};
369             }
370              
371             sub bioweapon_mode_toggle {
372 0     0 1   my ($self) = @_;
373 0           $self->_online_check;
374              
375 0           my $return = $self->api(endpoint => 'HVAC_BIOWEAPON_MODE', id => $self->id);
376              
377 0           $self->api_cache_clear;
378              
379 0 0 0       if (! $return->{result} && $self->warn) {
380 0           print "Couldn't toggle bioweapon mode: '$return->{reason}'\n";
381             }
382              
383 0           return $return->{result};
384             }
385             sub climate_on {
386 0     0 1   my ($self) = @_;
387 0           $self->_online_check;
388 0           my $return = $self->api(endpoint => 'CLIMATE_ON', id => $self->id);
389              
390 0           $self->api_cache_clear;
391              
392 0 0 0       if (! $return->{result} && $self->warn) {
393 0           print "Couldn't turn climate on: '$return->{reason}'\n";
394             }
395              
396 0           return $return->{result};
397             }
398             sub climate_off {
399 0     0 1   my ($self) = @_;
400 0           $self->_online_check;
401              
402 0           my $return = $self->api(endpoint => 'CLIMATE_OFF', id => $self->id);
403              
404 0           $self->api_cache_clear;
405              
406 0 0 0       if (! $return->{result} && $self->warn) {
407 0           print "Couldn't turn climate off: '$return->{reason}'\n";
408             }
409              
410 0           return $return->{result};
411             }
412             sub climate_defrost_max {
413 0     0 1   my ($self) = @_;
414 0           $self->_online_check;
415              
416 0           my $return = $self->api(endpoint => 'MAX_DEFROST', id => $self->id);
417              
418 0           $self->api_cache_clear;
419              
420 0 0 0       if (! $return->{result} && $self->warn) {
421 0           print "Couldn't enable the defroster: '$return->{reason}'\n";
422             }
423              
424 0           return $return->{result};
425             }
426              
427             sub doors_lock {
428 0     0 1   my ($self) = @_;
429 0           $self->_online_check;
430              
431 0           my $return = $self->api(endpoint => 'LOCK', id => $self->id);
432              
433 0           $self->api_cache_clear;
434              
435 0 0 0       if (! $return->{result} && $self->warn) {
436 0           print "Couldn't lock the doors: '$return->{reason}'\n";
437             }
438              
439 0           return $return->{result};
440             }
441             sub doors_unlock {
442 0     0 1   my ($self) = @_;
443 0           $self->_online_check;
444              
445 0           my $return = $self->api(endpoint => 'UNLOCK', id => $self->id);
446              
447 0           $self->api_cache_clear;
448              
449 0 0 0       if (! $return->{result} && $self->warn) {
450 0           print "Couldn't unlock the doors: '$return->{reason}'\n";
451             }
452              
453 0           return $return->{result};
454             }
455              
456             sub horn_honk {
457 0     0 1   my ($self) = @_;
458 0           $self->_online_check;
459              
460 0           my $return = $self->api(endpoint => 'HONK_HORN', id => $self->id);
461              
462 0 0 0       if (! $return->{result} && $self->warn) {
463 0           print "Couldn't honk the horn: '$return->{reason}'\n";
464             }
465              
466 0           return $return->{result};
467             }
468              
469             sub lights_flash {
470 0     0 1   my ($self) = @_;
471 0           $self->_online_check;
472              
473 0           my $return = $self->api(endpoint => 'FLASH_LIGHTS', id => $self->id);
474              
475 0 0 0       if (! $return->{result} && $self->warn) {
476 0           print "Couldn't flash the exterior lights: '$return->{reason}'\n";
477             }
478              
479 0           return $return->{result};
480             }
481              
482             sub media_playback_toggle {
483 0     0 1   my ($self) = @_;
484 0           $self->_online_check;
485              
486 0           my $return = $self->api(endpoint => 'MEDIA_TOGGLE_PLAYBACK', id => $self->id);
487              
488 0 0 0       if (! $return->{result} && $self->warn) {
489 0           print "Couldn't toggle audio playback: '$return->{reason}'\n";
490             }
491              
492 0           return $return->{result};
493             }
494             sub media_track_next {
495 0     0 1   my ($self) = @_;
496 0           $self->_online_check;
497              
498 0           my $return = $self->api(endpoint => 'MEDIA_NEXT_TRACK', id => $self->id);
499              
500 0 0 0       if (! $return->{result} && $self->warn) {
501 0           print "Couldn't skip to next audio track: '$return->{reason}'\n";
502             }
503              
504 0           return $return->{result};
505             }
506             sub media_track_previous {
507 0     0 1   my ($self) = @_;
508 0           $self->_online_check;
509              
510 0           my $return = $self->api(endpoint => 'MEDIA_PREVIOUS_TRACK', id => $self->id);
511              
512 0 0 0       if (! $return->{result} && $self->warn) {
513 0           print "Couldn't skip to previous audio track: '$return->{reason}'\n";
514             }
515              
516 0           return $return->{result};
517             }
518             sub media_volume_down {
519 0     0 1   my ($self) = @_;
520 0           $self->_online_check;
521              
522 0           my $return = $self->api(endpoint => 'MEDIA_VOLUME_DOWN', id => $self->id);
523              
524 0 0 0       if (! $return->{result} && $self->warn) {
525 0           print "Couldn't turn volume down: '$return->{reason}'\n";
526             }
527              
528 0           return $return->{result};
529             }
530             sub media_volume_up {
531 0     0 1   my ($self) = @_;
532 0           $self->_online_check;
533              
534 0           my $return = $self->api(endpoint => 'MEDIA_VOLUME_UP', id => $self->id);
535              
536 0 0 0       if (! $return->{result} && $self->warn) {
537 0           print "Couldn't turn volume up: '$return->{reason}'\n";
538             }
539              
540 0           return $return->{result};
541             }
542              
543             sub trunk_front_actuate {
544 0     0 1   my ($self) = @_;
545              
546 0           $self->_online_check;
547              
548 0           my $return = $self->api(
549             endpoint => 'ACTUATE_TRUNK',
550             id => $self->id,
551             api_params => { which_trunk => 'front' }
552             );
553              
554 0           $self->api_cache_clear;
555              
556 0 0 0       if (! $return->{result} && $self->warn) {
557 0           print "Couldn't actuate front trunk: '$return->{reason}'\n";
558             }
559              
560 0           return $return->{result};
561             }
562             sub trunk_rear_actuate {
563 0     0 1   my ($self) = @_;
564              
565 0           $self->_online_check;
566              
567 0           my $return = $self->api(
568             endpoint => 'ACTUATE_TRUNK',
569             id => $self->id,
570             api_params => { which_trunk => 'rear' }
571             );
572              
573 0           $self->api_cache_clear;
574              
575 0 0 0       if (! $return->{result} && $self->warn) {
576 0           print "Couldn't actuate rear trunk: '$return->{reason}'\n";
577             }
578              
579 0           return $return->{result};
580             }
581              
582             sub wake {
583 0     0 1   my ($self) = @_;
584              
585 0 0         if (! $self->online) {
586              
587 0           $self->api(endpoint => 'WAKE_UP', id => $self->id);
588              
589 0           my $wakeup_called_at = time;
590 0           my $wake_interval = WAKE_INTERVAL;
591              
592 0           while (! $self->online) {
593 0           select(undef, undef, undef, $wake_interval);
594 0 0         if ($wakeup_called_at + WAKE_TIMEOUT - $wake_interval < time) {
595 0           printf(
596             "\nVehicle with ID %d couldn't be woken up within %d " .
597             "seconds. Exiting...\n\n",
598             $self->id,
599             WAKE_TIMEOUT
600             );
601 0           exit;
602             }
603 0           $wake_interval *= WAKE_BACKOFF;
604             }
605             }
606             }
607              
608             # Private Methods
609              
610             sub _id {
611 0     0     my ($self, $id) = @_;
612              
613 0 0         return $self->{data}{vehicle_id} if $self->{data}{vehicle_id};
614              
615 0 0         if (defined $id) {
616 0           $self->{data}{vehicle_id} = $id;
617             }
618             else {
619 0           my @vehicle_ids = keys %{$self->list};
  0            
620 0           $self->{data}{vehicle_id} = $vehicle_ids[0];
621             }
622              
623 0   0       return $self->{data}{vehicle_id} || -1;
624             }
625             sub _online_check {
626 0     0     my ($self) = @_;
627              
628 0           if (DEBUG_ONLINE) {
629             my $online = $self->online;
630             printf "Vehicle is %s\n", $online ? 'ONLINE' : 'OFFLINE';
631             }
632              
633 0 0         if (! $self->online) {
634 0 0         if ($self->auto_wake) {
635 0           $self->wake;
636             }
637             else {
638 0           printf(
639             "\nVehicle with ID %d is offline. Either wake it up with a call to " .
640             "wake(), or set 'auto_wake => 1' in your call to new()\n\n",
641             $self->id
642             );
643 0           exit;
644             }
645             }
646             }
647              
648       0     sub __placeholder{}
649              
650             1;
651              
652             =head1 NAME
653              
654             Tesla::Vehicle - Access information and command Tesla automobiles via the API
655              
656             =for html
657            
658             Coverage Status
659              
660             =head1 SYNOPSIS
661              
662             use Tesla::Vehicle;
663              
664             my $car = Tesla::Vehicle->new;
665              
666             $car->wake if ! $car->online;
667              
668             if ($car->locked) {
669             $car->doors_unlock;
670             $car->climate_on;
671              
672             if ($car->temperature_outside < 0) { # Freezing!
673             $car->climate_defrost_max;
674             }
675             }
676              
677             printf(
678             "%s is at %d%% charge, is moving %d MPH and is using %.2f kWh per mile\n",
679             $car->name,
680             $car->battery_level,
681             $car->speed,
682             $car->power
683             );
684              
685             =head1 DESCRIPTION
686              
687             This distribution provides methods for accessing and updating aspects of your
688             Tesla vehicle. Not all attributes available through Tesla's API have methods
689             listed here yet, but more will be added as time goes on.
690              
691             To access attributes that we don't have methods for, see the
692             L section, pull that data, then extract out the info
693             you want. If we don't have an aggregate data method for something you want yet,
694             see L to be able to get this yourself.
695              
696             As always, requests for updates to my software is encouraged. Please just open
697             an L.
698              
699             =head1 IMPORTANT
700              
701             The parent module L that we inherit the Tesla API access code from
702             has a complex caching mechanism in place that you ought to know about. Please do
703             read through the L documentation.
704              
705             =head1 OBJECT MANAGEMENT METHODS
706              
707             =head2 new(%params)
708              
709             Instantiates and returns a new L object. We subclass L
710             so there are several things inherited.
711              
712             B:
713              
714             All parameters are sent in as a hash. See the documentation for L
715             for further parameters that can be sent into this method.
716              
717             id
718              
719             I: The ID of the vehicle you want to associate this object
720             with. Most methods require this to be set. You can send it in after
721             instantiation by using the C method. If you don't know what the ID is,
722             you can instantiate the object, and dump the returned hashref from a call to
723             C.
724              
725             As a last case resort, we will try to figure out the ID by ourselves. If we
726             can't, and no ID has been set, methods that require an ID will C.
727              
728             auto_wake
729              
730             I: If set, we will automatically wake up your vehicle on calls
731             that require the car to be in an online state to retrieve data (via a call to
732             C). If not set and the car is asleep, we will print a warning and exit.
733             You can set this after instantiation by a call to C.
734              
735             I: False.
736              
737             api_cache_time
738              
739             I: The number of seconds to cache data returned from Tesla's
740             API.
741              
742             I: 2
743              
744             warn
745              
746             Enables or disables the warnings that we receive from Tesla if there's a failure
747             to execute one of the L.
748              
749             If enabled, we print these warnings to C.
750              
751             I: True (C<1>) to enable, false (C<0>) to disable the warnings.
752              
753             I: True
754              
755             =head2 auto_wake($bool)
756              
757             Informs this software if we should automatically wake a vehicle for calls that
758             require it online, and the vehicle is currently offline.
759              
760             Send in a true value to allow us to do this.
761              
762             I: False
763              
764             =head2 warn($bool)
765              
766             Enables or disables the warnings that we receive from Tesla if there's a failure
767             to execute one of the L.
768              
769             If enabled, we print these warnings to C.
770              
771             B:
772              
773             $bool
774              
775             I: True (C<1>) to enable, false (C<0>) to disable the warnings.
776              
777             I: True
778              
779             =head1 VEHICLE IDENTIFICATION METHODS
780              
781             =head2 id($id)
782              
783             Sets/gets your primary vehicle ID. If set, we will use this in all API calls
784             that require it.
785              
786             B:
787              
788             $id
789              
790             I: The vehicle ID you want to use in all API calls that require
791             one. This can be set as a parameter in C. If you attempt an API call that
792             requires and ID and one isn't set, we C.
793              
794             If you only have a single Tesla vehicle registered under your account, we will
795             set C to that ID when you instantiate the object.
796              
797             You can also have this auto-populated in C by sending it in with the
798             C<< id => $id >> parameter.
799              
800             If you don't know the ID of the vehicle you want to use, make a call to
801             C, and it will return a hash reference where each key is a vehice ID, and
802             the value is the name you've assigned your vehicle.
803              
804             =head2 name
805              
806             Returns the name you associated with your vehicle under your Tesla account.
807              
808             B:L must have already been set, either through the C
809             method, or in C.
810              
811             =head2 list
812              
813             Returns a hash reference of your listed vehicles. The key is the vehicle ID,
814             and the value is the name you've assigned to that vehicle.
815              
816             Example:
817              
818             {
819             1234567891011 => "Dream machine",
820             1234567891012 => "Steve's Model S",
821             }
822              
823             =head1 VEHICLE SUMMARY METHODS
824              
825             =head2 in_service
826              
827             Returns a bool whether your vehicle is in service mode or not.
828              
829             =head2 options
830              
831             B: The Tesla API, since 2019, has been returning wrong information about
832             vehicle option codes, so do not trust them. For my Model X, I'm getting
833             returned option codes for a Model 3. Several people I've spoken to about the
834             issue see the same thing for their Model S.
835              
836             Returns a hash reference of the options available on your vehicle. The key is
837             the option code, and the value is the option description.
838              
839             {
840             'APH3' => 'Autopilot 2.5 Hardware',
841             'RENA' => 'Region: North America',
842             'MR31' => 'Uplevel Mirrors',
843             'GLFR' => 'Final Assembly Fremont',
844             }
845              
846             =head2 vehicle_id
847              
848             Returns an integer of Tesla's representation of the vehicle identification of
849             your vehicle. This is not the same as the ID you use to access the API.
850              
851             =head2 vin
852              
853             Returns an alpha-numeric string that contains the actual Vehicle Identification
854             Number of your vehicle. This value is located on a stamped plate on the driver's
855             side bottom on the outside of your windshield.
856              
857             =head1 COMMAND METHODS
858              
859             All command methods return a true value (C<1>)if the operation was successful,
860             and a false value (C<0>) if the command failed.
861              
862             We will also print to C the reason for the failure if one occurred.
863             This warning includes the message we received from Tesla.
864              
865             You can disable these warnings from being displayed by sending in a false value
866             to C, or instantiate the object with C 0)>.
867              
868             Example warning:
869              
870             $vehicle->media_volume_up;
871              
872             # Output
873              
874             Couldn't turn volume up: 'user_not_present'
875              
876             =head2 bioweapon_mode_toggle
877              
878             Toggles the HVAC Bio Weapon mode on or off.
879              
880             Returns true on success, false on failure.
881              
882             =head2 climate_on
883              
884             Turns the climate system on to whatever settings they last had.
885              
886             Returns true on success.
887              
888             Follow up with a call to C to verify.
889              
890             =head2 climate_off
891              
892             Turns the climate system off.
893              
894             Returns true on success.
895              
896             Follow up with a call to C to verify.
897              
898             =head2 climate_defrost_max
899              
900             Returns true if the call was successful, false otherwise.
901              
902             =head2 doors_lock
903              
904             Locks the car doors. Returns true on success.
905              
906             Follow up with a call to C to verify.
907              
908             =head2 doors_unlock
909              
910             Unlocks the car doors. Returns true on success.
911              
912             Follow up with a call to C to verify.
913              
914             =head2 horn_honk
915              
916             Honks the horn once. Returns true on success.
917              
918             =head2 lights_flash
919              
920             Flashes the exterior lights of the vehicle.
921              
922             Returns true on success.
923              
924             =head2 media_playback_toggle
925              
926             Play/Pause the currently loaded audio in the vehicle.
927              
928             Returns true on success, false on failure.
929              
930             I: Most often reason for fail is "User Not Present".
931              
932             =head2 media_track_next
933              
934             Skips to the next audio track.
935              
936             Returns true on success, false on failure.
937              
938             I: Most often reason for fail is "User Not Present".
939              
940             =head2 media_track_previous
941              
942             Skips to the previous audio track.
943              
944             Returns true on success, false on failure.
945              
946             I: Most often reason for fail is "User Not Present".
947              
948             =head2 media_volume_down
949              
950             Turns down the audio volume by one notch.
951              
952             Returns true on success, false on failure.
953              
954             I: Most often reason for fail is "User Not Present".
955              
956             =head2 media_volume_up
957              
958             Turns up the audio volume by one notch.
959              
960             Returns true on success, false on failure.
961              
962             I: Most often reason for fail is "User Not Present".
963              
964             =head2 charge_limit_set($percent)
965              
966             Sets the limit in percent the battery can be charged to.
967              
968             Returns true if the operation was successful, and false if not.
969              
970             Follow up with a call to C.
971              
972             =head2 trunk_rear_actuate
973              
974             Opens or closes the rear trunk.
975              
976             Returns true if the operation was successful, and false if not.
977              
978             You must give time for the trunk to shut before checking its status with the
979             C call.
980              
981             =head2 trunk_front_actuate
982              
983             Opens or closes the rear trunk.
984              
985             Returns true if the operation was successful, and false if not.
986              
987             You must give time for the trunk to shut before checking its status with the
988             C call.
989              
990             =head2 wake
991              
992             Attempt to wake the vehicle up from sleep mode. Most method calls against this
993             object require the vehicle to be awake.
994              
995             We don't return anything; the vehicle will be woken up, or it won't and your
996             next method call will fail.
997              
998             By default, this software does not wake up the car automatically, it just
999             Cs if the car isn't awake and you attempt something it can't do while
1000             sleeping.
1001              
1002             Set C<< auto_wake => 1 >> in C or C to allow us to
1003             automatically wake the vehicle up.
1004              
1005             =head1 AGGREGATE DATA METHODS
1006              
1007             These methods aggregate all attributes of the vehicle that relate to a specific
1008             aspect of the vehicle. Methods that allow access to individual attributes of
1009             these larger aggregates are listed below. For example, C will
1010             return the C attribute, but so will C. By using
1011             the aggregate method, you'll have to fish that attribute out yourself.
1012              
1013             =head2 data
1014              
1015             Returns a hash reference containing all available API data that Tesla provides
1016             for your vehicles.
1017              
1018             Cs if you haven't specified a vehicle ID through C or C,
1019             and we weren't able to figure one out automatically.
1020              
1021             This data will be retained and re-used for a period of two (C<2>) seconds to
1022             reduce API calls through the Tesla API. This timing can be overridden in the
1023             C method by specifying the C<< refresh => $seconds >> parameter, or by
1024             a call to the object's C method.
1025              
1026             I: Hash reference. Contains every attribute Tesla has available through
1027             their API for their vehicles.
1028              
1029             The data accessor methods listed below use this data, simply selecting out
1030             individual parts of it.
1031              
1032             =head2 summary
1033              
1034             Returns an important list of information about your vehicle, and Tesla's API
1035             access.
1036              
1037             The most important piece of information is the vehicle's C, which shows
1038             whether the car is online or not. Other information includes C,
1039             C, the C etc.
1040              
1041             I: Hash reference.
1042              
1043             =head2 state
1044              
1045             Returns the C section of Tesla's vehicle data. This includes
1046             things like whether the car is locked, whether there is media playing, the
1047             odometer reading, whether sentry mode is enabled or not etc.
1048              
1049             I: Hash reference.
1050              
1051             =head2 charge_state
1052              
1053             Returns information regarding battery and charging information of your vehicle.
1054              
1055             I: Hash reference.
1056              
1057             =head2 climate_state
1058              
1059             Returns information regarding the climate state of the vehicle.
1060              
1061             I: Hash reference.
1062              
1063             =head2 drive_state
1064              
1065             Returns the information about the operation of the vehicle.
1066              
1067             I: Hash reference.
1068              
1069             =head2 vehicle_config
1070              
1071             Returns attributes related to the actual configuration of your vehicle.
1072              
1073             I: Hash reference.
1074              
1075             =head1 VEHICLE STATE ATTRIBUTE METHODS
1076              
1077             =head2 dashcam
1078              
1079             Returns a string of the state of the dashcam (eg. "Recording").
1080              
1081             =head2 locked
1082              
1083             Returns true if the doors are locked, false if not.
1084              
1085             =head2 online
1086              
1087             Returns true if the vehicle is online and ready to communicate, and false if
1088              
1089             =head2 odometer
1090              
1091             Returns the number of miles the vehicle is traveled since new, as a floating point
1092             number.
1093              
1094             =head2 sentry_mode
1095              
1096             Returns a bool indicating whether the vehicle is in sentry mode or not.
1097              
1098             =head2 santa_mode
1099              
1100             Returns a bool whether the vehicle is in "Santa" mode or not.
1101              
1102             =head2 trunk_front
1103              
1104             Returns true if the front trunk (ie. Frunk) is open, and false if it's
1105             closed.
1106              
1107             =head2 trunk_rear
1108              
1109             Returns true if the rear trunk is open, and false if it's closed.
1110              
1111             =head2 user_present
1112              
1113             Returns a bool indicating whether someone with a valid FOB key is in proximity
1114             of the vehicle.
1115              
1116             =head1 DRIVE STATE ATTRIBUTE METHODS
1117              
1118             Retrieves information regarding the actual operation and location of the
1119             vehicle.
1120              
1121             =head2 gear
1122              
1123             Returns a single alpha character representing the gear the vehicle is in.
1124              
1125             One of C

for parked, C for Neutral, C for Drive and C for reverse.

1126              
1127             This value is very often retured as undefined by Tesla, so a custom value of
1128             C is returned if the Tesla API doesn't return a valid value after
1129             C attempts to get one.
1130              
1131             =head2 gps_as_of
1132              
1133             Returns an integer that is the timestamp that the GPS data was last refreshed
1134             from the vehicle.
1135              
1136             =head2 heading
1137              
1138             Returns an integer between C<0> and C<360> which is the current compass
1139             heading of the vehicle.
1140              
1141             =head2 latitude
1142              
1143             Returns a signed float of the current Latitude of the vehicle.
1144              
1145             =head2 longitude
1146              
1147             Returns a signed float of the current Longitude of the vehicle.
1148              
1149             =head2 power
1150              
1151             Returns a signed float that contains the current kWh (Kilowatt-hours) per mile
1152             the car is currently consuming in its operation.
1153              
1154             A negative value indicates that either the car is plugged in and charging, or
1155             that the regenerative brakes are engaged and are replenishing the battery (eg.
1156             the car is going downhill and the car is decelerating).
1157              
1158             =head2 speed
1159              
1160             Returns a float of the vehicle's speed in MPH.
1161              
1162             =head1 CHARGE STATE ATTRIBUTE METHODS
1163              
1164             =head2 battery_level
1165              
1166             Returns an integer of the percent that the battery is charged to.
1167              
1168             =head2 charge_amps
1169              
1170             Returns a float indicating how many Amps the vehicle is set to draw through the
1171             current charger connection.
1172              
1173             =head2 charge_actual_current
1174              
1175             Returns a float indicating how many Amps are actually being drawn through the
1176             charger.
1177              
1178             =head2 charge_limit_soc
1179              
1180             Returns an integer stating what percentage of battery level you've indicated
1181             the charging will be cut off at.
1182              
1183             "soc" stands for "State of Charge"
1184              
1185             =head2 charge_limit_soc_std
1186              
1187             Returns an integer stating Tesla's default B is set to.
1188              
1189             =head2 charge_limit_soc_min
1190              
1191             Returns an integer stating what the minimum number you can set as the Charge
1192             Limit SOC (C).
1193              
1194             =head2 charge_limit_soc_max
1195              
1196             Returns an integer stating what the maximum number you can set as the Charge
1197             Limit SOC (C).
1198              
1199             =head2 charge_port_color
1200              
1201             Returns a string containing the color of the vehicle's charge port (eg. "Green
1202             Flashing" etc).
1203              
1204             =head2 charger_voltage
1205              
1206             Returns a float containing the actual Voltage level that the charger is connected
1207             through.
1208              
1209             =head2 charging_sites_nearby
1210              
1211             Returns a hash reference of arrays. The keys are C and
1212             C. Under each key is an array of charging station
1213             details, each in a hash reference. The hash references are sorted in the
1214             array as closest first, farthest last. All stations with no available stalls
1215             have been removed. Each station has the following properties:
1216              
1217             {
1218             total_stalls => 8,
1219             site_closed => $VAR1->{'super_chargers'}[0]{'site_closed'},
1220             location => {
1221             long => '-119.429277',
1222             lat => '49.885799'
1223             },
1224             name => 'Kelowna, BC',
1225             type => 'supercharger',
1226             distance_miles => '26.259798',
1227             available_stalls => 4
1228             }
1229              
1230             =head2 charging_state
1231              
1232             Returns a string that identifies the state of the vehicle's charger. Eg.
1233             "Disconnected", "Connected" etc.
1234              
1235             =head2 minutes_to_full_charge
1236              
1237             Returns an integer containing the estimated number of minutes to fully charge
1238             the batteries, taking into consideration voltage level, Amps requested and
1239             drawn etc.
1240              
1241             =head1 CLIMATE STATE ATTRIBUTE METHODS
1242              
1243             =head2 bioweapon_mode
1244              
1245             Yes, this is truly a thing. At least my Tesla vehicle has a mode that seals the
1246             vehicle from all outside air, and puts positive pressure inside the cabin to
1247             ensure that no contaminents can enter the vehicle.
1248              
1249             This method returns a bool to indicate whether this mode is enabled or not.
1250              
1251             =head2 defroster_front
1252              
1253             Is the front windshield defroster on or not
1254              
1255             =head2 defroster_rear
1256              
1257             Is the rear window defroster on or not.
1258              
1259             =head2 fan_status
1260              
1261             Returns an integer that represents the climate fan speed.
1262              
1263             =head2 heater_battery
1264              
1265             Is the battery warmer on or not.
1266              
1267             =head2 heater_seat_driver
1268              
1269             Is the driver's seat warmer on.
1270              
1271             =head2 heater_seat_passenger
1272              
1273             Is the passenger's seat warmer on.
1274              
1275             =head2 heater_side_mirrors
1276              
1277             Is the wing mirror heater on.
1278              
1279             =head2 heater_steering_wheel
1280              
1281             Is the steering wheel warmer on or not
1282              
1283             =head2 heater_wipers
1284              
1285             Is the windshield wiper warmer on.
1286              
1287             =head2 is_climate_on
1288              
1289             Is the climate system currently active.
1290              
1291             =head2 is_air_conditioning_on
1292              
1293             Is the air conditioning unit active.
1294              
1295             =head2 temperature_inside
1296              
1297             The current temperature inside of the vehicle cabin.
1298              
1299             =head2 temperature_outside
1300              
1301             The temperature outside of the vehicle.
1302              
1303             =head2 temperature_setting_driver
1304              
1305             What the driver's side temperature setting is set to.
1306              
1307             =head2 temperature_setting_passenger
1308              
1309             What the passenger's side temperature setting is set to.
1310              
1311             =head1 AUTHOR
1312              
1313             Steve Bertrand, C<< >>
1314              
1315             =head1 LICENSE AND COPYRIGHT
1316              
1317             Copyright 2022 Steve Bertrand.
1318              
1319             This program is free software; you can redistribute it and/or modify it
1320             under the terms of the the Artistic License (2.0). You may obtain a
1321             copy of the full license at:
1322              
1323             L