From eaf7a4453aefd91b303a2061df714f989a8c1c3c Mon Sep 17 00:00:00 2001 From: Luc Rubio Date: Tue, 19 May 2020 22:06:49 +0100 Subject: [PATCH] First prototype. --- .gitignore | 2 + LICENSE | 165 ++++++++++ README.md | 19 ++ __init__.py | 11 + plugin.json | 8 + resources/png/monoprice_select_mini_v2.png | Bin 0 -> 138250 bytes resources/qml/MonitorBuildplate.qml | 70 +++++ resources/qml/MonitorExtruder.qml | 66 ++++ resources/qml/MonitorIconExtruder.qml | 36 +++ resources/qml/MonitorPrintJobProgressBar.qml | 38 +++ resources/qml/MonitorPrinterCard.qml | 286 ++++++++++++++++++ resources/qml/MonitorPrinterConfiguration.qml | 29 ++ resources/qml/MonitorPrinterPill.qml | 30 ++ resources/qml/MonitorStage.qml | 56 ++++ resources/svg/icons/buildplate.svg | 5 + resources/svg/icons/extruder.svg | 5 + src/GCodeWriteFileJob.py | 21 ++ src/MPSM2NetworkedPrinterOutputDevice.py | 250 +++++++++++++++ src/MPSM2OutputController.py | 21 ++ src/MPSM2OutputDevicePlugin.py | 52 ++++ src/Messages/PrintJobUploadBlockedMessage.py | 14 + src/Messages/PrintJobUploadCancelMessage.py | 14 + src/Messages/PrintJobUploadErrorMessage.py | 14 + .../PrintJobUploadIsPrintingMessage.py | 14 + src/Messages/PrintJobUploadProgressMessage.py | 35 +++ src/Messages/PrintJobUploadSuccessMessage.py | 14 + src/Messages/__init__.py | 0 src/Models/MPSM2PrintJobOutputModel.py | 26 ++ src/Models/MPSM2PrinterOutputModel.py | 12 + src/Models/MPSM2PrinterStatusModel.py | 18 ++ src/Models/__init__.py | 0 src/Network/ApiClient.py | 114 +++++++ src/Network/DeviceManager.py | 233 ++++++++++++++ src/Network/PrinterHeartbeat.py | 44 +++ src/Network/__init__.py | 0 src/Parser/MPSM2PrinterStatusParser.py | 27 ++ src/Parser/__init__.py | 0 src/__init__.py | 0 38 files changed, 1749 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 __init__.py create mode 100644 plugin.json create mode 100644 resources/png/monoprice_select_mini_v2.png create mode 100644 resources/qml/MonitorBuildplate.qml create mode 100644 resources/qml/MonitorExtruder.qml create mode 100644 resources/qml/MonitorIconExtruder.qml create mode 100644 resources/qml/MonitorPrintJobProgressBar.qml create mode 100644 resources/qml/MonitorPrinterCard.qml create mode 100644 resources/qml/MonitorPrinterConfiguration.qml create mode 100644 resources/qml/MonitorPrinterPill.qml create mode 100644 resources/qml/MonitorStage.qml create mode 100644 resources/svg/icons/buildplate.svg create mode 100644 resources/svg/icons/extruder.svg create mode 100644 src/GCodeWriteFileJob.py create mode 100644 src/MPSM2NetworkedPrinterOutputDevice.py create mode 100644 src/MPSM2OutputController.py create mode 100644 src/MPSM2OutputDevicePlugin.py create mode 100644 src/Messages/PrintJobUploadBlockedMessage.py create mode 100644 src/Messages/PrintJobUploadCancelMessage.py create mode 100644 src/Messages/PrintJobUploadErrorMessage.py create mode 100644 src/Messages/PrintJobUploadIsPrintingMessage.py create mode 100644 src/Messages/PrintJobUploadProgressMessage.py create mode 100644 src/Messages/PrintJobUploadSuccessMessage.py create mode 100644 src/Messages/__init__.py create mode 100644 src/Models/MPSM2PrintJobOutputModel.py create mode 100644 src/Models/MPSM2PrinterOutputModel.py create mode 100644 src/Models/MPSM2PrinterStatusModel.py create mode 100644 src/Models/__init__.py create mode 100644 src/Network/ApiClient.py create mode 100644 src/Network/DeviceManager.py create mode 100644 src/Network/PrinterHeartbeat.py create mode 100644 src/Network/__init__.py create mode 100644 src/Parser/MPSM2PrinterStatusParser.py create mode 100644 src/Parser/__init__.py create mode 100644 src/__init__.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..23ef278 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea +resources/qml/*.qmlc \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..07b1d92 --- /dev/null +++ b/LICENSE @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..62cba76 --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# Cura network plugin for Monoprice Select Mini V2 + +## Overview + +This plugin for [Cura](https://github.com/ultimaker/cura) enables network interoperability with Monoprice Select Mini V2 printers. + +## Author + +Luc Rubio + +## License + +See LICENSE. + +## Donate + +If this plugin was useful to you, please consider making a donation. + +[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=AHZG8HGU4GM8G) \ No newline at end of file diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..54857bf --- /dev/null +++ b/__init__.py @@ -0,0 +1,11 @@ +from .src import MPSM2OutputDevicePlugin + + +def getMetaData(): + return {} + + +def register(app): + return { + "output_device": MPSM2OutputDevicePlugin.MPSM2OutputDevicePlugin(), + } diff --git a/plugin.json b/plugin.json new file mode 100644 index 0000000..3bfba13 --- /dev/null +++ b/plugin.json @@ -0,0 +1,8 @@ +{ + "name": "Monoprice Select Mini V2 Network Connectivity", + "author": "Luc Rubio", + "description": "Network support for Monoprice Select Mini V2 printers.", + "version": "0.0.1", + "api": "7.1", + "i18n-catalog": "cura" +} diff --git a/resources/png/monoprice_select_mini_v2.png b/resources/png/monoprice_select_mini_v2.png new file mode 100644 index 0000000000000000000000000000000000000000..371472731093f9875b6edc9b4d8b020e4cf0cc9c GIT binary patch literal 138250 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 literal 0 HcmV?d00001 diff --git a/resources/qml/MonitorBuildplate.qml b/resources/qml/MonitorBuildplate.qml new file mode 100644 index 0000000..bb4b2e6 --- /dev/null +++ b/resources/qml/MonitorBuildplate.qml @@ -0,0 +1,70 @@ +// Copyright 2020 Luc Rubio +// Plugin is licensed under the GNU Lesser General Public License v3.0. +import QtQuick 2.2 +import QtQuick.Controls 2.0 +import UM 1.3 as UM + +Item { + property var bedTemperature: null + property var targetBedTemperature: null + height: 40 * screenScaleFactor + width: childrenRect.width + + UM.RecolorImage { + id: buildplateIcon + color: UM.Theme.getColor('monitor_icon_primary') + source: '../svg/icons/buildplate.svg' + width: 32 * screenScaleFactor + height: width + visible: buildplate + } + + Rectangle { + id: bedTemperatureWrapper + anchors { + left: buildplateIcon.right + leftMargin: 12 * screenScaleFactor + } + color: bedTemperatureLabel.visible > 0 ? 'transparent' : UM.Theme.getColor('monitor_skeleton_loading') + height: 18 * screenScaleFactor + width: Math.max(bedTemperatureLabel.contentWidth, 60 * screenScaleFactor) + radius: 2 * screenScaleFactor + + Label { + id: bedTemperatureLabel + color: UM.Theme.getColor('monitor_text_primary') + elide: Text.ElideRight + font: UM.Theme.getFont('large_bold') + text: bedTemperature !== -1 ? bedTemperature + 'ºC' : '' + visible: bedTemperature !== -1 // Default bed temperature in PrinterOutputModel + height: 18 * screenScaleFactor + verticalAlignment: Text.AlignVCenter + renderType: Text.NativeRendering + } + } + + Rectangle { + id: targetBedTemperatureWrapper + anchors + { + left: bedTemperatureWrapper.left + bottom: parent.bottom + } + color: targetBedTemperatureLabel.visible > 0 ? 'transparent' : UM.Theme.getColor('monitor_skeleton_loading') + height: 18 * screenScaleFactor + width: Math.max(targetBedTemperatureLabel.contentWidth, 36 * screenScaleFactor) + radius: 2 * screenScaleFactor + + Label { + id: targetBedTemperatureLabel + color: UM.Theme.getColor('monitor_text_primary') + elide: Text.ElideRight + font: UM.Theme.getFont('default') + text: targetBedTemperature !== '' ? 'Target: ' + targetBedTemperature + 'ºC' : '' + visible: text !== '' + height: 18 * screenScaleFactor + verticalAlignment: Text.AlignVCenter + renderType: Text.NativeRendering + } + } +} diff --git a/resources/qml/MonitorExtruder.qml b/resources/qml/MonitorExtruder.qml new file mode 100644 index 0000000..20c098d --- /dev/null +++ b/resources/qml/MonitorExtruder.qml @@ -0,0 +1,66 @@ +// Copyright 2020 Luc Rubio +// Plugin is licensed under the GNU Lesser General Public License v3.0. +import QtQuick 2.2 +import QtQuick.Controls 2.0 +import UM 1.3 as UM + +Item { + property var hotendTemperature : null // int + property var targetHotendTemperature : null // int + height: 40 * screenScaleFactor + width: childrenRect.width + + MonitorIconExtruder { + id: extruderIcon + color: 'orange' + position: 0 + } + + Rectangle { + id: hotendTemperatureWrapper + anchors { + left: extruderIcon.right + leftMargin: 12 * screenScaleFactor + } + color: hotendTemperatureLabel.visible > 0 ? 'transparent' : UM.Theme.getColor('monitor_skeleton_loading') + height: 18 * screenScaleFactor + width: Math.max(hotendTemperatureLabel.contentWidth, 60 * screenScaleFactor) + radius: 2 * screenScaleFactor + + Label { + id: hotendTemperatureLabel + color: UM.Theme.getColor('monitor_text_primary') + elide: Text.ElideRight + font: UM.Theme.getFont('large_bold') + text: hotendTemperature + 'ºC' + visible: hotendTemperature !== 0 + height: parent.height + verticalAlignment: Text.AlignVCenter + renderType: Text.NativeRendering + } + } + + Rectangle { + id: targetHotendTemperatureWrapper + anchors { + left: hotendTemperatureWrapper.left + bottom: parent.bottom + } + color: targetHotendTemperatureLabel.visible > 0 ? 'transparent' : UM.Theme.getColor('monitor_skeleton_loading') + height: 18 * screenScaleFactor + width: Math.max(targetHotendTemperatureLabel.contentWidth, 36 * screenScaleFactor) + radius: 2 * screenScaleFactor + + Label { + id: targetHotendTemperatureLabel + color: UM.Theme.getColor('monitor_text_primary') + elide: Text.ElideRight + font: UM.Theme.getFont('default') + text: targetHotendTemperature !== '' ? 'Target: ' + targetHotendTemperature + 'ºC' : '' + visible: text !== '' + height: parent.height + verticalAlignment: Text.AlignVCenter + renderType: Text.NativeRendering + } + } +} diff --git a/resources/qml/MonitorIconExtruder.qml b/resources/qml/MonitorIconExtruder.qml new file mode 100644 index 0000000..cea2475 --- /dev/null +++ b/resources/qml/MonitorIconExtruder.qml @@ -0,0 +1,36 @@ +// Copyright 2020 Luc Rubio +// Plugin is licensed under the GNU Lesser General Public License v3.0. +import QtQuick 2.2 +import QtQuick.Controls 2.0 +import UM 1.3 as UM + +Item { + property alias color: icon.color + property int position: 0 + property int size: 32 * screenScaleFactor + property string iconSource: '../svg/icons/extruder.svg' + height: size + width: size + + UM.RecolorImage { + id: icon + anchors.fill: parent + source: iconSource + width: size + } + + Label { + id: positionLabel + font: UM.Theme.getFont('small') + color: UM.Theme.getColor('monitor_text_primary') + height: Math.round(size / 2) + horizontalAlignment: Text.AlignHCenter + text: position + 1 + verticalAlignment: Text.AlignVCenter + width: Math.round(size / 2) + x: Math.round(size * 0.25) + y: Math.round(size * 0.15625) + visible: position >= 0 + renderType: Text.NativeRendering + } +} diff --git a/resources/qml/MonitorPrintJobProgressBar.qml b/resources/qml/MonitorPrintJobProgressBar.qml new file mode 100644 index 0000000..210d2ef --- /dev/null +++ b/resources/qml/MonitorPrintJobProgressBar.qml @@ -0,0 +1,38 @@ +// Copyright 2020 Luc Rubio +// Plugin is licensed under the GNU Lesser General Public License v3.0. +import QtQuick 2.3 +import QtQuick.Controls.Styles 1.3 +import QtQuick.Controls 1.4 +import UM 1.3 as UM + +Item { + property var printJob: null + width: childrenRect.width + height: UM.Theme.getSize('monitor_text_line').height + + UM.ProgressBar { + id: progressBar + anchors { + verticalCenter: parent.verticalCenter + left: parent.left + } + value: printJob ? printJob.progress / 100 : 0 + width: UM.Theme.getSize('monitor_progress_bar').width + } + + Label { + id: percentLabel + anchors { + left: progressBar.right + leftMargin: UM.Theme.getSize('monitor_margin').width + verticalCenter: parent.verticalCenter + } + text: printJob ? printJob.progress + '%' : '0%' + color: printJob && printJob.isActive ? UM.Theme.getColor('monitor_text_primary') : UM.Theme.getColor('monitor_text_disabled') + width: contentWidth + font: UM.Theme.getFont('default') + height: UM.Theme.getSize('monitor_text_line').height + verticalAlignment: Text.AlignVCenter + renderType: Text.NativeRendering + } +} diff --git a/resources/qml/MonitorPrinterCard.qml b/resources/qml/MonitorPrinterCard.qml new file mode 100644 index 0000000..9cbaff3 --- /dev/null +++ b/resources/qml/MonitorPrinterCard.qml @@ -0,0 +1,286 @@ +// Copyright 2020 Luc Rubio +// Plugin is licensed under the GNU Lesser General Public License v3.0. +import QtQuick 2.3 +import QtQuick.Controls 2.0 +import QtQuick.Dialogs 1.1 +import UM 1.3 as UM +import Cura 1.0 as Cura + +Item { + id: base + property var printer: null + property var borderSize: 1 * screenScaleFactor + property var enabled: true + width: 834 * screenScaleFactor + height: childrenRect.height + + Rectangle { + id: background + anchors.fill: parent + color: UM.Theme.getColor('monitor_card_background') + border { + color: UM.Theme.getColor('monitor_card_border') + width: borderSize + } + radius: 2 * screenScaleFactor + } + + Item { + id: printerInfo + width: parent.width + height: 144 * screenScaleFactor + + Row { + anchors { + left: parent.left + leftMargin: 36 * screenScaleFactor + verticalCenter: parent.verticalCenter + } + spacing: 18 * screenScaleFactor + + Rectangle { + id: printerImage + width: 108 * screenScaleFactor + height: 108 * screenScaleFactor + color: printer ? 'transparent' : UM.Theme.getColor('monitor_skeleton_loading') + radius: 8 + Image { + anchors.fill: parent + fillMode: Image.PreserveAspectFit + source: '../png/monoprice_select_mini_v2.png' + mipmap: true + } + } + + Item { + anchors { + verticalCenter: parent.verticalCenter + } + width: 180 * screenScaleFactor + height: childrenRect.height + + Rectangle { + id: printerNameLabel + color: printer ? 'transparent' : UM.Theme.getColor('monitor_skeleton_loading') + height: 18 * screenScaleFactor + width: parent.width + radius: 2 * screenScaleFactor + + Label { + text: printer && printer.name ? printer.name : '' + color: UM.Theme.getColor('monitor_text_primary') + elide: Text.ElideRight + font: UM.Theme.getFont('large_bold') + width: parent.width + visible: printer + height: parent.height + verticalAlignment: Text.AlignVCenter + renderType: Text.NativeRendering + } + } + + MonitorPrinterPill { + id: printerFamilyPill + anchors { + top: printerNameLabel.bottom + topMargin: 6 * screenScaleFactor + left: printerNameLabel.left + } + text: printer ? printer.type : '' + } + } + MonitorPrinterConfiguration { + id: printerConfiguration + anchors.verticalCenter: parent.verticalCenter + buildplate: { + if (printer) { + return [printer.bedTemperature, printer.targetBedTemperature] + } + return null + } + extruder: { + if (printer) { + return printer.extruders[0] + } + return null + } + height: 72 * screenScaleFactor + } + } + } + + Rectangle { + id: divider + anchors { + top: printJobInfo.top + left: printJobInfo.left + right: printJobInfo.right + } + height: borderSize + color: background.border.color + } + + Rectangle { + id: printJobInfo + anchors { + top: printerInfo.bottom + topMargin: -borderSize * screenScaleFactor + } + border { + color: 'transparent' + width: borderSize + } + color: 'transparent' + height: 84 * screenScaleFactor + borderSize + width: parent.width + + Row { + anchors { + fill: parent + topMargin: 12 * screenScaleFactor + borderSize + bottomMargin: 12 * screenScaleFactor + leftMargin: 36 * screenScaleFactor + } + height: childrenRect.height + spacing: 18 * screenScaleFactor + + Label { + id: printerStatus + anchors { + verticalCenter: parent.verticalCenter + } + color: UM.Theme.getColor('monitor_text_primary') + font: UM.Theme.getFont('medium') + text: { + if (printer) { + switch(printer.state) { + case 'idle': + return catalog.i18nc('@label:status', 'Ready') + case 'printing': + return catalog.i18nc('@label:status', 'Printing') + case 'paused': + return catalog.i18nc('@label:status', 'Paused') + } + } + return '' + } + visible: text !== '' + width: 108 * screenScaleFactor + renderType: Text.NativeRendering + } + + MonitorPrintJobProgressBar { + anchors { + verticalCenter: parent.verticalCenter + } + printJob: printer && printer.activePrintJob + visible: printer && printer.activePrintJob && (printer.activePrintJob.state === 'active' || printer.activePrintJob.state === 'paused') + } + } + + Button { + id: pauseOrResumePrintButton + anchors { + verticalCenter: parent.verticalCenter + right: cancelPrintButton.left + rightMargin: 18 * screenScaleFactor + } + background: Rectangle { + color: UM.Theme.getColor('monitor_secondary_button_shadow') + radius: 2 * screenScaleFactor + Rectangle { + anchors.fill: parent + anchors.bottomMargin: 2 * screenScaleFactor + color: pauseOrResumePrintButton.hovered ? UM.Theme.getColor('monitor_secondary_button_hover') : UM.Theme.getColor('monitor_secondary_button') + radius: 2 * screenScaleFactor + } + } + contentItem: Label { + anchors.fill: parent + anchors.bottomMargin: 2 * screenScaleFactor + color: UM.Theme.getColor('monitor_secondary_button_text') + font: UM.Theme.getFont('medium') + text: printer.activePrintJob.state === 'paused' ? catalog.i18nc('@action:button', 'Resume Print') : catalog.i18nc('@action:button', 'Pause Print') + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + height: 18 * screenScaleFactor + renderType: Text.NativeRendering + } + implicitHeight: 32 * screenScaleFactor + implicitWidth: 96 * screenScaleFactor + visible: printer && printer.activePrintJob && (printer.activePrintJob.state === 'active' || printer.activePrintJob.state === 'paused') + onClicked: base.enabled ? OutputDevice.pauseOrResumePrint() : {} + enabled: true // TODO + } + + Button { + id: cancelPrintButton + anchors { + verticalCenter: parent.verticalCenter + right: parent.right + rightMargin: 18 * screenScaleFactor + } + background: Rectangle { + color: UM.Theme.getColor('monitor_secondary_button_shadow') + radius: 2 * screenScaleFactor + Rectangle { + anchors.fill: parent + anchors.bottomMargin: 2 * screenScaleFactor + color: cancelPrintButton.hovered ? UM.Theme.getColor('monitor_secondary_button_hover') : UM.Theme.getColor('monitor_secondary_button') + radius: 2 * screenScaleFactor + } + } + contentItem: Label { + anchors.fill: parent + anchors.bottomMargin: 2 * screenScaleFactor + color: UM.Theme.getColor('monitor_secondary_button_text') + font: UM.Theme.getFont('medium') + text: catalog.i18nc('@action:button', 'Cancel Print') + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + height: 18 * screenScaleFactor + renderType: Text.NativeRendering + } + implicitHeight: 32 * screenScaleFactor + implicitWidth: 96 * screenScaleFactor + visible: printer && printer.activePrintJob && (printer.activePrintJob.state === 'active' || printer.activePrintJob.state === 'paused') + onClicked: base.enabled ? OutputDevice.cancelPrint() : {} + enabled: true // TODO + } + + Button { + id: printCachedButton + anchors { + verticalCenter: parent.verticalCenter + right: parent.right + rightMargin: 18 * screenScaleFactor + } + background: Rectangle { + color: UM.Theme.getColor('monitor_secondary_button_shadow') + radius: 2 * screenScaleFactor + Rectangle { + anchors.fill: parent + anchors.bottomMargin: 2 * screenScaleFactor + color: printCachedButton.hovered ? UM.Theme.getColor('monitor_secondary_button_hover') : UM.Theme.getColor('monitor_secondary_button') + radius: 2 * screenScaleFactor + } + } + contentItem: Label { + anchors.fill: parent + anchors.bottomMargin: 2 * screenScaleFactor + color: UM.Theme.getColor('monitor_secondary_button_text') + font: UM.Theme.getFont('medium') + text: catalog.i18nc('@action:button', 'Print Cached Model') + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + height: 18 * screenScaleFactor + renderType: Text.NativeRendering + } + implicitHeight: 32 * screenScaleFactor + implicitWidth: 150 * screenScaleFactor + visible: printer && printer.activePrintJob && printer.activePrintJob.state === 'not_started' + onClicked: base.enabled ? OutputDevice.startPrint() : {} + enabled: true // TODO + } + } +} diff --git a/resources/qml/MonitorPrinterConfiguration.qml b/resources/qml/MonitorPrinterConfiguration.qml new file mode 100644 index 0000000..ecc657c --- /dev/null +++ b/resources/qml/MonitorPrinterConfiguration.qml @@ -0,0 +1,29 @@ +// Copyright 2020 Luc Rubio +// Plugin is licensed under the GNU Lesser General Public License v3.0. +import QtQuick 2.2 +import QtQuick.Controls 2.0 +import UM 1.3 as UM + +Item { + id: base + property var extruder: null + property var buildplate: null + height: parent.height + width: 450 * screenScaleFactor // Default size, but should be stretched to fill parent + + Column { + spacing: 18 * screenScaleFactor + + MonitorExtruder { + hotendTemperature: extruder.hotendTemperature + targetHotendTemperature: extruder.targetHotendTemperature + width: base.width + } + + MonitorBuildplate { + bedTemperature: buildplate[0] + targetBedTemperature: buildplate[1] + width: base.width + } + } +} diff --git a/resources/qml/MonitorPrinterPill.qml b/resources/qml/MonitorPrinterPill.qml new file mode 100644 index 0000000..2f97e67 --- /dev/null +++ b/resources/qml/MonitorPrinterPill.qml @@ -0,0 +1,30 @@ +// Copyright 2020 Luc Rubio +// Plugin is licensed under the GNU Lesser General Public License v3.0. +import QtQuick 2.2 +import QtQuick.Controls 1.4 +import UM 1.2 as UM + +Item { + id: monitorPrinterPill + property var text: '' + + implicitHeight: 18 * screenScaleFactor + implicitWidth: Math.max(printerNameLabel.contentWidth + 12 * screenScaleFactor, 36 * screenScaleFactor) + + Rectangle { + id: background + anchors.fill: parent + color: printerNameLabel.visible ? UM.Theme.getColor('monitor_printer_family_tag') : UM.Theme.getColor('monitor_skeleton_loading') + radius: 2 * screenScaleFactor + } + + Label { + id: printerNameLabel + anchors.centerIn: parent + color: UM.Theme.getColor('monitor_text_primary') + text: monitorPrinterPill.text + font.pointSize: 10 + visible: monitorPrinterPill.text !== '' + renderType: Text.NativeRendering + } +} diff --git a/resources/qml/MonitorStage.qml b/resources/qml/MonitorStage.qml new file mode 100644 index 0000000..1291b30 --- /dev/null +++ b/resources/qml/MonitorStage.qml @@ -0,0 +1,56 @@ +// Copyright 2020 Luc Rubio +// Plugin is licensed under the GNU Lesser General Public License v3.0. +import QtQuick 2.2 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import UM 1.3 as UM +import Cura 1.0 as Cura +import QtGraphicalEffects 1.0 + +Component +{ + Rectangle + { + height: maximumHeight + width: maximumWidth + color: UM.Theme.getColor('monitor_stage_background') + Component.onCompleted: forceActiveFocus() + + UM.I18nCatalog { + id: catalog + name: 'cura' + } + + Item { + anchors { + top: parent.top + topMargin: 48 * screenScaleFactor + } + width: parent.width + height: 264 * screenScaleFactor + + Item { + height: centerSection.height + width: maximumWidth + + Item { + id: centerSection + anchors { + verticalCenter: parent.verticalCenter + horizontalCenter: parent.horizontalCenter + } + width: 834 * screenScaleFactor + height: printerCard.height + z: 1 + + MonitorPrinterCard { + id: printerCard + printer: { + return OutputDevice.printer + } + } + } + } + } + } +} diff --git a/resources/svg/icons/buildplate.svg b/resources/svg/icons/buildplate.svg new file mode 100644 index 0000000..bcb278a --- /dev/null +++ b/resources/svg/icons/buildplate.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/resources/svg/icons/extruder.svg b/resources/svg/icons/extruder.svg new file mode 100644 index 0000000..235cb43 --- /dev/null +++ b/resources/svg/icons/extruder.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/GCodeWriteFileJob.py b/src/GCodeWriteFileJob.py new file mode 100644 index 0000000..ed20d7e --- /dev/null +++ b/src/GCodeWriteFileJob.py @@ -0,0 +1,21 @@ +# Copyright 2020 Luc Rubio +# Plugin is licensed under the GNU Lesser General Public License v3.0. +import io +from typing import List, Optional + +from UM.FileHandler.FileHandler import FileHandler +from UM.FileHandler.WriteFileJob import WriteFileJob +from UM.FileHandler.FileWriter import FileWriter +from UM.Scene.SceneNode import SceneNode + +from cura.CuraApplication import CuraApplication + + +class GCodeWriteFileJob(WriteFileJob): + def __init__(self, file_handler: Optional[FileHandler], nodes: List[SceneNode]) -> None: + super().__init__(file_handler.getWriterByMimeType('text/x-gcode'), io.StringIO(), nodes, + FileWriter.OutputMode.TextMode) # GCodeWriter only supports TextMode + self.setFileName('{}.gcode'.format(CuraApplication.getInstance().getPrintInformation().jobName)) + + def getGcodeOutput(self) -> bytes: + return self.getStream().getvalue().encode('utf-8') diff --git a/src/MPSM2NetworkedPrinterOutputDevice.py b/src/MPSM2NetworkedPrinterOutputDevice.py new file mode 100644 index 0000000..c5561e7 --- /dev/null +++ b/src/MPSM2NetworkedPrinterOutputDevice.py @@ -0,0 +1,250 @@ +# Copyright 2020 Luc Rubio +# Plugin is licensed under the GNU Lesser General Public License v3.0. +import os +from typing import List, Optional, Dict + +from PyQt5.QtCore import pyqtProperty, pyqtSignal, QObject, pyqtSlot + +from UM.FileHandler.FileHandler import FileHandler +from UM.Logger import Logger +from UM.i18n import i18nCatalog +from UM.Scene.SceneNode import SceneNode + +from cura.CuraApplication import CuraApplication +from cura.PrinterOutput.Models.ExtruderConfigurationModel import ExtruderConfigurationModel +from cura.PrinterOutput.Models.PrinterConfigurationModel import PrinterConfigurationModel +from cura.PrinterOutput.Models.PrinterOutputModel import PrinterOutputModel +from cura.PrinterOutput.NetworkedPrinterOutputDevice import NetworkedPrinterOutputDevice, AuthState +from cura.PrinterOutput.PrinterOutputDevice import ConnectionType, ConnectionState + +from .MPSM2OutputController import MPSM2OutputController +from .Models.MPSM2PrinterOutputModel import MPSM2PrinterOutputModel +from .Models.MPSM2PrinterStatusModel import MPSM2PrinterStatusModel +from .Models.MPSM2PrintJobOutputModel import MPSM2PrintJobOutputModel +from .Network.ApiClient import ApiClient +from .GCodeWriteFileJob import GCodeWriteFileJob +from .Messages.PrintJobUploadProgressMessage import PrintJobUploadProgressMessage +from .Messages.PrintJobUploadBlockedMessage import PrintJobUploadBlockedMessage +from .Messages.PrintJobUploadSuccessMessage import PrintJobUploadSuccessMessage +from .Messages.PrintJobUploadCancelMessage import PrintJobUploadCancelMessage +from .Messages.PrintJobUploadIsPrintingMessage import PrintJobUploadIsPrintingMessage +from .Parser.MPSM2PrinterStatusParser import MPSM2PrinterStatusParser + +I18N_CATALOG = i18nCatalog('cura') + + +class MPSM2NetworkedPrinterOutputDevice(NetworkedPrinterOutputDevice): + META_NETWORK_KEY = 'mpsm2_network_key' + + printerStatusChanged = pyqtSignal() + onPrinterUpload = pyqtSignal(bool) + + def __init__(self, device_id: str, address: str, properties: Dict[bytes, bytes], connection_type: ConnectionType, + parent=None) -> None: + super().__init__(device_id=device_id, address=address, properties=properties, connection_type=connection_type, + parent=parent) + self._printer_output_controller = MPSM2OutputController(self) + self._printer_raw_response = '' # HTTP string response body + self._is_busy = False + + # Set the display name from the properties. + self.setName(self.getProperty('name')) + + # Set the display name of the printer type. + definitions = CuraApplication.getInstance().getContainerRegistry().findContainers(id=self.printerType) + self._printer_type_name = definitions[0].getName() if definitions else '' + self._job_upload_message = PrintJobUploadProgressMessage(self._onPrintUploadCancelled) + self._api_client = ApiClient(self.address, on_error=lambda error: Logger.log('e', str(error))) + + self._print_job_model = MPSM2PrintJobOutputModel(self._printer_output_controller) + self._printer_output_model = self._buildPrinterOutputModel() # type: MPSM2PrinterOutputModel + + self.setAuthenticationState(AuthState.Authenticated) + self._loadMonitorTab() + self._setInterfaceElements() + + # Produces main object for rendering the Printer Monitor tab. + @pyqtProperty(QObject, notify=printerStatusChanged) + def printer(self) -> PrinterOutputModel: + if self._printer_raw_response.upper() != 'OK': + self._onPrinterStatusChanged(self._printer_raw_response) + else: + Logger.log('d', self._printer_output_model.extruders[0].__dict__) + return self._printer_output_model + + @pyqtSlot(name='startPrint') + def startPrint(self) -> None: + Logger.log('d', 'Printing cache.gc.') + self._api_client.startPrint(self._onPrintStarted) + + @pyqtSlot(name='pauseOrResumePrint') + def pauseOrResumePrint(self) -> None: + if self._print_job_model.getState() == 'paused': + Logger.log('d', 'Resuming print.') + self._api_client.resumePrint(self._onPrintResumed) + else: + Logger.log('d', 'Pausing print.') + self._api_client.pausePrint(self._onPrintPaused) + + @pyqtSlot(name='cancelPrint') + def cancelPrint(self) -> None: + Logger.log('d', 'Cancelling print.') + self._api_client.cancelPrint(self._onPrintCancelled) + + # Override + def connect(self) -> None: + Logger.log('d', 'Connecting.') + super().connect() + self._update() + + # Override + def close(self) -> None: + Logger.log('d', 'Closing.') + super().close() + self.setConnectionState(ConnectionState.Closed) + if self.key in CuraApplication.getInstance().getOutputDeviceManager().getOutputDeviceIds(): + CuraApplication.getInstance().getOutputDeviceManager().removeOutputDevice(self.key) + + # Override + def requestWrite(self, nodes: List[SceneNode], file_name: Optional[str] = None, limit_mimetypes: bool = False, + file_handler: Optional[FileHandler] = None, filter_by_machine: bool = False, **kwargs) -> None: + Logger.log('d', 'Write to Output Device was requested.') + if self._job_upload_message.visible: + PrintJobUploadBlockedMessage().show() + return + if self._printer_output_model.getPrinterState() == 'printing': + PrintJobUploadIsPrintingMessage().show() + return + + self.writeStarted.emit(self) + job = GCodeWriteFileJob(file_handler=file_handler, nodes=nodes) + job.finished.connect(self._onPrintJobCreated) + job.start() + + def updatePrinterStatus(self, raw_response: str) -> None: + self._printer_raw_response = raw_response + + def isBusy(self) -> bool: + return self._is_busy + + def _onPrintJobCreated(self, job: GCodeWriteFileJob) -> None: + if not job: + Logger.log('e', 'No active exported job to upload!') + return + self.onPrinterUpload.emit(True) + self._is_busy = True + self._job_upload_message.show() + self._api_client.uploadPrint(job.getFileName(), job.getGcodeOutput(), self._onPrintUploadCompleted, + self._onPrintJobUploadProgress) + + def _onPrintUploadCancelled(self) -> None: + self._is_busy = False + self._job_upload_message.hide() + self._api_client.cancelUploadPrint() + PrintJobUploadCancelMessage().show() + self.writeFinished.emit() + self.onPrinterUpload.emit(False) + + def _onPrintUploadCompleted(self) -> None: + self._is_busy = False + self._job_upload_message.hide() + PrintJobUploadSuccessMessage().show() + self._api_client.startPrint() # force start + self.writeFinished.emit() + self.onPrinterUpload.emit(False) + + def _onPrintJobUploadProgress(self, bytes_sent: int, bytes_total: int) -> None: + percentage = (bytes_sent / bytes_total) if bytes_total else 0 + self._job_upload_message.setProgress(percentage * 100) + self.writeProgress.emit() + + def _onPrintStarted(self, raw_response: str) -> None: + self._onPrintResumed(raw_response) + + def _onPrintResumed(self, raw_response: str) -> None: + self._printer_raw_response = raw_response + if raw_response.upper() == 'OK': + self._printer_output_model.updateState('printing') + self._print_job_model.updateState('active') + self.printerStatusChanged.emit() + else: + Logger.log('d', 'Could not resume print') # TODO message + + def _onPrintPaused(self, raw_response: str) -> None: + self._printer_raw_response = raw_response + if raw_response.upper() == 'OK': + self._printer_output_model.updateState('paused') + self._print_job_model.updateState('paused') + self.printerStatusChanged.emit() + else: + Logger.log('d', 'Could not pause print') # TODO: message + + def _onPrintCancelled(self, raw_response: str) -> None: + self._printer_raw_response = raw_response + if raw_response.upper() == 'OK': + self._printer_output_model.updateState('idle') + self._print_job_model.updateState('not_started') + self._print_job_model.updateProgress(0) + self.printerStatusChanged.emit() + else: + Logger.log('d', 'Could not cancel print') # TODO: message + + def _setInterfaceElements(self) -> None: + self.setPriority(3) # Make sure the output device gets selected above local file output + self.setShortDescription(I18N_CATALOG.i18nc('@action:button Preceded by "Ready to".', 'Print over network')) + self.setDescription(I18N_CATALOG.i18nc('@properties:tooltip', 'Print over network')) + self.setConnectionText(I18N_CATALOG.i18nc('@info:status', 'Connected over the network')) + + def _loadMonitorTab(self) -> None: + plugin_registry = CuraApplication.getInstance().getPluginRegistry() + if not plugin_registry: + Logger.log('e', 'Could not get plugin registry.') + return + plugin_path = plugin_registry.getPluginPath('MPSM2NetworkPrinting') + if not plugin_path: + Logger.log('e', 'Could not get plugin path.') + return + self._monitor_view_qml_path = os.path.join(plugin_path, 'resources', 'qml', 'MonitorStage.qml') + + def _buildPrinterOutputModel(self) -> MPSM2PrinterOutputModel: + printer_output_model = MPSM2PrinterOutputModel(self._printer_output_controller) + printer_output_model.updateKey(self._address) + printer_output_model.updateName(self.address) + printer_output_model.updateState('idle') + printer_output_model.setAvailableConfigurations([self._buildPrinterConfigurationModel()]) + printer_output_model.updateType('Monoprice Select Mini') + printer_output_model.updateActivePrintJob(self._print_job_model) + return printer_output_model + + def _buildExtruderConfigurationModel(self) -> ExtruderConfigurationModel: + extruder_conf_model = ExtruderConfigurationModel() + extruder_conf_model.setPosition(0) + return extruder_conf_model + + def _buildPrinterConfigurationModel(self) -> PrinterConfigurationModel: + printer_configuration_model = PrinterConfigurationModel() + printer_configuration_model.setExtruderConfigurations([self._buildExtruderConfigurationModel()]) + printer_configuration_model.setPrinterType('type') + return printer_configuration_model + + def _onPrinterStatusChanged(self, raw_response: str) -> None: + printer_status_model = MPSM2PrinterStatusParser.parse(raw_response) + if printer_status_model: + self._printer_output_model.extruders[0].updateHotendTemperature( + float(printer_status_model.hotend_temperature)) + self._printer_output_model.extruders[0].updateTargetHotendTemperature( + float(printer_status_model.target_hotend_temperature)) + self._printer_output_model.updateBedTemperature(float(printer_status_model.bed_temperature)) + self._printer_output_model.updateTargetBedTemperature(float(printer_status_model.target_bed_temperature)) + if printer_status_model.state == MPSM2PrinterStatusModel.State.IDLE: + self._printer_output_model.updateState('idle') + self._print_job_model.updateState('not_started') + self._print_job_model.updateProgress(0) + elif printer_status_model.state == MPSM2PrinterStatusModel.State.PRINTING: # printing includes paused print + if self._printer_output_model.getPrinterState() == 'idle': + self._printer_output_model.updateState('printing') + if self._print_job_model.getState() == 'not_started': + self._print_job_model.updateState('active') + self._print_job_model.updateProgress(float(printer_status_model.progress)) + else: + Logger.log('d', 'Unknown printer status') # TODO: message diff --git a/src/MPSM2OutputController.py b/src/MPSM2OutputController.py new file mode 100644 index 0000000..ae8a290 --- /dev/null +++ b/src/MPSM2OutputController.py @@ -0,0 +1,21 @@ +# Copyright 2020 Luc Rubio +# Plugin is licensed under the GNU Lesser General Public License v3.0. +from cura.PrinterOutput.Models.PrintJobOutputModel import PrintJobOutputModel +from cura.PrinterOutput.PrinterOutputController import PrinterOutputController +from cura.PrinterOutput.PrinterOutputDevice import PrinterOutputDevice + + +class MPSM2OutputController(PrinterOutputController): + + def __init__(self, output_device: PrinterOutputDevice) -> None: + super().__init__(output_device) + self.can_pause = True + self.can_abort = True + self.can_pre_heat_bed = True + self.can_pre_heat_hotends = True + self.can_send_raw_gcode = True + self.can_control_manually = True + self.can_update_firmware = False + + def setJobState(self, job: PrintJobOutputModel, state: str) -> None: + self._output_device.setJobState(job.key, state) diff --git a/src/MPSM2OutputDevicePlugin.py b/src/MPSM2OutputDevicePlugin.py new file mode 100644 index 0000000..d89ecf3 --- /dev/null +++ b/src/MPSM2OutputDevicePlugin.py @@ -0,0 +1,52 @@ +# Copyright 2020 Luc Rubio +# Plugin is licensed under the GNU Lesser General Public License v3.0. +from typing import Optional, Callable + +from UM.Signal import Signal +from UM.OutputDevice.OutputDeviceManager import ManualDeviceAdditionAttempt +from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin + +from cura.CuraApplication import CuraApplication + +from .Network.DeviceManager import DeviceManager + + +## This plugin enables network interoperability with Monoprice Select Mini V2 printers. +class MPSM2OutputDevicePlugin(OutputDevicePlugin): + + # Signal emitted when the list of discovered devices changed. Used by printer action in this plugin. + discoveredDevicesChanged = Signal() + + def __init__(self) -> None: + super().__init__() + self._device_manager = DeviceManager() + self._device_manager.discoveredDevicesChanged.connect(self.discoveredDevicesChanged) + CuraApplication.getInstance().globalContainerStackChanged.connect(self.refreshConnections) + + # Overrides + def start(self) -> None: + self._device_manager.start() + + # Overrides + def stop(self) -> None: + self._device_manager.stop() + + # Overrides + def startDiscovery(self) -> None: + self._device_manager.startDiscovery() + + # Overrides + def refreshConnections(self) -> None: + self._device_manager.refreshConnections() + + # Overrides + def canAddManualDevice(self, address: str = '') -> ManualDeviceAdditionAttempt: + return ManualDeviceAdditionAttempt.PRIORITY + + # Overrides + def addManualDevice(self, address: str, callback: Optional[Callable[[bool, str], None]] = None) -> None: + self._device_manager.addManualDevice(address, callback) + + # Overrides + def removeManualDevice(self, key: str, address: Optional[str] = None) -> None: + self._device_manager.removeManualDevice(key, address) diff --git a/src/Messages/PrintJobUploadBlockedMessage.py b/src/Messages/PrintJobUploadBlockedMessage.py new file mode 100644 index 0000000..a267761 --- /dev/null +++ b/src/Messages/PrintJobUploadBlockedMessage.py @@ -0,0 +1,14 @@ +# Copyright 2020 Luc Rubio +# Plugin is licensed under the GNU Lesser General Public License v3.0. +from UM import i18nCatalog +from UM.Message import Message + +I18N_CATALOG = i18nCatalog('cura') + + +class PrintJobUploadBlockedMessage(Message): + def __init__(self) -> None: + super().__init__( + title=I18N_CATALOG.i18nc('@info:title', 'Print error'), + text=I18N_CATALOG.i18nc('@info:status', 'A print job transfer is in progress.'), + lifetime=10) diff --git a/src/Messages/PrintJobUploadCancelMessage.py b/src/Messages/PrintJobUploadCancelMessage.py new file mode 100644 index 0000000..4ab9f63 --- /dev/null +++ b/src/Messages/PrintJobUploadCancelMessage.py @@ -0,0 +1,14 @@ +# Copyright 2020 Luc Rubio +# Plugin is licensed under the GNU Lesser General Public License v3.0. +from UM import i18nCatalog +from UM.Message import Message + +I18N_CATALOG = i18nCatalog('cura') + + +class PrintJobUploadCancelMessage(Message): + def __init__(self) -> None: + super().__init__( + title=I18N_CATALOG.i18nc('@info:title', 'Print Cancelled'), + text=I18N_CATALOG.i18nc('@info:status', 'Print job was cancelled.'), + lifetime=0) diff --git a/src/Messages/PrintJobUploadErrorMessage.py b/src/Messages/PrintJobUploadErrorMessage.py new file mode 100644 index 0000000..b8bc1ec --- /dev/null +++ b/src/Messages/PrintJobUploadErrorMessage.py @@ -0,0 +1,14 @@ +# Copyright 2020 Luc Rubio +# Plugin is licensed under the GNU Lesser General Public License v3.0. +from UM import i18nCatalog +from UM.Message import Message + +I18N_CATALOG = i18nCatalog('cura') + + +class PrintJobUploadErrorMessage(Message): + def __init__(self) -> None: + super().__init__( + title=I18N_CATALOG.i18nc('@info:title', 'Network error'), + text=I18N_CATALOG.i18nc('@info:text', 'Could not upload the data to the printer.'), + lifetime=10) diff --git a/src/Messages/PrintJobUploadIsPrintingMessage.py b/src/Messages/PrintJobUploadIsPrintingMessage.py new file mode 100644 index 0000000..db63593 --- /dev/null +++ b/src/Messages/PrintJobUploadIsPrintingMessage.py @@ -0,0 +1,14 @@ +# Copyright 2020 Luc Rubio +# Plugin is licensed under the GNU Lesser General Public License v3.0. +from UM import i18nCatalog +from UM.Message import Message + +I18N_CATALOG = i18nCatalog('cura') + + +class PrintJobUploadIsPrintingMessage(Message): + def __init__(self) -> None: + super().__init__( + title=I18N_CATALOG.i18nc('@info:title', 'Printer is busy'), + text=I18N_CATALOG.i18nc('@info:status', 'Cannot upload when the printer is printing.'), + lifetime=0) diff --git a/src/Messages/PrintJobUploadProgressMessage.py b/src/Messages/PrintJobUploadProgressMessage.py new file mode 100644 index 0000000..787b242 --- /dev/null +++ b/src/Messages/PrintJobUploadProgressMessage.py @@ -0,0 +1,35 @@ +# Copyright 2020 Luc Rubio +# Plugin is licensed under the GNU Lesser General Public License v3.0. +from typing import Callable +from UM import i18nCatalog +from UM.Message import Message + +I18N_CATALOG = i18nCatalog('cura') + + +class PrintJobUploadProgressMessage(Message): + def __init__(self, on_cancelled: Callable) -> None: + super().__init__( + title=I18N_CATALOG.i18nc('@info:status', 'Sending Print Job'), + text=I18N_CATALOG.i18nc('@info:status', 'Uploading print job to printer.'), + progress=-1, + lifetime=0, + dismissable=False, + use_inactivity_timer=False) + self._on_cancelled = on_cancelled + self.addAction('cancel', I18N_CATALOG.i18nc('@action:button', 'Cancel'), 'cancel', + I18N_CATALOG.i18nc('@action', 'Cancels job upload.')) + self.actionTriggered.connect(self._onActionTriggered) + + def show(self) -> None: + self.setProgress(0) + super().show() + + def update(self, percentage: int) -> None: + if not self._visible: + super().show() + self.setProgress(percentage) + + def _onActionTriggered(self, message: str, action: str) -> None: + if action == 'cancel': + self._on_cancelled() diff --git a/src/Messages/PrintJobUploadSuccessMessage.py b/src/Messages/PrintJobUploadSuccessMessage.py new file mode 100644 index 0000000..37c6306 --- /dev/null +++ b/src/Messages/PrintJobUploadSuccessMessage.py @@ -0,0 +1,14 @@ +# Copyright 2020 Luc Rubio +# Plugin is licensed under the GNU Lesser General Public License v3.0. +from UM import i18nCatalog +from UM.Message import Message + +I18N_CATALOG = i18nCatalog("cura") + + +class PrintJobUploadSuccessMessage(Message): + def __init__(self) -> None: + super().__init__( + title=I18N_CATALOG.i18nc("@info:title", 'Data Sent'), + text=I18N_CATALOG.i18nc("@info:status", 'Print job was successfully sent. Starting print.'), + lifetime=5) diff --git a/src/Messages/__init__.py b/src/Messages/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/Models/MPSM2PrintJobOutputModel.py b/src/Models/MPSM2PrintJobOutputModel.py new file mode 100644 index 0000000..d85399b --- /dev/null +++ b/src/Models/MPSM2PrintJobOutputModel.py @@ -0,0 +1,26 @@ +# Copyright 2020 Luc Rubio +# Plugin is licensed under the GNU Lesser General Public License v3.0. +from PyQt5.QtCore import pyqtProperty, pyqtSignal + +from cura.PrinterOutput import PrinterOutputController +from cura.PrinterOutput.Models.PrintJobOutputModel import PrintJobOutputModel + + +class MPSM2PrintJobOutputModel(PrintJobOutputModel): + _timeElapsedChanged = pyqtSignal() + def __init__(self, output_controller: PrinterOutputController) -> None: + super().__init__(output_controller=output_controller, key='', name='') + self._state = 'not_started' + self._progress = 0 + self.timeElapsedChanged.connect(self._timeElapsedChanged) + + # Override + @pyqtProperty(float, notify=_timeElapsedChanged) + def progress(self) -> float: + return self._progress + + def updateProgress(self, progress: float) -> None: + self._progress = progress + + def getState(self) -> str: + return self._state diff --git a/src/Models/MPSM2PrinterOutputModel.py b/src/Models/MPSM2PrinterOutputModel.py new file mode 100644 index 0000000..bea3866 --- /dev/null +++ b/src/Models/MPSM2PrinterOutputModel.py @@ -0,0 +1,12 @@ +# Copyright 2020 Luc Rubio +# Plugin is licensed under the GNU Lesser General Public License v3.0. +from cura.PrinterOutput.Models.PrinterOutputModel import PrinterOutputModel +from cura.PrinterOutput.PrinterOutputController import PrinterOutputController + + +class MPSM2PrinterOutputModel(PrinterOutputModel): + def __init__(self, output_controller: PrinterOutputController) -> None: + super().__init__(output_controller, number_of_extruders=1) + + def getPrinterState(self) -> str: + return self._printer_state diff --git a/src/Models/MPSM2PrinterStatusModel.py b/src/Models/MPSM2PrinterStatusModel.py new file mode 100644 index 0000000..8f16940 --- /dev/null +++ b/src/Models/MPSM2PrinterStatusModel.py @@ -0,0 +1,18 @@ +# Copyright 2020 Luc Rubio +# Plugin is licensed under the GNU Lesser General Public License v3.0. +import enum + + +class MPSM2PrinterStatusModel: + class State(enum.Enum): + UNKNOWN = 1 + IDLE = 2 + PRINTING = 3 + def __init__(self, hotend_temperature: int, target_hotend_temperature: int, + bed_temperature: int, target_bed_temperature: int, progress: int, state: State) -> None: + self.hotend_temperature = hotend_temperature + self.target_hotend_temperature = target_hotend_temperature + self.bed_temperature = bed_temperature + self.target_bed_temperature = target_bed_temperature + self.progress = progress + self.state = state \ No newline at end of file diff --git a/src/Models/__init__.py b/src/Models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/Network/ApiClient.py b/src/Network/ApiClient.py new file mode 100644 index 0000000..841936f --- /dev/null +++ b/src/Network/ApiClient.py @@ -0,0 +1,114 @@ +# Copyright 2020 Luc Rubio +# Plugin is licensed under the GNU Lesser General Public License v3.0. +from typing import Callable, Tuple + +from PyQt5.QtCore import QUrl +from PyQt5.QtNetwork import QNetworkReply, QHttpPart, QNetworkRequest, QHttpMultiPart, QNetworkAccessManager + +from UM.Logger import Logger + + +class ApiClient: + # In order to avoid garbage collection we keep the callbacks in this list. + _anti_gc_callbacks = [] + + def __init__(self, address: str, on_error: Callable) -> None: + super().__init__() + self._manager = QNetworkAccessManager() + self._manager.finished.connect(self._handleOnFinished) + self._address = address + self._on_error = on_error + self._upload_reply = None + # QHttpMultiPart objects need to be kept alive and not garbage collected during the + # HTTP which uses them. We hold references to these QHttpMultiPart objects here. + self._cached_multiparts = {} + + def getPrinterStatus(self, on_finished: Callable) -> None: + reply = self._manager.get(self._createEmptyRequest('/inquiry')) + self._addCallback(reply, on_finished) + + def startPrint(self, on_finished: Callable = None) -> None: + reply = self._manager.get(self._createEmptyRequest('/set?cmd={P:M}')) + if on_finished: + self._addCallback(reply, on_finished) + + def resumePrint(self, on_finished: Callable = None) -> None: + reply = self._manager.get(self._createEmptyRequest('/set?cmd={P:R}')) + self._addCallback(reply, on_finished) + + def pausePrint(self, on_finished: Callable = None) -> None: + reply = self._manager.get(self._createEmptyRequest('/set?cmd={P:P}')) + self._addCallback(reply, on_finished) + + def cancelPrint(self, on_finished: Callable = None) -> None: + reply = self._manager.get(self._createEmptyRequest('/set?cmd={P:X}')) + self._addCallback(reply, on_finished) + + def uploadPrint(self, filename: str, payload: bytes, on_finished: Callable, on_progress: Callable) -> None: + http_part = QHttpPart() + http_part.setHeader(QNetworkRequest.ContentDispositionHeader, + 'form-data; name="file"; filename="{}"'.format(filename)) + http_part.setHeader(QNetworkRequest.ContentTypeHeader, 'application/octet-stream') + http_part.setBody(payload) + + http_multi_part = QHttpMultiPart(QHttpMultiPart.FormDataType) + http_multi_part.append(http_part) + + request = self._createEmptyRequest('/upload') + # Must encode bytes boundary into string! + request.setHeader(QNetworkRequest.ContentTypeHeader, + 'multipart/form-data; boundary=%s' % str(http_multi_part.boundary(), 'utf-8')) + + reply = self._manager.post(request, http_multi_part) + self._addCallback(reply, on_finished) + self._anti_gc_callbacks.append(on_progress) + reply.uploadProgress.connect(on_progress) + self._cached_multiparts[reply] = http_multi_part # prevent HTTP multi-part to be garbage-collected. + self._upload_reply = reply # cache to cancel + + def cancelUploadPrint(self) -> None: + Logger.log('d', 'Cancelling upload request.') + if self._upload_reply: + self._upload_reply.abort() + + def _handleOnFinished(self, reply: QNetworkReply) -> None: + # Due to garbage collection, we need to cache certain bits of post operations. + # As we don't want to keep them around forever, delete them if we get a reply. + if reply.operation() == QNetworkAccessManager.PostOperation: + self._clearCachedMultiPart(reply) + + def _clearCachedMultiPart(self, reply: QNetworkReply) -> None: + if reply in self._cached_multiparts: + del self._cached_multiparts[reply] + + def _createEmptyRequest(self, path: str) -> QNetworkRequest: + url = QUrl('http://' + self._address + path) + Logger.log('d', url.toString()) + request = QNetworkRequest(url) + request.setAttribute(QNetworkRequest.FollowRedirectsAttribute, True) + return request + + @staticmethod + def _parseReply(reply: QNetworkReply) -> Tuple[int, str]: + status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) + try: + response = bytes(reply.readAll()).decode() + return status_code, response + except (UnicodeDecodeError, ValueError) as err: + Logger.logException('e', 'Could not parse the printer response: %s', err) + return status_code, err + + def _addCallback(self, reply: QNetworkReply, on_finished: Callable) -> None: + def parse() -> None: + self._anti_gc_callbacks.remove(parse) + self._upload_reply = None + + if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) is None or reply.error() > 0: + Logger.log('e', 'No response received from printer.') + return + + status_code, raw_response = self._parseReply(reply) + on_finished(raw_response) + + self._anti_gc_callbacks.append(parse) + reply.finished.connect(parse) diff --git a/src/Network/DeviceManager.py b/src/Network/DeviceManager.py new file mode 100644 index 0000000..5e4220f --- /dev/null +++ b/src/Network/DeviceManager.py @@ -0,0 +1,233 @@ +# Copyright 2020 Luc Rubio +# Plugin is licensed under the GNU Lesser General Public License v3.0. +from typing import Optional, Callable, List + +from PyQt5.QtCore import pyqtSignal, QObject + +from UM import i18nCatalog +from UM.Logger import Logger +from UM.Settings.ContainerRegistry import ContainerRegistry +from UM.Signal import Signal + +from cura.CuraApplication import CuraApplication +from cura.PrinterOutput.PrinterOutputDevice import ConnectionType +from cura.Settings.CuraStackBuilder import CuraStackBuilder +from cura.Settings.GlobalStack import GlobalStack + +from .ApiClient import ApiClient +from .PrinterHeartbeat import PrinterHeartbeat +from ..MPSM2NetworkedPrinterOutputDevice import MPSM2NetworkedPrinterOutputDevice + + +class DeviceManager(QObject): + META_NETWORK_KEY = 'mpsm2_network_key' + MANUAL_DEVICES_PREFERENCE_KEY = 'mpsm2networkprinting/manual_instances' + I18N_CATALOG = i18nCatalog('cura') + + discoveredDevicesChanged = Signal() + manualAddressChanged = pyqtSignal(str) + onPrinterUpload = pyqtSignal(bool) + + MPSM2_PROPERTIES = { + b'name': b'Monoprice Select Mini V2', + b'machine': b'Malyan M200', + b'manual': b'true', + b'printer_type': b'monoprice_select_mini_v2', + b'firmware_version': b'Unknown', + } + + def __init__(self) -> None: + super().__init__() + self._discovered_devices = {} + self._machines = {} + self._output_device_manager = CuraApplication.getInstance().getOutputDeviceManager() + + self.heartbeatThread = PrinterHeartbeat() + self.manualAddressChanged.connect(self.heartbeatThread.setPrinterIpAddress) + self.onPrinterUpload.connect(self.heartbeatThread.handlePrinterBusy) + self.heartbeatThread.heartbeatSignal.connect(self._onPrinterHeartbeat) + ContainerRegistry.getInstance().containerRemoved.connect(self._onPrinterContainerRemoved) + + def start(self) -> None: + Logger.log('d', 'Starting Device Manager.') + for address in self._getStoredManualAddresses(): + self.addManualDevice(address) + self.manualAddressChanged.emit(address) + + def stop(self) -> None: + Logger.log('d', 'Stopping Device Manager.') + for instance_name in list(self._discovered_devices): + self._onDiscoveredDeviceRemoved(instance_name) + + def startDiscovery(self) -> None: + self.stop() + self.start() + + def addManualDevice(self, address: str, callback: Optional[Callable[[bool, str], None]] = None) -> None: + Logger.log('d', 'Adding manual device with address: %s', address) + api_client = ApiClient(address, lambda error: Logger.log('e', str(error))) + api_client.getPrinterStatus(lambda response: self._onPrinterStatusResponse(response, address, callback)) + + def removeManualDevice(self, device_id: str, address: Optional[str] = None) -> None: + Logger.log('d', 'Removing manual device with device_id: %s and address: %s', device_id, address) + if device_id not in self._discovered_devices and address is not None: + device_id = DeviceManager._getDeviceId(address) + + if device_id in self._discovered_devices: + address = address or self._discovered_devices[device_id].ipAddress + self._onDiscoveredDeviceRemoved(device_id) + + if address in self._getStoredManualAddresses(): + self._removeStoredManualAddress(address) + + if self.heartbeatThread.isRunning(): + self.heartbeatThread.exit() + + self._machines = {} + + def refreshConnections(self) -> None: + Logger.log('d', 'Refreshing connections.') + self._connectToActiveMachine() + + def _onPrinterContainerRemoved(self, container) -> None: + if container.getName() == DeviceManager.MPSM2_PROPERTIES[b'name'].decode('utf-8'): + device_ids = set(self._discovered_devices.keys()) + # FIXME: this is a simplification. + for device_id in device_ids: + self.removeManualDevice(device_id) + + def _connectToActiveMachine(self) -> None: + Logger.log('d', 'Connecting to active machine.') + active_machine = CuraApplication.getInstance().getGlobalContainerStack() + if not active_machine: + return + + if not self.heartbeatThread.isRunning(): + self.heartbeatThread.start() + output_device_manager = CuraApplication.getInstance().getOutputDeviceManager() + stored_device_id = active_machine.getMetaDataEntry(self.META_NETWORK_KEY) + for device in self._discovered_devices.values(): + if device.key == stored_device_id: + self._connectToOutputDevice(device, active_machine) + elif device.key in output_device_manager.getOutputDeviceIds(): + output_device_manager.removeOutputDevice(device.key) + + def _onPrinterStatusResponse(self, response, address: str, + callback: Optional[Callable[[bool, str], None]] = None) -> None: + if response is None and callback is not None: + CuraApplication.getInstance().callLater(callback, False, address) + return + + Logger.log('d', 'Received response from printer on address %s: %s.', address, response) + properties = DeviceManager.MPSM2_PROPERTIES.copy() + properties[b'address'] = address.encode('utf-8') + device = MPSM2NetworkedPrinterOutputDevice(DeviceManager._getDeviceId(address), address, properties, + ConnectionType.NetworkConnection) + device.onPrinterUpload.connect(self.onPrinterUpload) + device.updatePrinterStatus(response) + device.printerStatusChanged.emit() + + discovered_printers_model = CuraApplication.getInstance().getDiscoveredPrintersModel() + discovered_printers_model.addDiscoveredPrinter( + ip_address=address, + key=device.getId(), + name=device.getName(), + create_callback=self._createMachineFromDiscoveredDevice, + machine_type=device.printerType, + device=device) + + self._discovered_devices[device.getId()] = device + self.discoveredDevicesChanged.emit() + self._connectToActiveMachine() + self._storeManualAddress(address) + self.manualAddressChanged.emit(address) + if callback is not None: + CuraApplication.getInstance().callLater(callback, True, address) + + def _onDiscoveredDeviceRemoved(self, device_id: str) -> None: + Logger.log('d', 'Removing discovered device with device_id: %s', device_id) + device = self._discovered_devices.pop(device_id, None) + if not device: + return + device.close() + CuraApplication.getInstance().getDiscoveredPrintersModel().removeDiscoveredPrinter(device.address) + self.discoveredDevicesChanged.emit() + + def _createMachineFromDiscoveredDevice(self, device_id: str) -> None: + Logger.log('d', 'Creating machine.') + device = self._discovered_devices.get(device_id) + if device is None: + return + + if self._machines.get(device_id) is None: + new_machine = CuraStackBuilder.createMachine(device.name, device.printerType) + if not new_machine: + Logger.log('e', 'Failed to create a new machine') + return + new_machine.setMetaDataEntry(self.META_NETWORK_KEY, device.key) + CuraApplication.getInstance().getMachineManager().setActiveMachine(new_machine.getId()) + self._connectToOutputDevice(device, new_machine) + if not self.heartbeatThread.isRunning(): + self.heartbeatThread.start() + self._machines[device_id] = new_machine + + def _storeManualAddress(self, address: str) -> None: + Logger.log('d', 'Storing address %s in user preferences', address) + stored_addresses = self._getStoredManualAddresses() + if address in stored_addresses: + return # Prevent duplicates. + if len(stored_addresses) == 1 and not stored_addresses[0]: + new_value = address + else: + stored_addresses.append(address) + new_value = ','.join(stored_addresses) + CuraApplication.getInstance().getPreferences().setValue(self.MANUAL_DEVICES_PREFERENCE_KEY, new_value) + + def _removeStoredManualAddress(self, address: str) -> None: + Logger.log('d', 'Removing address %s from user preferences.', address) + stored_addresses = self._getStoredManualAddresses() + try: + stored_addresses.remove(address) # Can throw a ValueError + new_value = ','.join(stored_addresses) + CuraApplication.getInstance().getPreferences().setValue(self.MANUAL_DEVICES_PREFERENCE_KEY, new_value) + except ValueError: + Logger.log('w', 'Could not remove address from stored_addresses, it was not there') + + def _getStoredManualAddresses(self) -> List[str]: + preferences = CuraApplication.getInstance().getPreferences() + preferences.addPreference(self.MANUAL_DEVICES_PREFERENCE_KEY, '') + manual_instances = preferences.getValue(self.MANUAL_DEVICES_PREFERENCE_KEY).split(',') + return manual_instances + + def _connectToOutputDevice(self, device: MPSM2NetworkedPrinterOutputDevice, machine: GlobalStack) -> None: + Logger.log('d', 'Connecting to Output Device with key: %s.', device.key) + machine.setName(device.name) + machine.setMetaDataEntry(self.META_NETWORK_KEY, device.key) + machine.setMetaDataEntry('group_name', device.name) + machine.addConfiguredConnectionType(device.connectionType.value) + + if not device.isConnected(): + device.connect() + + output_device_manager = CuraApplication.getInstance().getOutputDeviceManager() + if device.key not in output_device_manager.getOutputDeviceIds(): + output_device_manager.addOutputDevice(device) + + def _isDiscovered(self, address: str) -> MPSM2NetworkedPrinterOutputDevice: + return self._discovered_devices.get(DeviceManager._getDeviceId(address)) + + def _onPrinterHeartbeat(self, address: str, raw_response: str) -> None: + device = self._discovered_devices.get(DeviceManager._getDeviceId(address)) + if device and raw_response == 'timeout': + if not device.isBusy(): + self.stop() + return + if not device: + self.start() + else: + device.updatePrinterStatus(raw_response) + device.printerStatusChanged.emit() + + @staticmethod + def _getDeviceId(address: str) -> str: + return 'manual:{}'.format(address) diff --git a/src/Network/PrinterHeartbeat.py b/src/Network/PrinterHeartbeat.py new file mode 100644 index 0000000..09e994c --- /dev/null +++ b/src/Network/PrinterHeartbeat.py @@ -0,0 +1,44 @@ +# Copyright 2020 Luc Rubio +# Plugin is licensed under the GNU Lesser General Public License v3.0. +import time +from http.client import HTTPConnection + +from PyQt5.QtCore import QThread, pyqtSignal + + +# Background thread that polls printer status. Status contains printer state, temperatures and printing progress. +class PrinterHeartbeat(QThread): + REQUEST_TIMEOUT_SECS = 2 + POLL_INTERVAL_SECS = 5 + heartbeatSignal = pyqtSignal(str, str) # address, raw response + onPrinterUpload = pyqtSignal(bool) + + def __init__(self, parent=None) -> None: + QThread.__init__(self, parent) + self._printer_ip_address = None + self.is_running = True + + def setPrinterIpAddress(self, printer_ip_address) -> None: + self._printer_ip_address = printer_ip_address + + def handlePrinterBusy(self, is_uploading: bool) -> None: + self.is_running = not is_uploading + + # Override + def run(self) -> None: + while True: + if self.is_running: + self._inquiry() + time.sleep(PrinterHeartbeat.POLL_INTERVAL_SECS) + + def _inquiry(self) -> None: + if self._printer_ip_address: + connection = HTTPConnection(self._printer_ip_address, timeout=PrinterHeartbeat.REQUEST_TIMEOUT_SECS) + try: + connection.request('GET', '/inquiry') + response = connection.getresponse() + self.heartbeatSignal.emit(self._printer_ip_address, response.read().decode('utf-8')) + except Exception: + self.heartbeatSignal.emit(self._printer_ip_address, 'timeout') + finally: + connection.close() diff --git a/src/Network/__init__.py b/src/Network/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/Parser/MPSM2PrinterStatusParser.py b/src/Parser/MPSM2PrinterStatusParser.py new file mode 100644 index 0000000..daacd4c --- /dev/null +++ b/src/Parser/MPSM2PrinterStatusParser.py @@ -0,0 +1,27 @@ +# Copyright 2020 Luc Rubio +# Plugin is licensed under the GNU Lesser General Public License v3.0. +import re +from typing import Optional + +from UM.Logger import Logger +from ..Models.MPSM2PrinterStatusModel import MPSM2PrinterStatusModel + + +class MPSM2PrinterStatusParser: + @staticmethod + def parse(raw_response: str) -> Optional[MPSM2PrinterStatusModel]: + matches = re.match(r"^T(\d+)/(\d+)P(\d+)/(\d+)/(\d+)([IP])$", raw_response) + if matches is None: + return None + state = matches.group(6) + return MPSM2PrinterStatusModel( + int(matches.group(1)), + int(matches.group(2)), + int(matches.group(3)), + int(matches.group(4)), + int(matches.group(5)), + MPSM2PrinterStatusModel.State.IDLE if state == 'I' + else + MPSM2PrinterStatusModel.State.PRINTING if state == 'P' + else + MPSM2PrinterStatusModel.State.UNKNOWN) diff --git a/src/Parser/__init__.py b/src/Parser/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..e69de29