New time estimate hooks (python questions)

I'm having some startup issues with these (mostly 'cause I'm not python dev) so if some help can be offered I'd be grateful :slight_smile:

your example is

from octoprint.printer.estimation import PrintTimeEstimator

class CustomPrintTimeEstimator(PrintTimeEstimator):
    def __init__(self, job_type):
        pass

    def estimate(self, progress, printTime, cleanedPrintTime, statisticalTotalPrintTime, statisticalTotalPrintTimeType):
        # always reports 2h as printTimeLeft
        return 2 * 60 * 60, "estimate"

def create_estimator_factory(*args, **kwargs):
    return CustomPrintTimeEstimator

__plugin_hooks__ = {
  "octoprint.printer.estimation.factory": create_estimator_factory
}

now, you write that this will be called with job_type parameter ... what if I only want to implement for local and don't care about sdcard? any chance I can do something like "if sdcard use the default estimator" here ?!

I think I'm ok with everything else, just need to solve the "sdcard" issue :slight_smile:

In that case try something like this:

from octoprint.printer.estimation import PrintTimeEstimator

class CustomPrintTimeEstimator(PrintTimeEstimator):
    def __init__(self, job_type):
        PrintTimeEstimator.__init__(self, job_type)
        self._job_type = job_type

    def estimate(self, progress, printTime, cleanedPrintTime, statisticalTotalPrintTime, statisticalTotalPrintTimeType):
        if self._job_type != "local":
            # no local print? use the default implementation
            PrintTimeEstimator.estimate(self, progress, printTime, cleanedPrintTime, statisticalTotalPrintTime, statisticalTotalPrintTimeType)

        # your implementation for local files goes here

def create_estimator_factory(*args, **kwargs):
    return CustomPrintTimeEstimator

__plugin_hooks__ = {
  "octoprint.printer.estimation.factory": create_estimator_factory
}
1 Like

I'm having issues - this does not work on maintainance branch ?!

2018-05-23 05:57:55,456 - octoprint.plugin.core - ERROR - Error loading plugin gcodestatEstimator
Traceback (most recent call last):
  File "/home/pi/OctoPrint/venv/local/lib/python2.7/site-packages/OctoPrint-1.3.9.dev181_g8a1db8e4-py2.7.egg/octoprint/plugin/core.py", line 828, in _import_plugin
    instance = imp.load_module(key, f, filename, description)
  File "/home/pi/OctoPrint/venv/local/lib/python2.7/site-packages/octoprint_gcodestatEstimator/__init__.py", line 6, in <module>
    from octoprint.printer.estimation import PrintTimeEstimator
ImportError: cannot import name PrintTimeEstimator

I have no idea what's up there, but over here this works just fine on the maintenance branch:

$ python
Python 2.7.14 (v2.7.14:84471935ed, Sep 16 2017, 20:19:30) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from octoprint import __version__
>>> __version__
u'1.3.9.dev181+g8a1db8e4'
>>> from octoprint.printer.estimation import PrintTimeEstimator
>>> PrintTimeEstimator
<class 'octoprint.printer.estimation.PrintTimeEstimator'>

Also tested with a copy of the plugin example, no errors on startup, everything works as expected.

This is on a fresh checkout of the maintenance branch at commit 8a1db8e4c, in a fresh virtual environment.

Did you maybe forget a python setup.py clean before the pip install . (or python setup.py install) after the branch switch? I remember old pyc files occasionally being the source of such problems.

will do it from scratch, no idea what's wrong with it.... this sample also works for me too ..

pi@orangepione:~/OctoPrint$ venv/bin/python
Python 2.7.9 (default, Aug 13 2016, 17:56:53)
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from octoprint import __version__
>>> __version__
u'1.3.9.dev181+g8a1db8e4'
>>> from octoprint.printer.estimation import PrintTimeEstimator
>>> PrintTimeEstimator
<class 'octoprint.printer.estimation.PrintTimeEstimator'>
>>>

but the plugin fails .. hm .. I made something wrong for sure, will restart, thanks

I managed to make it work, the local prints with M117 codes now work awesome, the ones without M117 work using original estimator :slight_smile: so that's done too ... testing right now the sdcard but I don't see why that won't work too ... so I'm more less happy with how this works ... found out some interesting python concepts on the way (still not liking it) ..

now.. I have two other questions ... the estimator() function returns 2 values, integer and string .. the integer is time in seconds I figured out and second parameter, string, is "estimate" from your example ... now I know (because original estimator is doing this) you can return
"still stabilizing" info but I don't know how, also is there a way estimator can return the % done (or % to go) ? as currently % shown is % of bytes in a file being printed ... it's not a big deal really that % is pretty accurate and with accurate time shown it works great but since I already have that info I might as well push it trough if there's something that will catch it :smiley:

thanks for help!!!!11 :smiley:
b.

looking at source of the original function, here

I'm confused... when I was returning None, None from the plugin the Octoprint behaved very badly - it was printing, log shown it was printing to virtual printer, that status is "printing" but status on web was "operational" and was pretty unresponsive... when I removed the None, None and put maxint, "estimate" it worked ok...

Hm, I cannot reproduce this here:

image

Using this code:

from octoprint.printer.estimation import PrintTimeEstimator

class CustomPrintTimeEstimator(PrintTimeEstimator):
    def __init__(self, job_type):
        pass

    def estimate(self, progress, printTime, cleanedPrintTime, statisticalTotalPrintTime, statisticalTotalPrintTimeType):
        return None, None

def create_estimator_factory(*args, **kwargs):
    return CustomPrintTimeEstimator

__plugin_hooks__ = {
  "octoprint.printer.estimation.factory": create_estimator_factory
}

Returning None will cause it to say "still stabilizing".

Origin of estimate can be either estimate (so, calculated based on progress, elapsed time and estimated total print time, green bubble), linear (only based on progress and elapsed time, the "dumb" linear extrapolation, red bubble), mixed-analysis and mixed-average (based on a mixture of progress, elapsed time and estimated total print time mixed together with where it should be based on progress and total print time from analysis or past prints, ratio based on progress - the farther into the print, the more the actual live estimate gets used). In plugins you probably only ever want to return estimate here.

No. The estimator currently works as a "progress in, estimate out" kinda deal.

1 Like

hm, I'm not reproducing it now so it was most probably something else that was doing that was causing octoprint to fail to behave normally. Anyhow I'm now returning original estimator in those cases where I used to send None, None and that solved all my problems :smiley:

all clear, yes, it only makes sense to send "estimate" from my plugin

makes sense :slight_smile:

thanks!!!

now one more question, this works as is and I was not able to crash it or get any errors in the log but this part of the plugin is made by "guessing" and not "I know what I'm doing" :smiley: so I need checkup

__plugin_implementation__ = GcodestatPrintTimeEstimator(None)
__plugin_hooks__ = {
  "octoprint.comm.protocol.gcode.queuing": __plugin_implementation__.updateEstimation,
  "octoprint.printer.estimation.factory": create_estimator_factory
}

since I'm both monitoring g-code (to catch m117) and implementing estimator I need the "octoprint.comm.protocol.gcode.queuing" but the value is unclear to me as I'm creating plugin_implementation as GcodestatPrintTimeEstimator(None) ... the issue is (None) .. I assume self is already a default first parameter and the second parameter when creating this should be job_type but I don't have job_type at this moment, it happens later... so since I'm not sure if there will be to objects created now or only one I made sure my 2 variables I use for estimation are static so if I have 2 objects they share the same value but the question is "is this a proper way to handle this" or I should of done it differently... as I said, it works! but is it a proper way to do it I have no clue :smiley:

p.s. I'd appreciate if anyone who really knows python just take a quick look at


or more precise
https://github.com/arhi/OctoPrint-gcodestatEstimator/blob/master/octoprint_gcodestatEstimator/init.py

I don't want to burden this forum with my fight with python but I'd appreciate any pointers if I made something very stupid there syntax wise :smiley: