diff --git a/src/octoprint/plugins/octopi_support/__init__.py b/src/octoprint/plugins/octopi_support/__init__.py index 0ffc6d11..d71eb60f 100644 --- a/src/octoprint/plugins/octopi_support/__init__.py +++ b/src/octoprint/plugins/octopi_support/__init__.py @@ -55,18 +55,32 @@ def get_octopi_version(): return version_line.strip() -def get_pi_revision(): +def get_pi_cpuinfo(): + fields = dict(revision="Revision", + hardware="Hardware", + serial="Serial") + + result = dict() with open(_CPUINFO_PATH) as f: for line in f: - if line and line.startswith("Revision:"): - return line[line.index(":") + 1:].strip() - return "unknown" + if not line: + continue + + for key, prefix in fields.items(): + if line.startswith(prefix): + result[key] = line[line.index(":") + 1:].strip() + + return result -def get_pi_model(revision): +def get_pi_model(hardware, revision): + if hardware not in ("BCM2835",): + return "unknown" + if revision.startswith("1000"): # strip flag for over-volted (https://elinux.org/RPi_HardwareHistory#Which_Pi_have_I_got.3F) revision = revision[4:] + return _RPI_REVISION_MAP.get(revision.lower(), "unknown") @@ -77,22 +91,20 @@ class OctoPiSupportPlugin(octoprint.plugin.EnvironmentDetectionPlugin, def __init__(self): self._version = None - self._revision = None + self._cpuinfo = dict() self._model = None #~~ EnvironmentDetectionPlugin def get_additional_environment(self): return dict(version=self._get_version(), - revision=self._get_revision(), + revision=self._get_cpuinfo().get("revision", "unknown"), model=self._get_model()) #~~ SimpleApiPlugin def on_api_get(self, request): - return flask.jsonify(version=self._get_version(), - revision=self._get_revision(), - model=self._get_model()) + return flask.jsonify(version=self._get_version()) #~~ AssetPlugin @@ -111,12 +123,12 @@ class OctoPiSupportPlugin(octoprint.plugin.EnvironmentDetectionPlugin, def get_template_vars(self): version = self._get_version() - revision = self._get_revision() + cpuinfo = self._get_cpuinfo() model = self._get_model() return dict(version=version, - rpi=(revision is not None and revision != "unknown" and model is not None and model != "unknown"), - rpi_revision=revision, + rpi_revision=cpuinfo.get("revision", "unknown"), + rpi_serial=cpuinfo.get("serial", "unknown"), rpi_model=model) #~~ Helpers @@ -127,23 +139,28 @@ class OctoPiSupportPlugin(octoprint.plugin.EnvironmentDetectionPlugin, self._version = get_octopi_version() except: self._logger.exception("Error while reading OctoPi version from file {}".format(_OCTOPI_VERSION_PATH)) + self._version = "unknown" return self._version def _get_model(self): if self._model is None: try: - self._model = get_pi_model(self._get_revision()) + cpuinfo = self._get_cpuinfo() + self._model = get_pi_model(cpuinfo.get("hardware", "unknown"), + cpuinfo.get("revision", "unknown")) except: self._logger.exception("Error while detecting RPi model") + self._model = "unknown" return self._model - def _get_revision(self): - if self._revision is None: + def _get_cpuinfo(self): + if self._cpuinfo is None: try: - self._revision = get_pi_revision() + self._cpuinfo = get_pi_cpuinfo() except: - self._logger.exception("Error while detecting RPi revision") - return self._revision + self._logger.exception("Error while fetching cpu info") + self._cpuinfo = dict() + return self._cpuinfo def __plugin_check__(): from octoprint.util.platform import get_os diff --git a/src/octoprint/plugins/octopi_support/templates/octopi_support_about.jinja2 b/src/octoprint/plugins/octopi_support/templates/octopi_support_about.jinja2 index 6272b1ab..dcc15c26 100644 --- a/src/octoprint/plugins/octopi_support/templates/octopi_support_about.jinja2 +++ b/src/octoprint/plugins/octopi_support/templates/octopi_support_about.jinja2 @@ -30,12 +30,13 @@ www.gnu.org/licenses/gpl-3.0.en.html.

-{% if plugin_octopi_support_rpi %} +{% if plugin_octopi_support_rpi_model != "unknown" %}

{{ _('About this Raspberry Pi') }}

{% endif %} diff --git a/tests/plugins/test_octopi_support.py b/tests/plugins/test_octopi_support.py new file mode 100644 index 00000000..ad6140a3 --- /dev/null +++ b/tests/plugins/test_octopi_support.py @@ -0,0 +1,89 @@ + +import unittest +import ddt +import mock + +OCTOPI_VERSION = "0.14.0" + +CPUINFO = """ +processor : 0 +model name : ARMv7 Processor rev 4 (v7l) +BogoMIPS : 38.40 +Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32 +CPU implementer : 0x41 +CPU architecture: 7 +CPU variant : 0x0 +CPU part : 0xd03 +CPU revision : 4 + +processor : 1 +model name : ARMv7 Processor rev 4 (v7l) +BogoMIPS : 38.40 +Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32 +CPU implementer : 0x41 +CPU architecture: 7 +CPU variant : 0x0 +CPU part : 0xd03 +CPU revision : 4 + +processor : 2 +model name : ARMv7 Processor rev 4 (v7l) +BogoMIPS : 38.40 +Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32 +CPU implementer : 0x41 +CPU architecture: 7 +CPU variant : 0x0 +CPU part : 0xd03 +CPU revision : 4 + +processor : 3 +model name : ARMv7 Processor rev 4 (v7l) +BogoMIPS : 38.40 +Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32 +CPU implementer : 0x41 +CPU architecture: 7 +CPU variant : 0x0 +CPU part : 0xd03 +CPU revision : 4 + +Hardware : BCM2835 +Revision : a02082 +Serial : 000000000abcdef1 +""" + +@ddt.ddt +class OctoPiSupportTestCase(unittest.TestCase): + + def test_get_octopi_version(self): + from octoprint.plugins.octopi_support import get_octopi_version + + with mock.patch("__builtin__.open", mock.mock_open(), create=True) as m: + m.return_value.readline.return_value = OCTOPI_VERSION + version = get_octopi_version() + + m.assert_called_once_with("/etc/octopi_version", "r") + self.assertEqual(version, "0.14.0") + + def test_get_pi_cpuinfo(self): + from octoprint.plugins.octopi_support import get_pi_cpuinfo + + with mock.patch("__builtin__.open", mock.mock_open(), create=True) as m: + m.return_value.__iter__.return_value = CPUINFO.splitlines() + cpuinfo = get_pi_cpuinfo() + + m.assert_called_once_with("/proc/cpuinfo") + self.assertDictEqual(cpuinfo, dict(hardware="BCM2835", revision="a02082", serial="000000000abcdef1")) + + @ddt.data( + ("BCM2835", "a02082", "3B"), + ("BCM2835", "1000a02082", "3B"), + + # failures + ("something else", "a02082", "unknown"), + ("BCM2835", "aabbccdd", "unknown") + ) + @ddt.unpack + def test_get_pi_model(self, hardware, revision, expected): + from octoprint.plugins.octopi_support import get_pi_model + actual = get_pi_model(hardware, revision) + self.assertEqual(actual, expected)