### TeslaUSB Setup and Management Commands Source: https://context7.com/marcone/teslausb/llms.txt These commands are used for initial setup, upgrading, installing specific features, and running diagnostics for TeslaUSB. Ensure you have the correct configuration file loaded for setup. ```bash sudo /root/bin/setup-teslausb ``` ```bash sudo /root/bin/setup-teslausb upgrade ``` ```bash sudo /root/bin/setup-teslausb install run/archiveloop ``` ```bash sudo /root/bin/setup-teslausb diagnose ``` -------------------------------- ### Install TeslaUSB Script Source: https://github.com/marcone/teslausb/wiki/Orange-Pi-Zero-3-Installation Download and execute the TeslaUSB installation script from GitHub. This script automates the setup process. ```bash curl https://raw.githubusercontent.com/marcone/teslausb/main-dev/setup/generic/install.sh | bash ``` -------------------------------- ### Monitor TeslaUSB Setup Log Source: https://github.com/marcone/teslausb/wiki/Installation If the device reboots during setup, use this command to log in again and follow the setup progress by tailing the log file. ```bash tail -f /teslausb/teslausb-headless-setup.log ``` -------------------------------- ### Example rsync Configuration Source: https://github.com/marcone/teslausb/blob/main-dev/doc/SetupRSync.md An example demonstrating how to set the rsync environment variables with specific user, server, and path details. ```bash export ARCHIVE_SYSTEM=rsync export RSYNC_USER=pi export RSYNC_SERVER=192.168.1.254 export RSYNC_PATH=/mnt/PIHDD/TeslaCam/ ``` -------------------------------- ### Setup Script for TeslaUSB Source: https://context7.com/marcone/teslausb/llms.txt The main setup script for TeslaUSB, which orchestrates the full installation and provides maintenance sub-commands. This script must be run as root. ```bash #!/bin/bash # setup-teslausb # The main idempotent setup script for TeslaUSB. # Must be run as root. # ... (rest of the script) ``` -------------------------------- ### Install TeslaUSB on Raspberry Pi OS Source: https://context7.com/marcone/teslausb/llms.txt Run this script as root on a fresh Raspberry Pi OS Lite or Armbian image to bootstrap the TeslaUSB setup. After running, edit the configuration file and rerun to complete the setup. Monitor progress using tail. ```bash sudo -i apt update && apt install -y curl curl https://raw.githubusercontent.com/marcone/teslausb/main-dev/setup/generic/install.sh | bash # Edit the generated config, then rerun to complete setup: nano /teslausb/teslausb_setup_variables.conf /etc/rc.local # Monitor progress: tail -f /teslausb/teslausb-headless-setup.log ``` -------------------------------- ### Execute TeslaUSB Setup Script Source: https://github.com/marcone/teslausb/wiki/Orange-Pi-Zero-3-Installation Run the local TeslaUSB setup script after configuring the variables. This initiates the main setup process. ```bash /etc/rc.local ``` -------------------------------- ### Install Text Editors Source: https://github.com/marcone/teslausb/wiki/Rock-Pi-4C-plus-Installation Installs common text editors like nano and vim for file editing. Choose your preferred editor. ```bash apt-get install nano vim ``` -------------------------------- ### Rerun Headless Setup Script Source: https://github.com/marcone/teslausb/wiki/Troubleshooting If you cannot SSH into the device, try rerunning the headless setup script to potentially log more useful messages. This command is useful when the `/teslausb/teslausb-headless-setup.log` file does not end with 'All done.' ```bash sudo /etc/rc.local ``` -------------------------------- ### Install libsensor for CPU Temperature Source: https://github.com/marcone/teslausb/wiki/Rock-Pi-4C-plus-Installation Installs the libsensor package to enable CPU temperature monitoring. Run this after updating package lists. ```bash apt-get update && apt-get install libsensors5 ``` -------------------------------- ### Install TeslaUSB Script Source: https://github.com/marcone/teslausb/wiki/Installation Run these commands to update package lists, install curl, and download/execute the TeslaUSB installation script. Ensure your device has internet access before running. ```bash sudo -i apt update apt install curl curl https://raw.githubusercontent.com/marcone/teslausb/main-dev/setup/generic/install.sh | bash ``` -------------------------------- ### Install Rclone Source: https://github.com/marcone/teslausb/blob/main-dev/doc/SetupRClone.md Installs rclone using a curl command piped to bash. This is a prerequisite for configuring rclone. ```bash curl https://rclone.org/install.sh | sudo bash ``` -------------------------------- ### Install TeslaUSB Script (Skip Root Shrink) Source: https://github.com/marcone/teslausb/wiki/Installation Use this command to install TeslaUSB and skip shrinking the root partition of the SD card, which is useful when configuring TeslaUSB with a separate data drive. ```bash curl https://raw.githubusercontent.com/marcone/teslausb/main-dev/setup/generic/install.sh | bash -s norootshrink ``` -------------------------------- ### Configure Network Interfaces (Alternative Method) Source: https://github.com/marcone/teslausb/wiki/Setting-up-External-Wi‐Fi-Adapter-for-Archiving Replace 'ap0' with 'wlan0' in the network interfaces file for an alternative setup. This method configures 'wlan0' as a static interface with hostapd support. ```config source-directory /etc/network/interfaces.d auto lo auto wlan0 iface lo inet loopback allow-hotplug wlan0 iface wlan0 inet static address 192.168.66.1 netmask 255.255.255.0 hostapd /etc/hostapd/hostapd.conf ``` -------------------------------- ### Edit TeslaUSB Configuration Source: https://github.com/marcone/teslausb/wiki/Orange-Pi-Zero-3-Installation Modify the TeslaUSB setup variables configuration file using the nano editor. This file contains essential settings for the TeslaUSB installation. ```bash nano /teslausb/teslausb_setup_variables.conf ``` -------------------------------- ### Configure Dhcpcd for wlan0 (Alternative Method) Source: https://github.com/marcone/teslausb/wiki/Setting-up-External-Wi‐Fi-Adapter-for-Archiving In the alternative setup, update dhcpcd configuration to use 'wlan0' and disable the wpa_supplicant hook. This ensures proper network configuration for the wlan0 interface. ```config interface wlan0 nohook wpa_supplicant ``` -------------------------------- ### Resize Observer Setup Source: https://github.com/marcone/teslausb/blob/main-dev/teslausb-www/html/index.html Sets up ResizeObserver to monitor the size of the sentry map and tickmark canvas. When a resize event occurs, it calls a specific handler function on the observed element, likely to adjust UI elements or redraw content. ```javascript var ro = new ResizeObserver(entries => { log(entries); for (var entry of entries) { entry.target.resizeHandler(); } }); var m = document.getElementById('sentrymap'); m.resizeHandler = function() { if (currentsequence != undefined) { currentsequence.onMapResize(); } } ro.observe(m); var t = document.getElementById('tickmarkscanvas'); t.resizeHandler = function () { if (currentsequence != undefined) { currentsequence.onTickResize(); } } ro.observe(t); ``` -------------------------------- ### Local Storage Management (JavaScript) Source: https://github.com/marcone/teslausb/blob/main-dev/teslausb-www/html/index.html Provides functions to safely get and set items in the browser's local storage, with error handling. ```javascript function localStorageGet(name) { try { return localStorage.getItem(name); } catch (error) { log(error); } } ``` ```javascript function localStorageSet(name, value) { try { localStorage.setItem(name, value); } catch (error) { log(error); } } ``` -------------------------------- ### Inspect Partition Layout Source: https://context7.com/marcone/teslausb/llms.txt This command inspects the partition layout of a disk image file. It's called internally during setup to verify the structure of the created disk images. ```bash parted -s /backingfiles/cam_disk.bin print ``` -------------------------------- ### Remount Filesystem as Read-Write Source: https://context7.com/marcone/teslausb/llms.txt Execute the `remountfs_rw` command to remount the read-only root filesystem as read-write, allowing for manual file edits and package installations. The filesystem returns to read-only on the next reboot. ```bash /root/bin/remountfs_rw # Now safe to edit files, install packages, etc. # Root returns to read-only on next reboot. ``` -------------------------------- ### Initialize UI and Event Handlers Source: https://github.com/marcone/teslausb/blob/main-dev/teslausb-www/html/index.html Sets up the initial state of the UI, including loading log files and attaching event listeners to buttons and window interactions for settings. ```javascript function init() { readfile({pre:'setuplogpre', url:'teslausb-headless-setup.log', tail:true, button:'aldwnbtn'}); readfile({pre:'setuplogpre', url:'teslausb-headless-setup.log', tail:true, button:'sudwnbtn'}); showstatus(); refreshdiagnostics(); var settingsbtn = document.querySelector('.settingsbutton'); settingsbtn.onclick = showsettings; var closebutton = document.querySelector('.closebutton'); closebutton.onclick = closesettings; window.onclick = function(event) { var overlay = document.getElementById("settingsoverlay"); if (event.target == overlay) { overlay.style.display = "none"; } } } ``` -------------------------------- ### Read Configuration and Video List Source: https://github.com/marcone/teslausb/blob/main-dev/teslausb-www/html/index.html Reads configuration and then fetches the video list from the server. Initializes video data and UI elements based on the response. ```javascript readconfig(); readfile({ url:'cgi-bin/videolist.sh', callback:function(value) { var newest="0-"; var newestsequence; var lines = value.split('\n'); var haspillarviews = false; for (line of lines) { var [group, sequencename, filename] = line.split('/'); if (sequencename == undefined) { continue; } if (filename.includes("~")) { /* skip fsck recovered files for now */ continue; } if (filename.includes("_pillar.mp4")) { haspillarviews = true; } if (sequencename.includes("json")) { /* this shouldn't be necessary, and can be removed once teslausb no longer creates an "event.json" folder */ continue; } if (!videos.hasOwnProperty(group)) { videos[group]={}; } var sequence; if (videos[group].hasOwnProperty(sequencename)) { sequence=videos[group][sequencename]; } else { sequence=new VideoSequence(group, sequencename); videos[group][sequencename]=sequence; } if (filename != "event.mp4" && filename.includes(".mp4")) { videotime=filename.substring(0, 19); segment=sequence.getSegmentByName(videotime); segment.addVideo(filename); if (sequencename > newest) { newest = sequencename; newestsequence=sequence; } } else if (filename.includes("thumb")) { sequence.thumb=filename; } else if (filename.includes("json")) { var jsonpath = group + "/" + sequencename + "/" + filename; sequence.jsonfile[0] = jso ``` -------------------------------- ### Snapshot System (`run/make_snapshot.sh`) Source: https://context7.com/marcone/teslausb/llms.txt Creates copy-on-write snapshots of the cam disk image using `cp --reflink=always`. Each snapshot is independently mountable and tracked by a `.toc` file. ```APIDOC ## Snapshot System (`run/make_snapshot.sh`) Creates copy-on-write snapshots of the cam disk image using `cp --reflink=always`. Each snapshot is independently mountable and tracked by a `.toc` (table of contents) file listing all clip filenames and sizes. Symlinks in `/mutable/TeslaCam/` point into the latest snapshot's mount, giving the archive loop a unified view of all footage across snapshots without mounting them all simultaneously. ### Usage ```bash # Take a snapshot manually (with fsck): /root/bin/make_snapshot.sh # Take a snapshot without fsck (faster, used mid-session): /root/bin/make_snapshot.sh nofsck # Inspect snapshots: ls -la /backingfiles/snapshots/ # drwxr-xr-x snap-000000/ ← oldest # drwxr-xr-x snap-000001/ # drwxr-xr-x snap-000002/ ← newest ls /backingfiles/snapshots/snap-000002/ # snap.bin ← the copy-on-write disk image # snap.bin.toc ← file list (present = snapshot complete) # mnt -> /tmp/snapshots/snap-000002 ← autofs-mounted symlink # Release (unmount + allow deletion) of a snapshot: /root/bin/release_snapshot.sh /backingfiles/snapshots/snap-000000 ``` ``` -------------------------------- ### Confirm Settings and Redirect Source: https://github.com/marcone/teslausb/blob/main-dev/teslausb-www/html/index.html Saves the 'usealtui' setting to local storage and redirects to the new interface if enabled. Includes a placeholder for a non-existent function call. ```javascript function confirmsettings() { var usealtui = document.getElementById('altui').checked; localStorageSet("usealtui", usealtui); if (usealtui) { document.location.replace('/new/?source=legacy'); nonExistentFunction(); } closesettings(); } ``` -------------------------------- ### Minimal TeslaUSB Configuration for Prebuilt Image Source: https://context7.com/marcone/teslausb/llms.txt This minimal configuration is required when using a prebuilt image. Place this file in the boot partition before the first boot. It includes essential network and archiving settings. ```bash # Minimal required config (CIFS/SMB archiving example): export SSID='MyHomeWifi' export WIFIPASS='wifipassword' export ARCHIVE_SYSTEM=cifs export ARCHIVE_SERVER=192.168.1.100 export SHARE_NAME='Backups/TeslaCam' export SHARE_USER=myuser export SHARE_PASSWORD='mypassword' export CAM_SIZE=40G ``` -------------------------------- ### Get Video Error Message Source: https://github.com/marcone/teslausb/blob/main-dev/teslausb-www/html/index.html Returns a string describing the error of a video element, or 'unknown' if the element is invalid or has no error. ```javascript function videoError(elem) { if (elem == null || elem == undefined || elem.nodeName != 'VIDEO' || elem.error == null || elem.error == undefined) { return "unknown"; } return elem.error.message; } ``` -------------------------------- ### Read Configuration File Source: https://github.com/marcone/teslausb/blob/main-dev/teslausb-www/html/index.html Reads the configuration file asynchronously and parses it as JSON. It then updates the UI based on configuration options like 'has_music', 'has_lightshow', 'has_boombox', and 'uses_ble'. ```javascript function readconfig() { readfile({url:'cgi-bin/config.sh', callback:function(value) { config = JSON.parse(value); const filestab = document.querySelector(".tablabel6"); var numdrives = 0; if (config.has_music == "yes") numdrives++; if (config.has_lightshow == "yes") numdrives++; if (config.has_boombox == "yes") numdrives++; if (numdrives == 1) { var filestabname = "Music" if (config.has_lightshow == "yes") filestabname = "LightShow"; if (config.has_boombox == "yes") filestabname = "Boombox"; filestab.innerText = filestabname; } if (numdrives > 0 && filestab.style.display == "") { filestab.style.display = "inline-block"; const fb = document.querySelector("#filebrowser"); new FileBrowser(fb, [ ...config.has_music == "yes" ? [{ path: "fs/Music", label: "Music" }] : [], ...config.has_lightshow == "yes" ? [{ path: "fs/LightShow", label: "LightShow" }] : [], ...config.has_boombox == "yes" ? [{ path: "fs/Boombox", label: "Boombox" }] : [] ]); } if (config.has_cam == "yes") { const recordingstab = document.querySelector(".tablabel5"); const viewertab = document.querySelector(".tablabel7"); recordingstab.style.display = "inline-block"; viewertab.style.display = "inline-block"; } else if (numdrives > 0) { const filesbtn = document.querySelector("#tab6"); filesbtn.checked = true; } else { const toolsbtn = document.querySelector("#tab4"); toolsbtn.checked = true; } const blebtn = document.getElementById("pairingdiv"); if (config.uses_ble == "yes") { blebtn.style.display = "block"; } else { blebtn.style.display = "none"; } }}); } ``` -------------------------------- ### Play Video Segment Source: https://github.com/marcone/teslausb/blob/main-dev/teslausb-www/html/index.html Starts playing the current video segment. Sets the `isplaying` flag and updates the play/pause button to a pause icon. ```javascript play() { log("play: " + this.currentsegmentidx); this.isplaying = true; var segment = this.getSegmentByIndex(this.currentsegmentidx); segment.play(); var b = document.getElementById('playpause'); b.classList.add("pause"); if (isFirefox || isWebkit) { b.firstElementChild.firstChild.setAttribute('d', 'M 8,30 14,30 14,6 8,6 z M 24,30 30,30 30,6 24,6 z'); } } ``` -------------------------------- ### Configure CIFS (SMB/Windows Share) Archive Backend Source: https://context7.com/marcone/teslausb/llms.txt Sets environment variables for connecting to a Windows share as an archive backend. Requires server IP/hostname, share name, and user credentials. ```bash # teslausb_setup_variables.conf export ARCHIVE_SYSTEM=cifs export ARCHIVE_SERVER=192.168.1.100 # IP or hostname export SHARE_NAME='NAS/TeslaCam' # Share path export SHARE_USER=teslausb export SHARE_PASSWORD='s3cr3t' # Optional: fix negotiation issues # export CIFS_VERSION="3.0" # export CIFS_SEC="ntlmssp" export MUSIC_SHARE_NAME='NAS/Music' # Sync music from here too ``` -------------------------------- ### Remount Filesystems Read-Write Source: https://github.com/marcone/teslausb/blob/main-dev/doc/SetupRClone.md Remounts the Raspberry Pi's filesystems in read-write mode, which is necessary before making system changes like installing rclone. ```bash sudo -i /root/bin/remountfs_rw ``` -------------------------------- ### Initialize Application Source: https://github.com/marcone/teslausb/blob/main-dev/teslausb-www/html/index.html Sets the inner HTML of the 'No recordings' element and calls the main initialization function. ```javascript nr.innerHTML = "No recordings"; initialize(); ``` -------------------------------- ### UI State Management (JavaScript) Source: https://github.com/marcone/teslausb/blob/main-dev/teslausb-www/html/index.html Handles switching between the default and alternative UI based on referrer and local storage settings. Redirects to the new UI if configured. ```javascript if (document.referrer.includes("/new/")) { /* user switched back from the Vue UI */ localStorageSet("usealtui", "false"); } else { if (localStorageGet("usealtui") == "true") { document.location.replace('/new/?source=legacy'); nonExistentFunction(); } } ``` -------------------------------- ### Show Settings Overlay Source: https://github.com/marcone/teslausb/blob/main-dev/teslausb-www/html/index.html Displays the settings overlay and updates the 'usealtui' checkbox based on local storage. ```javascript function showsettings() { var altui = document.getElementById('altui'); altui.checked = (localStorageGet("usealtui") == "true"); var overlay = document.getElementById("settingsoverlay"); overlay.style.display = "block"; } ``` -------------------------------- ### Get System Status via CGI Endpoint Source: https://context7.com/marcone/teslausb/llms.txt Retrieves system status information in JSON format from the `/cgi-bin/status.sh` endpoint. Useful for monitoring TeslaUSB's operational state. ```bash curl http://teslausb.local/cgi-bin/status.sh # { # "cpu_temp": "42000", # "fan_speed": "N/A", # "throttled": "0x0", # "num_snapshots": "3", # "snapshot_oldest": "1737168600", # "snapshot_newest": "1737175800", # "total_space": "42949672960", # "free_space": "18253611008", # "uptime": "3721.45", # "drives_active": "yes", # "wifi_ssid": "MyHomeWifi", # "wifi_freq": "5.18", # "wifi_strength": "68/70", # "wifi_ip": "192.168.1.42", # "ether_ip": "", # "ether_speed": "" # } ``` -------------------------------- ### Configure Rclone Remote Source: https://github.com/marcone/teslausb/blob/main-dev/doc/SetupRClone.md Launches the interactive rclone configuration process. Follow the on-screen prompts to set up a remote storage service. ```bash rclone config ``` -------------------------------- ### Configure Dnsmasq for Network Interfaces Source: https://github.com/marcone/teslausb/wiki/Setting-up-External-Wi‐Fi-Adapter-for-Archiving Modify dnsmasq configuration to specify active network interfaces and DHCP ranges. This setup excludes the external Wi-Fi interface from DHCP and binds to specific interfaces. ```config interface=lo,wlan0 no-dhcp-interface=lo,wlan1 #bind-interfaces bogus-priv dhcp-range=192.168.66.100,192.168.66.150,12h # don't configure a default route, we're not a router dhcp-option=3 ``` -------------------------------- ### Configure Hostname for TeslaUSB Source: https://context7.com/marcone/teslausb/llms.txt Set the TESLAUSB_HOSTNAME variable in the setup configuration file to define the hostname for mDNS discovery and notifications. The device then becomes reachable via SSH and its Web UI using this hostname. ```bash export TESLAUSB_HOSTNAME=teslausb-model3 ``` ```bash ssh pi@teslausb-model3.local ``` ```bash http://teslausb-model3.local ``` -------------------------------- ### Configure rclone (Cloud Storage) Archive Backend Source: https://context7.com/marcone/teslausb/llms.txt Sets environment variables for using rclone to archive to cloud storage. Requires a configured rclone remote name and path. rclone must be configured separately. ```bash export ARCHIVE_SYSTEM=rclone export RCLONE_DRIVE="gdrive" # Name of configured rclone remote export RCLONE_PATH="TeslaCam/Model3" export RCLONE_FLAGS=('--transfers=4' '--drive-chunk-size=128M') # Configure rclone first (stored in /mutable/.config/rclone/rclone.conf): rclone config ``` -------------------------------- ### Manual WiFi Configuration Source: https://github.com/marcone/teslausb/blob/main-dev/doc/OneStepSetup.md As a last resort for WiFi issues, copy this sample configuration file and manually edit the TEMP variables to your desired WiFi settings. ```ini /boot/wpa_supplicant.conf.sample ``` -------------------------------- ### Free Space Manager (`run/manage_free_space.sh`) Source: https://context7.com/marcone/teslausb/llms.txt Maintains a minimum free space buffer on the backing store partition by deleting the oldest snapshots first. The target reserve is 10 GB plus 3% of total cam disk capacity. ```APIDOC ## Free Space Manager (`run/manage_free_space.sh`) Maintains a minimum free space buffer on the backing store partition by deleting the oldest snapshots first. The target reserve is 10 GB plus 3% of total cam disk capacity. ### Usage ```bash # Called automatically by archiveloop's freespacemanager background process. # Can be invoked manually with a custom reserve in bytes: /root/bin/manage_free_space.sh 21474836480 # 20 GB reserve # The freespacemanager loop in archiveloop: # Checks every 30 seconds; deletes oldest snap-XXXXXX if free < reserve. # Log output example: # Sat Jan 18 03:10:01 UTC 2025: low space, deleting /backingfiles/snapshots/snap-000000 ``` ``` -------------------------------- ### Enable USB Gadget Layer Source: https://context7.com/marcone/teslausb/llms.txt Activates the USB mass-storage gadget, registering disk images as LUNs. Verify the UDC binding and check LUN assignments to confirm the car can see the drives. ```bash /root/bin/enable_gadget.sh ``` ```bash cat /sys/kernel/config/usb_gadget/teslausb/UDC ``` ```bash for i in 0 1 2 3; do f="/sys/kernel/config/usb_gadget/teslausb/functions/mass_storage.0/lun.${i}/file" [ -e "$f" ] && echo "LUN$i: $(cat $f)" done ``` -------------------------------- ### Configure DietPi Environment for USB OTG Source: https://github.com/marcone/teslausb/wiki/Rock-4c-Plus-DietPi-Install-with-external-Drive Add or update these lines in `/boot/dietpiEnv.txt` to configure the Rock Pi 4C+ for USB OTG peripheral mode. ```bash overlay_prefix=rockchip overlays=dwc3 user_overlays=rk3399-dwc3-0-peripheral param_dwcore.dr_mode=peripheral ``` -------------------------------- ### Configure Network Interface with nmtui Source: https://github.com/marcone/teslausb/wiki/Orange-Pi-Zero-3-Installation Use the NetworkManager Text User Interface (nmtui) to configure network settings, particularly Wi-Fi. ```bash nmtui ``` -------------------------------- ### Configure Temperature Monitoring Thresholds Source: https://context7.com/marcone/teslausb/llms.txt Set environment variables in `teslausb_setup_variables.conf` to define temperature thresholds for push notifications and logging intervals. Values are in milli-degrees Celsius. ```bash # teslausb_setup_variables.conf (values in milli-°C): export TEMPERATURE_WARNING=68000 # 68°C → push notification export TEMPERATURE_CAUTION=55000 # 55°C → push notification export TEMPERATURE_INTERVAL=60 # Log temp every 60 minutes (no push) export TEMPERATURE_POSTARCHIVE=true # Always log after each archive cycle # Check current temperature (milli-°C): cat /sys/class/thermal/thermal_zone0/temp # 47234 → 47.2°C ``` -------------------------------- ### Configure and Test Push Notifications Source: https://context7.com/marcone/teslausb/llms.txt Set environment variables to enable and configure various push notification services like Pushover, Telegram, Discord, ntfy, Slack, and generic webhooks. A test can be performed manually. ```bash # Called by archiveloop with: send-push-message "TITLE" "MESSAGE" [start|finish] # Pushover export PUSHOVER_ENABLED=true export PUSHOVER_USER_KEY=uXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX export PUSHOVER_APP_KEY=aXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # Telegram export TELEGRAM_ENABLED=true export TELEGRAM_CHAT_ID=123456789 export TELEGRAM_BOT_TOKEN=bot123456789:AbCdEfGhIjKlMnOpQrStUvWxYz export TELEGRAM_SILENT_NOTIFY=false # Discord webhook export DISCORD_ENABLED=true export DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/XXXXX/YYYYY # ntfy (self-hosted or ntfy.sh) export NTFY_ENABLED=true export NTFY_URL=https://ntfy.sh/my-teslausb-topic export NTFY_PRIORITY=3 # Slack export SLACK_ENABLED=true export SLACK_WEBHOOK_URL=https://hooks.slack.com/services/T.../B.../... # Generic webhook (Home Assistant, Node-RED, etc.) export WEBHOOK_ENABLED=true export WEBHOOK_URL=http://homeassistant.local:8123/api/webhook/teslausb # Test manually: source /root/bin/envsetup.sh /root/bin/send-push-message "TeslaUSB" "Test notification" finish ``` -------------------------------- ### Become Root User Source: https://github.com/marcone/teslausb/wiki/Orange-Pi-Zero-3-Installation Switch to the root user to execute administrative commands. ```bash sudo -i ``` -------------------------------- ### Configure Car Awake Methods Source: https://context7.com/marcone/teslausb/llms.txt Set environment variables to configure methods for keeping the car awake during archiving. Choose one SENTRY_CASE and configure specific services like TeslaFi, Tessie, BLE, or Webhook. ```bash # Choose one SENTRY_CASE: # 1 = Sentry always ON; TeslaUSB turns it off when done # 2 = Sentry only ON during archiving # 3 = Periodic "nudge" (no Sentry; Tessie/BLE/Webhook only) export SENTRY_CASE=2 # TeslaFi (Cases 1 or 2 only): export TESLAFI_API_TOKEN='your_teslafi_token' # Tessie: export TESSIE_API_TOKEN='your_tessie_token' export TESSIE_VIN=5YJ3E1EA4JF000001 # BLE (direct, no third-party service): export TESLA_BLE_VIN=5YJ3E1EA4JF000001 # One-time pairing from SSH: sudo /root/bin/tesla-control -ble -vin 5YJ3E1EA4JF000001 \ add-key-request /root/.ble/key_public.pem owner cloud_key # Then tap a key card on the center console when prompted in the car. # Webhook (Home Assistant, etc.): export KEEP_AWAKE_WEBHOOK_URL=http://homeassistant.local:8123/api/webhook/wake_tesla # Payload shape: { "awake_command": "start" | "stop" | "nudge" } ``` -------------------------------- ### Configure NFS Archive Backend Source: https://context7.com/marcone/teslausb/llms.txt Sets environment variables for connecting to an NFS share. Requires the server's hostname or IP and the exact NFS export path. ```bash export ARCHIVE_SYSTEM=nfs export ARCHIVE_SERVER=nas.local export SHARE_NAME='/volume1/TeslaCam' # Must be the exact NFS export path ``` -------------------------------- ### List Available Rclone Remotes Source: https://github.com/marcone/teslausb/blob/main-dev/doc/SetupRClone.md Run this command to verify that your remote drive has been successfully created and is recognized by rclone. If the remote is not listed, re-run the rclone configuration. ```bash rclone listremotes ``` -------------------------------- ### Create and Manage Snapshots of Cam Disk Image Source: https://context7.com/marcone/teslausb/llms.txt Creates copy-on-write snapshots of the cam disk image for independent mounting and tracking. Snapshots are managed via a .toc file and symlinks for unified access. ```bash # Take a snapshot manually (with fsck): /root/bin/make_snapshot.sh # Take a snapshot without fsck (faster, used mid-session): /root/bin/make_snapshot.sh nofsck # Inspect snapshots: ls -la /backingfiles/snapshots/ # drwxr-xr-x snap-000000/ ← oldest # drwxr-xr-x snap-000001/ # drwxr-xr-x snap-000002/ ← newest ls /backingfiles/snapshots/snap-000002/ # snap.bin ← the copy-on-write disk image # snap.bin.toc ← file list (present = snapshot complete) # mnt -> /tmp/snapshots/snap-000002 ← autofs-mounted symlink # Release (unmount + allow deletion) of a snapshot: /root/bin/release_snapshot.sh /backingfiles/snapshots/snap-000000 ``` -------------------------------- ### VideoSegment Class Initialization Source: https://github.com/marcone/teslausb/blob/main-dev/teslausb-www/html/index.html Initializes a VideoSegment object, setting default properties and binding event handler methods. ```javascript class VideoSegment { group; sequence; front; leftrepeater; rightrepeater; leftpillar; rightpillar; back; datetime; numangles; activevideoelems = []; longestvideoelem; readytoplay; autoplay; autoseek; timestampMs; constructor(group, sequence) { this.group = group; // RecentClips, SavedClips or SentryClips this.sequence = sequence; this.numangles = 0; this.onDurationChange = this.onDurationChange.bind(this); this.onScanError = this.onScanError.bind(this); this.onTimeUpdate = this.onTimeUpdate.bind(this); this.onVideoEnded = this.onVideoEnded.bind(this); this.onVideoError = this.onVideoError.bind(this); this.onDblClickVideo = this.onDblClickVideo.bind(this); this.initdefaults(); } initdefaults() { this.activevideoelems = []; this.longestvideoelem = undefined; this.autoplay = false; this.autoseek = -1; this.readytoplay = false; } addVideo(path) { if (path.includes('front')) { this.front=path; } else if (path.includes('left_repeater')) { this.leftrepeater=path; } else if (path.includes('right_repeater')) { this.rightrepeater=path; } else if (path.includes('left_pillar')) { this.leftpillar=path; } else if (path.includes('right_pillar')) { this.rightpillar=path; } else if (path.includes('back')) { this.back=path; } else { log("unknown video path"); return; } if (this.timestampMs == undefined) { var dateStr = path.substring(0, 10); var timeStr = path.substring(11, 19).replaceAll("-", ":"); var d = Date.parse(dateStr + " " + timeStr); this.timestampMs = d; } if (this.datetime == undefined) { this.datetime = path.substring(0,19); } } onDblClickVideo(event) { log(event); event.target.requestFullscreen(); } onDurationChange(event) { var elem = event.target; this.activevideoelems = this.activevideoelems.concat(elem); log(this.activevideoelems.length + "/" + this.numangles + " duration: " + elem.duration); if (this.longestvideoelem == undefined || elem.duration > this.longestvideoelem.duration) { this.longestvideoelem = elem; } if (this.activevideoelems.length == this.numangles) { log("all videos loaded. Longest: " + this.longestvideoelem.id + ": " + this.longestvideoelem.duration); this.readytoplay = true; this.longestvideoelem.ontimeupdate = this.onTimeUpdate; for (var vid of this.activevideoelems) { vid.onended=this.onVideoEnded; vid.onerror=this.onVideoError; } if (this.autoseek) { this.seekTo(this.autoseek); this.autoseek = -1; } unfreezeVideoElems(); if (this.autoplay) { log("autoplay was set"); this.autoplay = false; this.play(); } else { log("no autoplay"); } } } onScanError(event) { var elem = event.target; log("scan error on '" + elem.src + "': " + videoError(elem)); this.numangles--; elem.onerror = undefined; elem.ondurationchange = undefined; elem.removeAttribute('src' ``` -------------------------------- ### Configure Gotify Notifications Source: https://github.com/marcone/teslausb/blob/main-dev/doc/ConfigureNotificationsForArchive.md Enable Gotify notifications by setting environment variables for the Gotify domain, application token, and message priority. This requires a self-hosted Gotify server. ```bash export GOTIFY_ENABLED=true export GOTIFY_DOMAIN=https://gotify.domain.com export GOTIFY_APP_TOKEN=put_your_token_here export GOTIFY_PRIORITY=5 ``` -------------------------------- ### Configure Pushover Notifications Source: https://github.com/marcone/teslausb/blob/main-dev/doc/ConfigureNotificationsForArchive.md Set environment variables to enable Pushover notifications and provide your user and application keys. Ensure your device has internet access. ```bash export PUSHOVER_ENABLED=true export PUSHOVER_USER_KEY=put_your_userkey_here export PUSHOVER_APP_KEY=put_your_appkey_here ``` -------------------------------- ### Configure Network Interfaces (Standard Method) Source: https://github.com/marcone/teslausb/wiki/Setting-up-External-Wi‐Fi-Adapter-for-Archiving Comment out or remove configurations related to 'ap0' in the network interfaces file. This prevents conflicts and ensures the system uses the correct interface for the access point. ```config #auto ap0 #allow-hotplug ap0 #iface ap0 inet static # address 192.168.66.1 # netmask 255.255.255.0 # hostapd /etc/hostapd/hostapd.conf ``` -------------------------------- ### /cgi-bin/status.sh — System status (JSON) Source: https://context7.com/marcone/teslausb/llms.txt Provides system status information in JSON format, including CPU temperature, fan speed, snapshot details, storage capacity, uptime, and network information. ```APIDOC ## `/cgi-bin/status.sh` — System status (JSON) ### Description Provides system status information in JSON format. ### Method GET ### Endpoint `/cgi-bin/status.sh` ### Response #### Success Response (200) - **cpu_temp** (string) - CPU temperature in millidegrees Celsius. - **fan_speed** (string) - Current fan speed (e.g., "N/A"). - **throttled** (string) - Throttling status. - **num_snapshots** (string) - Number of available snapshots. - **snapshot_oldest** (string) - Timestamp of the oldest snapshot. - **snapshot_newest** (string) - Timestamp of the newest snapshot. - **total_space** (string) - Total storage space in bytes. - **free_space** (string) - Free storage space in bytes. - **uptime** (string) - System uptime in seconds. - **drives_active** (string) - Indicates if drives are active. - **wifi_ssid** (string) - SSID of the connected Wi-Fi network. - **wifi_freq** (string) - Frequency of the Wi-Fi connection. - **wifi_strength** (string) - Wi-Fi signal strength. - **wifi_ip** (string) - IP address of the Wi-Fi connection. - **ether_ip** (string) - IP address of the Ethernet connection (if any). - **ether_speed** (string) - Speed of the Ethernet connection (if any). ### Request Example ```bash curl http://teslausb.local/cgi-bin/status.sh ``` ### Response Example ```json { "cpu_temp": "42000", "fan_speed": "N/A", "throttled": "0x0", "num_snapshots": "3", "snapshot_oldest": "1737168600", "snapshot_newest": "1737175800", "total_space": "42949672960", "free_space": "18253611008", "uptime": "3721.45", "drives_active": "yes", "wifi_ssid": "MyHomeWifi", "wifi_freq": "5.18", "wifi_strength": "68/70", "wifi_ip": "192.168.1.42", "ether_ip": "", "ether_speed": "" } ``` ``` -------------------------------- ### Configure rsync Environment Variables Source: https://github.com/marcone/teslausb/blob/main-dev/doc/SetupRSync.md Set environment variables to enable rsync archiving and specify connection details for the remote storage server. ```bash export ARCHIVE_SYSTEM=rsync export RSYNC_USER= export RSYNC_SERVER= export RSYNC_PATH= ``` -------------------------------- ### Configure Archive Connection Environment Variables Source: https://github.com/marcone/teslausb/blob/main-dev/doc/SetupShare.md Set environment variables on the Raspberry Pi to define the archive system type, server address, share name, and user credentials. Ensure 'Nautilus', 'SailfishCam', 'sailfish', and 'pa$$w0rd' are replaced with your specific network share details. ```bash export ARCHIVE_SYSTEM="cifs" export ARCHIVE_SERVER="Nautilus" export SHARE_NAME="SailfishCam" export SHARE_USER="sailfish" export SHARE_PASSWORD="pa$$w0rd" ``` -------------------------------- ### Remount Filesystem as Read-Write Source: https://github.com/marcone/teslausb/blob/main-dev/doc/SetupRSync.md Make the filesystem writable to allow modifications. ```bash bin/remountfs_rw ``` -------------------------------- ### Configure Generic Webhook Notifications Source: https://github.com/marcone/teslausb/blob/main-dev/doc/ConfigureNotificationsForArchive.md Set environment variables to enable and configure generic webhook notifications. Provide your webhook URL. ```bash export WEBHOOK_ENABLED=true export WEBHOOK_URL=http://domain/path ``` -------------------------------- ### VideoSequence Class Initialization Source: https://github.com/marcone/teslausb/blob/main-dev/teslausb-www/html/index.html Initializes a VideoSequence object, which manages a series of video segments. It sets up arrays for segments and their timestamps, and prepares for parsing JSON data and identifying subsequences. ```javascript class VideoSequence { segments; segmentsbytime; sequencegroup; // RecentClips, SavedClips or SentryClips sequencename; currentsegmentidx; isplaying; jsonfile; jsonparsed; sentryeventrel; subsequencestart; constructor(group, name) { this.segments = []; this.segmentsbytime = {}; this.sequencegroup = group; this.sequencename = name; this.reset(); this.jsonfile = []; this.jsonparsed = []; this.sentryeventrel = []; this.subsequencestart = []; } initialize() { /* find any gaps in the sequence so those can be indicated on the timeline */ var subseqstart = 0; for (var i = 0; i < this.length(); i++) { var segment = this.getSegmentByIndex(i); var ts = segment.timestampMs; if ((ts - subseqstart) > 90000) { this.subsequencestart.push(i); } subseqstart = ts; } } reset() { this.currentsegmentidx = -1; this.isplaying = false; var b = document.getElementById('playpause'); b.classList.remove("pause"); if ``` -------------------------------- ### Set Rclone Archive Path Source: https://github.com/marcone/teslausb/blob/main-dev/doc/SetupRClone.md Define the name of the folder that will store archived clips on the remote drive. Replace 'TeslaCam' with your chosen folder name. ```bash export RCLONE_PATH="TeslaCam" ``` -------------------------------- ### Configure Slack Notifications Source: https://github.com/marcone/teslausb/blob/main-dev/doc/ConfigureNotificationsForArchive.md Set environment variables to enable and configure Slack notifications. Provide your Slack webhook URL. ```bash export SLACK_ENABLED=true export SLACK_WEBHOOK_URL=http://localhost ``` -------------------------------- ### Layout Management (JavaScript) Source: https://github.com/marcone/teslausb/blob/main-dev/teslausb-www/html/index.html Manages different video layout configurations by adding/removing CSS classes to video elements and updating local storage. Includes a function to cycle through layouts. ```javascript function setLayout(layout) { var leftrepeaterview = document.getElementById("leftrepeaterview"); var leftpillarview = document.getElementById("leftpillarview"); var rightrepeaterview = document.getElementById("rightrepeaterview"); var rightpillarview = document.getElementById("rightpillarview"); var backview = document.getElementById("backview"); var videogrid = document.querySelector(".videoholder"); if (layout == 3 || layout == 5 || layout == 6) { leftrepeaterview.classList.remove("flipped"); rightrepeaterview.classList.remove("flipped"); backview.classList.remove("flipped"); } if (layout == 1) { // mirrorleft-front-mirrorright on top, map-mirrorrear-info on bottom leftrepeaterview.classList.add("flipped"); rightrepeaterview.classList.add("flipped"); backview.classList.add("flipped"); videogrid.classList="videoholder layout1"; } else if (layout == 2) { // map-front-info on top, mirrorleft-mirrorrear-mirrorright on bottom leftrepeaterview.classList.add("flipped"); rightrepeaterview.classList.add("flipped"); backview.classList.add("flipped"); videogrid.classList="videoholder layout2"; } else if (layout == 4) { // front on top, sides in middle, rear on bottom, mirrored leftrepeaterview.classList.add("flipped"); rightrepeaterview.classList.add("flipped"); backview.classList.add("flipped"); videogrid.classList="videoholder layout4"; } else if (layout == 5) { // front on top, sides in middle, rear on bottom videogrid.classList="videoholder layout5"; } else if (layout == 6) { // map-front-info on top, pillars on the side, repeaters and rear on bottom videogrid.classList="videoholder layout6"; } else { layout = 3; // (default) map-front-info on top, right-rear-left on bottom videogrid.classList="videoholder layout3"; } currentLayout = layout; localStorageSet("layout", layout); var l = document.querySelector("#layouts.subnav-content"); for (var i = 0; i < l.childElementCount; i++) { var item = l.children[i]; if (i == (currentLayout - 1) ) { item.classList.add("selected"); } else { item.classList.remove("selected"); } } if (typeof currentsequence !== 'undefined') { setTimeout(function() { for (var i=0; i < 6;i++) { var v = videoelems[i]; var c = canvaselems[i]; if (v.clientWidth > 0 && v.clientHeight > 0) { c.width = v.clientWidth; c.height = v.clientHeight; } if (v.style.visibility == "hidden") { var ctx = c.getContext("2d"); if (v.classList.contains("flipped")) { ctx.scale(-1, 1); ctx.drawImage(v, 0, 0, -c.width, c.height); } else { ctx.drawImage(v, 0, 0, c.width, c.height); } } } }, 50); } } ``` ```javascript function cycleLayout() { setLayout(currentLayout + 1); } ``` ```javascript setLayout(localStorageGet("layout")); ``` -------------------------------- ### Configure Matrix Notifications Source: https://github.com/marcone/teslausb/blob/main-dev/doc/ConfigureNotificationsForArchive.md Set environment variables to enable and configure Matrix notifications. Ensure you have your Matrix server URL, username, password, and room ID. Passwords and room IDs require single quotes. ```bash export MATRIX_ENABLED=true export MATRIX_SERVER_URL=https://matrix.org export MATRIX_USERNAME=put_your_matrix_username_here export MATRIX_PASSWORD='put_your_matrix_password_here' export MATRIX_ROOM='put_the_matrix_target_room_id_here' ``` -------------------------------- ### Configure Discord Notifications Source: https://github.com/marcone/teslausb/blob/main-dev/doc/ConfigureNotificationsForArchive.md Set environment variables to enable and configure Discord notifications. Provide your Discord webhook URL. ```bash export DISCORD_ENABLED=true export DISCORD_WEBHOOK_URL=put_your_webhook_url_here ``` -------------------------------- ### Download and Extract USB OTG Overlay Source: https://github.com/marcone/teslausb/wiki/Rock-4c-Plus-DietPi-Install-with-external-Drive Use these commands to download and extract the necessary USB OTG overlay file for enabling peripheral mode on the Rock Pi 4C+. ```bash mkdir -p /boot/overlay-user cd /boot/overlay-user wget https://github.com/user-attachments/files/18145944/rk3399-dwc3-0-peripheral.zip unzip rk3399-dwc3-0-peripheral.zip ``` -------------------------------- ### Create Directory on Remote Drive Source: https://github.com/marcone/teslausb/blob/main-dev/doc/SetupRClone.md Create the specified folder on your remote drive to hold the archived clips. This command uses the previously set RCLONE_DRIVE and RCLONE_PATH variables. ```bash rclone mkdir "$RCLONE_DRIVE:TeslaCam" ``` -------------------------------- ### File Download Helper (JavaScript) Source: https://github.com/marcone/teslausb/blob/main-dev/teslausb-www/html/index.html Creates a temporary anchor element to trigger a file download with the specified filename and text content. ```javascript function download(filename, text) { var elem = document.createElement('a'); elem.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); elem.setAttribute('download', filename); elem.style.display = 'none'; document.body.appendChild(elem); elem.click(); document.body.removeChild(elem); } ``` -------------------------------- ### Add DTS Overlay and Reboot Source: https://github.com/marcone/teslausb/wiki/Rock-Pi-4C-plus-Installation Applies the created DTS overlay to the system and reboots the Rock Pi 4C+ to activate the USB device controller configuration. ```bash armbian-add-overlay /boot/dtb/rockchip/overlay/dwc3-0-device.dts ``` -------------------------------- ### Configure rsync over SSH Archive Backend Source: https://context7.com/marcone/teslausb/llms.txt Sets environment variables for using rsync over SSH to an archive server. Requires SSH user, server address, and remote path. SSH key authentication is recommended. ```bash export ARCHIVE_SYSTEM=rsync export RSYNC_USER=pi export RSYNC_SERVER=nas.local export RSYNC_PATH=/mnt/tank/TeslaCam # Pre-configure SSH key auth: # ssh-keygen -t ed25519 && ssh-copy-id pi@nas.local ``` -------------------------------- ### Manage Free Space by Deleting Oldest Snapshots Source: https://context7.com/marcone/teslausb/llms.txt Maintains a minimum free space buffer by deleting the oldest snapshots. The reserve is configurable and automatically managed by a background process. ```bash # Called automatically by archiveloop's freespacemanager background process. # Can be invoked manually with a custom reserve in bytes: /root/bin/manage_free_space.sh 21474836480 # 20 GB reserve # The freespacemanager loop in archiveloop: # Checks every 30 seconds; deletes oldest snap-XXXXXX if free < reserve. # Log output example: # Sat Jan 18 03:10:01 UTC 2025: low space, deleting /backingfiles/snapshots/snap-000000 ``` -------------------------------- ### JavaScript: Sequence Selection and UI Update Source: https://github.com/marcone/teslausb/blob/main-dev/teslausb-www/html/index.html Handles the selection of a video sequence, updating UI elements like sliders and map displays. Initializes the sequence and seeks to the beginning. ```javascript select() { this.reset(); currentsequence=this; var slider = document.getElementById('position'); slider.max = (this.length() * 60000) - 1; slider.oninput = this.onSeek.bind(this); slider.onmousedown = this.onSeekStart.bind(this); slider.onchange = this.onSeekEnd.bind(this); this.seekTo(0); this.onMapResize(); this.onTickResize(); this.showSentryLocation(); } ``` -------------------------------- ### Ping Archive Server by Name Source: https://github.com/marcone/teslausb/blob/main-dev/doc/SetupShare.md Test network connectivity to your archive server by its hostname. Ensure the server name 'nautilus' is replaced with your actual server's name. ```bash ping -c 3 nautilus ```