sunnypilot v2026.02.09-4080

version: sunnypilot v2025.003.000 (dev)
date: 2026-02-09T02:04:38
master commit: 254f55ac15a40343d7255f2f098de3442e0c4a6f
This commit is contained in:
github-actions[bot]
2026-02-09 02:04:38 +00:00
commit 7fa972be6a
3996 changed files with 1485883 additions and 0 deletions

42
tools/scripts/adb_ssh.sh Executable file
View File

@@ -0,0 +1,42 @@
#!/usr/bin/env bash
set -euo pipefail
# Forward all openpilot service ports
mapfile -t SERVICE_PORTS < <(python3 - <<'PY'
from cereal.services import SERVICE_LIST
FNV_PRIME = 0x100000001b3
FNV_OFFSET_BASIS = 0xcbf29ce484222325
START_PORT = 8023
MAX_PORT = 65535
PORT_RANGE = MAX_PORT - START_PORT
MASK = 0xffffffffffffffff
def fnv1a(endpoint: str) -> int:
h = FNV_OFFSET_BASIS
for b in endpoint.encode():
h ^= b
h = (h * FNV_PRIME) & MASK
return h
ports = set()
for name in SERVICE_LIST.keys():
port = START_PORT + fnv1a(name) % PORT_RANGE
ports.add((name, port))
for name, port in sorted(ports):
print(f"{name} {port}")
PY
)
for entry in "${SERVICE_PORTS[@]}"; do
name="${entry% *}"
port="${entry##* }"
adb forward "tcp:${port}" "tcp:${port}" > /dev/null
done
# Forward SSH port first for interactive shell access.
adb forward tcp:2222 tcp:22
# SSH!
ssh comma@localhost -p 2222 "$@"

77
tools/scripts/extract_audio.py Executable file
View File

@@ -0,0 +1,77 @@
#!/usr/bin/env python3
import os
import sys
import wave
import argparse
import numpy as np
from openpilot.tools.lib.logreader import LogReader, ReadMode
def extract_audio(route_or_segment_name, output_file=None, play=False):
lr = LogReader(route_or_segment_name, default_mode=ReadMode.AUTO_INTERACTIVE)
audio_messages = list(lr.filter("rawAudioData"))
if not audio_messages:
print("No rawAudioData messages found in logs")
return
sample_rate = audio_messages[0].sampleRate
audio_chunks = []
total_frames = 0
for msg in audio_messages:
audio_array = np.frombuffer(msg.data, dtype=np.int16)
audio_chunks.append(audio_array)
total_frames += len(audio_array)
full_audio = np.concatenate(audio_chunks)
print(f"Found {total_frames} frames from {len(audio_messages)} audio messages at {sample_rate} Hz")
if output_file:
if write_wav_file(output_file, full_audio, sample_rate):
print(f"Audio written to {output_file}")
else:
print("Audio extraction canceled.")
if play:
play_audio(full_audio, sample_rate)
def write_wav_file(filename, audio_data, sample_rate):
if os.path.exists(filename):
if input(f"File '{filename}' exists. Overwrite? (y/N): ").lower() not in ['y', 'yes']:
return False
with wave.open(filename, 'wb') as wav_file:
wav_file.setnchannels(1) # Mono
wav_file.setsampwidth(2) # 16-bit
wav_file.setframerate(sample_rate)
wav_file.writeframes(audio_data.tobytes())
return True
def play_audio(audio_data, sample_rate):
try:
import sounddevice as sd
print("Playing audio... Press Ctrl+C to stop")
sd.play(audio_data, sample_rate)
sd.wait()
except KeyboardInterrupt:
print("\nPlayback stopped")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Extract audio data from openpilot logs")
parser.add_argument("-o", "--output", help="Output WAV file path")
parser.add_argument("--play", action="store_true", help="Play audio with sounddevice")
parser.add_argument("route_or_segment_name", nargs='?', help="The route or segment name")
if len(sys.argv) == 1:
parser.print_help()
sys.exit()
args = parser.parse_args()
output_file = args.output
if not args.output and not args.play:
output_file = "extracted_audio.wav"
extract_audio(args.route_or_segment_name.strip(), output_file, args.play)

View File

@@ -0,0 +1,43 @@
#!/usr/bin/env python3
import sys
if len(sys.argv) < 4:
print(f"{sys.argv[0]} <route> <segment> <frame number> [front|wide|driver]")
print('example: ./fetch_image_from_route.py "02c45f73a2e5c6e9|2020-06-01--18-03-08" 3 500 driver')
exit(0)
cameras = {
"front": "cameras",
"wide": "ecameras",
"driver": "dcameras"
}
import requests
from PIL import Image
from openpilot.tools.lib.auth_config import get_token
from openpilot.tools.lib.framereader import FrameReader
jwt = get_token()
route = sys.argv[1]
segment = int(sys.argv[2])
frame = int(sys.argv[3])
camera = cameras[sys.argv[4]] if len(sys.argv) > 4 and sys.argv[4] in cameras else "cameras"
url = f'https://api.commadotai.com/v1/route/{route}/files'
r = requests.get(url, headers={"Authorization": f"JWT {jwt}"}, timeout=10)
assert r.status_code == 200
print("got api response")
segments = r.json()[camera]
if segment >= len(segments):
raise Exception(f"segment {segment} not found, got {len(segments)} segments")
fr = FrameReader(segments[segment])
if frame >= fr.frame_count:
raise Exception("frame {frame} not found, got {fr.frame_count} frames")
im = Image.fromarray(fr.get(frame))
fn = f"uxxx_{route.replace('|', '_')}_{segment}_{frame}.png"
im.save(fn)
print(f"saved {fn}")

View File

@@ -0,0 +1,47 @@
#!/usr/bin/env python3
import argparse
import os
import sys
from openpilot.common.basedir import BASEDIR
from openpilot.tools.lib.logreader import LogReader
os.environ['BASEDIR'] = BASEDIR
def get_arg_parser():
parser = argparse.ArgumentParser(
description="Unlogging and save to file",
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument("route", type=(lambda x: x.replace("#", "|")), nargs="?",
help="The route whose messages will be published.")
parser.add_argument("--out_path", nargs='?', default='/data/ubloxRaw.stream',
help="Output pickle file path")
return parser
def main():
args = get_arg_parser().parse_args(sys.argv[1:])
lr = LogReader(args.route)
with open(args.out_path, 'wb') as f:
try:
done = False
i = 0
while not done:
msg = next(lr)
if not msg:
break
smsg = msg.as_builder()
typ = smsg.which()
if typ == 'ubloxRaw':
f.write(smsg.to_bytes())
i += 1
except StopIteration:
print('All done')
print(f'Writed {i} msgs')
if __name__ == "__main__":
main()

8
tools/scripts/serial.sh Executable file
View File

@@ -0,0 +1,8 @@
#!/usr/bin/env bash
while true; do
if ls /dev/serial/by-id/usb-FTDI_FT230X* 2> /dev/null; then
sudo screen /dev/serial/by-id/usb-FTDI_FT230X* 115200
fi
sleep 0.005
done

23
tools/scripts/setup_ssh_keys.py Executable file
View File

@@ -0,0 +1,23 @@
#!/usr/bin/env python3
import requests
from openpilot.common.params import Params
import sys
if __name__ == "__main__":
if len(sys.argv) < 2:
print(f"{sys.argv[0]} <github username>")
exit(1)
username = sys.argv[1]
keys = requests.get(f"https://github.com/{username}.keys", timeout=10)
if keys.status_code == 200:
params = Params()
params.put_bool("SshEnabled", True)
params.put("GithubSshKeys", keys.text)
params.put("GithubUsername", username)
print("Set up ssh keys successfully")
else:
print("Error getting public keys from github")

57
tools/scripts/ssh.py Executable file
View File

@@ -0,0 +1,57 @@
#!/usr/bin/env python3
import os
import sys
import argparse
import re
from openpilot.common.basedir import BASEDIR
from openpilot.tools.lib.auth_config import get_token
from openpilot.tools.lib.api import CommaApi
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="A helper for connecting to devices over the comma prime SSH proxy.\
Adding your SSH key to your SSH config is recommended for more convenient use; see https://docs.comma.ai/how-to/connect-to-comma/.")
parser.add_argument("device", help="device name or dongle id")
parser.add_argument("--host", help="ssh jump server host", default="ssh.comma.ai")
parser.add_argument("--port", help="ssh jump server port", default=22, type=int)
parser.add_argument("--key", help="ssh key", default=os.path.join(BASEDIR, "system/hardware/tici/id_rsa"))
parser.add_argument("--debug", help="enable debug output", action="store_true")
args = parser.parse_args()
r = CommaApi(get_token()).get("v1/me/devices")
devices = {x['dongle_id']: x['alias'] for x in r}
if not re.match("[0-9a-zA-Z]{16}", args.device):
user_input = args.device.replace(" ", "").lower()
matches = { k: v for k, v in devices.items() if isinstance(v, str) and user_input in v.replace(" ", "").lower() }
if len(matches) == 1:
dongle_id = list(matches.keys())[0]
else:
print(f"failed to look up dongle id for \"{args.device}\"", file=sys.stderr)
if len(matches) > 1:
print("found multiple matches:", file=sys.stderr)
for k, v in matches.items():
print(f" \"{v}\" ({k})", file=sys.stderr)
exit(1)
else:
dongle_id = args.device
name = dongle_id
if dongle_id in devices:
name = f"{devices[dongle_id]} ({dongle_id})"
print(f"connecting to {name} through {args.host}:{args.port} ...")
command = [
"ssh",
"-i", args.key,
"-o", f"ProxyCommand=ssh -i {args.key} -W %h:%p -p %p %h@{args.host}",
"-p", str(args.port),
]
if args.debug:
command += ["-v"]
command += [
f"comma@comma-{dongle_id}",
]
if args.debug:
print(" ".join([f"'{c}'" if " " in c else c for c in command]))
os.execvp(command[0], command)