File Coverage

blib/lib/Tesla/Vehicle.pm
Criterion Covered Total %
statement 18 260 6.9
branch 0 58 0.0
condition 0 51 0.0
subroutine 6 86 6.9
pod 77 77 100.0
total 101 532 18.9


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

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

1077              
1078             =head2 gps_as_of
1079              
1080             Returns an integer that is the timestamp that the GPS data was last refreshed
1081             from the vehicle.
1082              
1083             =head2 heading
1084              
1085             Returns an integer between C<0> and C<360> which is the current compass
1086             heading of the vehicle.
1087              
1088             =head2 latitude
1089              
1090             Returns a signed float of the current Latitude of the vehicle.
1091              
1092             =head2 longitude
1093              
1094             Returns a signed float of the current Longitude of the vehicle.
1095              
1096             =head2 power
1097              
1098             Returns a signed float that contains the current kWh (Kilowatt-hours) per mile
1099             the car is currently consuming in its operation.
1100              
1101             A negative value indicates that either the car is plugged in and charging, or
1102             that the regenerative brakes are engaged and are replenishing the battery (eg.
1103             the car is going downhill and the car is decelerating).
1104              
1105             =head2 speed
1106              
1107             Returns a float of the vehicle's speed in MPH.
1108              
1109             =head1 CHARGE STATE ATTRIBUTE METHODS
1110              
1111             =head2 battery_level
1112              
1113             Returns an integer of the percent that the battery is charged to.
1114              
1115             =head2 charge_amps
1116              
1117             Returns a float indicating how many Amps the vehicle is set to draw through the
1118             current charger connection.
1119              
1120             =head2 charge_actual_current
1121              
1122             Returns a float indicating how many Amps are actually being drawn through the
1123             charger.
1124              
1125             =head2 charge_limit_soc
1126              
1127             Returns an integer stating what percentage of battery level you've indicated
1128             the charging will be cut off at.
1129              
1130             "soc" stands for "State of Charge"
1131              
1132             =head2 charge_limit_soc_std
1133              
1134             Returns an integer stating Tesla's default B is set to.
1135              
1136             =head2 charge_limit_soc_min
1137              
1138             Returns an integer stating what the minimum number you can set as the Charge
1139             Limit SOC (C).
1140              
1141             =head2 charge_limit_soc_max
1142              
1143             Returns an integer stating what the maximum number you can set as the Charge
1144             Limit SOC (C).
1145              
1146             =head2 charge_port_color
1147              
1148             Returns a string containing the color of the vehicle's charge port (eg. "Green
1149             Flashing" etc).
1150              
1151             =head2 charger_voltage
1152              
1153             Returns a float containing the actual Voltage level that the charger is connected
1154             through.
1155              
1156             =head2 charging_sites_nearby
1157              
1158             Returns a hash reference of arrays. The keys are C and
1159             C. Under each key is an array of charging station
1160             details, each in a hash reference. The hash references are sorted in the
1161             array as closest first, farthest last. All stations with no available stalls
1162             have been removed. Each station has the following properties:
1163              
1164             {
1165             total_stalls => 8,
1166             site_closed => $VAR1->{'super_chargers'}[0]{'site_closed'},
1167             location => {
1168             long => '-119.429277',
1169             lat => '49.885799'
1170             },
1171             name => 'Kelowna, BC',
1172             type => 'supercharger',
1173             distance_miles => '26.259798',
1174             available_stalls => 4
1175             }
1176              
1177             =head2 charging_state
1178              
1179             Returns a string that identifies the state of the vehicle's charger. Eg.
1180             "Disconnected", "Connected" etc.
1181              
1182             =head2 minutes_to_full_charge
1183              
1184             Returns an integer containing the estimated number of minutes to fully charge
1185             the batteries, taking into consideration voltage level, Amps requested and
1186             drawn etc.
1187              
1188             =head1 CLIMATE STATE ATTRIBUTE METHODS
1189              
1190             =head2 bioweapon_mode
1191              
1192             Yes, this is truly a thing. At least my Tesla vehicle has a mode that seals the
1193             vehicle from all outside air, and puts positive pressure inside the cabin to
1194             ensure that no contaminents can enter the vehicle.
1195              
1196             This method returns a bool to indicate whether this mode is enabled or not.
1197              
1198             =head2 defroster_front
1199              
1200             Is the front windshield defroster on or not
1201              
1202             =head2 defroster_rear
1203              
1204             Is the rear window defroster on or not.
1205              
1206             =head2 fan_status
1207              
1208             Returns an integer that represents the climate fan speed.
1209              
1210             =head2 heater_battery
1211              
1212             Is the battery warmer on or not.
1213              
1214             =head2 heater_seat_driver
1215              
1216             Is the driver's seat warmer on.
1217              
1218             =head2 heater_seat_passenger
1219              
1220             Is the passenger's seat warmer on.
1221              
1222             =head2 heater_side_mirrors
1223              
1224             Is the wing mirror heater on.
1225              
1226             =head2 heater_steering_wheel
1227              
1228             Is the steering wheel warmer on or not
1229              
1230             =head2 heater_wipers
1231              
1232             Is the windshield wiper warmer on.
1233              
1234             =head2 is_climate_on
1235              
1236             Is the climate system currently active.
1237              
1238             =head2 is_air_conditioning_on
1239              
1240             Is the air conditioning unit active.
1241              
1242             =head2 temperature_inside
1243              
1244             The current temperature inside of the vehicle cabin.
1245              
1246             =head2 temperature_outside
1247              
1248             The temperature outside of the vehicle.
1249              
1250             =head2 temperature_setting_driver
1251              
1252             What the driver's side temperature setting is set to.
1253              
1254             =head2 temperature_setting_passenger
1255              
1256             What the passenger's side temperature setting is set to.
1257              
1258             =head1 AUTHOR
1259              
1260             Steve Bertrand, C<< >>
1261              
1262             =head1 LICENSE AND COPYRIGHT
1263              
1264             Copyright 2022 Steve Bertrand.
1265              
1266             This program is free software; you can redistribute it and/or modify it
1267             under the terms of the the Artistic License (2.0). You may obtain a
1268             copy of the full license at:
1269              
1270             L