mirror of
https://github.com/akuker/RASCSI.git
synced 2024-12-21 23:29:39 +00:00
Shutdown splash for the OLED script; restore non-Latin transliteration; other refactoring (#991)
- Bring back the shutdown splash, with the tweak that is blanks out after 700ms - Restore the non-Latin transliteration originally from https://github.com/akuker/RASCSI/pull/449 which was lost when the `common` package was introduced - Bump to the latest libraries, while removing implicit dependencies from requirements.txt - Shorter duration of the startup splash - Reintroduce shell shutdown/reboot methods for use with the Web UI. This addresses https://github.com/akuker/RASCSI/issues/538 (the ctrlboard client will continue to use the built-in rascsi system calls which are slightly faster) - Remove overt references to RPi. This addresses https://github.com/akuker/RASCSI/issues/990 - Other refactorings
This commit is contained in:
parent
8c5dcd2f49
commit
4afb11d3dd
@ -445,10 +445,12 @@ class RaCtlCmds:
|
||||
result.ParseFromString(data)
|
||||
return {"status": result.status, "msg": result.msg}
|
||||
|
||||
def shutdown_pi(self, mode):
|
||||
def shutdown(self, mode):
|
||||
"""
|
||||
Sends a SHUT_DOWN command to the server.
|
||||
Takes (str) mode as an argument.
|
||||
The backend will use system calls to reboot or shut down the system.
|
||||
It can also shut down the backend process itself.
|
||||
Returns (bool) status and (str) msg.
|
||||
"""
|
||||
command = proto.PbCommand()
|
||||
|
@ -223,3 +223,31 @@ class SysCmds:
|
||||
return process.returncode, process.stdout.decode("utf-8")
|
||||
|
||||
return process.returncode, process.stderr.decode("utf-8")
|
||||
|
||||
@staticmethod
|
||||
def reboot_system():
|
||||
"""
|
||||
Sends a reboot command to the system
|
||||
"""
|
||||
process = run(
|
||||
["sudo", "reboot"],
|
||||
capture_output=True,
|
||||
)
|
||||
if process.returncode == 0:
|
||||
return process.returncode, process.stdout.decode("utf-8")
|
||||
|
||||
return process.returncode, process.stderr.decode("utf-8")
|
||||
|
||||
@staticmethod
|
||||
def shutdown_system():
|
||||
"""
|
||||
Sends a shutdown command to the system
|
||||
"""
|
||||
process = run(
|
||||
["sudo", "shutdown", "-h", "now"],
|
||||
capture_output=True,
|
||||
)
|
||||
if process.returncode == 0:
|
||||
return process.returncode, process.stdout.decode("utf-8")
|
||||
|
||||
return process.returncode, process.stderr.decode("utf-8")
|
||||
|
@ -193,7 +193,7 @@ class CtrlBoardMenuUpdateEventHandler(Observer):
|
||||
# noinspection PyUnusedLocal
|
||||
def handle_action_menu_shutdown(self, info_object):
|
||||
"""Method handles the rotary button press on 'Shutdown' in the action menu."""
|
||||
self.ractl_cmd.shutdown_pi("system")
|
||||
self.ractl_cmd.shutdown("system")
|
||||
self._menu_controller.show_message("Shutting down!", 150)
|
||||
self._menu_controller.segue(CtrlBoardMenuBuilder.SCSI_ID_MENU,
|
||||
transition_attributes=self._menu_renderer_config.
|
||||
|
@ -19,7 +19,7 @@ class RascsiShutdownCycler(Cycler):
|
||||
if self.executed_once is False:
|
||||
self.executed_once = True
|
||||
self._menu_controller.show_timed_message("Shutting down...")
|
||||
self.ractl_cmd.shutdown_pi("system")
|
||||
self.ractl_cmd.shutdown("system")
|
||||
return "shutdown"
|
||||
|
||||
return None
|
||||
|
@ -1,16 +1,5 @@
|
||||
Adafruit-Blinka==6.15.0
|
||||
adafruit-circuitpython-busdevice==5.1.0
|
||||
adafruit-circuitpython-framebuf==1.4.7
|
||||
adafruit-circuitpython-ssd1306==2.12.2
|
||||
Adafruit-PlatformDetect==3.17.2
|
||||
Adafruit-PureIO==1.1.9
|
||||
Pillow==9.0.1
|
||||
pkg-resources==0.0.0
|
||||
pyftdi==0.53.3
|
||||
pyserial==3.5
|
||||
pyusb==1.2.1
|
||||
rpi-ws281x==4.3.0
|
||||
RPi.GPIO==0.7.0
|
||||
sysv-ipc==1.1.0
|
||||
protobuf==3.19.5
|
||||
unidecode==1.3.2
|
||||
adafruit-circuitpython-ssd1306==2.12.11
|
||||
Pillow==9.3.0
|
||||
protobuf==3.20.2
|
||||
unidecode==1.3.6
|
||||
|
BIN
python/oled/resources/splash_stop_32.bmp
Normal file
BIN
python/oled/resources/splash_stop_32.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 574 B |
BIN
python/oled/resources/splash_stop_64.bmp
Normal file
BIN
python/oled/resources/splash_stop_64.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
@ -35,6 +35,7 @@ import argparse
|
||||
import sys
|
||||
from time import sleep
|
||||
from collections import deque
|
||||
from unidecode import unidecode
|
||||
from board import I2C
|
||||
from adafruit_ssd1306 import SSD1306_I2C
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
@ -125,19 +126,11 @@ print("Will update the OLED display every " + str(DELAY_TIME_MS) + "ms (approxim
|
||||
# Show a startup splash bitmap image before starting the main loop
|
||||
# Convert the image to mode '1' for 1-bit color (monochrome)
|
||||
# Make sure the splash bitmap image is in the same dir as this script
|
||||
IMAGE_STOP = Image.open(f"resources/splash_stop_{HEIGHT}.bmp").convert("1")
|
||||
IMAGE = Image.open(f"resources/splash_start_{HEIGHT}.bmp").convert("1")
|
||||
OLED.image(IMAGE)
|
||||
OLED.show()
|
||||
|
||||
# Keep the pretty splash on screen for a number of seconds
|
||||
sleep(4)
|
||||
|
||||
# Get drawing object to draw on image.
|
||||
DRAW = ImageDraw.Draw(IMAGE)
|
||||
|
||||
# Draw a black filled box to clear the image.
|
||||
DRAW.rectangle((0, 0, WIDTH, HEIGHT), outline=0, fill=0)
|
||||
|
||||
# Draw some shapes.
|
||||
# First define some constants to allow easy resizing of shapes.
|
||||
# Depending on the font used, you may want to change the value of PADDING
|
||||
@ -164,6 +157,15 @@ IP_ADDR, HOSTNAME = sys_cmd.get_ip_and_host()
|
||||
REMOVABLE_DEVICE_TYPES = ractl_cmd.get_removable_device_types()
|
||||
PERIPHERAL_DEVICE_TYPES = ractl_cmd.get_peripheral_device_types()
|
||||
|
||||
# Keep the pretty splash up on screen for a number of seconds
|
||||
sleep(2)
|
||||
|
||||
# Get drawing object to draw on image.
|
||||
DRAW = ImageDraw.Draw(IMAGE)
|
||||
|
||||
# Draw a black filled box to clear the image.
|
||||
DRAW.rectangle((0, 0, WIDTH, HEIGHT), outline=0, fill=0)
|
||||
|
||||
def formatted_output():
|
||||
"""
|
||||
Formats the strings to be displayed on the Screen
|
||||
@ -176,6 +178,9 @@ def formatted_output():
|
||||
output.append("Permission denied!")
|
||||
elif rascsi_list:
|
||||
for line in rascsi_list:
|
||||
# Transliterate non-Latin characters
|
||||
if line["file"]:
|
||||
line["file"] = unidecode(line["file"])
|
||||
if line["device_type"] in REMOVABLE_DEVICE_TYPES:
|
||||
# Print image file name only when there is an image attached
|
||||
if line["file"]:
|
||||
@ -207,10 +212,24 @@ def formatted_output():
|
||||
output.append("Check network connection")
|
||||
return output
|
||||
|
||||
def shutdown():
|
||||
"""
|
||||
Display the shutdown splash, then blank the screen after a sleep
|
||||
Finally shuts down the script
|
||||
"""
|
||||
OLED.image(IMAGE_STOP)
|
||||
OLED.show()
|
||||
OLED.fill(0)
|
||||
sleep(700/1000)
|
||||
OLED.show()
|
||||
sys.exit("Shutting down the OLED display...")
|
||||
|
||||
|
||||
with GracefulInterruptHandler() as handler:
|
||||
"""
|
||||
The main display loop inside an interrupt handler
|
||||
"""
|
||||
while True:
|
||||
|
||||
# The reference snapshot of attached devices that will be compared against each cycle
|
||||
# to identify changes in RaSCSI backend
|
||||
ref_snapshot = formatted_output()
|
||||
@ -239,8 +258,4 @@ with GracefulInterruptHandler() as handler:
|
||||
snapshot = formatted_output()
|
||||
|
||||
if handler.interrupted:
|
||||
# Catch interrupt signals and blank out the screen
|
||||
DRAW.rectangle((0, 0, WIDTH, HEIGHT), outline=0, fill=0)
|
||||
OLED.image(IMAGE)
|
||||
OLED.show()
|
||||
sys.exit("Shutting down the OLED display...")
|
||||
shutdown()
|
||||
|
@ -348,7 +348,7 @@
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<p><small>{{ _("%(disk_space)s MiB disk space remaining on the Pi", disk_space=env["free_disk_space"]) }}</small></p>
|
||||
<p><small>{{ _("%(disk_space)s MiB disk space remaining on the system", disk_space=env["free_disk_space"]) }}</small></p>
|
||||
</section>
|
||||
|
||||
<hr/>
|
||||
@ -723,18 +723,18 @@
|
||||
<section id="system">
|
||||
<details>
|
||||
<summary class="heading">
|
||||
{{ _("Raspberry Pi Operations") }}
|
||||
{{ _("System Operations") }}
|
||||
</summary>
|
||||
<ul>
|
||||
<li>{{ _("IMPORTANT: Always shut down the Pi before turning off the power. Failing to do so may lead to data loss.") }}</li>
|
||||
<li>{{ _("IMPORTANT: Always shut down the system before turning off the power. Failing to do so may lead to data loss.") }}</li>
|
||||
</ul>
|
||||
</details>
|
||||
|
||||
<form action="/pi/reboot" method="post" onclick="if (confirm('{{ _("Reboot the Raspberry Pi?") }}')) shutdownNotify('{{ _("Rebooting the Raspberry Pi...") }}'); else event.preventDefault();">
|
||||
<input type="submit" value="{{ _("Reboot Raspberry Pi") }}">
|
||||
<form action="/sys/reboot" method="post" onclick="if (confirm('{{ _("Reboot the System?") }}')) shutdownNotify('{{ _("Rebooting the system...") }}'); else event.preventDefault();">
|
||||
<input type="submit" value="{{ _("Reboot System") }}">
|
||||
</form>
|
||||
<form action="/pi/shutdown" method="post" onclick="if (confirm('{{ _("Shut down the Raspberry Pi?") }}')) shutdownNotify('{{ _("Shutting down the Raspberry Pi...") }}'); else event.preventDefault();">
|
||||
<input type="submit" value="{{ _("Shut Down Raspberry Pi") }}">
|
||||
<form action="/sys/shutdown" method="post" onclick="if (confirm('{{ _("Shut down the System?") }}')) shutdownNotify('{{ _("Shutting down the system...") }}'); else event.preventDefault();">
|
||||
<input type="submit" value="{{ _("Shut Down System") }}">
|
||||
</form>
|
||||
</section>
|
||||
|
||||
|
@ -797,24 +797,30 @@ def release_id():
|
||||
return response(error=True, message=process["msg"])
|
||||
|
||||
|
||||
@APP.route("/pi/reboot", methods=["POST"])
|
||||
@APP.route("/sys/reboot", methods=["POST"])
|
||||
@login_required
|
||||
def restart():
|
||||
"""
|
||||
Restarts the Pi
|
||||
Restarts the system
|
||||
"""
|
||||
ractl_cmd.shutdown_pi("reboot")
|
||||
return response()
|
||||
returncode, message = sys_cmd.reboot_system()
|
||||
if not returncode:
|
||||
return response()
|
||||
|
||||
return response(error=True, message=message)
|
||||
|
||||
|
||||
@APP.route("/pi/shutdown", methods=["POST"])
|
||||
@APP.route("/sys/shutdown", methods=["POST"])
|
||||
@login_required
|
||||
def shutdown():
|
||||
"""
|
||||
Shuts down the Pi
|
||||
Shuts down the system
|
||||
"""
|
||||
ractl_cmd.shutdown_pi("system")
|
||||
return response()
|
||||
returncode, message = sys_cmd.shutdown_system()
|
||||
if not returncode:
|
||||
return response()
|
||||
|
||||
return response(error=True, message=message)
|
||||
|
||||
|
||||
@APP.route("/files/download_to_iso", methods=["POST"])
|
||||
@ -889,7 +895,7 @@ def download_to_iso():
|
||||
@login_required
|
||||
def download_file():
|
||||
"""
|
||||
Downloads a remote file onto the images dir on the Pi
|
||||
Downloads a remote file onto the images dir on the system
|
||||
"""
|
||||
destination = request.form.get("destination")
|
||||
url = request.form.get("url")
|
||||
@ -915,7 +921,7 @@ def download_file():
|
||||
@APP.route("/files/upload", methods=["POST"])
|
||||
def upload_file():
|
||||
"""
|
||||
Uploads a file from the local computer to the images dir on the Pi
|
||||
Uploads a file from the local computer to the images dir on the system
|
||||
Depending on the Dropzone.js JavaScript library
|
||||
"""
|
||||
# Due to the embedded javascript library, we cannot use the @login_required decorator
|
||||
@ -1052,7 +1058,7 @@ def create_file():
|
||||
@login_required
|
||||
def download():
|
||||
"""
|
||||
Downloads a file from the Pi to the local computer
|
||||
Downloads a file from the system to the local computer
|
||||
"""
|
||||
file_name = Path(request.form.get("file"))
|
||||
safe_path = is_safe_path(file_name)
|
||||
|
@ -164,7 +164,7 @@ def test_set_theme(http_client, theme):
|
||||
response = http_client.post(
|
||||
"/theme",
|
||||
data={
|
||||
"theme": theme,
|
||||
"name": theme,
|
||||
},
|
||||
)
|
||||
|
||||
@ -187,7 +187,7 @@ def test_set_theme_via_query_string(http_client, theme):
|
||||
response = http_client.get(
|
||||
"/theme",
|
||||
params={
|
||||
"v": theme,
|
||||
"name": theme,
|
||||
},
|
||||
)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user