def sniff(self): request = get_uri(self.ip, endpoint="/api/version") if request is None: app.logger.debug( "%s is not responding on /api/version - not octoprint" % self.ip) self.client = PrinterClientInfo({}, False) return if request.status_code == 403: app.logger.debug( "%s is responding with %s on /api/version - might be access-protected octoprint" % (self.ip, request.status_code)) settings_req = get_uri(self.ip, endpoint="/api/settings") if settings_req and settings_req.status_code == 200: app.logger.debug( "%s is responding with 200 on /api/settings - probably access-protected octoprint" % self.ip) self.client = PrinterClientInfo({}, True, True) else: app.logger.debug( "%s is responding with %s on /api/settings - probably not octoprint" % (self.ip, settings_req.status_code)) self.client = PrinterClientInfo({}, False) return if request.status_code != 200: app.logger.debug( "%s is responding with %s on /api/version - not accessible" % (self.ip, request.status_code)) self.client = PrinterClientInfo({}, False) return try: data = request.json() if "text" not in data: app.logger.debug( "%s is responding with unfamiliar JSON %s on /api/version - probably not octoprint" % (self.ip, data)) self.client = PrinterClientInfo(data, False) return except json.decoder.JSONDecodeError: app.logger.debug( "%s is not responding with JSON on /api/version - probably not octoprint" % self.ip) self.client = PrinterClientInfo({}, False) return if re.match(r"^octoprint", data["text"], re.IGNORECASE) is None: app.logger.debug( "%s is responding with %s on /api/version - probably not octoprint" % (self.ip, data["text"])) self.client = PrinterClientInfo(data, False) return self.client = PrinterClientInfo(data, True)
def webcam(self): request = None if self.client.connected: request = get_uri(self.ip, endpoint="/api/settings") if not request: self.client.connected = False if request is not None and request.status_code == 200: try: data = request.json() self.client.connected = True if "webcam" not in data or not data["webcam"]["webcamEnabled"]: return {"message": "Stream disabled in octoprint"} stream_url = data["webcam"]["streamUrl"] if re.match(r"^https?", stream_url, re.IGNORECASE) is None: # TODO reflect eventual HTTPS stream_url = "http://%s%s" % (self.ip, stream_url) return { "message": "OK", "stream": stream_url, "flipHorizontal": data["webcam"]["flipH"], "flipVertical": data["webcam"]["flipV"], "rotate90": data["webcam"]["rotate90"], } except json.decoder.JSONDecodeError: return {"message": "Cannot decode JSON"} else: return {"message": "Stream not accessible"}
def status(self): request = None if self.client.connected: request = get_uri(self.ip, endpoint="/api/printer?exclude=history") if not request: self.client.connected = False if request is not None and request.status_code == 200: try: data = request.json() return { "state": data["state"]["text"], "temperature": data["temperature"], } except json.decoder.JSONDecodeError: return { "state": "Printer is responding with invalid data", "temperature": {}, } elif request is not None and request.status_code == 409: return { "state": "Printer is not connected to Octoprint", "temperature": {} } else: return {"state": "Printer is not responding", "temperature": {}}
def is_alive(self): request = get_uri(self.ip, endpoint="/api/version") # TODO test for access-protected octoprint if request is None or request.status_code != 200: self.client.connected = False else: if not self.client.connected: self.sniff() self.client.connected = True return self.client.connected
def test_no_success(self, mock_requests): def mock_call(uri, **kwargs): raise requests.exceptions.ConnectionError("mocked") mock_requests.side_effect = mock_call request = get_uri("1.2.3.4", "/api/version") self.assertEqual(request, None) self.assertEqual(mock_requests.call_count, 1) mock_requests.assert_has_calls( [mock.call("http://1.2.3.4/api/version", timeout=2)] )
def job(self): request = None if self.client.connected: request = get_uri(self.ip, endpoint="/api/job") if not request: self.client.connected = False if request is not None and request.status_code == 200: try: data = request.json() self.client.connected = True if "state" in data and re.match(r"Operational|Offline", data["state"]): return {} return { "name": data["job"]["file"]["display"], "completion": data["progress"]["completion"], "printTimeLeft": data["progress"]["printTimeLeft"], "printTime": data["progress"]["printTime"], } except json.decoder.JSONDecodeError: return {} else: return {}
def test_try_root(self, mock_requests): request = get_uri("1.2.3.4") mock_requests.assert_called_with("http://1.2.3.4/", timeout=2)
def test_try_nothing(self, mock_requests): request = get_uri(None, "/api/version") self.assertEqual(mock_requests.call_count, 0) self.assertEqual(request, None)
def test_ip_port(self, mock_requests): get_uri("1.2.3.4:5000", "api/version") mock_requests.assert_called_with("http://1.2.3.4:5000/api/version", timeout=2)
def test_add_leading_slash(self, mock_requests): get_uri("1.2.3.4", "api/version") mock_requests.assert_called_with("http://1.2.3.4/api/version", timeout=2)
def test_pass_protocol_timeout(self, mock_requests): get_uri("1.2.3.4", "/api/version", protocol="https", timeout=3) mock_requests.assert_called_with("https://1.2.3.4/api/version", timeout=3)
def test_try_hostname(self, mock_requests): get_uri("1.2.3.4", "/api/version") mock_requests.assert_called_with("http://1.2.3.4/api/version", timeout=2)