Version {{ plugin_pi_support_octopi_version }}, running on {{ plugin_pi_support_model }}
6 | 7 |13 | © 2013-{{ now.strftime("%Y") }} The OctoPi Authors 14 |
15 | 16 |17 | OctoPi is free software: you can redistribute it and/or modify 18 | it under the terms of the GNU General Public License as published by 19 | the Free Software Foundation, either version 3 of the License, or 20 | (at your option) any later version. 21 |
22 |23 | OctoPi is distributed in the hope that it will be useful, 24 | but WITHOUT ANY WARRANTY; without even the implied warranty of 25 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26 | GNU General Public License for more details. 27 |
28 |29 | For a copy of the GNU General Public License, see 30 | www.gnu.org/licenses/gpl-3.0.en.html. 31 |
32 | -------------------------------------------------------------------------------- /octoprint_pi_support/health_checks.py: -------------------------------------------------------------------------------- 1 | from . import ( 2 | _UNRECOMMENDED_MODELS, 3 | get_proc_dt_model, 4 | has_default_password, 5 | is_model_any_of, 6 | ) 7 | 8 | try: 9 | import octoprint.plugins.health_check.checks as checks 10 | except ImportError: 11 | try: 12 | # in case we extract it into a standalone plugin in the future... 13 | import octoprint_health_check.checks as checks 14 | except ImportError: 15 | # apparently the plugin is disabled 16 | checks = None 17 | 18 | if checks is not None: 19 | 20 | class PiSupportHealthCheck(checks.HealthCheck): 21 | def __init__(self, plugin, settings: dict): 22 | super().__init__(settings) 23 | self._plugin = plugin 24 | 25 | class PiUndervoltageHealthCheck(PiSupportHealthCheck): 26 | key = "pi_undervoltage" 27 | 28 | def perform_check(self, force=False): 29 | state = self._plugin.get_throttle_state() 30 | 31 | if state["current_undervoltage"]: 32 | return checks.CheckResult(result=checks.Result.ISSUE, context=state) 33 | elif state["past_undervoltage"]: 34 | return checks.CheckResult(result=checks.Result.WARNING, context=state) 35 | 36 | class PiUnsupportedHealthCheck(PiSupportHealthCheck): 37 | key = "pi_unsupported" 38 | 39 | def perform_check(self, force=False): 40 | model = get_proc_dt_model() 41 | if is_model_any_of(model, *_UNRECOMMENDED_MODELS): 42 | return checks.CheckResult(result=checks.Result.WARNING) 43 | 44 | class PiDefaultPasswordHealthCheck(PiSupportHealthCheck): 45 | key = "pi_default_password" 46 | 47 | def perform_check(self, force=False): 48 | if has_default_password(): 49 | return checks.CheckResult(result=checks.Result.WARNING) 50 | 51 | all_checks = [ 52 | PiUndervoltageHealthCheck, 53 | PiUnsupportedHealthCheck, 54 | PiDefaultPasswordHealthCheck, 55 | ] 56 | 57 | else: 58 | all_checks = [] 59 | -------------------------------------------------------------------------------- /octoprint_pi_support/templates/pi_support_about_octopiuptodate.jinja2: -------------------------------------------------------------------------------- 1 |Build {{ plugin_pi_support_octopiuptodate_build_short }} with "{{ plugin_pi_support_octopi_camera_stack }}", based on OctoPi {{ plugin_pi_support_octopi_version }}, running on {{ plugin_pi_support_model }}
6 | 7 |15 | © 2021-{{ now.strftime("%Y") }} The OctoPi-UpToDate Authors 16 |
17 | 18 |19 | OctoPi-UpToDate is free software: you can redistribute it and/or modify 20 | it under the terms of the GNU General Public License as published by 21 | the Free Software Foundation, either version 3 of the License, or 22 | (at your option) any later version. 23 |
24 |25 | OctoPi-UpToDate is distributed in the hope that it will be useful, 26 | but WITHOUT ANY WARRANTY; without even the implied warranty of 27 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 | GNU General Public License for more details. 29 |
30 |31 | For a copy of the GNU General Public License, see 32 | www.gnu.org/licenses/gpl-3.0.en.html. 33 |
34 | 35 | {% include "pi_support_about_octopi.jinja2" %} 36 | -------------------------------------------------------------------------------- /Taskfile.yml: -------------------------------------------------------------------------------- 1 | # https://taskfile.dev 2 | 3 | version: "3" 4 | 5 | env: 6 | LOCALES: ["de"] # list your included locales here, e.g. ["de", "fr"] 7 | TRANSLATIONS: "octoprint_pi_support/translations" # translations folder, do not touch 8 | 9 | tasks: 10 | install: 11 | desc: Installs the plugin into the current venv 12 | cmds: 13 | - "python -m pip install -e .[develop]" 14 | 15 | test: 16 | desc: Run the plugin's test suite 17 | cmds: 18 | - "python -m pytest" 19 | 20 | ### Build related 21 | 22 | build: 23 | desc: Builds sdist & wheel 24 | cmds: 25 | - python -m build --sdist --wheel 26 | 27 | build-sdist: 28 | desc: Builds sdist 29 | cmds: 30 | - python -m build --sdist 31 | 32 | build-wheel: 33 | desc: Builds wheel 34 | cmds: 35 | - python -m build --wheel 36 | 37 | ### Translation related 38 | 39 | babel-new: 40 | desc: Create a new translation for a locale 41 | cmds: 42 | - task: babel-extract 43 | - | 44 | pybabel init --input-file=translations/messages.pot --output-dir=translations --locale="{{ .CLI_ARGS }}" 45 | 46 | babel-extract: 47 | desc: Update pot file from source 48 | cmds: 49 | - pybabel extract --mapping-file=babel.cfg --output-file=translations/messages.pot --msgid-bugs-address=i18n@octoprint.org --copyright-holder="The OctoPrint Project" . 50 | 51 | babel-update: 52 | desc: Update translation files from pot file 53 | cmds: 54 | - for: 55 | var: LOCALES 56 | cmd: pybabel update --input-file=translations/messages.pot --output-dir=translations --locale={{ .ITEM }} 57 | 58 | babel-refresh: 59 | desc: Update translation files from source 60 | cmds: 61 | - task: babel-extract 62 | - task: babel-update 63 | 64 | babel-compile: 65 | desc: Compile translation files 66 | cmds: 67 | - pybabel compile --directory=translations 68 | 69 | babel-bundle: 70 | desc: Bundle translations 71 | preconditions: 72 | - test -d {{ .TRANSLATIONS }} 73 | cmds: 74 | - for: 75 | var: LOCALES 76 | cmd: | 77 | locale="{{ .ITEM }}" 78 | source="translations/${locale}" 79 | target="{{ .TRANSLATIONS }}/${locale}" 80 | 81 | [ ! -d "${target}" ] || rm -r "${target}" 82 | 83 | echo "Copying translations for locale ${locale} from ${source} to ${target}..." 84 | cp -r "${source}" "${target}" 85 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pi Support 2 | 3 | The Pi Support plugin provides additional information about your Pi in the UI and also 4 | alerts you about undervoltage or overheating issues observed on your Pi or if your Pi is 5 | unsupported. If you are running OctoPi, the Pi Support plugin will also provide additional 6 | information about that. 7 | 8 | OctoPrint will only load this plugin when it detects that it is being run on a 9 | Raspberry Pi. 10 | 11 | This plugin was bundled right with OctoPrint's sources until version 1.6.0. It has been 12 | extracted into a standalone project to allow for a different release cycle, but is still 13 | considered a bundled plugin. 14 | 15 | ## Setup 16 | 17 | The plugin is part of the core dependencies of OctoPrint 1.6.0+ and will be installed automatically alongside it. 18 | 19 | In case you want to manually install it into an older version for whatever reason, install via the bundled 20 | [Plugin Manager](https://docs.octoprint.org/en/main/bundledplugins/pluginmanager.html) 21 | or manually using this URL: 22 | 23 | https://github.com/OctoPrint/OctoPrint-PiSupport/archive/main.zip 24 | 25 | To install and/or rollback to a specific version `{{ _('Please restart OctoPrint after changing any of this plugin\'s settings.') }}
4 | 5 | 59 | -------------------------------------------------------------------------------- /.github/workflows/issue_automation.yml: -------------------------------------------------------------------------------- 1 | name: "Issue Automation" 2 | on: 3 | issues: 4 | types: [opened, edited, closed, reopened, labeled, unlabeled] 5 | 6 | jobs: 7 | issue-automation: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/github-script@v7 11 | env: 12 | REMINDER: > 13 | Hi @${{ github.event.issue.user.login }}! 14 | 15 | 16 | It looks like you didn't upload a [system info bundle](https://community.octoprint.org/t/29887) as requested by the template. 17 | A bundle is required to further process your issue. It contains important logs and 18 | system information to be able to put your issue into context and give pointers as to 19 | what has happened. 20 | 21 | 22 | Please **edit your original post above** and upload **a bundle zip file**. Actually upload the file please and 23 | do not paste some link to a cloud provider, we want to have everything in one place here. Also do 24 | not unpack, repack or otherwise modify the bundle or its name, share it **exactly** like you get it from OctoPrint. 25 | 26 | 27 | Without the availability of a bundle, your issue will have to be closed. 28 | 29 | 30 | Thank you for your collaboration. 31 | THANKYOU: > 32 | Thank you @${{ github.event.issue.user.login }} for adding a bundle! Now this can actually get looked at. 33 | with: 34 | script: | 35 | const { REMINDER, THANKYOU } = process.env; 36 | const bundleRegex = /\[(octoprint-systeminfo-\d{14}\.zip)\]\(([^)]+)\)/g; 37 | const marker = ""; 38 | 39 | const issueLabels = await github.rest.issues.listLabelsOnIssue({ 40 | owner: context.repo.owner, 41 | repo: context.repo.repo, 42 | issue_number: context.issue.number 43 | }); 44 | let labels = issueLabels.data.map(label => label.name); 45 | 46 | const comments = await github.rest.issues.listComments({ 47 | owner: context.repo.owner, 48 | repo: context.repo.repo, 49 | issue_number: context.issue.number, 50 | }) 51 | const comment = comments.data.find(c => c.user.login === "github-actions[bot]" && c.body.includes(marker)); 52 | if (comment) { 53 | console.log("Found comment, id=" + comment.id); 54 | } else { 55 | console.log("No comment found"); 56 | } 57 | 58 | if (!labels.includes("triage") || !labels.includes("bug") || labels.includes("approved")) { 59 | console.log("Deleting comment if it exists..."); 60 | if (comment) { 61 | await github.rest.issues.deleteComment({ 62 | owner: context.repo.owner, 63 | repo: context.repo.repo, 64 | comment_id: comment.id, 65 | }) 66 | } 67 | return; 68 | } 69 | 70 | const found = !!context.payload.issue.body.match(bundleRegex); 71 | 72 | if (!found) { 73 | console.log("No bundle found, posting/updating reminder"); 74 | const text = REMINDER + "\n" + marker; 75 | if (!comment) { 76 | await github.rest.issues.createComment({ 77 | owner: context.repo.owner, 78 | repo: context.repo.repo, 79 | issue_number: context.issue.number, 80 | body: text 81 | }); 82 | } else if (comment.body !== text) { 83 | await github.rest.issues.updateComment({ 84 | owner: context.repo.owner, 85 | repo: context.repo.repo, 86 | comment_id: comment.id, 87 | body: text 88 | }); 89 | } 90 | } else if (found && comment) { 91 | console.log("Bundle found, saying thanks"); 92 | const text = REMINDER.split("\n\n").map(line => `~~${line.trim()}~~`).join("\n\n") + "\n\n" + THANKYOU + "\n" + marker; 93 | if (comment.body !== text) { 94 | await github.rest.issues.updateComment({ 95 | owner: context.repo.owner, 96 | repo: context.repo.repo, 97 | comment_id: comment.id, 98 | body: text 99 | }); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: 🐛 Report a bug 2 | description: Create a bug report to help improve Pi Support 3 | labels: 4 | - bug 5 | - triage 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: >- 10 | **Thank you for wanting to report a bug in Pi Support!** 11 | 12 | * First, be sure you are running the [latest version of the Pi Support plugin](https://github.com/OctoPrint/OctoPrint-PiSupport/releases). 13 | * You will also need to [enable debug logging on the plugin](https://docs.octoprint.org/en/main/configuration/logging_yaml.html). 14 | * This may be done through the *Settings* > *OctoPrint* > *Logging* > *Logging Levels* section. 15 | * Select the `octoprint.plugins.pi_support` name, and make sure Level is "DEBUG". 16 | * Save, then restart OctoPrint, which allows the developers to see debug information from the moment the plugin is loaded. 17 | * Finally, when submitting a bug report, you **must** [include a Systeminfo Bundle](https://community.octoprint.org/t/what-is-a-systeminfo-bundle-and-how-can-i-obtain-one/29887), generated after the point the bug occurs. This allows the developers to examine the debug logs produced from your plugin installation. 18 | 19 | Thank you for your help! 20 | - type: textarea 21 | attributes: 22 | label: The problem 23 | description: >- 24 | Describe the issue you are experiencing here. Tell us what you were trying to do 25 | step by step, and what happened that you did not expect. 26 | 27 | Provide a clear and concise description of what the problem is and include as many 28 | details as possible. 29 | placeholder: | 30 | 1. ... 31 | 2. ... 32 | 3. ... 33 | validations: 34 | required: true 35 | - type: markdown 36 | attributes: 37 | value: | 38 | ## Environment 39 | - type: input 40 | attributes: 41 | label: Version of Pi Support 42 | description: Can be found in *Settings* > *Plugin Manager*, next to "Pi Support". 43 | validations: 44 | required: true 45 | - type: input 46 | attributes: 47 | label: Version of OctoPrint 48 | description: Can be found in the lower left corner of the web interface. 49 | validations: 50 | required: true 51 | - type: input 52 | attributes: 53 | label: Operating system running OctoPrint 54 | description: >- 55 | OctoPi, Linux, Windows, MacOS, something else? With version please? OctoPi's 56 | version can be found in `/etc/octopi_version` or in the lower left corner of the 57 | web interface. 58 | validations: 59 | required: true 60 | - type: input 61 | attributes: 62 | label: Printer model & used firmware incl. version 63 | description: If applicable, always include if unsure 64 | - type: input 65 | attributes: 66 | label: Browser and version of browser, operating system running browser 67 | description: If applicable, always include if unsure 68 | - type: markdown 69 | attributes: 70 | value: | 71 | ## Logs and other files needed for analysis 72 | - type: markdown 73 | attributes: 74 | value: >- 75 | Please also be sure to upload the following files below: 76 | 77 | * Systeminfo Bundle: See [here](https://community.octoprint.org/t/what-is-a-systeminfo-bundle-and-how-can-i-obtain-one/29887) if you don't know where to find that. Just attach down below as-is. 78 | * If you are reporting an issue that involves communicating with you printer, **be sure to enable `serial.log` before reproducing and creating the Systeminfo Bundle**! 79 | * Your browser's JavaScript console, if you are reporting a problem with the user interface. See [here](https://webmasters.stackexchange.com/questions/8525/how-to-open-the-javascript-console-in-different-browsers) on where to find that. 80 | * If possible, screenshots or videos showing the problem, especially if you are reporting a problem with the user interface! 81 | * GCODE files with which to reproduce. 82 | 83 | Please be aware that unless at least Systeminfo Bundle is included, your bug report 84 | will not be processed and closed after a while. 85 | - type: checkboxes 86 | attributes: 87 | label: Checklist of files to include below 88 | options: 89 | - label: Systeminfo Bundle (always include!) 90 | required: true 91 | - label: Contents of the JavaScript browser console (always include in cases of issues with the user interface) 92 | - label: Screenshots and/or videos showing the problem (always include in case of issues with the user interface) 93 | - label: GCODE file with which to reproduce. 94 | - type: textarea 95 | attributes: 96 | label: Additional information & file uploads 97 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build pipeline 2 | on: 3 | push: 4 | branches: 5 | - main 6 | - devel 7 | release: 8 | types: [released] 9 | 10 | jobs: 11 | build: 12 | name: 🔨 Build distribution 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - name: 🏗 Set up Python 3.10 17 | uses: actions/setup-python@v5 18 | with: 19 | python-version: "3.10" 20 | - name: 🔨 Build distribution 21 | uses: OctoPrint/actions/build-dist@main 22 | with: 23 | artifact: dist 24 | 25 | pre-commit: 26 | name: 🧹 Pre-commit 27 | runs-on: ubuntu-latest 28 | steps: 29 | - uses: actions/checkout@v4 30 | - name: 🏗 Set up Python 3.10 31 | uses: actions/setup-python@v4 32 | with: 33 | python-version: "3.10" 34 | - name: 🏗 Set up dev dependencies 35 | run: | 36 | pip install -e .[develop] 37 | - name: 🚀 Run pre-commit 38 | run: | 39 | pre-commit run --all-files --show-diff-on-failure 40 | 41 | test-unit: 42 | name: 🧪 Unit tests 43 | strategy: 44 | fail-fast: false 45 | matrix: 46 | python: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] 47 | runs-on: ubuntu-22.04 # change back to ubuntu-latest once we drop Python 3.7 48 | steps: 49 | - uses: actions/checkout@v4 50 | - name: 🏗 Set up Python ${{ matrix.python }} 51 | uses: actions/setup-python@v4 52 | with: 53 | python-version: ${{ matrix.python }} 54 | - name: 🏗 Set up test dependencies 55 | run: | 56 | pip install octoprint 57 | pip install -e .[develop] 58 | - name: 🚀 Run test suite 59 | run: | 60 | pytest | tee report.txt 61 | pytest_exit=${PIPESTATUS[0]} 62 | 63 | # generate summary 64 | python=$(python -c 'import sys; print(".".join(map(str, sys.version_info[:3])))') 65 | today=$(date +'%Y-%m-%d') 66 | now=$(date +'%H:%M') 67 | summary=$(tail -n1 report.txt | sed 's/^=*\s//g' | sed 's/\s=*$//g') 68 | 69 | cat << EOF >> $GITHUB_STEP_SUMMARY 70 | ### Test Report 71 | 72 | *generated on $today at $now under Python $python* 73 | 74 |vcgencmd doesn't work as expected. Make sure the system user"
65 | " OctoPrint is running under is a member of the \"video\" group."
66 | msgstr ""
67 |
68 | #: octoprint_pi_support/static/js/pi_support.js:86
69 | msgid "Cannot check for throttling"
70 | msgstr ""
71 |
72 | #: octoprint_pi_support/static/js/pi_support.js:99
73 | msgid ""
74 | "Your Raspberry Pi is reporting insufficient power. Switch to an adequate "
75 | "power supply or risk bad performance and failed prints."
76 | msgstr ""
77 |
78 | #: octoprint_pi_support/static/js/pi_support.js:111
79 | msgid "Undervoltage detected"
80 | msgstr ""
81 |
82 | #: octoprint_pi_support/static/js/pi_support.js:134
83 | msgid ""
84 | "The default password for the system user \"pi\" has not been changed. "
85 | "This is a security risk - please login to your Pi via SSH and change the "
86 | "password."
87 | msgstr ""
88 |
89 | #: octoprint_pi_support/static/js/pi_support.js:143
90 | msgid ""
91 | "You can disable this message via Settings > Pi Support > Disable warning "
92 | "about default system password"
93 | msgstr ""
94 |
95 | #: octoprint_pi_support/static/js/pi_support.js:150
96 | msgid "Default system password not changed"
97 | msgstr ""
98 |
99 | #: octoprint_pi_support/static/js/pi_support.js:176
100 | msgid "OctoPi"
101 | msgstr ""
102 |
103 | #: octoprint_pi_support/static/js/pi_support.js:199
104 | msgid ""
105 | "Make sure your power supply and cabling are providing enough power to the"
106 | " Pi."
107 | msgstr ""
108 |
109 | #: octoprint_pi_support/static/js/pi_support.js:205
110 | msgid "Frequency capping due to overheating. Improve cooling of the CPU and GPU."
111 | msgstr ""
112 |
113 | #: octoprint_pi_support/static/js/pi_support.js:211
114 | msgid "Current issues:"
115 | msgstr ""
116 |
117 | #: octoprint_pi_support/static/js/pi_support.js:214
118 | msgid "The following issues are being observed right now:"
119 | msgstr ""
120 |
121 | #: octoprint_pi_support/static/js/pi_support.js:232
122 | msgid "Issues since boot:"
123 | msgstr ""
124 |
125 | #: octoprint_pi_support/static/js/pi_support.js:235
126 | msgid "The following issues have been observed since the Pi was booted:"
127 | msgstr ""
128 |
129 | #: octoprint_pi_support/static/js/pi_support.js:249
130 | msgid "Click the navbar icon for more information."
131 | msgstr ""
132 |
133 | #: octoprint_pi_support/static/js/pi_support.js:279
134 | msgid "Undervoltage detected, print anyway?"
135 | msgstr ""
136 |
137 | #: octoprint_pi_support/static/js/pi_support.js:281
138 | msgid ""
139 | "Your Pi is reporting undervoltage. It is not recommended to start a print"
140 | " job until an adequate power supply has been installed."
141 | msgstr ""
142 |
143 | #: octoprint_pi_support/static/js/pi_support.js:285
144 | msgid "See also the FAQ"
145 | msgstr ""
146 |
147 | #: octoprint_pi_support/static/js/pi_support.js:287
148 | msgid "Start the print job anyway?"
149 | msgstr ""
150 |
151 | #: octoprint_pi_support/static/js/pi_support.js:288
152 | msgid "No, don't print"
153 | msgstr ""
154 |
155 | #: octoprint_pi_support/static/js/pi_support.js:290
156 | msgid "Yes, print"
157 | msgstr ""
158 |
159 | #: octoprint_pi_support/static/js/pi_support.js:291
160 | msgid "Yes, print & don't warn again"
161 | msgstr ""
162 |
163 | #: octoprint_pi_support/templates/pi_support_about_octopi.jinja2:1
164 | msgid "About OctoPi"
165 | msgstr ""
166 |
167 | #: octoprint_pi_support/templates/pi_support_navbar.jinja2:1
168 | msgid "What do the symbols mean?"
169 | msgstr ""
170 |
171 | #: octoprint_pi_support/templates/pi_support_navbar.jinja2:2
172 | msgid "Undervoltage"
173 | msgstr ""
174 |
175 | #: octoprint_pi_support/templates/pi_support_navbar.jinja2:3
176 | msgid "Overheat"
177 | msgstr ""
178 |
179 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:3
180 | msgid "Please restart OctoPrint after changing any of this plugin's settings."
181 | msgstr ""
182 |
183 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:9
184 | msgid "Disable warning about unsupported hardware"
185 | msgstr ""
186 |
187 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:9
188 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:18
189 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:28
190 | msgid "Warning"
191 | msgstr ""
192 |
193 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:11
194 | msgid ""
195 | "If you check this, you will no longer get warned if you run OctoPrint on "
196 | "Raspberry Pi models that are not officially supported due to bad "
197 | "performance that can lead to failed prints. Do so at your own risk."
198 | msgstr ""
199 |
200 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:18
201 | msgid "Disable warning about default system password"
202 | msgstr ""
203 |
204 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:20
205 | msgid ""
206 | "If you check this, you will no longer get warned if you still have the "
207 | "default password set on your \"pi\" system user. This is a security risk."
208 | msgstr ""
209 |
210 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:28
211 | msgid "Disable warning about undervoltage on print start"
212 | msgstr ""
213 |
214 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:30
215 | msgid ""
216 | "If you check this, you will no longer get warned when starting prints "
217 | "during observed undervoltage issues. Do so at your own risk."
218 | msgstr ""
219 |
220 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:38
221 | msgid ""
222 | "Enable under voltage and overheat detection via vcgencmd "
223 | "get_throttled"
224 | msgstr ""
225 |
226 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:40
227 | msgid ""
228 | "This will regularly check with the Pi if something is amiss either with "
229 | "power regulation or CPU/GPU temperature. Disable at your own risk. You "
230 | "will have to re-enable this when getting assistance on the forums or "
231 | "Discord. Changes require a restart of OctoPrint."
232 | msgstr ""
233 |
234 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:45
235 | msgid "Advanced options"
236 | msgstr ""
237 |
238 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:49
239 | msgid "Command for under voltage/overheat detection"
240 | msgstr ""
241 |
242 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:52
243 | msgid ""
244 | "Defaults to /usr/bin/vcgencmd get_throttled. You usually "
245 | "shouldn't have to change this."
246 | msgstr ""
247 |
248 |
--------------------------------------------------------------------------------
/tests/fakes/fake_camerastack_journal.txt:
--------------------------------------------------------------------------------
1 | -- Journal begins at Thu 2022-09-22 01:23:40 BST, ends at Wed 2023-05-24 16:28:00 BST. --
2 | May 24 01:48:08 octopic systemd[1]: Starting camera-streamer...
3 | May 24 01:48:08 octopic camera-streamer-control[533]: Running start for camera-streamer-libcamera.service...
4 | May 24 01:48:08 octopic camera-streamer-control[533]: ... done.
5 | May 24 01:48:08 octopic camera-streamer-control[533]: Adding path unit for autolaunch of camera-streamer-usb@default
6 | May 24 01:48:08 octopic systemd[1]: Starting camera-streamer libcamera...
7 | May 24 01:48:09 octopic camera-streamer-control[533]: Running start for camera-streamer-usb-default.path...
8 | May 24 01:48:09 octopic camera-streamer-control[533]: ... done.
9 | May 24 01:48:09 octopic systemd[1]: Started camera-streamer default autolaunch.
10 | May 24 01:48:09 octopic systemd[1]: Finished camera-streamer.
11 | May 24 01:48:11 octopic sh[549]: /base/soc/i2c0mux/i2c@1/ov5647@36
12 | May 24 01:48:11 octopic systemd[1]: Started camera-streamer libcamera.
13 | May 24 01:48:15 octopic sh[589]: /usr/bin/camera-streamer Version: v0.1-21-g54f538e (54f538e)
14 | May 24 01:48:15 octopic sh[589]: [0:00:20.341406502] [589] INFO Camera camera_manager.cpp:299 libcamera v0.0.4+22-923f5d70
15 | May 24 01:48:15 octopic sh[589]: [0:00:20.411405304] [705] INFO RPI raspberrypi.cpp:1476 Registered camera /base/soc/i2c0mux/i2c@1/ov5647@36 to Unicam device /dev/media2 and ISP device /dev/media0
16 | May 24 01:48:15 octopic sh[589]: device/libcamera/device.cc: CAMERA: Device path=/base/soc/i2c0mux/i2c@1/ov5647@36 opened
17 | May 24 01:48:15 octopic sh[589]: [0:00:20.413811397] [589] INFO Camera camera.cpp:1028 configuring streams: (0) 1920x1080-YUYV
18 | May 24 01:48:15 octopic sh[589]: [0:00:20.414694522] [705] INFO RPI raspberrypi.cpp:851 Sensor: /base/soc/i2c0mux/i2c@1/ov5647@36 - Selected sensor format: 1920x1080-SGBRG10_1X10 - Selected unicam format: 1920x1080-pGAA
19 | May 24 01:48:15 octopic sh[589]: [0:00:20.418496866] [589] INFO Camera camera.cpp:1028 configuring streams: (0) 1920x1080-YUYV (1) 1920x1080-SGBRG10_CSI2P
20 | May 24 01:48:15 octopic sh[589]: [0:00:20.419256345] [705] INFO RPI raspberrypi.cpp:851 Sensor: /base/soc/i2c0mux/i2c@1/ov5647@36 - Selected sensor format: 1920x1080-SGBRG10_1X10 - Selected unicam format: 1920x1080-pGAA
21 | May 24 01:48:15 octopic sh[589]: device/buffer_list.c: CAMERA:capture: Using: 1920x1080/YUYV, buffers=2, bytesperline=3840, sizeimage=0.0MiB
22 | May 24 01:48:15 octopic sh[589]: device/buffer_list.c: CAMERA:capture: Opened 2 buffers. Memory used: 7.9 MiB
23 | May 24 01:48:15 octopic sh[589]: device/buffer_list.c: CAMERA:capture:1: Using: 1920x1080/GB10, buffers=2, bytesperline=2400, sizeimage=0.0MiB
24 | May 24 01:48:15 octopic sh[589]: device/buffer_list.c: CAMERA:capture:1: Opened 2 buffers. Memory used: 4.9 MiB
25 | May 24 01:48:15 octopic sh[589]: device/v4l2/device.c: SNAPSHOT: Device path=/dev/video31 fd=37 opened
26 | May 24 01:48:15 octopic sh[589]: device/v4l2/buffer_list.c: SNAPSHOT:output:mplane: Requested resolution=1920x1080 is unavailable. Got 1920x1088.
27 | May 24 01:48:15 octopic sh[589]: device/buffer_list.c: SNAPSHOT:output:mplane: Using: 1920x1056/YUYV, buffers=2, bytesperline=3840, sizeimage=3.9MiB
28 | May 24 01:48:15 octopic sh[589]: device/buffer_list.c: SNAPSHOT:output:mplane: Opened 2 buffers. Memory used: 0.0 MiB
29 | May 24 01:48:15 octopic sh[589]: device/buffer_list.c: SNAPSHOT:capture:mplane: Using: 1920x1056/JPEG, buffers=2, bytesperline=0, sizeimage=4.0MiB
30 | May 24 01:48:15 octopic sh[589]: device/buffer_list.c: SNAPSHOT:capture:mplane: Opened 2 buffers. Memory used: 8.0 MiB
31 | May 24 01:48:15 octopic sh[589]: device/v4l2/device.c: RESCALLER:STREAM: Device path=/dev/video12 fd=40 opened
32 | May 24 01:48:15 octopic sh[589]: device/buffer_list.c: RESCALLER:STREAM:output:mplane: Using: 1920x1080/YUYV, buffers=2, bytesperline=3840, sizeimage=4.0MiB
33 | May 24 01:48:15 octopic sh[589]: device/buffer_list.c: RESCALLER:STREAM:output:mplane: Opened 2 buffers. Memory used: 0.0 MiB
34 | May 24 01:48:15 octopic sh[589]: device/buffer_list.c: RESCALLER:STREAM:capture:mplane: Using: 1312x736/YUYV, buffers=2, bytesperline=2624, sizeimage=1.8MiB
35 | May 24 01:48:15 octopic sh[589]: device/buffer_list.c: RESCALLER:STREAM:capture:mplane: Opened 2 buffers. Memory used: 3.7 MiB
36 | May 24 01:48:15 octopic sh[589]: device/v4l2/device.c: STREAM: Device path=/dev/video31 fd=43 opened
37 | May 24 01:48:15 octopic sh[589]: device/buffer_list.c: STREAM:output:mplane: Using: 1312x736/YUYV, buffers=2, bytesperline=2624, sizeimage=1.8MiB
38 | May 24 01:48:15 octopic sh[589]: device/buffer_list.c: STREAM:output:mplane: Opened 2 buffers. Memory used: 0.0 MiB
39 | May 24 01:48:15 octopic sh[589]: device/buffer_list.c: STREAM:capture:mplane: Using: 1312x736/JPEG, buffers=2, bytesperline=0, sizeimage=4.0MiB
40 | May 24 01:48:15 octopic sh[589]: device/buffer_list.c: STREAM:capture:mplane: Opened 2 buffers. Memory used: 8.0 MiB
41 | May 24 01:48:15 octopic sh[589]: device/v4l2/device.c: VIDEO: Device path=/dev/video11 fd=46 opened
42 | May 24 01:48:15 octopic sh[589]: device/buffer_list.c: VIDEO:output:mplane: Using: 1312x736/YUYV, buffers=2, bytesperline=2624, sizeimage=1.8MiB
43 | May 24 01:48:15 octopic sh[589]: device/buffer_list.c: VIDEO:output:mplane: Opened 2 buffers. Memory used: 0.0 MiB
44 | May 24 01:48:15 octopic sh[589]: device/buffer_list.c: VIDEO:capture:mplane: Using: 1312x736/H264, buffers=2, bytesperline=0, sizeimage=0.8MiB
45 | May 24 01:48:15 octopic sh[589]: device/buffer_list.c: VIDEO:capture:mplane: Opened 2 buffers. Memory used: 1.5 MiB
46 | May 24 01:48:15 octopic sh[589]: device/device.c: CAMERA: Setting frame interval_us=0 for FPS=15
47 | May 24 01:48:15 octopic sh[589]: device/v4l2/device_options.c: SNAPSHOT: Configuring option compressionquality (009d0903) = 80
48 | May 24 01:48:15 octopic sh[589]: device/v4l2/device_options.c: STREAM: Configuring option compressionquality (009d0903) = 80
49 | May 24 01:48:15 octopic sh[589]: device/v4l2/device_options.c: VIDEO: Configuring option repeatsequenceheader (009909e2) = 1
50 | May 24 01:48:15 octopic sh[589]: device/v4l2/device_options.c: VIDEO: Configuring option videobitratemode (009909ce) = 0
51 | May 24 01:48:15 octopic sh[589]: device/v4l2/device_options.c: VIDEO: Configuring option videobitrate (009909cf) = 2000000
52 | May 24 01:48:15 octopic sh[589]: device/v4l2/device_options.c: VIDEO: Configuring option repeatsequenceheader (009909e2) = 5000000
53 | May 24 01:48:15 octopic sh[589]: device/v4l2/device_options.c: VIDEO: Configuring option h264iframeperiod (00990a66) = 30
54 | May 24 01:48:15 octopic sh[589]: device/v4l2/device_options.c: VIDEO: Configuring option h264level (00990a67) = 11
55 | May 24 01:48:15 octopic sh[589]: device/v4l2/device_options.c: VIDEO: Configuring option h264profile (00990a6b) = 4
56 | May 24 01:48:15 octopic sh[589]: device/v4l2/device_options.c: VIDEO: Configuring option h264minimumqpvalue (00990a61) = 16
57 | May 24 01:48:15 octopic sh[589]: device/v4l2/device_options.c: VIDEO: Configuring option h264maximumqpvalue (00990a62) = 32
58 | May 24 01:48:15 octopic sh[589]: device/links.c: ?: Link 0: CAMERA:capture[1920x1080/YUYV/2] => [SNAPSHOT:output:mplane[1920x1056/YUYV/2], RESCALLER:STREAM:output:mplane[1920x1080/YUYV/2]]
59 | May 24 01:48:15 octopic sh[589]: device/links.c: ?: Link 1: SNAPSHOT:capture:mplane[1920x1056/JPEG/2] => [SNAPSHOT-CAPTURE]
60 | May 24 01:48:15 octopic sh[589]: device/links.c: ?: Link 2: RESCALLER:STREAM:capture:mplane[1312x736/YUYV/2] => [STREAM:output:mplane[1312x736/YUYV/2], VIDEO:output:mplane[1312x736/YUYV/2]]
61 | May 24 01:48:15 octopic sh[589]: device/links.c: ?: Link 3: STREAM:capture:mplane[1312x736/JPEG/2] => [STREAM-CAPTURE]
62 | May 24 01:48:15 octopic sh[589]: device/links.c: ?: Link 4: VIDEO:capture:mplane[1312x736/H264/2] => [VIDEO-CAPTURE]
63 | May 24 01:48:16 octopic sh[589]: device/buffer_list.c: CAMERA:capture: Streaming started... Was 0 of 2 enqueud
64 | May 24 01:48:16 octopic sh[589]: device/buffer_list.c: SNAPSHOT:output:mplane: Streaming started... Was 0 of 2 enqueud
65 | May 24 01:48:16 octopic sh[589]: device/buffer_list.c: RESCALLER:STREAM:output:mplane: Streaming started... Was 0 of 2 enqueud
66 | May 24 01:48:16 octopic sh[589]: device/buffer_list.c: SNAPSHOT:capture:mplane: Streaming started... Was 0 of 2 enqueud
67 | May 24 01:48:16 octopic sh[589]: device/buffer_list.c: RESCALLER:STREAM:capture:mplane: Streaming started... Was 0 of 2 enqueud
68 | May 24 01:48:16 octopic sh[589]: device/buffer_list.c: STREAM:output:mplane: Streaming started... Was 0 of 2 enqueud
69 | May 24 01:48:16 octopic sh[589]: device/buffer_list.c: VIDEO:output:mplane: Streaming started... Was 0 of 2 enqueud
70 | May 24 01:48:16 octopic sh[589]: device/buffer_list.c: STREAM:capture:mplane: Streaming started... Was 0 of 2 enqueud
71 | May 24 01:48:16 octopic sh[589]: device/buffer_list.c: VIDEO:capture:mplane: Streaming started... Was 0 of 2 enqueud
72 | May 24 12:16:11 octopic sh[589]: util/http/http.c: HTTP8080/2: Client connected 127.0.0.1 (fd=5).
73 | May 24 12:16:11 octopic sh[589]: util/http/http.c: HTTP8080/2: Request 'GET' '/' ''
74 | May 24 12:16:11 octopic sh[589]: util/http/http.c: HTTP8080/2: Client disconnected 127.0.0.1.
75 |
--------------------------------------------------------------------------------
/translations/de/LC_MESSAGES/messages.po:
--------------------------------------------------------------------------------
1 | # German translations for OctoPrint-PiSupport.
2 | # Copyright (C) 2020 The OctoPrint Project
3 | # This file is distributed under the same license as the
4 | # OctoPrint-PiSupport project.
5 | # FIRST AUTHOR vcgencmd doesn't work as expected. Make sure the system user"
79 | " OctoPrint is running under is a member of the \"video\" group."
80 | msgstr ""
81 |
82 | #: octoprint_pi_support/static/js/pi_support.js:86
83 | msgid "Cannot check for throttling"
84 | msgstr ""
85 |
86 | #: octoprint_pi_support/static/js/pi_support.js:99
87 | msgid ""
88 | "Your Raspberry Pi is reporting insufficient power. Switch to an adequate "
89 | "power supply or risk bad performance and failed prints."
90 | msgstr ""
91 | "Dein Raspberry Pi meldet eine zu niedrige Spannung. Wechsle auf ein "
92 | "ausreichendes Netzteil, oder riskiere schlechte Performance und "
93 | "fehlgeschlagene Druckaufträge."
94 |
95 | #: octoprint_pi_support/static/js/pi_support.js:111
96 | msgid "Undervoltage detected"
97 | msgstr "Zu niedrige Spannung"
98 |
99 | #: octoprint_pi_support/static/js/pi_support.js:134
100 | msgid ""
101 | "The default password for the system user \"pi\" has not been changed. "
102 | "This is a security risk - please login to your Pi via SSH and change the "
103 | "password."
104 | msgstr ""
105 | "Das Standardpasswort des Systemnutzers \"pi\" wurde nicht geändert. Das "
106 | "ist ein Sicherheitsrisiko - bitte melde dich bei deinem Pi über SSH an "
107 | "und ändere das Passwort."
108 |
109 | #: octoprint_pi_support/static/js/pi_support.js:143
110 | msgid ""
111 | "You can disable this message via Settings > Pi Support > Disable warning "
112 | "about default system password"
113 | msgstr ""
114 | "Du kannst diese Nachricht deaktiveren über Einstellungen > Pi Support > "
115 | "Ignoriere Warnung über Standardsystempasswort"
116 |
117 | #: octoprint_pi_support/static/js/pi_support.js:150
118 | msgid "Default system password not changed"
119 | msgstr "Standardsystempasswort nicht geändert"
120 |
121 | #: octoprint_pi_support/static/js/pi_support.js:176
122 | msgid "OctoPi"
123 | msgstr "OctoPi"
124 |
125 | #: octoprint_pi_support/static/js/pi_support.js:199
126 | msgid ""
127 | "Make sure your power supply and cabling are providing enough power to the"
128 | " Pi."
129 | msgstr ""
130 | "Stelle sicher, dass dein Netzteil und die Verkabelung dem Pi genug Strom "
131 | "liefern."
132 |
133 | #: octoprint_pi_support/static/js/pi_support.js:205
134 | msgid "Frequency capping due to overheating. Improve cooling of the CPU and GPU."
135 | msgstr ""
136 | "Heruntertaktung aufgrund von Überhitzung. Verbessere die Kühlung von CPU "
137 | "und GPU."
138 |
139 | #: octoprint_pi_support/static/js/pi_support.js:211
140 | msgid "Current issues:"
141 | msgstr "Aktuelle Probleme:"
142 |
143 | #: octoprint_pi_support/static/js/pi_support.js:214
144 | msgid "The following issues are being observed right now:"
145 | msgstr "Die folgenden Probleme werden gerade jetzt gemeldet:"
146 |
147 | #: octoprint_pi_support/static/js/pi_support.js:232
148 | msgid "Issues since boot:"
149 | msgstr "Probleme seit dem Bootvorgang:"
150 |
151 | #: octoprint_pi_support/static/js/pi_support.js:235
152 | msgid "The following issues have been observed since the Pi was booted:"
153 | msgstr ""
154 | "Die folgenden Probleme wurde seit dem letzten Bootvorgang des Pis "
155 | "gemeldet:"
156 |
157 | #: octoprint_pi_support/static/js/pi_support.js:249
158 | msgid "Click the navbar icon for more information."
159 | msgstr "Klick für weitere Informationen auf das Symbol in der Navbar."
160 |
161 | #: octoprint_pi_support/static/js/pi_support.js:279
162 | msgid "Undervoltage detected, print anyway?"
163 | msgstr "Zu niedrige Spannung erkannt, trotzdem drucken?"
164 |
165 | #: octoprint_pi_support/static/js/pi_support.js:281
166 | msgid ""
167 | "Your Pi is reporting undervoltage. It is not recommended to start a print"
168 | " job until an adequate power supply has been installed."
169 | msgstr ""
170 | "Dein Pi meldet eine zu niedrige Spannung. Es ist nicht empfohlen, einen "
171 | "Druckauftrag zu starten, bis ein ausreichendes Netzteil installiert ist."
172 |
173 | #: octoprint_pi_support/static/js/pi_support.js:285
174 | msgid "See also the FAQ"
175 | msgstr "Siehe also die FAQ"
176 |
177 | #: octoprint_pi_support/static/js/pi_support.js:287
178 | msgid "Start the print job anyway?"
179 | msgstr "Den Druck trotzdem starten?"
180 |
181 | #: octoprint_pi_support/static/js/pi_support.js:288
182 | msgid "No, don't print"
183 | msgstr "Nein, nicht drucken"
184 |
185 | #: octoprint_pi_support/static/js/pi_support.js:290
186 | msgid "Yes, print"
187 | msgstr "Ja, drucken"
188 |
189 | #: octoprint_pi_support/static/js/pi_support.js:291
190 | msgid "Yes, print & don't warn again"
191 | msgstr "Ja, drucken & nicht mehr warnen"
192 |
193 | #: octoprint_pi_support/templates/pi_support_about_octopi.jinja2:1
194 | msgid "About OctoPi"
195 | msgstr "Über OctoPi"
196 |
197 | #: octoprint_pi_support/templates/pi_support_navbar.jinja2:1
198 | msgid "What do the symbols mean?"
199 | msgstr "Was bedeuten die Symbole?"
200 |
201 | #: octoprint_pi_support/templates/pi_support_navbar.jinja2:2
202 | msgid "Undervoltage"
203 | msgstr "Zu niedrige Spannung"
204 |
205 | #: octoprint_pi_support/templates/pi_support_navbar.jinja2:3
206 | msgid "Overheat"
207 | msgstr "Überhitzung"
208 |
209 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:3
210 | msgid "Please restart OctoPrint after changing any of this plugin's settings."
211 | msgstr ""
212 | "Bitte starte OctoPrint neu, nachdem du die Einstellungen dieses Plugins "
213 | "geändert hast."
214 |
215 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:9
216 | msgid "Disable warning about unsupported hardware"
217 | msgstr "Ignoriere Warnung über nicht unterstützte Hardware"
218 |
219 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:9
220 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:18
221 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:28
222 | msgid "Warning"
223 | msgstr "Warnung"
224 |
225 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:11
226 | msgid ""
227 | "If you check this, you will no longer get warned if you run OctoPrint on "
228 | "Raspberry Pi models that are not officially supported due to bad "
229 | "performance that can lead to failed prints. Do so at your own risk."
230 | msgstr ""
231 | "Falls du das aktivierst, wird dich OctoPrint nicht mehr davor warnen, "
232 | "wenn du es auf Raspberry Pi Modellen laufen lässt, die aufgrund bekannter"
233 | " Probleme mit Performance und fehlgeschlagenen Druckaufträgen nicht "
234 | "offiziell unterstützt werden. Du tust dies auf deine eigene "
235 | "Verantwortung."
236 |
237 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:18
238 | msgid "Disable warning about default system password"
239 | msgstr "Ignoriere Warnung über Standardsystempasswort"
240 |
241 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:20
242 | msgid ""
243 | "If you check this, you will no longer get warned if you still have the "
244 | "default password set on your \"pi\" system user. This is a security risk."
245 | msgstr ""
246 |
247 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:28
248 | msgid "Disable warning about undervoltage on print start"
249 | msgstr "Ignoriere Warnung über zu niedrige Spannung beim Druckstart"
250 |
251 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:30
252 | msgid ""
253 | "If you check this, you will no longer get warned when starting prints "
254 | "during observed undervoltage issues. Do so at your own risk."
255 | msgstr ""
256 | "Wenn du das aktivierst, wird OctoPrint dich nicht mehr warnen, wenn du "
257 | "einen Druckjob startest während dein Pi zu niedrige Spannung meldet. Du "
258 | "tust dies auf deine eigene Verantwortung."
259 |
260 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:38
261 | msgid ""
262 | "Enable under voltage and overheat detection via vcgencmd "
263 | "get_throttled"
264 | msgstr ""
265 | "Erkennung zu niedriger Spannung und Überhitzung via vcgencmd "
266 | "get_throttled einschalten"
267 |
268 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:40
269 | msgid ""
270 | "This will regularly check with the Pi if something is amiss either with "
271 | "power regulation or CPU/GPU temperature. Disable at your own risk. You "
272 | "will have to re-enable this when getting assistance on the forums or "
273 | "Discord. Changes require a restart of OctoPrint."
274 | msgstr ""
275 | "Es wird regelmäßig geprüft, ob etwas mit der Spannungsversorgung oder der "
276 | "CPU/GPU Temperatur des Pis nicht stimmt. Deaktivere dies auf deine eigene "
277 | "Verantwortung. Du wirst es reaktivieren müssen, wenn du Hilfe im Forum "
278 | "oder auf Discord erbittest. Änderungen erfordern einen Neustart von "
279 | "OctoPrint."
280 |
281 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:45
282 | msgid "Advanced options"
283 | msgstr "Erweiterte Optionen"
284 |
285 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:49
286 | msgid "Command for under voltage/overheat detection"
287 | msgstr "Befehl für Spannungs-/Überhitzungserkennung"
288 |
289 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:52
290 | msgid ""
291 | "Defaults to /usr/bin/vcgencmd get_throttled. You usually "
292 | "shouldn't have to change this."
293 | msgstr ""
294 | "Standardeinstellung ist /usr/bin/vcgencmd get_throttled. Du "
295 | "solltest das gewöhnlich nicht ändern müssen."
296 |
--------------------------------------------------------------------------------
/octoprint_pi_support/translations/de/LC_MESSAGES/messages.po:
--------------------------------------------------------------------------------
1 | # German translations for OctoPrint-PiSupport.
2 | # Copyright (C) 2020 The OctoPrint Project
3 | # This file is distributed under the same license as the
4 | # OctoPrint-PiSupport project.
5 | # FIRST AUTHOR vcgencmd doesn't work as expected. Make sure the system user"
79 | " OctoPrint is running under is a member of the \"video\" group."
80 | msgstr ""
81 |
82 | #: octoprint_pi_support/static/js/pi_support.js:86
83 | msgid "Cannot check for throttling"
84 | msgstr ""
85 |
86 | #: octoprint_pi_support/static/js/pi_support.js:99
87 | msgid ""
88 | "Your Raspberry Pi is reporting insufficient power. Switch to an adequate "
89 | "power supply or risk bad performance and failed prints."
90 | msgstr ""
91 | "Dein Raspberry Pi meldet eine zu niedrige Spannung. Wechsle auf ein "
92 | "ausreichendes Netzteil, oder riskiere schlechte Performance und "
93 | "fehlgeschlagene Druckaufträge."
94 |
95 | #: octoprint_pi_support/static/js/pi_support.js:111
96 | msgid "Undervoltage detected"
97 | msgstr "Zu niedrige Spannung"
98 |
99 | #: octoprint_pi_support/static/js/pi_support.js:134
100 | msgid ""
101 | "The default password for the system user \"pi\" has not been changed. "
102 | "This is a security risk - please login to your Pi via SSH and change the "
103 | "password."
104 | msgstr ""
105 | "Das Standardpasswort des Systemnutzers \"pi\" wurde nicht geändert. Das "
106 | "ist ein Sicherheitsrisiko - bitte melde dich bei deinem Pi über SSH an "
107 | "und ändere das Passwort."
108 |
109 | #: octoprint_pi_support/static/js/pi_support.js:143
110 | msgid ""
111 | "You can disable this message via Settings > Pi Support > Disable warning "
112 | "about default system password"
113 | msgstr ""
114 | "Du kannst diese Nachricht deaktiveren über Einstellungen > Pi Support > "
115 | "Ignoriere Warnung über Standardsystempasswort"
116 |
117 | #: octoprint_pi_support/static/js/pi_support.js:150
118 | msgid "Default system password not changed"
119 | msgstr "Standardsystempasswort nicht geändert"
120 |
121 | #: octoprint_pi_support/static/js/pi_support.js:176
122 | msgid "OctoPi"
123 | msgstr "OctoPi"
124 |
125 | #: octoprint_pi_support/static/js/pi_support.js:199
126 | msgid ""
127 | "Make sure your power supply and cabling are providing enough power to the"
128 | " Pi."
129 | msgstr ""
130 | "Stelle sicher, dass dein Netzteil und die Verkabelung dem Pi genug Strom "
131 | "liefern."
132 |
133 | #: octoprint_pi_support/static/js/pi_support.js:205
134 | msgid "Frequency capping due to overheating. Improve cooling of the CPU and GPU."
135 | msgstr ""
136 | "Heruntertaktung aufgrund von Überhitzung. Verbessere die Kühlung von CPU "
137 | "und GPU."
138 |
139 | #: octoprint_pi_support/static/js/pi_support.js:211
140 | msgid "Current issues:"
141 | msgstr "Aktuelle Probleme:"
142 |
143 | #: octoprint_pi_support/static/js/pi_support.js:214
144 | msgid "The following issues are being observed right now:"
145 | msgstr "Die folgenden Probleme werden gerade jetzt gemeldet:"
146 |
147 | #: octoprint_pi_support/static/js/pi_support.js:232
148 | msgid "Issues since boot:"
149 | msgstr "Probleme seit dem Bootvorgang:"
150 |
151 | #: octoprint_pi_support/static/js/pi_support.js:235
152 | msgid "The following issues have been observed since the Pi was booted:"
153 | msgstr ""
154 | "Die folgenden Probleme wurde seit dem letzten Bootvorgang des Pis "
155 | "gemeldet:"
156 |
157 | #: octoprint_pi_support/static/js/pi_support.js:249
158 | msgid "Click the navbar icon for more information."
159 | msgstr "Klick für weitere Informationen auf das Symbol in der Navbar."
160 |
161 | #: octoprint_pi_support/static/js/pi_support.js:279
162 | msgid "Undervoltage detected, print anyway?"
163 | msgstr "Zu niedrige Spannung erkannt, trotzdem drucken?"
164 |
165 | #: octoprint_pi_support/static/js/pi_support.js:281
166 | msgid ""
167 | "Your Pi is reporting undervoltage. It is not recommended to start a print"
168 | " job until an adequate power supply has been installed."
169 | msgstr ""
170 | "Dein Pi meldet eine zu niedrige Spannung. Es ist nicht empfohlen, einen "
171 | "Druckauftrag zu starten, bis ein ausreichendes Netzteil installiert ist."
172 |
173 | #: octoprint_pi_support/static/js/pi_support.js:285
174 | msgid "See also the FAQ"
175 | msgstr "Siehe also die FAQ"
176 |
177 | #: octoprint_pi_support/static/js/pi_support.js:287
178 | msgid "Start the print job anyway?"
179 | msgstr "Den Druck trotzdem starten?"
180 |
181 | #: octoprint_pi_support/static/js/pi_support.js:288
182 | msgid "No, don't print"
183 | msgstr "Nein, nicht drucken"
184 |
185 | #: octoprint_pi_support/static/js/pi_support.js:290
186 | msgid "Yes, print"
187 | msgstr "Ja, drucken"
188 |
189 | #: octoprint_pi_support/static/js/pi_support.js:291
190 | msgid "Yes, print & don't warn again"
191 | msgstr "Ja, drucken & nicht mehr warnen"
192 |
193 | #: octoprint_pi_support/templates/pi_support_about_octopi.jinja2:1
194 | msgid "About OctoPi"
195 | msgstr "Über OctoPi"
196 |
197 | #: octoprint_pi_support/templates/pi_support_navbar.jinja2:1
198 | msgid "What do the symbols mean?"
199 | msgstr "Was bedeuten die Symbole?"
200 |
201 | #: octoprint_pi_support/templates/pi_support_navbar.jinja2:2
202 | msgid "Undervoltage"
203 | msgstr "Zu niedrige Spannung"
204 |
205 | #: octoprint_pi_support/templates/pi_support_navbar.jinja2:3
206 | msgid "Overheat"
207 | msgstr "Überhitzung"
208 |
209 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:3
210 | msgid "Please restart OctoPrint after changing any of this plugin's settings."
211 | msgstr ""
212 | "Bitte starte OctoPrint neu, nachdem du die Einstellungen dieses Plugins "
213 | "geändert hast."
214 |
215 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:9
216 | msgid "Disable warning about unsupported hardware"
217 | msgstr "Ignoriere Warnung über nicht unterstützte Hardware"
218 |
219 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:9
220 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:18
221 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:28
222 | msgid "Warning"
223 | msgstr "Warnung"
224 |
225 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:11
226 | msgid ""
227 | "If you check this, you will no longer get warned if you run OctoPrint on "
228 | "Raspberry Pi models that are not officially supported due to bad "
229 | "performance that can lead to failed prints. Do so at your own risk."
230 | msgstr ""
231 | "Falls du das aktivierst, wird dich OctoPrint nicht mehr davor warnen, "
232 | "wenn du es auf Raspberry Pi Modellen laufen lässt, die aufgrund bekannter"
233 | " Probleme mit Performance und fehlgeschlagenen Druckaufträgen nicht "
234 | "offiziell unterstützt werden. Du tust dies auf deine eigene "
235 | "Verantwortung."
236 |
237 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:18
238 | msgid "Disable warning about default system password"
239 | msgstr "Ignoriere Warnung über Standardsystempasswort"
240 |
241 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:20
242 | msgid ""
243 | "If you check this, you will no longer get warned if you still have the "
244 | "default password set on your \"pi\" system user. This is a security risk."
245 | msgstr ""
246 |
247 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:28
248 | msgid "Disable warning about undervoltage on print start"
249 | msgstr "Ignoriere Warnung über zu niedrige Spannung beim Druckstart"
250 |
251 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:30
252 | msgid ""
253 | "If you check this, you will no longer get warned when starting prints "
254 | "during observed undervoltage issues. Do so at your own risk."
255 | msgstr ""
256 | "Wenn du das aktivierst, wird OctoPrint dich nicht mehr warnen, wenn du "
257 | "einen Druckjob startest während dein Pi zu niedrige Spannung meldet. Du "
258 | "tust dies auf deine eigene Verantwortung."
259 |
260 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:38
261 | msgid ""
262 | "Enable under voltage and overheat detection via vcgencmd "
263 | "get_throttled"
264 | msgstr ""
265 | "Erkennung zu niedriger Spannung und Überhitzung via vcgencmd "
266 | "get_throttled einschalten"
267 |
268 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:40
269 | msgid ""
270 | "This will regularly check with the Pi if something is amiss either with "
271 | "power regulation or CPU/GPU temperature. Disable at your own risk. You "
272 | "will have to re-enable this when getting assistance on the forums or "
273 | "Discord. Changes require a restart of OctoPrint."
274 | msgstr ""
275 | "Es wird regelmäßig geprüft, ob etwas mit der Spannungsversorgung oder der "
276 | "CPU/GPU Temperatur des Pis nicht stimmt. Deaktivere dies auf deine eigene "
277 | "Verantwortung. Du wirst es reaktivieren müssen, wenn du Hilfe im Forum "
278 | "oder auf Discord erbittest. Änderungen erfordern einen Neustart von "
279 | "OctoPrint."
280 |
281 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:45
282 | msgid "Advanced options"
283 | msgstr "Erweiterte Optionen"
284 |
285 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:49
286 | msgid "Command for under voltage/overheat detection"
287 | msgstr "Befehl für Spannungs-/Überhitzungserkennung"
288 |
289 | #: octoprint_pi_support/templates/pi_support_settings.jinja2:52
290 | msgid ""
291 | "Defaults to /usr/bin/vcgencmd get_throttled. You usually "
292 | "shouldn't have to change this."
293 | msgstr ""
294 | "Standardeinstellung ist /usr/bin/vcgencmd get_throttled. Du "
295 | "solltest das gewöhnlich nicht ändern müssen."
296 |
--------------------------------------------------------------------------------
/octoprint_pi_support/static/js/pi_support.js:
--------------------------------------------------------------------------------
1 | $(function () {
2 | function PiSupportViewModel(parameters) {
3 | var self = this;
4 |
5 | const UNDERVOLTAGE_TITLE = gettext("Undervoltage detected");
6 | const UNDERVOLTAGE_WARNING = gettext(
7 | "Your Raspberry Pi is reporting insufficient power. " +
8 | "Switch to an adequate power supply or risk bad " +
9 | "performance and failed prints."
10 | );
11 | const UNDERVOLTAGE_FAQ = "https://faq.octoprint.org/pi-issues";
12 |
13 | const ZERO_TITLE = gettext("Unsupported hardware detected");
14 | const ZERO_WARNING = gettext(
15 | "OctoPrint does not and never has supported the " +
16 | "RPi Zero or Zero W. Use at least a Raspberry Pi 3 or Zero 2, or " +
17 | "risk bad performance and failed prints."
18 | );
19 | const ZERO_DISABLE = gettext(
20 | "You can disable this message via Settings > " +
21 | "Pi Support > Disable warning about unsupported hardware"
22 | );
23 | const ZERO_FAQ = "https://faq.octoprint.org/recommended-hardware";
24 |
25 | const PASSWORD_TITLE = gettext("Default system password not changed");
26 | const PASSWORD_WARNING = gettext(
27 | 'The default password for the system user "pi" has not ' +
28 | "been changed. This is a security risk - please login to " +
29 | "your Pi via SSH and change the password."
30 | );
31 | const PASSWORD_DISABLE = gettext(
32 | "You can disable this message via Settings > " +
33 | "Pi Support > Disable warning about default system password"
34 | );
35 | const PASSWORD_FAQ = "https://faq.octoprint.org/pi-default-password";
36 |
37 | const FAQ = gettext(
38 | 'You can read more in the FAQ.'
39 | );
40 |
41 | const generateHtml = (warning, faq, disable) => {
42 | const html =
43 | "" + 44 | warning + 45 | "
" + 46 | _.sprintf(FAQ, { 47 | url: faq 48 | }) + 49 | "
"; 50 | 51 | if (disable) { 52 | return html + "" + disable + "
"; 53 | } else { 54 | return html; 55 | } 56 | }; 57 | 58 | self.loginState = parameters[0]; 59 | self.access = parameters[1]; 60 | self.settings = parameters[2]; 61 | 62 | self.model = ko.observable(); 63 | 64 | self.currentUndervoltage = ko.observable(false); 65 | self.currentOverheat = ko.observable(false); 66 | self.pastUndervoltage = ko.observable(false); 67 | self.pastOverheat = ko.observable(false); 68 | self.currentIssue = ko.observable(false); 69 | self.pastIssue = ko.observable(false); 70 | 71 | self.notifications = {}; 72 | 73 | self.requestData = function () { 74 | if ( 75 | !self.loginState.hasPermission( 76 | self.access.permissions.PLUGIN_PI_SUPPORT_STATUS 77 | ) 78 | ) { 79 | return; 80 | } 81 | 82 | OctoPrint.plugins.pi_support.get().done(function (response) { 83 | // Raspberry Pi model 84 | self.model(response.model); 85 | 86 | // Unrecommended model 87 | if ( 88 | response.model_unrecommended && 89 | !self.settings.settings.plugins.pi_support.ignore_unrecommended_model() 90 | ) { 91 | if (self.notifications.unrecommended === undefined) { 92 | self.notifications.unrecommended = new PNotify({ 93 | title: ZERO_TITLE, 94 | text: generateHtml(ZERO_WARNING, ZERO_FAQ, ZERO_DISABLE), 95 | type: "error", 96 | hide: false 97 | }); 98 | } 99 | } else if (self.notifications.unrecommended !== undefined) { 100 | self.notifications.unrecommended.remove(); 101 | self.notifications.unrecommended = undefined; 102 | } 103 | 104 | // Throttle functional 105 | if (!response.throttle_functional) { 106 | var warning = gettext( 107 | "OctoPrint cannot check for throttling situations " + 108 | "reported by your Pi.vcgencmd doesn't work as expected. Make " +
109 | "sure the system user OctoPrint is running under is a member of " +
110 | 'the "video" group.'
111 | );
112 |
113 | if (self.notifications.vcgencmd_broken === undefined) {
114 | self.notifications.vcgencmd_broken = new PNotify({
115 | title: gettext("Cannot check for throttling"),
116 | text: "" + warning + "
", 117 | hide: false 118 | }); 119 | } 120 | } else if (self.notifications.vcgencmd_broken !== undefined) { 121 | self.notifications.vcgencmd_broken.remove(); 122 | self.notifications.vcgencmd_broken = undefined; 123 | } 124 | 125 | // Throttle state 126 | self.fromThrottleState(response.throttle_state); 127 | if (self.currentUndervoltage() || self.pastUndervoltage()) { 128 | if (self.notifications.throttled === undefined) { 129 | self.notifications.throttled = new PNotify({ 130 | title: UNDERVOLTAGE_TITLE, 131 | text: generateHtml(UNDERVOLTAGE_WARNING, UNDERVOLTAGE_FAQ), 132 | type: "error", 133 | hide: false 134 | }); 135 | } 136 | } else if (self.notifications.throttled !== undefined) { 137 | self.notifications.throttled.remove(); 138 | self.notifications.throttled = undefined; 139 | } 140 | 141 | // SSH warn 142 | if ( 143 | response.default_password && 144 | !self.settings.settings.plugins.pi_support.ignore_default_password() 145 | ) { 146 | if (self.notifications.default_password === undefined) { 147 | self.notifications.default_password = new PNotify({ 148 | title: PASSWORD_TITLE, 149 | text: generateHtml( 150 | PASSWORD_WARNING, 151 | PASSWORD_FAQ, 152 | PASSWORD_DISABLE 153 | ), 154 | hide: false 155 | }); 156 | } 157 | } else if (self.notifications.default_password !== undefined) { 158 | self.notifications.default_password.remove(); 159 | self.notifications.default_password = undefined; 160 | } 161 | 162 | // OctoPi version 163 | $("#pi_support_footer").remove(); 164 | if (!response.octopi_version) return; 165 | 166 | if (response.octopiuptodate_build_short) { 167 | let cam_suffix = 168 | response.octopi_camera_stack == "camera-streamer" ? "cam" : ""; 169 | var octoPiVersion = $( 170 | "Undervoltage: ' + 209 | gettext( 210 | "Make sure your power supply and cabling are providing enough power to the Pi." 211 | ) + 212 | "
"; 213 | var overheatParagraph = 214 | 'Overheating: ' + 215 | gettext( 216 | "Frequency capping due to overheating. Improve cooling of the CPU and GPU." 217 | ) + 218 | "
"; 219 | 220 | if (self.currentIssue()) { 221 | content += "" + gettext("Current issues:") + "
"; 222 | content += 223 | "" + 224 | gettext( 225 | "The following issues are being observed right now:" 226 | ) + 227 | "
"; 228 | if (self.currentUndervoltage()) { 229 | content += undervoltageParagraph; 230 | } 231 | if (self.currentOverheat()) { 232 | content += overheatParagraph; 233 | } 234 | } 235 | 236 | if (self.currentIssue() && self.pastIssue()) { 237 | content += "" + gettext("Issues since boot:") + "
"; 243 | content += 244 | "" + 245 | gettext( 246 | "The following issues have been observed since the Pi was booted:" 247 | ) + 248 | "
"; 249 | if (self.pastUndervoltage() && !self.currentUndervoltage()) { 250 | content += undervoltageParagraph; 251 | } 252 | if (self.pastOverheat() && !self.currentOverheat()) { 253 | content += overheatParagraph; 254 | } 255 | } 256 | 257 | content += 258 | "" + 259 | gettext("Click the navbar icon for more information.") + 260 | "
"; 261 | 262 | return content; 263 | }); 264 | 265 | self.onStartup = 266 | self.onServerReconnect = 267 | self.onUserLoggedIn = 268 | self.onUserLoggedOut = 269 | function () { 270 | self.requestData(); 271 | }; 272 | 273 | self.onDataUpdaterPluginMessage = function (plugin, data) { 274 | if (plugin !== "pi_support") return; 275 | if (!data.hasOwnProperty("state") || !data.hasOwnProperty("type")) return; 276 | if (data.type !== "throttle_state") return; 277 | if ( 278 | !self.loginState.hasPermission( 279 | self.access.permissions.PLUGIN_PI_SUPPORT_STATUS 280 | ) 281 | ) 282 | return; 283 | 284 | self.fromThrottleState(data.state); 285 | }; 286 | 287 | self.onBeforePrintStart = function (callback) { 288 | if ( 289 | !self.settings.settings.plugins.pi_support.ignore_undervoltage_on_printstart() && 290 | (self.currentUndervoltage() || self.pastUndervoltage()) 291 | ) { 292 | showConfirmationDialog({ 293 | title: gettext("Undervoltage detected, print anyway?"), 294 | message: 295 | gettext( 296 | "Your Pi is reporting undervoltage. It is not recommended to start a print job until an adequate power supply has been installed." 297 | ) + 298 | " " + 299 | gettext("See also the FAQ") + 300 | ".", 301 | question: gettext("Start the print job anyway?"), 302 | cancel: gettext("No, don't print"), 303 | proceed: [ 304 | gettext("Yes, print"), 305 | gettext("Yes, print & don't warn again") 306 | ], 307 | onproceed: function (idx) { 308 | if (idx === 1) { 309 | self.settings.settings.plugins.pi_support.ignore_undervoltage_on_printstart( 310 | true 311 | ); 312 | self.settings.saveData(); 313 | } 314 | callback(); 315 | }, 316 | nofade: true 317 | }); 318 | return false; 319 | } 320 | }; 321 | 322 | self.getAdditionalHealthCheckHandlers = function () { 323 | return { 324 | pi_undervoltage: (result, context) => { 325 | return { 326 | title: UNDERVOLTAGE_TITLE, 327 | html: generateHtml(UNDERVOLTAGE_WARNING, UNDERVOLTAGE_FAQ), 328 | result: result 329 | }; 330 | }, 331 | pi_unsupported: (result, context) => { 332 | return { 333 | title: ZERO_TITLE, 334 | html: generateHtml(ZERO_WARNING, ZERO_FAQ), 335 | result: result 336 | }; 337 | }, 338 | pi_default_password: (result, context) => { 339 | return { 340 | title: PASSWORD_TITLE, 341 | html: generateHtml(PASSWORD_WARNING, PASSWORD_FAQ), 342 | result: result 343 | }; 344 | } 345 | }; 346 | }; 347 | } 348 | 349 | OCTOPRINT_VIEWMODELS.push({ 350 | construct: PiSupportViewModel, 351 | elements: ["#navbar_plugin_pi_support"], 352 | dependencies: ["loginStateViewModel", "accessViewModel", "settingsViewModel"] 353 | }); 354 | }); 355 | -------------------------------------------------------------------------------- /octoprint_pi_support/__init__.py: -------------------------------------------------------------------------------- 1 | __license__ = "GNU Affero General Public License http://www.gnu.org/licenses/agpl.html" 2 | __copyright__ = "Copyright (C) 2017 The OctoPrint Project - Released under terms of the AGPLv3 License" 3 | 4 | import os 5 | from getpass import getuser 6 | 7 | import flask 8 | import octoprint.events 9 | import octoprint.plugin 10 | import sarge 11 | from flask_babel import gettext 12 | from octoprint.access.groups import USER_GROUP 13 | from octoprint.access.permissions import Permissions 14 | from octoprint.util import RepeatedTimer 15 | from octoprint.util.platform import CLOSE_FDS 16 | 17 | _PROC_DT_MODEL_PATH = "/proc/device-tree/model" 18 | _OCTOPI_VERSION_PATH = "/etc/octopi_version" 19 | _OCTOPIUPTODATE_BUILD_PATH = "/etc/octopiuptodate_build" 20 | _NEW_CAMERA_STACK_PATH = "/etc/systemd/system/camera-streamer-usb@.service" 21 | _VCGENCMD_THROTTLE = "/usr/bin/vcgencmd get_throttled" 22 | _SSHWARN_PATH = "/run/sshwarn" 23 | 24 | _CHECK_INTERVAL_OK = 300 25 | _CHECK_INTERVAL_THROTTLED = 30 26 | 27 | 28 | def _gather_new_camerastack_files(): 29 | import logging 30 | 31 | files = {} 32 | 33 | try: 34 | os.system( 35 | "journalctl --boot -u 'camera-streamer*' > /tmp/camerastack-journal.log" 36 | ) 37 | files["camerastack-journal.log"] = "/tmp/camerastack-journal.log" 38 | except Exception: 39 | logging.getLogger(__name__).exception( 40 | "Failed to create camerastack-journal.log file" 41 | ) 42 | 43 | try: 44 | os.system( 45 | "/usr/bin/libcamera-hello --list-cameras > /tmp/camerastack-libcamera.log" 46 | ) 47 | files["camerastack-libcamera.log"] = "/tmp/camerastack-libcamera.log" 48 | except Exception: 49 | logging.getLogger(__name__).exception( 50 | "Failed to create camerastack-libcamera.log file" 51 | ) 52 | 53 | try: 54 | os.system("/usr/bin/list-usb-cameras > /tmp/camerastack-usb.log") 55 | files["camerastack-usb.log"] = "/tmp/camerastack-usb.log" 56 | except Exception: 57 | logging.getLogger(__name__).exception("Failed to create camerastack-usb.log file") 58 | 59 | return files 60 | 61 | 62 | __LOCAL_DEBUG = os.path.exists( 63 | os.path.realpath(os.path.join(os.path.dirname(__file__), "..", ".local_debug")) 64 | ) 65 | 66 | if __LOCAL_DEBUG: 67 | ### mocks & settings for local debugging 68 | base = os.path.realpath( 69 | os.path.join( 70 | os.path.dirname(__file__), 71 | "..", 72 | "tests", 73 | "fakes", 74 | ) 75 | ) 76 | debug = os.path.realpath( 77 | os.path.join(os.path.dirname(__file__), "..", ".local_debug") 78 | ) 79 | _PROC_DT_MODEL_PATH = os.path.join(base, "fake_model.txt") 80 | _OCTOPI_VERSION_PATH = os.path.join(base, "fake_octopi.txt") 81 | _OCTOPIUPTODATE_BUILD_PATH = os.path.join(base, "fake_octopiuptodate.txt") 82 | _NEW_CAMERA_STACK_PATH = os.path.join(debug, "new-camera-stack") 83 | _SSHWARN_PATH = os.path.join(debug, "sshwarn") 84 | 85 | _gather_new_camerastack_files = lambda: { # noqa: F811 86 | "camerastack-journal.log": os.path.join(base, "fake_camerastack_journal.txt"), 87 | "camerastack-libcamera.log": os.path.join(base, "fake_camerastack_libcamera.txt"), 88 | "camerastack-usb.log": os.path.join(base, "fake_camerastack_usb.txt"), 89 | } 90 | 91 | import itertools 92 | 93 | _VCGENCMD_OUTPUT = itertools.chain( 94 | iter(("0x0", "0x0", "0x50005", "0x50000", "0x70007")), 95 | itertools.repeat("0x70005"), 96 | ) 97 | _VCGENCMD_BROKEN = os.path.exists(os.path.join(debug, "vcgencmd_broken")) 98 | 99 | _CHECK_INTERVAL_OK = 10 100 | _CHECK_INTERVAL_THROTTLED = 5 101 | 102 | 103 | # see https://www.raspberrypi.org/forums/viewtopic.php?f=63&t=147781&start=50#p972790 104 | _FLAG_UNDERVOLTAGE = 1 << 0 105 | _FLAG_FREQ_CAPPED = 1 << 1 106 | _FLAG_THROTTLED = 1 << 2 107 | _FLAG_PAST_UNDERVOLTAGE = 1 << 16 108 | _FLAG_PAST_FREQ_CAPPED = 1 << 17 109 | _FLAG_PAST_THROTTLED = 1 << 18 110 | 111 | _UNRECOMMENDED_MODELS = ("Zero", "Zero W") 112 | 113 | 114 | class ThrottleState: 115 | @classmethod 116 | def from_value(cls, value=0): 117 | if value == 0: 118 | return ThrottleState(raw_value=value) 119 | 120 | kwargs = { 121 | "undervoltage": _FLAG_UNDERVOLTAGE & value == _FLAG_UNDERVOLTAGE, 122 | "freq_capped": _FLAG_FREQ_CAPPED & value == _FLAG_FREQ_CAPPED, 123 | "throttled": _FLAG_THROTTLED & value == _FLAG_THROTTLED, 124 | "past_undervoltage": _FLAG_PAST_UNDERVOLTAGE & value 125 | == _FLAG_PAST_UNDERVOLTAGE, 126 | "past_freq_capped": _FLAG_PAST_FREQ_CAPPED & value == _FLAG_PAST_FREQ_CAPPED, 127 | "past_throttled": _FLAG_PAST_THROTTLED & value == _FLAG_PAST_THROTTLED, 128 | "raw_value": value, 129 | } 130 | return ThrottleState(**kwargs) 131 | 132 | def __init__(self, **kwargs): 133 | self._raw_value = kwargs.get("raw_value", -1) 134 | self._undervoltage = False 135 | self._freq_capped = False 136 | self._throttled = False 137 | self._past_undervoltage = False 138 | self._past_freq_capped = False 139 | self._past_throttled = False 140 | 141 | for key, value in kwargs.items(): 142 | local_key = f"_{key}" 143 | if hasattr(self, local_key) and isinstance(value, bool): 144 | setattr(self, local_key, value) 145 | 146 | @property 147 | def undervoltage(self): 148 | return self.current_undervoltage or self.past_undervoltage 149 | 150 | @property 151 | def current_undervoltage(self): 152 | return self._undervoltage 153 | 154 | @property 155 | def past_undervoltage(self): 156 | return self._past_undervoltage 157 | 158 | @property 159 | def overheat(self): 160 | return self.current_overheat or self.past_overheat 161 | 162 | @property 163 | def current_overheat(self): 164 | return self._freq_capped 165 | 166 | @property 167 | def past_overheat(self): 168 | return self._past_freq_capped 169 | 170 | @property 171 | def issue(self): 172 | return self.current_issue or self.past_issue 173 | 174 | @property 175 | def current_issue(self): 176 | return self._undervoltage or self._freq_capped or self._throttled 177 | 178 | @property 179 | def past_issue(self): 180 | return self._past_undervoltage or self._past_freq_capped or self._past_throttled 181 | 182 | @property 183 | def raw_value(self): 184 | return self._raw_value 185 | 186 | @property 187 | def raw_value_hex(self): 188 | return f"0x{self._raw_value:X}" 189 | 190 | def __eq__(self, other): 191 | if not isinstance(other, ThrottleState): 192 | return False 193 | 194 | return ( 195 | self._undervoltage == other._undervoltage 196 | and self._freq_capped == other._freq_capped 197 | and self._throttled == other._throttled 198 | and self._past_undervoltage == other._past_undervoltage 199 | and self._past_freq_capped == other._past_freq_capped 200 | and self._past_throttled == other._past_throttled 201 | and self._raw_value == other._raw_value 202 | ) 203 | 204 | def as_dict(self): 205 | return { 206 | "raw_value": self._raw_value, 207 | "current_undervoltage": self.current_undervoltage, 208 | "past_undervoltage": self.past_undervoltage, 209 | "current_overheat": self.current_overheat, 210 | "past_overheat": self.past_overheat, 211 | "current_issue": self.current_issue, 212 | "past_issue": self.past_issue, 213 | } 214 | 215 | 216 | _proc_dt_model = None 217 | 218 | 219 | def get_proc_dt_model(): 220 | global _proc_dt_model 221 | 222 | if _proc_dt_model is None: 223 | with open(_PROC_DT_MODEL_PATH, encoding="utf-8") as f: 224 | _proc_dt_model = f.readline().strip(" \t\r\n\0") 225 | 226 | return _proc_dt_model 227 | 228 | 229 | def get_vcgencmd_throttled_state(command): 230 | if __LOCAL_DEBUG: 231 | if _VCGENCMD_BROKEN: 232 | output = "" 233 | error = "VCHI initialization failed" 234 | else: 235 | output = "throttled={}".format( 236 | next(_VCGENCMD_OUTPUT) 237 | ) # mock for local debugging 238 | error = "" 239 | else: 240 | output, error = sarge.get_both(command, close_fds=CLOSE_FDS) 241 | 242 | if "throttled=0x" not in output: 243 | raise ValueError(f"Cannot parse {command!r} output: {error if error else output}") 244 | 245 | value = output[len("throttled=") :].strip(" \t\r\n\0") 246 | value = int(value, 0) 247 | return ThrottleState.from_value(value) 248 | 249 | 250 | def is_octopi(): 251 | return os.path.exists(_OCTOPI_VERSION_PATH) 252 | 253 | 254 | def is_octopiuptodate(): 255 | return os.path.exists(_OCTOPIUPTODATE_BUILD_PATH) 256 | 257 | 258 | def is_new_camerastack(): 259 | return os.path.exists(_NEW_CAMERA_STACK_PATH) 260 | 261 | 262 | def is_model_any_of(model, *args): 263 | model = model.lower() 264 | for arg in (x.lower() for x in args): 265 | if f"{arg} rev" in model or model.endswith(arg): 266 | return True 267 | return False 268 | 269 | 270 | _octopi_version = None 271 | 272 | 273 | def get_octopi_version(): 274 | global _octopi_version 275 | 276 | if _octopi_version is None: 277 | with open(_OCTOPI_VERSION_PATH, encoding="utf-8") as f: 278 | _octopi_version = f.readline().strip(" \t\r\n\0") 279 | 280 | return _octopi_version 281 | 282 | 283 | _octopiuptodate_build = None 284 | 285 | 286 | def get_octopiuptodate_build(): 287 | global _octopiuptodate_build 288 | 289 | if _octopiuptodate_build is None: 290 | with open(_OCTOPIUPTODATE_BUILD_PATH, encoding="utf-8") as f: 291 | _octopiuptodate_build = f.readline().strip(" \t\r\n\0") 292 | 293 | return _octopiuptodate_build 294 | 295 | 296 | def has_default_password(): 297 | # It would be nicer to actually fetch the hash from /etc/shadow here and verify it 298 | # has been changed, but for that we'd require super user access just to read the 299 | # file, which is just not a good idea. 300 | # 301 | # So instead we use the same mechanism that RPi OS uses to show the nag screen on the 302 | # command prompt, with the downside that it won't trigger if SSH is disabled for 303 | # whatever reason. 304 | return os.path.exists(_SSHWARN_PATH) 305 | 306 | 307 | class PiSupportPlugin( 308 | octoprint.plugin.EnvironmentDetectionPlugin, 309 | octoprint.plugin.SimpleApiPlugin, 310 | octoprint.plugin.AssetPlugin, 311 | octoprint.plugin.TemplatePlugin, 312 | octoprint.plugin.StartupPlugin, 313 | octoprint.plugin.SettingsPlugin, 314 | ): 315 | # noinspection PyMissingConstructor 316 | def __init__(self): 317 | self._throttle_state = ThrottleState() 318 | self._throttle_check = None 319 | self._throttle_undervoltage = False 320 | self._throttle_overheat = False 321 | self._throttle_check_enabled = True 322 | self._throttle_check_functional = True 323 | 324 | def initialize(self): 325 | self._throttle_check_enabled = self._settings.get_boolean( 326 | ["vcgencmd_throttle_check_enabled"] 327 | ) 328 | if not self._throttle_check_enabled: 329 | self._logger.warning( 330 | "Throttle check via vcgencmd disabled by user. Potential undervoltage or overheating issues will not be detected." 331 | ) 332 | 333 | # Additional permissions hook 334 | 335 | def get_additional_permissions(self): 336 | return [ 337 | { 338 | "key": "STATUS", 339 | "name": "Status", 340 | "description": gettext( 341 | "Allows to check for the Pi's throttling status and environment info" 342 | ), 343 | "roles": ["check"], 344 | "default_groups": [USER_GROUP], 345 | } 346 | ] 347 | 348 | # Additional bundle files hook 349 | 350 | def get_additional_bundle_files(self, *args, **kwargs): 351 | if is_octopi(): 352 | result = { 353 | "haproxy.log": "/var/log/haproxy.log", 354 | } 355 | 356 | if is_new_camerastack(): 357 | # new camera-streamer based camera stack 358 | files = _gather_new_camerastack_files() 359 | result.update(**files) 360 | 361 | else: 362 | # old mjpg-streamer based camera stack 363 | result["webcamd.log"] = "/var/log/webcamd.log" 364 | 365 | return result 366 | else: 367 | return {} 368 | 369 | ##~~ Additional health checks hook 370 | 371 | def get_additional_health_checks(self): 372 | from .health_checks import all_checks 373 | 374 | def health_check_factory(clz): 375 | def factory(settings): 376 | return clz(self, settings) 377 | 378 | factory.key = clz.key 379 | return factory 380 | 381 | return [health_check_factory(clz) for clz in all_checks] 382 | 383 | # ~~ EnvironmentDetectionPlugin 384 | 385 | def get_additional_environment(self): 386 | result = {"model": get_proc_dt_model()} 387 | 388 | self._check_throttled_state() 389 | result["throttle_check_enabled"] = self._throttle_check_enabled 390 | result["throttle_check_functional"] = self._throttle_check_functional 391 | if self._throttle_check_enabled and self._throttle_check_functional: 392 | result["throttle_state"] = self._throttle_state.raw_value_hex 393 | 394 | if is_octopi(): 395 | result["octopi_version"] = get_octopi_version() 396 | result["octopi_camera_stack"] = ( 397 | "camera-streamer" if is_new_camerastack() else "webcamd" 398 | ) 399 | 400 | if is_octopiuptodate(): 401 | result["octopiuptodate_build"] = get_octopiuptodate_build() 402 | try: 403 | build = result["octopiuptodate_build"].split("-")[-1] 404 | 405 | result["octopiuptodate_build_short"] = ( 406 | build[0:4] + "." + build[4:6] + "." + build[6:8] + "." + build[8:] 407 | ) 408 | except Exception: 409 | pass 410 | 411 | return result 412 | 413 | # ~~ SimpleApiPlugin 414 | 415 | def on_api_get(self, request): 416 | if not Permissions.PLUGIN_PI_SUPPORT_STATUS.can(): 417 | return flask.abort(403) 418 | 419 | result = self.get_additional_environment() 420 | result.update( 421 | { 422 | "throttle_enabled": self._throttle_check_enabled, 423 | "throttle_functional": self._throttle_check_functional, 424 | "throttle_state": self._throttle_state.as_dict(), 425 | "model_unrecommended": is_model_any_of( 426 | result.get("model"), *_UNRECOMMENDED_MODELS 427 | ), 428 | "default_password": has_default_password(), 429 | } 430 | ) 431 | return flask.jsonify(**result) 432 | 433 | def is_api_protected(self): 434 | return True 435 | 436 | # ~~ AssetPlugin 437 | 438 | def get_assets(self): 439 | return { 440 | "js": ["js/pi_support.js"], 441 | "clientjs": ["clientjs/pi_support.js"], 442 | "css": ["css/pi_support.css"], 443 | } 444 | 445 | # ~~ TemplatePlugin 446 | 447 | def get_template_configs(self): 448 | configs = [ 449 | { 450 | "type": "settings", 451 | "name": gettext("Pi Support"), 452 | "template": "pi_support_settings.jinja2", 453 | "custom_bindings": False, 454 | } 455 | ] 456 | 457 | if is_octopiuptodate(): 458 | configs.append( 459 | { 460 | "type": "about", 461 | "name": "About OctoPi", 462 | "template": "pi_support_about_octopiuptodate.jinja2", 463 | } 464 | ) 465 | elif is_octopi(): 466 | configs.append( 467 | { 468 | "type": "about", 469 | "name": "About OctoPi", 470 | "template": "pi_support_about_octopi.jinja2", 471 | } 472 | ) 473 | 474 | return configs 475 | 476 | def get_template_vars(self): 477 | return self.get_additional_environment() 478 | 479 | # ~~ StartupPlugin 480 | 481 | def on_startup(self, *args, **kwargs): 482 | if self._settings.get_boolean(["vcgencmd_throttle_check_enabled"]): 483 | self._check_throttled_state() 484 | self._throttle_check = RepeatedTimer( 485 | self._check_throttled_state_interval, 486 | self._check_throttled_state, 487 | condition=self._check_throttled_state_condition, 488 | ) 489 | self._throttle_check.start() 490 | 491 | # ~~ SettingsPlugin 492 | 493 | def get_settings_defaults(self): 494 | return { 495 | "vcgencmd_throttle_check_enabled": True, 496 | "vcgencmd_throttle_check_command": _VCGENCMD_THROTTLE, 497 | "ignore_unrecommended_model": False, 498 | "ignore_undervoltage_on_printstart": False, 499 | "ignore_default_password": False, 500 | } 501 | 502 | def get_settings_restricted_paths(self): 503 | return { 504 | "admin": [ 505 | ["vcgencmd_throttle_check_enabled"], 506 | ["vcgencmd_throttle_check_command"], 507 | ] 508 | } 509 | 510 | ##~~ Softwareupdate hook 511 | 512 | def get_update_information(self): 513 | return { 514 | "pi_support": { 515 | "displayName": "Pi Support Plugin", 516 | "displayVersion": self._plugin_version, 517 | # version check: github repository 518 | "type": "github_release", 519 | "user": "OctoPrint", 520 | "repo": "OctoPrint-PiSupport", 521 | "current": self._plugin_version, 522 | "stable_branch": { 523 | "name": "Stable", 524 | "branch": "main", 525 | "commitish": ["devel", "main"], 526 | }, 527 | "prerelease_branches": [ 528 | { 529 | "name": "Prerelease", 530 | "branch": "devel", 531 | "commitish": ["devel", "main"], 532 | } 533 | ], 534 | # update method: pip 535 | "pip": "https://github.com/OctoPrint/OctoPrint-PiSupport/archive/{target_version}.zip", 536 | } 537 | } 538 | 539 | # ~~ Helpers 540 | 541 | def _check_throttled_state_interval(self): 542 | if self._throttle_state.current_issue: 543 | return _CHECK_INTERVAL_THROTTLED 544 | else: 545 | return _CHECK_INTERVAL_OK 546 | 547 | def _check_throttled_state_condition(self): 548 | return self._throttle_check_enabled and self._throttle_check_functional 549 | 550 | def get_throttle_state(self, run_now=False): 551 | """Exposed as public helper.""" 552 | if run_now: 553 | self._check_throttled_state() 554 | 555 | if not self._throttle_check_enabled or not self._throttle_check_functional: 556 | return False 557 | 558 | return self._throttle_state.as_dict() 559 | 560 | def _check_throttled_state(self): 561 | if not self._throttle_check_enabled: 562 | return 563 | 564 | command = self._settings.get(["vcgencmd_throttle_check_command"]) 565 | 566 | self._logger.debug(f"Retrieving throttle state via {command!r}") 567 | try: 568 | state = get_vcgencmd_throttled_state(command) 569 | except ValueError as ex: 570 | error = str(ex) 571 | self._logger.warning(error) 572 | if "VCHI initialization failed" in error: 573 | self._logger.warning( 574 | 'Make sure the system user "{}" is in the "video" group.'.format( 575 | getuser() 576 | ) 577 | ) 578 | self._throttle_check_functional = False 579 | return 580 | 581 | if self._throttle_state == state: 582 | # no change 583 | return 584 | 585 | self._throttle_state = state 586 | 587 | if (not self._throttle_undervoltage and self._throttle_state.undervoltage) or ( 588 | not self._throttle_overheat and self._throttle_state.overheat 589 | ): 590 | message = ( 591 | "This Raspberry Pi is reporting problems that might lead to bad performance or errors caused " 592 | "by overheating or insufficient power." 593 | ) 594 | 595 | if self._throttle_state.undervoltage: 596 | self._throttle_undervoltage = True 597 | message += ( 598 | "\n!!! UNDERVOLTAGE REPORTED !!! Make sure that the power supply and power cable are " 599 | "capable of supplying enough voltage and current to your Pi." 600 | ) 601 | 602 | if self._throttle_state.overheat: 603 | self._throttle_overheat = True 604 | message += ( 605 | "\n!!! FREQUENCY CAPPING DUE TO OVERHEATING REPORTED !!! Improve cooling on the Pi's " 606 | "CPU and GPU." 607 | ) 608 | 609 | self._logger.warning(message) 610 | 611 | self._plugin_manager.send_plugin_message( 612 | self._identifier, 613 | {"type": "throttle_state", "state": self._throttle_state.as_dict()}, 614 | ) 615 | 616 | # noinspection PyUnresolvedReferences 617 | self._event_bus.fire( 618 | octoprint.events.Events.PLUGIN_PI_SUPPORT_THROTTLE_STATE, 619 | self._throttle_state.as_dict(), 620 | ) 621 | 622 | if hasattr(octoprint.events.Events, "PLUGIN_HEALTH_CHECK_UPDATE_HEALTHCHECK"): 623 | self._event_bus.fire( 624 | octoprint.events.Events.PLUGIN_HEALTH_CHECK_UPDATE_HEALTHCHECK 625 | ) 626 | 627 | 628 | def register_custom_events(*args, **kwargs): 629 | return [ 630 | "throttle_state", 631 | ] 632 | 633 | 634 | __plugin_name__ = "Pi Support Plugin" 635 | __plugin_author__ = "Gina Häußge" 636 | __plugin_description__ = "Provides additional information about your Pi in the UI." 637 | __plugin_disabling_discouraged__ = gettext( 638 | "Without this plugin OctoPrint will no longer be able to " 639 | "provide additional information about your Pi, " 640 | "which will make it more tricky to help you if you need support." 641 | ) 642 | __plugin_license__ = "AGPLv3" 643 | __plugin_pythoncompat__ = ">=2.7,<4" 644 | 645 | 646 | def __plugin_check__(): 647 | try: 648 | proc_dt_model = get_proc_dt_model() 649 | if proc_dt_model is None: 650 | return False 651 | except Exception: 652 | return False 653 | 654 | return "raspberry pi" in proc_dt_model.lower() 655 | 656 | 657 | def __plugin_load__(): 658 | plugin = PiSupportPlugin() 659 | global __plugin_implementation__ 660 | __plugin_implementation__ = plugin 661 | 662 | global __plugin_hooks__ 663 | __plugin_hooks__ = { 664 | "octoprint.plugin.softwareupdate.check_config": __plugin_implementation__.get_update_information, 665 | "octoprint.events.register_custom_events": register_custom_events, 666 | "octoprint.access.permissions": __plugin_implementation__.get_additional_permissions, 667 | "octoprint.systeminfo.additional_bundle_files": __plugin_implementation__.get_additional_bundle_files, 668 | "octoprint.plugin.health_check.get_additional_checks": __plugin_implementation__.get_additional_health_checks, 669 | } 670 | 671 | global __plugin_helpers__ 672 | __plugin_helpers__ = {"get_throttled": plugin.get_throttle_state} 673 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU AFFERO GENERAL PUBLIC LICENSE 2 | Version 3, 19 November 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc.