Rivian Geo via Meshtastic

The Autonomous Deezwatts Meshtastic Sync Service
Section titled “The Autonomous Deezwatts Meshtastic Sync Service”Tucked away in my Rivian’s center console, a Raspberry Pi acts as the silent tracker, a $25 lojack for my $80k+ truck. Every minute, the script springs to life, polling for precise geo data from a Meshtastic Wio Tracker Pro whenever the vehicle is in motion. This telemetry is serialized and streamed directly to a GCP bucket as JSON, creating a persistent, cloud-based record of every Michigan mile.
import meshtasticimport meshtastic.serial_interfaceimport jsonimport osimport globimport timefrom datetime import datetimefrom google.cloud import storage
# --- Configuration ---BUCKET_NAME = "deezwatts-meshtastic-bucket"LOCAL_DIR = "./pending_uploads"POLL_INTERVAL = 60 # 10 minutes in seconds# os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "/path/to/key.json"# ---------------------
os.makedirs(LOCAL_DIR, exist_ok=True)
def upload_to_gcp(data, filename): """Attempts to upload to GCP, returns True if successful.""" try: client = storage.Client() bucket = client.bucket(BUCKET_NAME) blob = bucket.blob(filename) blob.upload_from_string( data=json.dumps(data, indent=4, default=str), content_type='application/json' ) return True except Exception: return False
def sync_backlog(): """Checks the local folder for files that failed previously.""" backlog_files = sorted(glob.glob(os.path.join(LOCAL_DIR, "*.json"))) if not backlog_files: return
print(f"Found {len(backlog_files)} pending files. Attempting sync...") for file_path in backlog_files: filename = os.path.basename(file_path) try: with open(file_path, 'r') as f: data = json.load(f)
if upload_to_gcp(data, filename): os.remove(file_path) print(f" Synced and cleared: {filename}") else: print(f" Cloud still unreachable. Stopping sync.") break # Stop trying if the first one fails except Exception as e: print(f" Error reading {filename}: {e}")
def run_task(): """The core polling logic.""" print(f"\n--- Starting Poll: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} ---") interface = None try: # Connect to radio interface = meshtastic.serial_interface.SerialInterface() nodes = interface.nodes
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") filename = f"nodes_{timestamp}.json"
payload = { "polled_at": datetime.now().isoformat(), "nodes": nodes }
# Try Cloud if upload_to_gcp(payload, filename): print("Success: Data sent directly to GCP.") sync_backlog() # If cloud is up, clear any old local files else: # Fallback filepath = os.path.join(LOCAL_DIR, filename) with open(filepath, "w") as f: json.dump(payload, f, indent=4, default=str) print(f"Offline: Saved {filename} to local buffer.")
except Exception as e: print(f"Connection Error: {e}") finally: if interface: interface.close()
def main(): print(f"Service started. Polling every {POLL_INTERVAL/60} minutes.") print(f"Monitoring device and GCP bucket: {BUCKET_NAME}")
while True: run_task() print(f"Sleeping for {POLL_INTERVAL/60} minutes...") time.sleep(POLL_INTERVAL)
if __name__ == "__main__": try: main() except KeyboardInterrupt: print("\nStopping service...")To make this a professional background service, we will create a Systemd Service. This ensures the script starts when the Rivian is powered on, restarts automatically if it crashes, and logs all its output to the system journal.
Create the Service File
Section titled “Create the Service File”Open a terminal and create the following file (you’ll need sudo):
cat > /etc/systemd/system/deezwatts-meshtastic-sync.servicePaste the Configuration
Section titled “Paste the Configuration”Here is the meat and potatos of the service file.
[Unit]Description=Deezwatts Meshtastic to GCP Sync ServiceAfter=network.target
[Service]User=sweenGroup=dialoutWorkingDirectory=/home/sween/deezwatts-meshtasticExecStart=/usr/bin/python3 /home/sween/deezwatts-meshtastic/sync_script.py
# Environment variable for GCP CredentialsEnvironment="GOOGLE_APPLICATION_CREDENTIALS=/home/sween/deezwatts-meshtastic/deezwatts-bucket-key.json"
# Restart logicRestart=alwaysRestartSec=30
[Install]WantedBy=multi-user.targetEnable and Start
Section titled “Enable and Start”This raspberry pi is powered by the Rivian’s 12v system and is always on when the vehicle is on.
# Reload systemd to recognize the new filesudo systemctl daemon-reload
# Enable the service to start on bootsudo systemctl enable meshtastic-sync.service
# Start it right nowsudo systemctl start meshtastic-sync.service