What is the problem?
I wrote a script that monitors the connection status of my printer, then tries to connect to it when it is not connected. The flow is basically: use the api/connection API to get the connection status. If it is closed initiate a connection, then sleep for 30 seconds. Once the printer is connected, the script then queries every 30 seconds for the print status using the api/printer API. If there is a print, it writes to a file. That file is checked in the connection process and no connection is attempted if the printer lost connection while printing.
Should this use case work with the current rest api or is it too taxing? Should I file a bug?
Here is the info from octoprint.log
2018-05-27 05:27:46,923 - tornado.access - ERROR - 500 POST /api/connection (127.0.0.1) 395.82ms
2018-05-27 05:28:00,929 - octoprint.util.comm - INFO - Changing monitoring state from "Connecting" to "Offline"
2018-05-27 05:28:03,188 - octoprint - ERROR - Exception on /api/connection [POST]
Traceback (most recent call last):
File "/home/pi/oprint/local/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "/home/pi/oprint/local/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/pi/oprint/local/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/home/pi/oprint/local/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/home/pi/oprint/local/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
return self.view_functionsrule.endpoint
File "/home/pi/oprint/local/lib/python2.7/site-packages/octoprint/server/util/flask.py", line 1132, in decorated_view
return flask_login.login_required(func)(*args, **kwargs)
File "/home/pi/oprint/local/lib/python2.7/site-packages/flask_login.py", line 758, in decorated_view
return func(*args, **kwargs)
File "/home/pi/oprint/local/lib/python2.7/site-packages/octoprint/server/api/connection.py", line 67, in connectionCommand
printer.connect(port=port, baudrate=baudrate, profile=printerProfile)
File "/home/pi/oprint/local/lib/python2.7/site-packages/octoprint/printer/standard.py", line 226, in connect
self._comm = comm.MachineCom(port, baudrate, callbackObject=self, printerProfileManager=self._printerProfileManager)
File "/home/pi/oprint/local/lib/python2.7/site-packages/octoprint/util/comm.py", line 587, in init
self.sending_thread.start()
File "/usr/lib/python2.7/threading.py", line 736, in start
_start_new_thread(self.__bootstrap, ())
error: can't start new thread
2018-05-27 05:28:03,256 - tornado.access - ERROR - 500 POST /api/connection (127.0.0.1) 633.30ms
2018-05-27 05:28:03,263 - octoprint.util.comm - INFO - Changing monitoring state from "Offline" to "Opening serial port"
2018-05-27 05:28:03,297 - octoprint.util.comm - INFO - Changing monitoring state from "Opening serial port" to "Connecting"
2018-05-27 05:28:19,378 - octoprint - ERROR - Exception on /api/connection [POST]
Traceback (most recent call last):
File "/home/pi/oprint/local/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "/home/pi/oprint/local/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/pi/oprint/local/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
r
eraise(exc_type, exc_value, tb)
File "/home/pi/oprint/local/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/home/pi/oprint/local/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
return self.view_functionsrule.endpoint
File "/home/pi/oprint/local/lib/python2.7/site-packages/octoprint/server/util/flask.py", line 1132, in decorated_view
return flask_login.login_required(func)(*args, **kwargs)
File "/home/pi/oprint/local/lib/python2.7/site-packages/flask_login.py", line 758, in decorated_view
return func(*args, **kwargs)
File "/home/pi/oprint/local/lib/python2.7/site-packages/octoprint/server/api/connection.py", line 67, in connectionCommand
printer.connect(port=port, baudrate=baudrate, profile=printerProfile)
File "/home/pi/oprint/local/lib/python2.7/site-packages/octoprint/printer/standard.py", line 226, in connect
self._comm = comm.MachineCom(port, baudrate, callbackObject=self, printerProfileManager=self._printerProfileManager)
File "/home/pi/oprint/local/lib/python2.7/site-packages/octoprint/util/comm.py", line 581, in init
self.monitoring_thread.start()
File "/usr/lib/python2.7/threading.py", line 736, in start
_start_new_thread(self.__bootstrap, ())
error: can't start new thread
2018-05-27 05:28:19,402 - tornado.access - ERROR - 500 POST /api/connection (127.0.0.1) 439.98ms
What did you already try to solve it?
I tried increasing the sleep time to 1 minute but still got the same error.
Additional information about your setup (OctoPrint version, OctoPi version, printer, firmware, octoprint.log
, serial.log
or output on terminal tab, ...)
I only ever print from SD and this script is to prevent me from logging into a computer to connect to octoprint when I turn on my printer. PortLister did not work for me and I can't use udev to check if the printer is on because my printer appears the same when powered on or off.
My printer is a Prusa MK3 running fimrware 3.2.1
Here is info on octoprint version and plugins:
2018-05-26 20:53:59,671 - octoprint.server - INFO - --- Log roll over detected ---------------------------------------------------
2018-05-26 20:53:59,675 - octoprint.server - INFO - OctoPrint 1.3.8
2018-05-26 20:53:59,693 - octoprint.plugin.core - INFO - 22 plugin(s) registered with the system:
| Announcement Plugin (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/announcements
| Autoscroll (0.0.2) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_autoscroll
| Core Wizard (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/corewizard
| CuraEngine (<= 15.04) (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/cura
| Detailed Progress Plugin (0.1.4) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_detailedprogress
| Discovery (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/discovery
| DisplayZ (0.1.0) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_displayz
| Firmware Updater (1.0.0) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_firmwareupdater
| Fullscreen Plugin (0.0.4) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_fullscreen
| Gcodebar Plugin (0.1.4) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_GCodeBar
| HeaterTimeout (0.0.1) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_HeaterTimeout
| Logging (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/logging
| Navbar Temperature Plugin (0.9) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_navbartemp
| OctoPi Support Plugin (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/octopi_support
| Plugin Manager (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/pluginmanager
| PortLister (0.1.7) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_portlister
| Printer Safety Check (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/printer_safety_check
| Prusa Mesh Leveling (0.2.1) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_PrusaMeshMap
| Software Update (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/softwareupdate
| Telegram Notifications (1.4.2) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_telegram
| !TouchUI (0.3.11) = /home/pi/oprint/local/lib/python2.7/site-packages/octoprint_touchui
| Virtual Printer (bundled) = /home/pi/oprint/lib/python2.7/site-packages/octoprint/plugins/virtual_printer
2018-05-26 20:53:59,801 - octoprint.environment - INFO - Detected environment is Python 2.7.13 under Linux (linux2). Details:
| hardware:
| cores: 1
| freq: 1000.0
| ram: 388034560
| os:
| id: linux
| platform: linux2
| plugins:
| octopi_support:
| model: Zero W
| revision: 9000c1
| version: 0.15.0
| python:
| pip: 10.0.1
| version: 2.7.13
| virtualenv: /home/pi/oprint
Here is my python script that I run as a service:
#!/usr/bin/env python
import requests
import sys
import time
import json
import os
import subprocess
import datetime
LogLevel = 0
PrintLevel = 1
LOG_LEVEL_ERROR = 0
LOG_LEVEL_TRACE = 1
def Log(log, message, level):
if(level <= PrintLevel):
print(message + '\n')
if(level <= LogLevel):
logEntry = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + ' - ' + message + '\n'
log.write(logEntry)
#end Log
def CheckPrinting(printerApiUrl, headers, tempDetectEnabled, tempThreshExtruder, tempThreshBed, log, lockPath):
isPrinting = False
r = requests.get(
printerApiUrl,
headers=headers
)
Log(log, ('Check Printing status code (%s)' % r.status_code), LOG_LEVEL_TRACE)
if(r.status_code == 200):
forcePrinting = False
try:
jsonOut = r.json()
printing = jsonOut['state']['flags']['printing']
paused = jsonOut['state']['flags']['paused']
extruderTarget = jsonOut['temperature']['tool0']['target']
bedTarget = jsonOut['temperature']['bed']['target']
extruderTemp = jsonOut['temperature']['tool0']['actual']
bedTemp = jsonOut['temperature']['bed']['actual']
Log(log, ('printing(%s) paused(%s) extruder(cur %s/tgt %s/thresh %s) bedTarget(cur %s/tgt %s/thresh %s)\n' % (printing,paused,extruderTemp,extruderTarget,tempThreshExtruder,bedTemp,bedTarget,tempThreshBed)), LOG_LEVEL_TRACE)
except:
#assume we are printing if we can't read the print status to be safe
Log(log,("Error reading print status - %s"), LOG_LEVEL_ERROR)
forcePrinting = True
#we write this to a file so if we crash or restart during a print, we will know we used to be printing, will require a manual reconnect in these cases
f = open(lockPath,"w")
doLock = False
if(printing == True or paused == True or extruderTarget > 0 or bedTarget > 0 or forcePrinting == True):
doLock = True
else:
if(tempDetectEnabled):
if(extruderTemp > tempThreshExtruder or bedTemp > tempThreshBed):
doLock = True
if(doLock == True):
isPrinting = True
f.write('printing')
f.close()
#os.chmod(lockFile, stat.S_IREAD | stat.S_IWRITE | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH | stat.S_IWOTH)
else:
Log(log, ('Failed to get print status (%d)\n' % r.status_code), LOG_LEVEL_ERROR)
if(isPrinting):
Log(log, ('Printing'), LOG_LEVEL_TRACE)
else:
Log(log, ('Not Printing'), LOG_LEVEL_TRACE)
return isPrinting
#end CheckPrinting()
#Main()
LOCK_FILENAME = '.printlock'
lockPath = sys.path[0] + '/' + LOCK_FILENAME
LOG_FILENAME = 'oprintmon.log'
logPath = sys.path[0] + '/' + LOG_FILENAME
CONFIG_FILENAME = 'oprintmon.config'
configPath = sys.path[0] + '/' + CONFIG_FILENAME
log = open(logPath, "w+")
Log(log, ('oprintmon start'), LOG_LEVEL_ERROR)
if(os.path.isfile(configPath) == False):
Log(log, ('Failed to load config (%s) - exiting' % configPath), LOG_LEVEL_ERROR)
sys.exit(1)
configFile = open(configPath, "r")
try:
configJson = json.load(configFile)
except:
Log(log, ('Failed to read % - exiting' % configPath), LOG_LEVEL_ERROR)
configFile.close()
sys.exit(1)
octopiConfig = configJson['config']['octopi']
apiKey = octopiConfig['api-key']
baseUrl = octopiConfig['url-base']
port = octopiConfig['serial-port']
try:
baudRate = int(octopiConfig['baud'])
except:
Log(log, ('baudRate must be a number - exiting'), LOG_LEVEL_ERROR)
sys.exit(1)
configConnect = configJson['config']['connect']
try:
sleepTimeConnecting = float(configConnect['sleep-time'])
except:
Log(log, ('sleep-time must be a number - exiting'), LOG_LEVEL_ERROR)
sys.exit(1)
printmonConfig = configJson['config']['printmon']
tempDetectEnabled = printmonConfig['detection-enabled'] == "true"
if(tempDetectEnabled) :
try:
tempThreshBed = int(printmonConfig['thresh-bed'])
tempThreshExtruder = int(printmonConfig['thresh-hotend'])
except:
Log(log, ('temp thresholds must be numbers - exiting'), LOG_LEVEL_ERROR)
sys.exit(1)
try:
sleepTimePrinting = float(printmonConfig['sleep-time'])
except:
Log(log, ('sleep-time must be a number - exiting'), LOG_LEVEL_ERROR)
sys.exit(1)
Log(log, ('api-key (%s), base_url(%s), baud (%s), port (%s), sleeptime(connect) (%s), sleeptime(print) (%s) tempDetect(%s), bedThresh(%s), extruderThresh(%s)' % (apiKey, baseUrl, baudRate, port, sleepTimeConnecting, sleepTimePrinting, tempDetectEnabled, tempThreshBed, tempThreshExtruder)), LOG_LEVEL_TRACE)
headers = {'X-Api-Key': apiKey}
connectionApiURL = baseUrl + 'api/connection'
printerApiUrl = baseUrl + 'api/printer'
isPrinting = False
log.flush()
isConnected = False
while(1):
connectionState = 'Invalid'
wasConnected = isConnected
wasPrinting = isPrinting
status_code = 0
sleepTime = sleepTimeConnecting
if(os.path.isfile(lockPath)):
f = open(lockPath, "r")
lockResult = f.read()
isPrinting = lockResult == 'printing'
Log(log, ('Read (%s) isPrinting = %s' % (lockResult, isPrinting)), LOG_LEVEL_TRACE)
f.close()
try:
Log(log, ('%s\n%s' % (connectionApiURL, headers)), LOG_LEVEL_TRACE)
r = requests.get(connectionApiURL, headers=headers)
except:
Log(log, ("failed to send request, server may not be up yet\n"), LOG_LEVEL_ERROR)
status_code = -1
if(status_code != -1):
status_code = r.status_code
#received valid connection info
if(status_code == 200):
jsonOut = r.json()
#get connection state
connectionState = jsonOut['current']['state']
currentPort = jsonOut['current']['port']
Log(log,('State = %s Port = %s' % (connectionState, currentPort)), LOG_LEVEL_TRACE)
connecting = False
#if we are not connected and not printing, try to connect
if(not isPrinting):
if(connectionState == 'Closed'):
connecting = True
json = {
"command": "connect",
"port": port,
"baudrate": baudRate,
}
Log(log, ("Connecting to url %s on port %s with baud rate %s\n" % (connectionApiURL, port, baudRate)), LOG_LEVEL_TRACE)
r = requests.post(
connectionApiURL,
json=json,
headers=headers
)
if(r.status_code == 204):
Log(log, ("Connect Request Successful\n"), LOG_LEVEL_TRACE)
else:
Log(log, ("Connect Request Failed (%d)\n" % r.status_code), LOG_LEVEL_ERROR)
else:
sleepTime = sleepTimePrinting
if(not connecting):
sleepTime = sleepTimePrinting
if(connectionState != 'Closed' and connectionState != 'Connecting' and connectionState != 'Disconnecting'):
isPrinting = CheckPrinting(printerApiUrl, headers, tempDetectEnabled, tempThreshExtruder, tempThreshBed, log, lockPath)
if(connectionState != 'Closed'):
isConnected = True
if(not wasConnected):
Log(log, 'Connected to Server', LOG_LEVEL_ERROR)
else:
isConnected = False
if(wasConnected):
Log(log, 'Disconnected from Server', LOG_LEVEL_ERROR)
if(wasPrinting != isPrinting):
if(isPrinting):
Log(log, 'Started Printing', LOG_LEVEL_ERROR)
else:
Log(log, 'FinishedPrinting', LOG_LEVEL_ERROR)
Log(log, ('Sleeping for %s seconds' % sleepTime), LOG_LEVEL_TRACE)
log.flush()
time.sleep(sleepTime)
#end Main