Welcome to Tesla Motors Club
Discuss Tesla's Model S, Model 3, Model X, Model Y, Cybertruck, Roadster and More.
Register

[Software] TeslaPSTN: Access API via phone/PSTN/SIP

This site may earn commission on affiliate links.
Hello TMC!

Allow me to introduce TeslaPSTN: A "software" that allows you to access/control the Tesla API through the free-of-charge and open source Asterisk PBX. Why the quotes? Because it's just a single (Bash) shell script and I am not a programmer, a "scripter" at most if such a term exists. :)

What's this for?

I'm offering a Tesla Model S 85 with AP1 for rent here in Frankfurt, Germany, via Turo.com, and since recently I'm offering the car in "self-service" mode, meaning no human will be present during pickup and return of the car. Instead, the renter will get access to the Tesla app and can unlock the car this way and pick up the keyfob from the glovebox (Passive Entry disabled so the car won't open by itself when a stranger presses the door handle).

So far, so good, but when I realized that more renters are from abroad than from within Germany I thought about how to improve that process. Because, what if a renter doesn't own a smartphone, or the renter just arrived at the airport from abroad and their SIM doesn't allow data roaming (or it's too expensive), or the renter starts to mess around with the app the night before they're going to pick up the car and opens the frunk, which won't close again through the app, resulting in the car sitting on the street with the frunk open overnight. The app solution only allows access to everything or nothing.

TeslaPSTN solves this problem by the renter calling a cheap/free fixed-line telephone number (BTW, Wiki: PSTN), authorizes themselves via a previously assigned PIN code, and can then only access the API functionality that I granted them, in the Turo rental example that would be only unlocking and locking the doors, via DTMF (beep beep digits over the phone :) ).

Other possibilities: Maybe you want to grant a relative access to only some limited functionality of the car, and not everything that the app allows. Or maybe you are somewhere where there's no internet connectivity but you still would like to communicate with your Tesla to check if it's still charging, check SoC etc...

Asterisk not only allows connectivity via PSTN, but also via SIP ("Voice over IP") and many other communication channels, so you could also communicate with your Tesla through a SIP-compatible device, a softphone on your PC or whatever, or receive text messages from the cell network and send commands accordingly. I am not sure what this could be useful for, but maybe there is a use case. :)

Requirements:

- A computer with Linux, BSD or any other operating system which supports the "Bash" shell
- Asterisk
- curl
- jq
... and TeslaPSTN (link)

I set up a few phone numbers in the US and in Canada so you can test a simple demo by yourself and query the SoC of my rental Tesla, as follows:

LA: (213) 293-3690
NY: (646) 630-8643
Toronto: (437) 370-1837

(in English language)

Germany: 06083-8734444
Austria: 0720-022022
Switzerland: 044-5511111

(in German language)

PIN code: 445566

And when being prompted for a command, press 1

Have fun,
Markus

PS: As of today only a few API commands are implemented: flash, honk, unlock, lock, getsoc, gettypical. If you need something else just let me know and I'll implement it. (Or you can do it by yourself by just copying a few lines of code)
 
Also, here's a Asterisk dialplan example that provides a simple unlock/lock functionality with PIN code authorization to be used in, for example, Turo self-service mode, in English and German. All speech is generated on-the-fly via the inofficial Google Translate API using this cool AGI for Asterisk: https://zaf.github.io/asterisk-googletts

Only a minor modification is required:
Code:
diff googletts.agi googletts.orig.agi

266c266,268
<               print "SET VARIABLE KEYPRESS ", chr($response[0]), "\n";
---
>               print "SET EXTENSION ", chr($response[0]), "\n";
>               checkresponse();
>               print "SET PRIORITY 1\n";

Dialplan (/etc/asterisk/extensions.conf):
Code:
exten => _X.,1,Answer
exten => _X.,n(start),NoOp
exten => _X.,n,AGI(googletts.agi,"Welcome to the Tesla rental system. Please press 1 for English or 2 for German.",en,any)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "1"]?english)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "2"]?german)
exten => _X.,n,AGI(googletts.agi,"Willkommen im Tesla Mietsystem. Bitte druecken Sie 1 fuer Englisch oder 2 fuer Deutsch.",de,any)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "1"]?english)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "2"]?german:start)


exten => _X.,n(english),NoOp
exten => _X.,n,Set(KEYPRESS=)
exten => _X.,n,AGI(googletts.agi,"Thank you.",en)

exten => _X.,n(englishAgain),NoOp
exten => _X.,n,AGI(googletts.agi,"Please enter your PIN code after the beep.",en)
exten => _X.,n,Read(PIN,/var/lib/asterisk/sounds/en/beep,6,,,8)
exten => _X.,n,GotoIf($["${PIN}" = ""]?englishAgain:englishCheck)

exten => _X.,n(englishCheck),NoOp
exten => _X.,n,AGI(TeslaPSTN/TeslaPSTN.sh,checkpin,${PIN})
exten => _X.,n,GotoIf($["${CHECKPIN}" = "success"]?englishAuthOK:englishAuthIncorrect)

exten => _X.,n(englishAuthIncorrect),NoOp
exten => _X.,n,AGI(googletts.agi,"You entered",en)
exten => _X.,n,SayDigits(${PIN})
exten => _X.,n,AGI(googletts.agi,"That PIN is not valid. Please try again and enter your PIN code after the beep.",en)
exten => _X.,n,Read(PIN,/var/lib/asterisk/sounds/en/beep,6,,,8)
exten => _X.,n,GotoIf($["${PIN}" = ""]?englishAgain:englishCheck)

exten => _X.,n(englishAuthOK),NoOp
exten => _X.,n,AGI(googletts.agi,"Authorization successful.",en)
exten => _X.,n(englishMenu),NoOp
exten => _X.,n,Set(KEYPRESS=)
exten => _X.,n,AGI(googletts.agi,"Please press 1 to unlock the car or 2 to lock the car.",en,any)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "1"]?englishUnlock)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "2"]?englishLock)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "3"]?englishMenu)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "4"]?englishMenu)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "5"]?englishMenu)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "6"]?englishMenu)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "7"]?englishMenu)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "8"]?englishMenu)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "9"]?englishMenu)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "0"]?englishMenu)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "*"]?englishMenu)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "#"]?englishMenu)
exten => _X.,n,GotoIf($["${KEYPRESS}" = ""]?englishMenu)

exten => _X.,n(englishUnlock),NoOp
exten => _X.,n,AGI(googletts.agi,"Thank you. One moment please. I am trying to unlock the car.",en)

exten => _X.,n(englishRetryUnlock),NoOp
exten => _X.,n,AGI(TeslaPSTN/TeslaPSTN.sh,5YJSA6H17EF111111,unlock)
exten => _X.,n,GotoIf($["${CMD}" = "success"]?englishUnlockSuccess:englishUnlockFailed)

exten => _X.,n(englishUnlockSuccess),NoOp
exten => _X.,n,AGI(googletts.agi,"Unlocking the car was successful. Enjoy your ride. Returning you to the menu now.",en)
exten => _X.,n,Goto(englishMenu)

exten => _X.,n(englishUnlockFailed),NoOp
exten => _X.,n,AGI(googletts.agi,"Please hold on, I am still trying to unlock the car.",en)
exten => _X.,n,Wait(5)
exten => _X.,n,Goto(englishRetryUnlock)

exten => _X.,n(englishLock),NoOp
exten => _X.,n,AGI(googletts.agi,"Thank you. One moment please. I am trying to lock the car.",en)

exten => _X.,n(englishRetryLock),NoOp
exten => _X.,n,AGI(TeslaPSTN/TeslaPSTN.sh,5YJSA6H17EF111111,lock)
exten => _X.,n,GotoIf($["${CMD}" = "success"]?englishLockSuccess:englishLockFailed)

exten => _X.,n(englishLockSuccess),NoOp
exten => _X.,n,AGI(googletts.agi,"Locking the car was successful. I hope you had a good ride. Returning you to the menu now.",en)
exten => _X.,n,Goto(englishMenu)

exten => _X.,n(englishLockFailed),NoOp
exten => _X.,n,AGI(googletts.agi,"Please hold on, I am still trying to lock the car.",en)
exten => _X.,n,Wait(5)
exten => _X.,n,Goto(englishRetryLock)


exten => _X.,n(german),NoOp
exten => _X.,n,Set(KEYPRESS=)
exten => _X.,n,AGI(googletts.agi,"Danke.",de)

exten => _X.,n(germanAgain),NoOp
exten => _X.,n,AGI(googletts.agi,"Bitte geben Sie nach dem Piepton Ihren PIN-Code ein.",de)
exten => _X.,n,Read(PIN,/var/lib/asterisk/sounds/en/beep,6,,,8)
exten => _X.,n,GotoIf($["${PIN}" = ""]?germanAgain:germanCheck)

exten => _X.,n(germanCheck),NoOp
exten => _X.,n,AGI(TeslaPSTN/TeslaPSTN.sh,checkpin,${PIN})
exten => _X.,n,GotoIf($["${CHECKPIN}" = "success"]?germanAuthOK:germanAuthIncorrect)

exten => _X.,n(germanAuthIncorrect),NoOp
exten => _X.,n,AGI(googletts.agi,"Sie haben den folgenden PIN-Code eingegeben",de)
exten => _X.,n,Set(CHANNEL(language)=de)
exten => _X.,n,SayDigits(${PIN})
exten => _X.,n,AGI(googletts.agi,"Dieser PIN-Code ist ungueltig. Bitte versuchen Sie es nach dem Piepton erneut.",de)
exten => _X.,n,Read(PIN,/var/lib/asterisk/sounds/en/beep,6,,,8)
exten => _X.,n,GotoIf($["${PIN}" = ""]?germanAgain:germanCheck)

exten => _X.,n(germanAuthOK),NoOp
exten => _X.,n,AGI(googletts.agi,"Autorisierung erfolgreich.",de)
exten => _X.,n(germanMenu),NoOp
exten => _X.,n,Set(KEYPRESS=)
exten => _X.,n,AGI(googletts.agi,"Druecken Sie die 1 um das Auto aufzuschliessen oder die 2 um das Auto abzuschliessen.",de,any)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "1"]?germanUnlock)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "2"]?germanLock)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "3"]?germanMenu)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "4"]?germanMenu)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "5"]?germanMenu)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "6"]?germanMenu)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "7"]?germanMenu)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "8"]?germanMenu)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "9"]?germanMenu)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "0"]?germanMenu)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "*"]?germanMenu)
exten => _X.,n,GotoIf($["${KEYPRESS}" = "#"]?germanMenu)
exten => _X.,n,GotoIf($["${KEYPRESS}" = ""]?germanMenu)

exten => _X.,n(germanUnlock),NoOp
exten => _X.,n,AGI(googletts.agi,"Danke. Einen Moment bitte. Ich versuche das Auto aufzuschliessen.",de)

exten => _X.,n(germanRetryUnlock),NoOp
exten => _X.,n,AGI(TeslaPSTN/TeslaPSTN.sh,5YJSA6H17EF111111,unlock)
exten => _X.,n,GotoIf($["${CMD}" = "success"]?germanUnlockSuccess:germanUnlockFailed)

exten => _X.,n(germanUnlockSuccess),NoOp
exten => _X.,n,AGI(googletts.agi,"Ich konnte das Auto erfolgreich aufschliessen. Ich wuensche Ihnen eine gute Fahrt. Ich bringe Sie zurueck ins Hauptmenue.",de)
exten => _X.,n,Goto(germanMenu)

exten => _X.,n(germanUnlockFailed),NoOp
exten => _X.,n,AGI(googletts.agi,"Bitte noch einen Moment Geduld, ich versuche immer noch das Auto aufzuschliessen.",de)
exten => _X.,n,Wait(5)
exten => _X.,n,Goto(germanRetryUnlock)

exten => _X.,n(germanLock),NoOp
exten => _X.,n,AGI(googletts.agi,"Danke. Einen Moment bitte. Ich versuche das Auto abzuschliessen.",de)

exten => _X.,n(germanRetryLock),NoOp
exten => _X.,n,AGI(TeslaPSTN/TeslaPSTN.sh,5YJSA6H17EF111111,lock)
exten => _X.,n,GotoIf($["${CMD}" = "success"]?germanLockSuccess:germanLockFailed)

exten => _X.,n(germanLockSuccess),NoOp
exten => _X.,n,AGI(googletts.agi,"Ich konnte das Auto erfolgreich abschliessen. Ich hoffe Sie hatten eine gute Fahrt. Ich bringe Sie zurueck ins Hauptmenue.",de)
exten => _X.,n,Goto(germanMenu)

exten => _X.,n(germanLockFailed),NoOp
exten => _X.,n,AGI(googletts.agi,"Bitte noch einen Moment Geduld, ich versuche immer noch das Auto abzuschliessen.",de)
exten => _X.,n,Wait(5)
exten => _X.,n,Goto(germanRetryLock)