mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-23 14:44:13 -06:00
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:
parent
763206af32
commit
ca502705c2
2 changed files with 42 additions and 78 deletions
|
@ -1,11 +1,10 @@
|
|||
from UM.OutputDevice.OutputDevice import OutputDevice
|
||||
from UM.OutputDevice import OutputDeviceError
|
||||
import threading
|
||||
import http.client as httpclient
|
||||
import urllib
|
||||
import json
|
||||
import time
|
||||
import base64
|
||||
import requests
|
||||
|
||||
from . import HttpUploadDataStream
|
||||
from UM.i18n import i18nCatalog
|
||||
|
@ -24,8 +23,13 @@ class WifiConnection(OutputDevice, SignalEmitter):
|
|||
self._file = None
|
||||
self._do_update = True
|
||||
self._thread = None
|
||||
self._state = None
|
||||
|
||||
self._json_printer_state = None
|
||||
|
||||
self._is_connected = False
|
||||
|
||||
self._api_version = "1"
|
||||
self._api_prefix = "/api/v" + self._api_version + "/"
|
||||
self.connect()
|
||||
self.setName(address)
|
||||
self.setShortDescription(i18n_catalog.i18nc("@action:button", "Print with WIFI"))
|
||||
|
@ -37,23 +41,25 @@ class WifiConnection(OutputDevice, SignalEmitter):
|
|||
def isConnected(self):
|
||||
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):
|
||||
print("setting connection state: " , self._address, " " , state)
|
||||
if state != self._is_connected:
|
||||
Logger.log("i", "setting connection state of %s to %s " %(self._address, state))
|
||||
self._is_connected = state
|
||||
self.connectionStateChanged.emit(self._address)
|
||||
else:
|
||||
self._is_connected = state
|
||||
self._is_connected = state
|
||||
|
||||
def _update(self):
|
||||
while self._thread:
|
||||
state_reply = self._httpRequest('GET', '/api/v1/printer/state')
|
||||
if state_reply is not None:
|
||||
self._state = state_reply
|
||||
self.setConnectionState(True)
|
||||
reply = self._httpGet("printer")
|
||||
if reply.status_code == 200:
|
||||
self._json_printer_state = reply.json()
|
||||
if not self._is_connected:
|
||||
self.setConnectionState(True)
|
||||
else:
|
||||
self._state = {'state': 'CONNECTION_ERROR'}
|
||||
self.setConnectionState(False)
|
||||
time.sleep(1)
|
||||
|
||||
|
@ -61,11 +67,11 @@ class WifiConnection(OutputDevice, SignalEmitter):
|
|||
self._do_update = 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.startPrint()
|
||||
|
||||
#Open the active connection to the printer so we can send commands
|
||||
## Start the polling thread.
|
||||
def connect(self):
|
||||
if self._thread is None:
|
||||
self._do_update = True
|
||||
|
@ -78,65 +84,22 @@ class WifiConnection(OutputDevice, SignalEmitter):
|
|||
|
||||
def startPrint(self):
|
||||
try:
|
||||
result = self._httpRequest('POST', '/api/v1/printer/print_upload', {'print_name': 'Print from Cura', 'parameters':''}, {'file': ('file.gcode', self._file)})
|
||||
print(result.get('success',False))
|
||||
#result = self._httpRequest('POST', '/api/v1/printer/print_upload', {'print_name': 'Print from Cura'})
|
||||
result = self._httpPost("print_job", self._file)
|
||||
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:
|
||||
self._http_connection = httpclient.HTTPConnection(self._address, timeout = 30)
|
||||
try:
|
||||
if files is not None:
|
||||
boundary = 'wL36Yn8afVp8Ag7AmP8qZ0SA4n1v9T'
|
||||
s = HttpUploadDataStream.HttpUploadDataStream()
|
||||
for k, v in files.items():
|
||||
filename = v[0]
|
||||
file_contents = v[1]
|
||||
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')
|
||||
files_dict = {}
|
||||
if isinstance(file_data, list): # in case a list with strings is sent
|
||||
single_string_file_data = ""
|
||||
for line in file_data:
|
||||
single_string_file_data += line
|
||||
files_dict = {"file":("test.gcode", single_string_file_data)}
|
||||
else:
|
||||
files_dict = {"file":("test.gcode", file_data)}
|
||||
|
||||
if file_contents is not None:
|
||||
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
|
||||
return requests.post("http://" + self._address + self._api_prefix + path, files = files_dict)
|
|
@ -14,24 +14,24 @@ class WifiOutputDevicePlugin(OutputDevicePlugin, SignalEmitter):
|
|||
|
||||
addConnectionSignal = Signal()
|
||||
|
||||
## Start looking for devices on network.
|
||||
def start(self):
|
||||
self._browser = ServiceBrowser(Zeroconf(), u'_ultimaker._tcp.local.', [self._onServiceChanged])
|
||||
|
||||
## Stop looking for devices on network.
|
||||
def stop(self):
|
||||
self._zero_conf.close()
|
||||
|
||||
## Because the model needs to be created in the same thread as the QMLEngine, we use a signal.
|
||||
def addConnection(self, name, address, properties):
|
||||
connection = WifiConnection.WifiConnection(address, properties)
|
||||
connection.connect()
|
||||
self._connections[address] = connection
|
||||
if address == "10.180.1.23": #DEBUG
|
||||
#if address == "10.180.0.249": #DEBUG
|
||||
connection.startPrint()
|
||||
if address == "10.180.1.30": #DEBUG
|
||||
connection = WifiConnection.WifiConnection(address, properties)
|
||||
connection.connect()
|
||||
self._connections[address] = connection
|
||||
connection.connectionStateChanged.connect(self._onPrinterConnectionStateChanged)
|
||||
|
||||
def _onPrinterConnectionStateChanged(self, address):
|
||||
print(self._connections[address].isConnected())
|
||||
print("_onPrinterConnectionStateChanged" , self._connections[address].isConnected())
|
||||
if self._connections[address].isConnected():
|
||||
self.getOutputDeviceManager().addOutputDevice(self._connections[address])
|
||||
else:
|
||||
|
@ -49,5 +49,6 @@ class WifiOutputDevicePlugin(OutputDevicePlugin, SignalEmitter):
|
|||
self.addConnectionSignal.emit(str(name), address, info.properties)
|
||||
|
||||
elif state_change == ServiceStateChange.Removed:
|
||||
print("Device disconnected")
|
||||
#print("HERP DERP")
|
||||
info = zeroconf.get_service_info(service_type, name)
|
||||
address = '.'.join(map(lambda n: str(n), info.address))
|
||||
print("Device disconnected: ", address)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue