Add web UI notification for under voltage/throttling events (#1203)

This commit is contained in:
Benjamin Krein 2023-09-01 02:23:12 -04:00 committed by GitHub
parent 3b6822d7c8
commit b32027f8c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 207 additions and 2 deletions

View File

@ -6,7 +6,7 @@ Please check out the full story with much more detail on the [wiki](https://gith
# How do I contribute?
PiSCSI is using the <a href="https://datasift.github.io/gitflow/IntroducingGitFlow.html">Gitflow Workflow</a>. A quick overview:
- The *master* branch should always reflect the contents of the last stable release
- The *main* branch should always reflect the contents of the last stable release
- The *develop* branch should contain the latest tested & approved updates. Pull requests should be used to merge changes into develop.
- The rest of the feature branches are for developing new features
- A tag will be created for each "release". The releases will be named <year>.<month>.<release number> where the release number is incremented for each subsequent release tagged in the same calendar month. The first release of the month of January 2021 is called "21.01.01", the second one in the same month "21.01.02" and so on.

View File

@ -1,2 +1,3 @@
protobuf==3.19.5
requests==2.31.0
vcgencmd==0.1.1

View File

@ -27,3 +27,11 @@ class ReturnCodes:
EXTRACTIMAGE_NO_FILES_SPECIFIED = 91
EXTRACTIMAGE_NO_FILES_EXTRACTED = 92
EXTRACTIMAGE_COMMAND_ERROR = 93
UNDER_VOLTAGE_DETECTED = 100
ARM_FREQUENCY_CAPPED = 101
CURRENTLY_THROTTLED = 102
SOFT_TEMPERATURE_LIMIT_ACTIVE = 103
UNDER_VOLTAGE_HAS_OCCURRED = 116
ARM_FREQUENCY_CAPPING_HAS_OCCURRED = 117
THROTTLING_HAS_OCCURRED = 118
SOFT_TEMPERATURE_LIMIT_HAS_OCCURRED = 119

View File

@ -9,7 +9,9 @@ from re import findall, match
from socket import socket, gethostname, AF_INET, SOCK_DGRAM
from pathlib import Path
from platform import uname
from vcgencmd import Vcgencmd
from piscsi.return_codes import ReturnCodes
from piscsi.common_settings import SHELL_ERROR
@ -263,3 +265,37 @@ class SysCmds:
return process.returncode, process.stdout.decode("utf-8")
return process.returncode, process.stderr.decode("utf-8")
@staticmethod
def get_throttled(enabled_modes, test_modes):
"""
Takes (list) enabled_modes & (list) test_modes parameters & returns a
tuple of (str) category & (str) message.
enabled_modes is a list of modes that will be enabled for display if
they're triggered. test_modes works similarly to enabled_mode but will
ALWAYS display the modes listed for troubleshooting styling.
"""
vcgcmd = Vcgencmd()
t_states = vcgcmd.get_throttled()['breakdown']
matched_states = []
state_msgs = {
"0": ("error", ReturnCodes.UNDER_VOLTAGE_DETECTED),
"1": ("warning", ReturnCodes.ARM_FREQUENCY_CAPPED),
"2": ("error", ReturnCodes.CURRENTLY_THROTTLED),
"3": ("warning", ReturnCodes.SOFT_TEMPERATURE_LIMIT_ACTIVE),
"16": ("warning", ReturnCodes.UNDER_VOLTAGE_HAS_OCCURRED),
"17": ("warning", ReturnCodes.ARM_FREQUENCY_CAPPING_HAS_OCCURRED),
"18": ("warning", ReturnCodes.THROTTLING_HAS_OCCURRED),
"19": ("warning", ReturnCodes.SOFT_TEMPERATURE_LIMIT_HAS_OCCURRED),
}
for k in t_states:
if t_states[k] and k in enabled_modes:
matched_states.append(state_msgs[k])
for t in test_modes:
matched_states.append(state_msgs[t])
return matched_states

View File

@ -0,0 +1,23 @@
#!/usr/bin/env bash
# Info: https://www.raspberrypi.com/documentation/computers/os.html#vcgencmd
#
# Bit Hex value Meaning
# ----- ----------- ------------------------
# 0 0x1 Under-voltage detected
# 1 0x2 Arm frequency capped
# 2 0x4 Currently throttled
# 3 0x8 Soft temperature limit active
# 16 0x10000 Under-voltage has occurred
# 17 0x20000 Arm frequency capping has occurred
# 18 0x40000 Throttling has occurred
# 19 0x80000 Soft temperature limit has occurred
if [[ "$1" == "get_throttled" ]]
then
# Return 'Under-voltage detected' & 'Under-voltage has occurred'
echo "throttled=0x10001"
fi
echo "Mock does not recognize: $0 $@"
exit 1

View File

@ -5,4 +5,5 @@ protobuf==3.20.2
requests==2.31.0
simplepam==0.1.5
flask_babel==2.0.0
ua-parser==0.16.1
ua-parser==0.16.1
vcgencmd==0.1.1

View File

@ -50,6 +50,22 @@ class ReturnCodeMapper:
_("No files were extracted (existing files are skipped)"),
ReturnCodes.EXTRACTIMAGE_COMMAND_ERROR:
_("Unable to extract archive: %(error)s"),
ReturnCodes.UNDER_VOLTAGE_DETECTED:
_("Under voltage detected - Make sure to use a proper power source (2.5+ amps)."),
ReturnCodes.ARM_FREQUENCY_CAPPED:
_("ARM frequency capped - Ensure proper airflow/cooling."),
ReturnCodes.CURRENTLY_THROTTLED:
_("Currently throttled - Make sure to use a proper power source (2.5+ amps)."),
ReturnCodes.SOFT_TEMPERATURE_LIMIT_ACTIVE:
_("Soft-temperature limit active - Ensure proper airflow/cooling."),
ReturnCodes.UNDER_VOLTAGE_HAS_OCCURRED:
_("Under voltage has occurred since last reboot. Make sure to use a proper power source (2.5+ amps)."),
ReturnCodes.ARM_FREQUENCY_CAPPING_HAS_OCCURRED:
_("ARM frequency capping has occurred since last reboot. Ensure proper airflow/cooling."),
ReturnCodes.THROTTLING_HAS_OCCURRED:
_("Throttling has occurred since the last reboot. Make sure to use a proper power source (2.5+ amps)."),
ReturnCodes.SOFT_TEMPERATURE_LIMIT_HAS_OCCURRED:
_("Soft temperature limit has occurred since last reboot. Ensure proper airflow/cooling."),
}
# fmt: on

View File

@ -31,3 +31,19 @@ TEMPLATE_THEME_DEFAULT = "modern"
# Fallback theme for older browsers
TEMPLATE_THEME_LEGACY = "classic"
# Enable throttle notifications
#
# Available modes:
# "0": "Under-voltage detected"
# "1": "Arm frequency capped"
# "2": "Currently throttled"
# "3": "Soft temperature limit active"
# "16": "Under-voltage has occurred"
# "17": "Arm frequency capping has occurred"
# "18": "Throttling has occurred"
# "19": "Soft temperature limit has occurred"
THROTTLE_NOTIFY_MODES = ["0", "16"]
# Include a list of modes to be shown ALL THE TIME to be used for styling
# and formatting.
THROTTLE_TEST_MODES = []

View File

@ -172,3 +172,36 @@ summary.filename {
left: 50%;
margin-left: -27px;
}
div.throttle_notice > div {
display: grid;
align-items: center;
background-color: #efefef;
background-repeat: no-repeat;
background-position: 1rem center;
background-size: 1rem;
font-size: x-small;
font-weight: bold;
justify-content: center;
}
div.throttle_notice > div.error {
background-color: #dc3545;
align-items: center;
}
div.throttle_notice > div.warning {
background-color: #ffc107;
align-items: center;
}
div.throttle_notice > div a {
color: black;
text-decoration: none;
}
div.throttle_notice > div a:hover {
text-decoration: underline;
}

View File

@ -470,6 +470,49 @@ div.footer div.theme-change-hint a {
color: yellow;
}
/*
------------------------------------------------------------------------------
Throttle messages
------------------------------------------------------------------------------
*/
div.throttle_notice > div {
display: grid;
align-items: center;
background-color: #efefef;
background-repeat: no-repeat;
background-position: 1rem center;
background-size: 1rem;
font-size: x-small;
font-weight: bold;
}
div.throttle_notice > div.error {
background-color: var(--danger);
background-image: url("icons/error.svg");
color: #fff;
align-items: center;
}
div.throttle_notice > div.warning {
background-color: var(--warning);
background-image: url("icons/warning.svg");
align-items: center;
}
div.throttle_notice > div > span.message {
padding-left: 3rem;
}
div.throttle_notice > div a {
color: black;
text-decoration: none;
}
div.throttle_notice > div a:hover {
text-decoration: underline;
}
/*
------------------------------------------------------------------------------
Flash messages

View File

@ -73,6 +73,18 @@
</div>
</div>
<div class="throttle_notice">
{% if (env["throttle_status"]|length > 0) %}
{% for category, response in env["throttle_status"] %}
<div class="{{ category }}">
<span class="message" title="{{ response['msg'] }}"><a
href="https://www.raspberrypi.com/documentation/computers/configuration.html#undervoltage-warning">Potential
instability due to: {{ response['msg'] }}</a></span>
</div>
{% endfor %}
{% endif %}
</div>
<div class="flash" id="flash">
{% if get_flashed_messages(): %}
{% for category, message in get_flashed_messages(with_categories=true) %}

View File

@ -69,6 +69,8 @@ from settings import (
TEMPLATE_THEMES,
TEMPLATE_THEME_DEFAULT,
TEMPLATE_THEME_LEGACY,
THROTTLE_NOTIFY_MODES,
THROTTLE_TEST_MODES,
)
@ -88,6 +90,9 @@ def get_env_info():
else:
username = None
throttled_statuses = sys_cmd.get_throttled(
THROTTLE_NOTIFY_MODES, THROTTLE_TEST_MODES)
return {
"running_env": sys_cmd.running_env(),
"username": username,
@ -106,6 +111,8 @@ def get_env_info():
"cd_suffixes": tuple(server_info["sccd"]),
"rm_suffixes": tuple(server_info["scrm"]),
"mo_suffixes": tuple(server_info["scmo"]),
"throttle_status":
[(s[0], ReturnCodeMapper.add_msg({"return_code":s[1]})) for s in throttled_statuses],
}

View File

@ -286,3 +286,12 @@ def test_rename_system(env, http_client):
response_data = response.json()
assert response_data["data"]["system_name"] == old_name
def test_throttle_notification(http_client):
response = http_client.get("/")
response_data = response.json()
assert response.status_code == 200
assert response_data["status"] == STATUS_SUCCESS
assert "Under voltage detected" in response_data["data"]