marcone/teslausb

Custom car lock sound

KrzysztofHajdamowicz opened this issue · 18 comments

Describe the problem

2023 Holiday Update in Tesla firmware allows to change default "Honk on car close" sound to custom lock sound.
To do that, user have to put LockChime.wav file in / of any USB drive inserted to the car.
File have to be smaller than 1MiB.

Idea: add file upload form into web interface so file can be uploaded without detaching TeslaUSB from car.

Device

Raspberry Pi 4

OS Image

Prebuilt TeslaUSB image

Car Model

Model Y

USB connection

Glove box

Logs

No response

Additional information

No response

Further idea: allow uploading multiple, and scheduling different sounds either every x minutes or using the time of day (I don’t want a screaming goat waking my neighbours at 1am)

You can do this by just copying LockChime.wav to music sync folder. Just tried it and it works!

Yes and the Custom Light shows can be added in this way to the music folder under LightShow. Works a treat.

I created something that I can run on crontab every hour or so, to randomize a WAV file for the next time it locks. I'm sure it can be refined, but here's a rough idea:

#!/bin/bash -eu

# Mount /mnt/music
mount /mnt/music || :

# Set the source and destination folders
source_folder="/mnt/music/"
destination_file="/mnt/music/LockChime.wav"
curr_dir=$(pwd)

# Change to the source folder
cd "$source_folder" || exit

# Find all .wav files except LockChime.wav
files=($(find . -maxdepth 1 -type f -name "*.wav" ! -name "LockChime.wav"))

# Check if there are any eligible files
if [ ${#files[@]} -eq 0 ]; then
    echo "No eligible files found in $source_folder."
    exit 1
fi

# Get the total number of files
num_files=${#files[@]}

# Generate a random index
random_index=$((RANDOM % num_files))

# Choose a random file from the list
random_file=${files[random_index]}

# Copy the chosen file to the destination, overwriting the existing LockChime.wav
cp -f "$random_file" "$destination_file"

echo "Random file '$random_file' copied to '$destination_file'."

#
cd "$curr_dir"

# Unmount /mnt/music
umount /mnt/music || :

# Refresh USB gadget
/root/bin/disable_gadget.sh || :
/root/bin/enable_gadget.sh || :

@marcone - I'm sure the script above can be improved, but it generally works. A few bugs sometimes, because (I think) the mount/unmount operations are too quick and kind of cut-off the file operations.

I'm sure that you, as the author, will know of more elegant ways to perform (and wait for completion of) those operations.

But, I hope it can be a neat little addition!

The cause of the errors you're seeing script probably isn't that something is too quick, but that it is modifying the music drive while it is still connected to the car. In other words, the car would see disk sectors change out from under it, as if the drive is failing or corrupt.
The script needs to call disable_gadget.sh first, then mount the drive on the Pi, modify it, unmount it, and finally call enable_gadget.sh to reconnect the updated drive to the car.

I had the disable gadget at the top, but moving to the bottom kind of worked, too. Do you think you can "salvage" the script to make it into something official? Am I in the right track?

Another question, is it safe to run that script at boot time, or is there a routine that has to be awaited on?

I noticed the crontabs are wiped on reboot lol - any other way to have this run at boot?

I suppose the proper way to run it at boot would be to make it a systemd service, like TeslaUSB itself. If you make it so it runs before TeslaUSB, then you don't need to call disable_gadget/enable_gadget either.

You can do this by just copying LockChime.wav to music sync folder. Just tried it and it works!

Works only for the first time. It does not overwrite existing LockChime.wav unfortunately
@marcone any way to detect that it's a different file and overwrite?

any way to detect that it's a different file and overwrite?

It should already detect this based on the file date.

any way to detect that it's a different file and overwrite?

It should already detect this based on the file date.

Problem is that the file I want to copy is created/modified earlier than the file that already exists on the TeslaUSB
This is done because of -u option:

-u, --update
This forces rsync to skip any files which exist on the destination and have a modified time that is newer than the source file. (If an existing destination file has a modification time equal to the source file's, it will be updated if the sizes are different.)

Might want to add -t option to preserve original file dates.

The web interface now has a music browser that supports uploading files to it, and a way to copy any .wav file to LockChime.wav, so you can copy a bunch of lock sounds to your music drive, then right-click any one of them in the web interface to mark them as the current lock sound.
Not sure how this interacts with actual USB music playback in the car though.

In case anyone else is looking for the "random" functionality where you can drop a bunch of wav files in a folder and forget about it, you can indeed install systemd service which will persist reboot to achieve this functionality. The way I set it up is to use a subdirectory in the autosync music folder tied to a systemd service that is enabled to auto run and then set the script posted above in a loop. Really rough details here:

systemd service (install in /etc/systemd/system directory):

[Unit]
Description=This service randomizes lockchimes

[Service]
User=root
WorkingDirectory=/home/pi/
ExecStart=/home/pi/CronLockChime.sh
Restart=always
RestartSec=60

[Install]
WantedBy=multi-user.target

Script:
Remember to add execute perms (chmod +x):

#!/bin/bash -eu

while true
do

# Set the source and destination folders
source_folder="/var/www/html/fs/Music/LockChimes/"
destination_file="/var/www/html/fs/Music/LockChime.wav"
curr_dir=$(pwd)

# Change to the source folder
cd "$source_folder" || exit

# Find all .wav files except LockChime.wav
files=($(find . -maxdepth 1 -type f -name "*.wav" ! -name "LockChime.wav"))

# Check if there are any eligible files
if [ ${#files[@]} -eq 0 ]; then
    echo "No eligible files found in $source_folder."
    exit 1
fi

# Get the total number of files
num_files=${#files[@]}

# Generate a random index
random_index=$((RANDOM % num_files))

# Choose a random file from the list
random_file=${files[random_index]}

# Copy the chosen file to the destination, overwriting the existing LockChime.wav
cp -f "$random_file" "$destination_file"

echo "Random file '$random_file' copied to '$destination_file'."

#
cd "$curr_dir"

sleep 60
done

Then the one-time commands to get it going:

sudo -i /root/bin/remountfs_rw
sudo systemctl daemon-reload
sudo systemctl start lockchime.service
sudo systemctl enable lockchime.service

Note that that script will briefly remove the USB drive(s) from the car every minute, which will likely interrupt dashcam, sentry and music playback. The script also modifies the music drive while it is visible to the car, which to the car could look like disk corruption.

Since the car takes care of the lockchime automatically when you exit and the intent is randomization it probably is good enough to just let the script overwrite the file and stop there without any dynamic reloading that Helvio originally put in the script. That way on the "next" exit/reboot of the teslausb it will play the new chime. I've removed the umount / disable/enable part of the script above so that the only thing that remains is the random logic & copy paste of the file. This should eliminate the risks Marcone mentioned above.

Marcone - is there any method or existing script that detects if the car has been parked/idle for x amount of time? The randomization I posted above works but it will "stick with" a song until the drive goes offline (as the filesystem isn't remounted). With sentry mode and other things keeping the car awake, the randomization changes don't happen as frequently as I would like (maybe once a day). Wondering if I could add logic to detect car has been parked/idle for let's say 30m, force a disconnect reconnect once in that situation.