Skip to content

Commit

Permalink
Dashcam Viewer ▶️ Fleet Manager (commaai#174)
Browse files Browse the repository at this point in the history
* Dashcam Viewer ▶️ Fleet Manager

* missed

* process
  • Loading branch information
sunnyhaibin committed Jun 7, 2023
1 parent a34c596 commit 462b20a
Show file tree
Hide file tree
Showing 17 changed files with 28 additions and 28 deletions.
2 changes: 1 addition & 1 deletion CHANGELOGS.md
Expand Up @@ -6,7 +6,7 @@ sunnypilot - Version Latest (2023-06-xx)
* NEW❗: Nissan and Mazda upstream models support
* NEW❗: Pre-Global Subaru upstream models support
* HKG: smartMDPS automatic detection (installed with applicable firmware)
* Dashcam Viewer (native & screen recordings) via Browser support thanks to actuallylemoncurd, AlexandreSato, ntegan1, and royjr!
* Fleet Manager (native & screen recordings) via Browser support thanks to actuallylemoncurd, AlexandreSato, ntegan1, and royjr!
* Honda Clarity 2018-22 support thanks to mcallbosco, vanillagorillaa and wirelessnet2!
* Ram: Steer to 0/7 MPH support thanks to vincentw56!
* Retain hotspot/tethering state across reboots thanks to rogerioaguas!
Expand Down
2 changes: 1 addition & 1 deletion selfdrive/manager/process_config.py
Expand Up @@ -73,7 +73,7 @@ def qcomgps(started, params, CP: car.CarParams) -> bool:
PythonProcess("gpxd", "selfdrive.gpxd.gpxd"),
PythonProcess("gpxd_uploader", "selfdrive.gpxd.gpx_uploader", offroad=True),
PythonProcess("mapd", "selfdrive.mapd.mapd"),
PythonProcess("dashcam_viewer", "system.dashcamviewer.dashcam_viewer", onroad=False, offroad=True),
PythonProcess("dashcam_viewer", "system.fleetmanager.fleet_manager", onroad=False, offroad=True),

# debug procs
NativeProcess("bridge", "cereal/messaging", ["./bridge"], onroad=False, callback=notcar),
Expand Down
2 changes: 1 addition & 1 deletion selfdrive/ui/qt/offroad/settings.cc
Expand Up @@ -184,7 +184,7 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) {
QFile f("/data/otp/otp.conf");
f.open(QIODevice::ReadOnly | QIODevice::Text);
QString pin = f.readAll();
addItem(new LabelControl(tr("Dashcam Viewer PIN"), pin));
addItem(new LabelControl(tr("Fleet Manager PIN"), pin));

// offroad-only buttons

Expand Down
5 changes: 0 additions & 5 deletions system/dashcamviewer/README.md

This file was deleted.

5 changes: 5 additions & 0 deletions system/fleetmanager/README.md
@@ -0,0 +1,5 @@
# Fleet Manager

Fleet Manger on sunnypilot allows viewing dashcam footage and screen recordings by connecting to the comma device via the same network, with your mobile device or PC. Big thanks to [actuallylemoncurd](https://github.com/actuallylemoncurd), [AlexandreSato](https://github.com/alexandreSato), [ntegan1](https://github.com/ntegan1), and [royjr](https://github.com/royjr).

The network can be set up by Wi-Fi, mobile hotspot, or tethering on the comma device. Navigate to http://tici:5050/ OR http://ipAddress:5050 to access.
Expand Up @@ -2,7 +2,7 @@
import os
import random
import secrets
import system.dashcamviewer.helpers as dashcam
import system.fleetmanager.helpers as fleet
from flask import Flask, render_template, Response, request, send_from_directory, session, redirect, url_for
from functools import wraps
from system.loggerd.config import ROOT as REALDATA
Expand All @@ -29,7 +29,7 @@ def index_page():
@app.route("/login", methods=["POST"])
def login():
inputted_pin = request.form.get("pin")
with open(dashcam.PIN_PATH + "otp.conf", "r") as file:
with open(fleet.PIN_PATH + "otp.conf", "r") as file:
correct_pin = file.read().strip()

if inputted_pin == correct_pin:
Expand All @@ -51,10 +51,10 @@ def home_page():
def full(cameratype, route):
chunk_size = 1024 * 512 # 5KiB
file_name = cameratype + (".ts" if cameratype == "qcamera" else ".hevc")
vidlist = "|".join(REALDATA + "/" + segment + "/" + file_name for segment in dashcam.segments_in_route(route))
vidlist = "|".join(REALDATA + "/" + segment + "/" + file_name for segment in fleet.segments_in_route(route))

def generate_buffered_stream():
with dashcam.ffmpeg_mp4_concat_wrap_process_builder(vidlist, cameratype, chunk_size) as process:
with fleet.ffmpeg_mp4_concat_wrap_process_builder(vidlist, cameratype, chunk_size) as process:
for chunk in iter(lambda: process.stdout.read(chunk_size), b""):
yield bytes(chunk)
return Response(generate_buffered_stream(), status=200, mimetype='video/mp4')
Expand All @@ -63,10 +63,10 @@ def generate_buffered_stream():
@app.route("/footage/<cameratype>/<segment>")
@login_required
def fcamera(cameratype, segment):
if not dashcam.is_valid_segment(segment):
if not fleet.is_valid_segment(segment):
return render_template("error.html", error="invalid segment")
file_name = REALDATA + "/" + segment + "/" + cameratype + (".ts" if cameratype == "qcamera" else ".hevc")
return Response(dashcam.ffmpeg_mp4_wrap_process_builder(file_name).stdout.read(), status=200, mimetype='video/mp4')
return Response(fleet.ffmpeg_mp4_wrap_process_builder(file_name).stdout.read(), status=200, mimetype='video/mp4')


@app.route("/footage/<route>")
Expand All @@ -84,7 +84,7 @@ def route(route):

links = ""
segments = ""
for segment in dashcam.segments_in_route(route):
for segment in fleet.segments_in_route(route):
links += "<a href='"+route+"?"+segment.split("--")[2]+","+query_type+"'>"+segment+"</a><br>"
segments += "'"+segment+"',"
return render_template("route.html", route=route, query_type=query_type, links=links, segments=segments, query_segment=query_segment)
Expand All @@ -93,35 +93,35 @@ def route(route):
@app.route("/footage")
@login_required
def footage():
return render_template("footage.html", rows=dashcam.all_routes())
return render_template("footage.html", rows=fleet.all_routes())


@app.route("/screenrecords")
@login_required
def screenrecords():
rows = dashcam.all_screenrecords()
rows = fleet.all_screenrecords()
if not rows:
return render_template("error.html", error="no screenrecords found at:<br><br>" + dashcam.SCREENRECORD_PATH)
return render_template("error.html", error="no screenrecords found at:<br><br>" + fleet.SCREENRECORD_PATH)
return render_template("screenrecords.html", rows=rows, clip=rows[0])


@app.route("/screenrecords/<clip>")
@login_required
def screenrecord(clip):
return render_template("screenrecords.html", rows=dashcam.all_screenrecords(), clip=clip)
return render_template("screenrecords.html", rows=fleet.all_screenrecords(), clip=clip)


@app.route("/screenrecords/play/pipe/<file>")
@login_required
def videoscreenrecord(file):
file_name = dashcam.SCREENRECORD_PATH + file
return Response(dashcam.ffplay_mp4_wrap_process_builder(file_name).stdout.read(), status=200, mimetype='video/mp4')
file_name = fleet.SCREENRECORD_PATH + file
return Response(fleet.ffplay_mp4_wrap_process_builder(file_name).stdout.read(), status=200, mimetype='video/mp4')


@app.route("/screenrecords/download/<clip>")
@login_required
def download_file(clip):
return send_from_directory(dashcam.SCREENRECORD_PATH, clip, as_attachment=True)
return send_from_directory(fleet.SCREENRECORD_PATH, clip, as_attachment=True)


@app.route("/about")
Expand All @@ -131,10 +131,10 @@ def about():


def main():
if not os.path.exists(dashcam.PIN_PATH):
os.makedirs(dashcam.PIN_PATH)
if not os.path.exists(fleet.PIN_PATH):
os.makedirs(fleet.PIN_PATH)
pin = str(random.randint(100000, 999999))
with open(dashcam.PIN_PATH + "otp.conf", "w") as file:
with open(fleet.PIN_PATH + "otp.conf", "w") as file:
file.write(pin)

app.secret_key = secrets.token_hex(32)
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
Expand Up @@ -6,7 +6,7 @@

{% block main %}
<br>
<h1>Dashcam Viewer</h1>
<h1>Fleet Manager</h1>
<br>
<a href='/footage'>View Dashcam Footage</a><br>
<br><a href='/screenrecords'>View Screen Recordings</a><br>
Expand Down
File renamed without changes.
Expand Up @@ -28,8 +28,8 @@ <h1>Login</h1>
<summary>Where to find the PIN?</summary>
<br>
<p>The PIN can be found on the comma device:</p>
<p><b>Settings ➡️ Device ➡️ Dashcam Viewer PIN</b></p>
<img src=" {{ url_for("static", filename="dashcam_pin.png")}}" alt="Dashcam Viewer Pin Location" style="max-width: 100%; height: auto;">
<p><b>Settings ➡️ Device ➡️ Fleet Manager PIN</b></p>
<img src=" {{ url_for("static", filename="fleet_pin.png")}}" alt="Fleet Manager Pin Location" style="max-width: 100%; height: auto;">
<br><br>
</details>
</form>
Expand Down
File renamed without changes.

0 comments on commit 462b20a

Please sign in to comment.