Skip to content

Commit ed2461e

Browse files
authored
Backport changes from Pro (#1937)
Resolves tiny-pilot/tinypilot-pro#1516 This PR backports some of the changes from our Pro repo in order to keep the diff between projects as small as possible to reduce the maintenance admin. Notes: 1. These changes were created by temporarily replacing the repo's `.git` directory with that of TinyPilot Pro's `.git` directory and manually reverting changes that seem relevant. 1. Seeing as we don't officially support Community running on a cm4-based device, I decided to exclude any config specific to the cm4. This partially affects the boot config and included EDID files. 1. I've tested these changes on a Voyager 2a device and it seems to be working fine. <s>Also, I ran it on a Hobbyist pi4 device with usb dongle, however I kept getting no video signal with this `ustreamer` error in the logs: > ERROR [194.294 ] -- No access to capture device: No such file or directory I wasn't able to figure out the issue yet, but I suspect my pi4 device is faulty. I would appreciate a 2nd opinion from a reviewer.</s> Nevermind, I just disabled the `tc358743` chip on the Voyager 2a to mimic a Hobbyist device and it works. 1. These changes should create an empty diff when merging the automatically generated PR back into the TinyPilot Pro repo. <a data-ca-tag href="https://codeapprove.com/pr/tiny-pilot/tinypilot/1937"><img src="https://codeapprove.com/external/github-tag-allbg.png" alt="Review on CodeApprove" /></a>
1 parent e545dfc commit ed2461e

File tree

17 files changed

+241
-106
lines changed

17 files changed

+241
-106
lines changed

.circleci/config.yml

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -117,34 +117,30 @@ jobs:
117117
name: Check code style
118118
command: ./dev-scripts/check-style
119119
decode_edid:
120-
executor: python
120+
executor: ubuntu
121121
resource_class: small
122122
steps:
123123
- checkout
124124
- run:
125125
name: Install edid-decode
126126
command: sudo apt-get update && sudo apt-get install --yes edid-decode
127127
- run:
128-
name: Create virtual environment
129-
command: python3 -m venv venv
130-
- run:
131-
name: Install requirements and decode the EDID
132-
command: |
133-
. venv/bin/activate
134-
pip install --requirement requirements.txt
135-
./dev-scripts/decode-edid
128+
name: Check pi4 EDID
129+
command: edid-decode --check debian-pkg/usr/share/tinypilot/edid_pi4.hex
136130
check_python:
137131
executor: python
138132
steps:
139133
- checkout
140134
- run:
141-
name: Create virtual environment
142-
command: python3 -m venv venv
143-
- run:
144-
name: Install requirements and run build script
135+
name: Install Python requirements of main app
145136
command: |
137+
python3 -m venv venv
146138
. venv/bin/activate
147139
pip install --requirement dev_requirements.txt
140+
- run:
141+
name: Run check script
142+
command: |
143+
. venv/bin/activate
148144
./dev-scripts/check-python
149145
check_javascript:
150146
executor: node
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
-- Create a table for storing serial terminal settings.
2+
3+
CREATE TABLE IF NOT EXISTS serial_terminal(
4+
id INTEGER PRIMARY KEY,
5+
port TEXT NOT NULL UNIQUE,
6+
baud_rate INTEGER NOT NULL,
7+
data_bits INTEGER NOT NULL,
8+
stop_bits INTEGER NOT NULL,
9+
parity TEXT NOT NULL,
10+
flow_control TEXT NOT NULL
11+
);

app/static/js/app.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,9 @@ menuBar.addEventListener("manage-users-dialog-requested", () => {
368368
menuBar.addEventListener("change-password-dialog-requested", () => {
369369
document.getElementById("change-password-overlay").show();
370370
});
371+
menuBar.addEventListener("serial-terminal-dialog-requested", () => {
372+
document.getElementById("feature-pro-overlay").show();
373+
});
371374
menuBar.addEventListener("ctrl-alt-del-requested", () => {
372375
// Even though only the final keystroke matters, send them one at a time to
373376
// better match real user behavior. This ensures that the keystroke history

app/templates/custom-elements/menu-bar.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,13 @@
323323
>Wake on LAN</a
324324
>
325325
</li>
326+
<li class="item pro-badge" role="presentation">
327+
<a
328+
data-onclick-event="serial-terminal-dialog-requested"
329+
role="menuitem"
330+
>Serial Console</a
331+
>
332+
</li>
326333
<li class="item subgroup" role="presentation">
327334
<a role="menuitem">Keyboard Shortcuts</a>
328335
<ul class="items" role="group">

app/update/settings.py

Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -33,41 +33,6 @@
3333

3434
_SETTINGS_FILE_PATH = env.abs_path_in_home_dir('settings.yml')
3535

36-
# To create a new EDID:
37-
# 1. Convert the existing EDID to binary using "edid2bin".
38-
# 2. Edit the binary using "AW EDID Editor v.02.00.13".
39-
# 3. Save the new EDID in binary format.
40-
# 4. Convert the binary EDID to a hex EDID using "make-edid".
41-
# - Use the "--yaml" option if required.
42-
43-
# Note: You may need to perform a few extra steps in order for the EDID
44-
# to conform to edid-decode's check - but only if the "Display Range Limits"
45-
# block changes. This is due to a bug in AW EDID Editor v.02.00.13 that doesn't
46-
# set the correct bytes.
47-
# To work around this:
48-
# 1. Open the new EDID in "AW EDID Editor v.3.0.10".
49-
# 2. Save the EDID to set correct bytes in the "Display Range Limits" block
50-
# 3. Re-open the EDID in "AW EDID Editor v.02.00.13" and re-set
51-
# the screen size dimensions to 0 (both vertical and horizontal)
52-
_DEFAULT_TC358743_EDID = """
53-
00ffffffffffff005262769800888888
54-
2d1e0103800000781aee91a3544c9926
55-
0f50547fef8081c08140810081809500
56-
a9c081406140271f80f07138164038c0
57-
350000000000001eec2c80a070381a40
58-
3020350000000000001e000000fc0054
59-
696e7950696c6f740a202020000000fd
60-
00185a125010000a20202020202001aa
61-
02031ef14b010204131f2021223c3d3e
62-
2309070766030c00300080e2007f0000
63-
00000000000000000000000000000000
64-
00000000000000000000000000000000
65-
00000000000000000000000000000000
66-
00000000000000000000000000000000
67-
00000000000000000000000000000000
68-
0000000000000000000000000000008e
69-
""".strip()
70-
7136
# Define default values for user-configurable TinyPilot settings. The YAML data
7237
# in _SETTINGS_FILE_PATH take precedence over these defaults.
7338
_DEFAULTS = {
@@ -77,7 +42,7 @@
7742
# settings file if they want to provide their own TLS keys.
7843
'tinypilot_manage_tls_keys': True,
7944
'ustreamer_desired_fps': video_service.DEFAULT_MJPEG_FRAME_RATE,
80-
'ustreamer_edid': _DEFAULT_TC358743_EDID,
45+
'ustreamer_edid': video_service.DEFAULT_EDID,
8146
'ustreamer_quality': video_service.DEFAULT_MJPEG_QUALITY,
8247
'ustreamer_h264_bitrate': video_service.DEFAULT_H264_BITRATE,
8348
'janus_stun_server': video_service.DEFAULT_H264_STUN_SERVER,

app/version.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,18 @@ def latest_version():
8282
VersionRequestError: If an error occurred while making an HTTP request
8383
to the Gatekeeper API.
8484
"""
85+
# The URL is trusted because it's not based on user input.
86+
url = f'{env.GATEKEEPER_BASE_URL}/community/available-update'
8587
try:
86-
# The URL is trusted because it's not based on user input.
8788
# pylint: disable=line-too-long
8889
with urllib.request.urlopen( # noqa: S310 # nosemgrep: dynamic-urllib-use-detected
89-
f'{env.GATEKEEPER_BASE_URL}/community/available-update',
90+
url,
9091
timeout=10) as response:
9192
response_bytes = response.read()
93+
except urllib.error.HTTPError as e:
94+
message = e.fp.read().decode('utf-8').strip()
95+
raise VersionRequestError(
96+
f'Failed to request latest available version: {message}') from e
9297
except urllib.error.URLError as e:
9398
if (isinstance(e.reason, ssl.SSLCertVerificationError) and
9499
e.reason.verify_message == 'certificate is not yet valid'):

app/version_test.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import io
12
import json
23
import tempfile
34
import urllib.error
@@ -8,7 +9,7 @@
89
import version
910

1011

11-
class VersionTest(TestCase):
12+
class LocalVersionTest(TestCase):
1213

1314
def setUp(self):
1415
# Run all unit tests with debug mode disabled.
@@ -63,6 +64,17 @@ def test_local_version_raises_file_error_when_file_is_not_utf_8(self):
6364
with self.assertRaises(version.VersionFileError):
6465
version.local_version()
6566

67+
68+
class LatestVersionTest(TestCase):
69+
70+
def setUp(self):
71+
# Run all unit tests with version's debug mode enabled.
72+
version_is_debug_patch = mock.patch.object(version,
73+
'_is_debug',
74+
return_value=True)
75+
self.addCleanup(version_is_debug_patch.stop)
76+
version_is_debug_patch.start()
77+
6678
@mock.patch.object(urllib.request, 'urlopen')
6779
def test_latest_version_when_request_is_successful(self, mock_urlopen):
6880
mock_response = mock.Mock()
@@ -123,14 +135,20 @@ def test_latest_version_raises_request_error_when_response_missing_field(
123135
@mock.patch.object(urllib.request, 'urlopen')
124136
def test_latest_version_raises_request_error_when_request_fails(
125137
self, mock_urlopen):
126-
mock_urlopen.side_effect = urllib.error.URLError(
127-
'dummy error from gatekeeper', None)
138+
urlopen_mock = mock.Mock(side_effect=urllib.error.HTTPError(
139+
'127.0.0.1', 400, '400 Bad Request', None, io.BytesIO(
140+
b'bad request')))
141+
mock_urlopen.return_value.__enter__ = urlopen_mock
128142

129-
with self.assertRaises(version.VersionRequestError):
143+
with self.assertRaises(version.VersionRequestError) as ctx:
130144
version.latest_version()
131145

146+
self.assertEqual(
147+
'Failed to request latest available version: bad request',
148+
str(ctx.exception))
149+
132150

133-
class DebugModeVersionTest(TestCase):
151+
class DebugModeLocalVersionTest(TestCase):
134152

135153
def test_local_version_returns_dummy_version_when_in_debug_mode(self):
136154
# Enable debug mode.

app/video_service.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,45 @@
1+
import contextlib
12
import logging
23
import subprocess
34

45
import db.settings
56

7+
logger = logging.getLogger(__name__)
8+
9+
# To create a new EDID:
10+
# 1. Convert the existing EDID to binary using "edid2bin".
11+
# 2. Edit the binary using "AW EDID Editor v.02.00.13".
12+
# 3. Save the new EDID in binary format.
13+
# 4. Convert the binary EDID to a hex EDID using "make-edid".
14+
# - Use the "--yaml" option if required.
15+
#
16+
# Note: You may need to perform a few extra steps in order for the EDID
17+
# to conform to edid-decode's check - but only if the "Display Range Limits"
18+
# block changes. This is due to a bug in AW EDID Editor v.02.00.13 that doesn't
19+
# set the correct bytes.
20+
# To work around this:
21+
# 1. Open the new EDID in "AW EDID Editor v.3.0.10".
22+
# 2. Save the EDID to set correct bytes in the "Display Range Limits" block
23+
# 3. Re-open the EDID in "AW EDID Editor v.02.00.13" and re-set
24+
# the screen size dimensions to 0 (both vertical and horizontal)
25+
_EDID_PI4_FILE = '/usr/share/tinypilot/edid_pi4.hex'
26+
27+
28+
def _get_default_edid():
29+
with contextlib.suppress(FileNotFoundError):
30+
with open(_EDID_PI4_FILE, encoding='utf-8') as file:
31+
return file.read().strip()
32+
33+
return None
34+
35+
36+
DEFAULT_EDID = _get_default_edid()
637
DEFAULT_MJPEG_FRAME_RATE = 30
738
DEFAULT_MJPEG_QUALITY = 80
839
DEFAULT_H264_BITRATE = 5000
940
DEFAULT_H264_STUN_SERVER = None
1041
DEFAULT_H264_STUN_PORT = None
1142

12-
logger = logging.getLogger(__name__)
13-
1443

1544
def restart():
1645
"""Restarts the video streaming services for the remote screen.

bundler/bundle/install

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,11 @@ if [[ -n "${FORCE_INSTALL+x}" ]]; then
2525
else
2626
# Restrict installation to only specific configurations.
2727

28-
# Install only on Raspberry Pi 4 Model B.
29-
if ! grep --quiet "^Model\s*: Raspberry Pi 4 Model B" /proc/cpuinfo ; then
28+
# Install only on supported hardware:
29+
# - Raspberry Pi 4 Model B (e.g., Voyager 2)
30+
if ! grep --quiet \
31+
--regexp '^Model\s*: Raspberry Pi 4 Model B' \
32+
/proc/cpuinfo; then
3033
echo 'You are trying to install on unsupported hardware.' >&2
3134
echo 'Visit https://github.com/tiny-pilot/tinypilot/ for more details.' >&2
3235
exit 1

debian-pkg/Dockerfile

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@
44

55
FROM debian:bullseye-20220328-slim AS build
66

7+
ENV DEBIAN_FRONTEND=noninteractive
78
RUN set -exu && \
89
apt-get update && \
9-
DEBIAN_FRONTEND=noninteractive apt-get install -y \
10-
debhelper \
11-
dh-virtualenv \
12-
dpkg-dev
10+
apt-get install --yes --no-install-recommends \
11+
dpkg-dev \
12+
devscripts \
13+
equivs
1314

1415
# Docker populates this value from the --platform argument. See
1516
# https://docs.docker.com/build/building/multi-platform/
@@ -73,16 +74,35 @@ Source: ${PKG_NAME}
7374
Section: net
7475
Priority: optional
7576
Maintainer: TinyPilot Support <support@tinypilotkvm.com>
76-
Build-Depends: debhelper (>= 11)
77+
Build-Depends:
78+
debhelper (>= 11),
79+
dh-virtualenv,
80+
python3-dev,
81+
python3-pip,
82+
python3-venv
7783

7884
Package: ${PKG_NAME}
7985
Architecture: ${PKG_ARCH}
80-
Depends: \${shlibs:Depends}, adduser, janus, nginx, python3, python3-pip, python3-venv, sudo, ustreamer
86+
Depends: \${shlibs:Depends},
87+
\${misc:Depends},
88+
adduser,
89+
janus,
90+
nginx,
91+
python3,
92+
sudo,
93+
ustreamer
8194
Homepage: https://tinypilotkvm.com
8295
Description: Simple, easy-to-use KVM over IP
8396
XBS-Tinypilot-Version: ${TINYPILOT_VERSION}
8497
EOF
8598

99+
# Install build dependencies based on Debian control file.
100+
RUN mk-build-deps \
101+
--tool 'apt-get --option Debug::pkgProblemResolver=yes --no-install-recommends --yes -qq' \
102+
--install \
103+
--remove \
104+
control
105+
86106
RUN set -exu && \
87107
cat >changelog <<EOF
88108
tinypilot (${PKG_VERSION}) bullseye; urgency=medium

0 commit comments

Comments
 (0)