File Coverage

blib/lib/Tesla/Vehicle.pm
Criterion Covered Total %
statement 24 306 7.8
branch 0 74 0.0
condition 0 67 0.0
subroutine 8 91 8.7
pod 79 79 100.0
total 111 617 17.9


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

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

1205              
1206             This value is very often retured as undefined by Tesla, so a custom value of
1207             C is returned if the Tesla API doesn't return a valid value after
1208             C attempts to get one.
1209              
1210             =head2 gps_as_of
1211              
1212             Returns an integer that is the timestamp that the GPS data was last refreshed
1213             from the vehicle.
1214              
1215             =head2 heading
1216              
1217             Returns an integer between C<0> and C<360> which is the current compass
1218             heading of the vehicle.
1219              
1220             =head2 latitude
1221              
1222             Returns a signed float of the current Latitude of the vehicle.
1223              
1224             =head2 longitude
1225              
1226             Returns a signed float of the current Longitude of the vehicle.
1227              
1228             =head2 power
1229              
1230             Returns a signed float that contains the current kWh (Kilowatt-hours) per mile
1231             the car is currently consuming in its operation.
1232              
1233             A negative value indicates that either the car is plugged in and charging, or
1234             that the regenerative brakes are engaged and are replenishing the battery (eg.
1235             the car is going downhill and the car is decelerating).
1236              
1237             =head2 speed
1238              
1239             Returns a float of the vehicle's speed in MPH.
1240              
1241             =head1 CHARGE STATE ATTRIBUTE METHODS
1242              
1243             =head2 battery_level
1244              
1245             Returns an integer of the percent that the battery is charged to.
1246              
1247             =head2 charge_amps
1248              
1249             Returns a float indicating how many Amps the vehicle is set to draw through the
1250             current charger connection.
1251              
1252             =head2 charge_actual_current
1253              
1254             Returns a float indicating how many Amps are actually being drawn through the
1255             charger.
1256              
1257             =head2 charge_limit_soc
1258              
1259             Returns an integer stating what percentage of battery level you've indicated
1260             the charging will be cut off at.
1261              
1262             "soc" stands for "State of Charge"
1263              
1264             =head2 charge_limit_soc_std
1265              
1266             Returns an integer stating Tesla's default B is set to.
1267              
1268             =head2 charge_limit_soc_min
1269              
1270             Returns an integer stating what the minimum number you can set as the Charge
1271             Limit SOC (C).
1272              
1273             =head2 charge_limit_soc_max
1274              
1275             Returns an integer stating what the maximum number you can set as the Charge
1276             Limit SOC (C).
1277              
1278             =head2 charge_port_color
1279              
1280             Returns a string containing the color of the vehicle's charge port (eg. "Green
1281             Flashing" etc).
1282              
1283             =head2 charger_voltage
1284              
1285             Returns a float containing the actual Voltage level that the charger is connected
1286             through.
1287              
1288             =head2 charging_sites_nearby
1289              
1290             Returns a hash reference of arrays. The keys are C and
1291             C. Under each key is an array of charging station
1292             details, each in a hash reference. The hash references are sorted in the
1293             array as closest first, farthest last. All stations with no available stalls
1294             have been removed. Each station has the following properties:
1295              
1296             {
1297             total_stalls => 8,
1298             site_closed => $VAR1->{'super_chargers'}[0]{'site_closed'},
1299             location => {
1300             long => '-119.429277',
1301             lat => '49.885799'
1302             },
1303             name => 'Kelowna, BC',
1304             type => 'supercharger',
1305             distance_miles => '26.259798',
1306             available_stalls => 4
1307             }
1308              
1309             =head2 charging_state
1310              
1311             Returns a string that identifies the state of the vehicle's charger. Eg.
1312             "Disconnected", "Connected" etc.
1313              
1314             =head2 minutes_to_full_charge
1315              
1316             Returns an integer containing the estimated number of minutes to fully charge
1317             the batteries, taking into consideration voltage level, Amps requested and
1318             drawn etc.
1319              
1320             =head1 CLIMATE STATE ATTRIBUTE METHODS
1321              
1322             =head2 bioweapon_mode
1323              
1324             Yes, this is truly a thing. At least my Tesla vehicle has a mode that seals the
1325             vehicle from all outside air, and puts positive pressure inside the cabin to
1326             ensure that no contaminents can enter the vehicle.
1327              
1328             This method returns a bool to indicate whether this mode is enabled or not.
1329              
1330             =head2 defroster_front
1331              
1332             Is the front windshield defroster on or not
1333              
1334             =head2 defroster_rear
1335              
1336             Is the rear window defroster on or not.
1337              
1338             =head2 fan_status
1339              
1340             Returns an integer that represents the climate fan speed.
1341              
1342             =head2 heater_battery
1343              
1344             Is the battery warmer on or not.
1345              
1346             =head2 heater_seat_driver
1347              
1348             Is the driver's seat warmer on.
1349              
1350             =head2 heater_seat_passenger
1351              
1352             Is the passenger's seat warmer on.
1353              
1354             =head2 heater_side_mirrors
1355              
1356             Is the wing mirror heater on.
1357              
1358             =head2 heater_steering_wheel
1359              
1360             Is the steering wheel warmer on or not
1361              
1362             =head2 heater_wipers
1363              
1364             Is the windshield wiper warmer on.
1365              
1366             =head2 is_climate_on
1367              
1368             Is the climate system currently active.
1369              
1370             =head2 is_air_conditioning_on
1371              
1372             Is the air conditioning unit active.
1373              
1374             =head2 temperature_inside
1375              
1376             The current temperature inside of the vehicle cabin.
1377              
1378             =head2 temperature_outside
1379              
1380             The temperature outside of the vehicle.
1381              
1382             =head2 temperature_setting_driver
1383              
1384             What the driver's side temperature setting is set to.
1385              
1386             =head2 temperature_setting_passenger
1387              
1388             What the passenger's side temperature setting is set to.
1389              
1390             =head1 AUTHOR
1391              
1392             Steve Bertrand, C<< >>
1393              
1394             =head1 LICENSE AND COPYRIGHT
1395              
1396             Copyright 2022 Steve Bertrand.
1397              
1398             This program is free software; you can redistribute it and/or modify it
1399             under the terms of the the Artistic License (2.0). You may obtain a
1400             copy of the full license at:
1401              
1402             L