Reworked wifi connection to use requests instead of httpclient

This library is far easier to use and much cleaner. CURA-49
This commit is contained in:
Jaime van Kessel 2016-02-11 11:14:18 +01:00
parent 763206af32
commit ca502705c2
2 changed files with 42 additions and 78 deletions

View file

@ -1,11 +1,10 @@
from UM.OutputDevice.OutputDevice import OutputDevice from UM.OutputDevice.OutputDevice import OutputDevice
from UM.OutputDevice import OutputDeviceError from UM.OutputDevice import OutputDeviceError
import threading import threading
import http.client as httpclient
import urllib
import json import json
import time import time
import base64 import base64
import requests
from . import HttpUploadDataStream from . import HttpUploadDataStream
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
@ -24,8 +23,13 @@ class WifiConnection(OutputDevice, SignalEmitter):
self._file = None self._file = None
self._do_update = True self._do_update = True
self._thread = None self._thread = None
self._state = None
self._json_printer_state = None
self._is_connected = False self._is_connected = False
self._api_version = "1"
self._api_prefix = "/api/v" + self._api_version + "/"
self.connect() self.connect()
self.setName(address) self.setName(address)
self.setShortDescription(i18n_catalog.i18nc("@action:button", "Print with WIFI")) self.setShortDescription(i18n_catalog.i18nc("@action:button", "Print with WIFI"))
@ -37,23 +41,25 @@ class WifiConnection(OutputDevice, SignalEmitter):
def isConnected(self): def isConnected(self):
return self._is_connected return self._is_connected
## Set the connection state of this connection.
# Although we use a restfull API, we do poll the api to check if the machine is still responding.
def setConnectionState(self, state): def setConnectionState(self, state):
print("setting connection state: " , self._address, " " , state)
if state != self._is_connected: if state != self._is_connected:
Logger.log("i", "setting connection state of %s to %s " %(self._address, state))
self._is_connected = state self._is_connected = state
self.connectionStateChanged.emit(self._address) self.connectionStateChanged.emit(self._address)
else: else:
self._is_connected = state self._is_connected = state
def _update(self): def _update(self):
while self._thread: while self._thread:
state_reply = self._httpRequest('GET', '/api/v1/printer/state') self.setConnectionState(True)
if state_reply is not None: reply = self._httpGet("printer")
self._state = state_reply if reply.status_code == 200:
self._json_printer_state = reply.json()
if not self._is_connected: if not self._is_connected:
self.setConnectionState(True) self.setConnectionState(True)
else: else:
self._state = {'state': 'CONNECTION_ERROR'}
self.setConnectionState(False) self.setConnectionState(False)
time.sleep(1) time.sleep(1)
@ -61,11 +67,11 @@ class WifiConnection(OutputDevice, SignalEmitter):
self._do_update = False self._do_update = False
self._is_connected = False self._is_connected = False
def requestWrite(self, node): def requestWrite(self, node, file_name = None):
self._file = getattr( Application.getInstance().getController().getScene(), "gcode_list") self._file = getattr( Application.getInstance().getController().getScene(), "gcode_list")
self.startPrint() self.startPrint()
#Open the active connection to the printer so we can send commands ## Start the polling thread.
def connect(self): def connect(self):
if self._thread is None: if self._thread is None:
self._do_update = True self._do_update = True
@ -78,65 +84,22 @@ class WifiConnection(OutputDevice, SignalEmitter):
def startPrint(self): def startPrint(self):
try: try:
result = self._httpRequest('POST', '/api/v1/printer/print_upload', {'print_name': 'Print from Cura', 'parameters':''}, {'file': ('file.gcode', self._file)}) result = self._httpPost("print_job", self._file)
print(result.get('success',False))
#result = self._httpRequest('POST', '/api/v1/printer/print_upload', {'print_name': 'Print from Cura'})
except Exception as e: except Exception as e:
Logger.log('e' , 'An exception occured in wifi connection: ' , e) Logger.log("e" , "An exception occured in wifi connection: %s" % str(e))
def _httpRequest(self, method, path, post_data = None, files = None): def _httpGet(self, path):
return requests.get("http://" + self._address + self._api_prefix + path)
def _httpPost(self, path, file_data):
with self._http_lock: with self._http_lock:
self._http_connection = httpclient.HTTPConnection(self._address, timeout = 30) files_dict = {}
try: if isinstance(file_data, list): # in case a list with strings is sent
if files is not None: single_string_file_data = ""
boundary = 'wL36Yn8afVp8Ag7AmP8qZ0SA4n1v9T' for line in file_data:
s = HttpUploadDataStream.HttpUploadDataStream() single_string_file_data += line
for k, v in files.items(): files_dict = {"file":("test.gcode", single_string_file_data)}
filename = v[0] else:
file_contents = v[1] files_dict = {"file":("test.gcode", file_data)}
s.write('--%s\r\n' % (boundary))
s.write('Content-Disposition: form-data; name="%s"; filename="%s"\r\n' % (k, filename))
s.write('Content-Type: application/octet-stream\r\n')
s.write('Content-Transfer-Encoding: binary\r\n')
s.write('\r\n')
if file_contents is not None: return requests.post("http://" + self._address + self._api_prefix + path, files = files_dict)
for line in file_contents:
s.write(str(line))
s.write('\r\n')
for k, v in post_data.items():
s.write('--%s\r\n' % (boundary))
s.write('Content-Disposition: form-data; name="%s"\r\n' % (k))
s.write('\r\n')
s.write(str(v))
s.write('\r\n')
s.write('--%s--\r\n' % (boundary))
self._http_connection.request(method, path, s, {"Content-type": "multipart/form-data; boundary=%s" % (boundary), "Content-Length": len(s)})
elif post_data is not None:
self._http_connection.request(method, path, urllib.urlencode(post_data), {"Content-type": "application/x-www-form-urlencoded", "User-Agent": "Cura Doodle3D connection"})
else:
self._http_connection.request(method, path, headers={"Content-type": "application/x-www-form-urlencoded", "User-Agent": "Cura Doodle3D connection"})
except IOError:
self._http_connection.close()
return None
except Exception as e:
self._http_connection.close()
return None
try:
response = self._http_connection.getresponse()
response_text = response.read()
except IOError:
self._http_connection.close()
return None
try:
response = json.loads(response_text.decode("utf-8"))
except ValueError:
self._http_connection.close()
return None
self._http_connection.close()
return response

View file

@ -14,24 +14,24 @@ class WifiOutputDevicePlugin(OutputDevicePlugin, SignalEmitter):
addConnectionSignal = Signal() addConnectionSignal = Signal()
## Start looking for devices on network.
def start(self): def start(self):
self._browser = ServiceBrowser(Zeroconf(), u'_ultimaker._tcp.local.', [self._onServiceChanged]) self._browser = ServiceBrowser(Zeroconf(), u'_ultimaker._tcp.local.', [self._onServiceChanged])
## Stop looking for devices on network.
def stop(self): def stop(self):
self._zero_conf.close() self._zero_conf.close()
## Because the model needs to be created in the same thread as the QMLEngine, we use a signal. ## Because the model needs to be created in the same thread as the QMLEngine, we use a signal.
def addConnection(self, name, address, properties): def addConnection(self, name, address, properties):
connection = WifiConnection.WifiConnection(address, properties) if address == "10.180.1.30": #DEBUG
connection.connect() connection = WifiConnection.WifiConnection(address, properties)
self._connections[address] = connection connection.connect()
if address == "10.180.1.23": #DEBUG self._connections[address] = connection
#if address == "10.180.0.249": #DEBUG
connection.startPrint()
connection.connectionStateChanged.connect(self._onPrinterConnectionStateChanged) connection.connectionStateChanged.connect(self._onPrinterConnectionStateChanged)
def _onPrinterConnectionStateChanged(self, address): def _onPrinterConnectionStateChanged(self, address):
print(self._connections[address].isConnected()) print("_onPrinterConnectionStateChanged" , self._connections[address].isConnected())
if self._connections[address].isConnected(): if self._connections[address].isConnected():
self.getOutputDeviceManager().addOutputDevice(self._connections[address]) self.getOutputDeviceManager().addOutputDevice(self._connections[address])
else: else:
@ -49,5 +49,6 @@ class WifiOutputDevicePlugin(OutputDevicePlugin, SignalEmitter):
self.addConnectionSignal.emit(str(name), address, info.properties) self.addConnectionSignal.emit(str(name), address, info.properties)
elif state_change == ServiceStateChange.Removed: elif state_change == ServiceStateChange.Removed:
print("Device disconnected") info = zeroconf.get_service_info(service_type, name)
#print("HERP DERP") address = '.'.join(map(lambda n: str(n), info.address))
print("Device disconnected: ", address)