# Buggy code
def _estimatePrintTimeLeft(
    self,
    progress,
    printTime,
    cleanedPrintTime,
    statisticalTotalPrintTime,
    statisticalTotalPrintTimeType,
):
    """
    Tries to estimate the print time left for the print job

    This is somewhat horrible since accurate print time estimation is pretty much impossible to
    achieve, considering that we basically have only two data points (current progress in file and
    time needed for that so far - former prints or a file analysis might not have happened or simply
    be completely impossible e.g. if the file is stored on the printer's SD card) and
    hence can only do a linear estimation of a completely non-linear process. That's a recipe
    for inaccurate predictions right there. Yay.

    Anyhow, here's how this implementation works. This method gets the current progress in the
    printed file (percentage based on bytes read vs total bytes), the print time that elapsed,
    the same print time with the heat up times subtracted (if possible) and if available also
    some statistical total print time (former prints or a result from the GCODE analysis).

      1. First get an "intelligent" estimate based on the :class:`~octoprint.printer.estimation.TimeEstimationHelper`.
         That thing tries to detect if the estimation based on our progress and time needed for that becomes
         stable over time through a rolling window and only returns a result once that appears to be the
         case.
      2. If we have any statistical data (former prints or a result from the GCODE analysis)
         but no intelligent estimate yet, we'll use that for the next step. Otherwise, up to a certain percentage
         in the print we do a percentage based weighing of the statistical data and the intelligent
         estimate - the closer to the beginning of the print, the more precedence for the statistical
         data, the closer to the cut off point, the more precendence for the intelligent estimate. This
         is our preliminary total print time.
      3. If the total print time is set, we do a sanity check for it. Based on the total print time
         estimate and the time we already spent printing, we calculate at what percentage we SHOULD be
         and compare that to the percentage at which we actually ARE. If it's too far off, our total
         can't be trusted and we fall back on the dumb estimate. Same if the time we spent printing is
         already higher than our total estimate.
      4. If we do NOT have a total print time estimate yet but we've been printing for longer than
         a configured amount of minutes or are further in the file than a configured percentage, we
         also use the dumb estimate for now.

    Yes, all this still produces horribly inaccurate results. But we have to do this live during the print and
    hence can't produce to much computational overhead, we do not have any insight into the firmware implementation
    with regards to planner setup and acceleration settings, we might not even have access to the printed file's
    contents and such we need to find something that works "mostly" all of the time without costing too many
    resources. Feel free to propose a better solution within the above limitations (and I mean that, this solution
    here makes me unhappy).

    Args:
        progress (float or None): Current percentage in the printed file
        printTime (float or None): Print time elapsed so far
        cleanedPrintTime (float or None): Print time elapsed minus the time needed for getting up to temperature
            (if detectable).
        statisticalTotalPrintTime (float or None): Total print time of past prints against same printer profile,
            or estimated total print time from GCODE analysis.
        statisticalTotalPrintTimeType (str or None): Type of statistical print time, either "average" (total time
            of former prints) or "analysis"

    Returns:
        (2-tuple) estimated print time left or None if not proper estimate could be made at all, origin of estimation
    """

    if progress is None or printTime is None or cleanedPrintTime is None:
        return None

    dumbTotalPrintTime = printTime / progress
    estimatedTotalPrintTime = self._estimateTotalPrintTime(progress, cleanedPrintTime)
    totalPrintTime = estimatedTotalPrintTime

    printTimeLeftOrigin = "estimate"
    if statisticalTotalPrintTime is not None:
        if estimatedTotalPrintTime is None:
            # no estimate yet, we'll use the statistical total
            totalPrintTime = statisticalTotalPrintTime
            printTimeLeftOrigin = statisticalTotalPrintTimeType

        else:
            if progress < self._timeEstimationStatsWeighingUntil:
                # still inside weighing range, use part stats, part current estimate
                sub_progress = progress * (1 / self._timeEstimationStatsWeighingUntil)
                if sub_progress > 1.0:
                    sub_progress = 1.0
                printTimeLeftOrigin = "mixed-" + statisticalTotalPrintTimeType
            else:
                # use only the current estimate
                sub_progress = 1.0
                printTimeLeftOrigin = "estimate"

            # combine
            totalPrintTime = (
                1.0 - sub_progress
            ) * statisticalTotalPrintTime + sub_progress * estimatedTotalPrintTime

    printTimeLeft = None
    if totalPrintTime is not None:
        # sanity check current total print time estimate
        assumed_progress = cleanedPrintTime / totalPrintTime
        min_progress = progress - self._timeEstimationValidityRange
        max_progress = progress + self._timeEstimationValidityRange

        if (
            min_progress <= assumed_progress <= max_progress
            and totalPrintTime > cleanedPrintTime
        ):
            # appears sane, we'll use it
            printTimeLeft = totalPrintTime - cleanedPrintTime

        else:
            # too far from the actual progress or negative,
            # we use the dumb print time instead
            printTimeLeft = dumbTotalPrintTime - cleanedPrintTime
            printTimeLeftOrigin = "linear"

    elif (
        progress > self._timeEstimationForceDumbFromPercent
        or cleanedPrintTime * 60 >= self._timeEstimationForceDumbAfterMin
    ):
        # more than x% or y min printed and still no real estimate, ok, we'll use the dumb variant :/
        printTimeLeft = dumbTotalPrintTime - cleanedPrintTime
        printTimeLeftOrigin = "linear"

    if printTimeLeft < 0:
        # shouldn't actually happen, but let's make sure
        return None, None

    return printTimeLeft, printTimeLeftOrigin


# Traceback (ValueError)
2016-07-29 19:23:16,406 - octoprint.server.util.sockjs - INFO - New connection from client: 192.168.1.1
2016-07-29 19:23:16,410 - octoprint.server.util.sockjs - WARNING - Could not send message to client 192.168.1.1: 'utf8' codec can't decode byte 0x87 in position 1: invalid start byte
2016-07-29 19:23:16,562 - octoprint.plugins.cura - INFO - Path to CuraEngine has not been configured yet or does not exist (currently set to None), Cura will not be selectable for slicing
2016-07-29 19:23:20,946 - octoprint.plugins.softwareupdate - INFO - Saved version cache to disk
2016-07-29 19:23:21,216 - octoprint.plugins.announcements - INFO - Loaded channel _important from http://octoprint.org/feeds/important.xml in 0.25s
2016-07-29 19:23:53,291 - octoprint.plugins.softwareupdate - INFO - Starting update of gpx to 2.5.4...
2016-07-29 19:24:55,987 - octoprint.plugins.softwareupdate - INFO - Update of gpx to 2.5.4 successful!
2016-07-29 19:24:56,158 - octoprint.plugins.softwareupdate - INFO - Saved version cache to disk
2016-07-29 19:25:37,270 - octoprint.plugins.softwareupdate - INFO - Saved version cache to disk
2016-07-29 19:25:51,977 - octoprint.plugins.GPX - INFO - Open /home/pi/.octoprint/data/GPX/gpx.ini
2016-07-29 19:25:51,979 - octoprint.plugins.GPX - INFO - Write /home/pi/.octoprint/data/GPX/gpx.ini
2016-07-29 19:25:52,196 - octoprint.plugins.cura - INFO - Path to CuraEngine has not been configured yet or does not exist (currently set to None), Cura will not be selectable for slicing
2016-07-29 19:26:29,058 - octoprint.server.util.sockjs - INFO - Client connection closed: 192.168.1.1
2016-07-29 19:26:29,066 - octoprint.server - INFO - Shutting down...
2016-07-29 19:26:29,105 - octoprint.server - INFO - Goodbye!
2016-07-29 19:26:44,742 - octoprint.server - INFO - Starting OctoPrint 1.2.13 (master branch)
2016-07-29 19:26:44,790 - octoprint.plugin.core - INFO - Loading plugins from /home/pi/.octoprint/plugins, /home/pi/OctoPrint/venv/lib/python2.7/site-packages/OctoPrint-1.2.13-py2.7.egg/octoprint/plugins and installed plugin packages...
2016-07-29 19:26:45,582 - octoprint.plugins.discovery - INFO - pybonjour is not installed, Zeroconf Discovery won't be available
2016-07-29 19:26:45,583 - octoprint.plugin.core - INFO - Found 14 plugin(s) providing 14 mixin implementations, 14 hook handlers
2016-07-29 19:26:45,588 - octoprint.filemanager.storage - INFO - Initializing the file metadata for /home/pi/.octoprint/uploads...
2016-07-29 19:26:45,687 - octoprint.filemanager.storage - INFO - ... file metadata for /home/pi/.octoprint/uploads initialized successfully.
2016-07-29 19:26:45,777 - octoprint.plugins.softwareupdate - INFO - Loaded version cache from disk
2016-07-29 19:26:47,649 - octoprint.util.pip - INFO - Found pip at /home/pi/OctoPrint/venv/bin/pip, version is 8.1.1
2016-07-29 19:26:47,652 - octoprint.plugin.core - INFO - Initialized 14 plugin implementation(s)
2016-07-29 19:26:47,753 - octoprint.plugin.core - INFO - 14 plugin(s) registered with the system:
|  Announcement Plugin (bundled) = /home/pi/OctoPrint/venv/lib/python2.7/site-packages/OctoPrint-1.2.13-py2.7.egg/octoprint/plugins/announcements
|  BQ Android App Companion (0.1.1) = /home/pi/OctoPrint/venv/local/lib/python2.7/site-packages/octoprint_bqappcompanion
|  CuraEngine (<= 15.04) (bundled) = /home/pi/OctoPrint/venv/lib/python2.7/site-packages/OctoPrint-1.2.13-py2.7.egg/octoprint/plugins/cura
|  Discovery (bundled) = /home/pi/OctoPrint/venv/lib/python2.7/site-packages/OctoPrint-1.2.13-py2.7.egg/octoprint/plugins/discovery
|  DisplayProgress (0.1.1) = /home/pi/OctoPrint/venv/local/lib/python2.7/site-packages/octoprint_displayprogress
|  GPX (2.5.4) = /home/pi/OctoPrint/venv/local/lib/python2.7/site-packages/octoprint_GPX
|  Navbar Temperature Plugin (0.8) = /home/pi/OctoPrint/venv/local/lib/python2.7/site-packages/octoprint_navbartemp
|  Plugin Manager (bundled) = /home/pi/OctoPrint/venv/lib/python2.7/site-packages/OctoPrint-1.2.13-py2.7.egg/octoprint/plugins/pluginmanager
|  PortLister (0.1.5) = /home/pi/OctoPrint/venv/local/lib/python2.7/site-packages/octoprint_portlister
|  Slack (0.2.1) = /home/pi/OctoPrint/venv/local/lib/python2.7/site-packages/octoprint_slack
|  Software Update (bundled) = /home/pi/OctoPrint/venv/lib/python2.7/site-packages/OctoPrint-1.2.13-py2.7.egg/octoprint/plugins/softwareupdate
|  Status Line (0.1.0) = /home/pi/OctoPrint/venv/local/lib/python2.7/site-packages/status_line
|  STL Viewer (0.3.1) = /home/pi/OctoPrint/venv/local/lib/python2.7/site-packages/octoprint_stlviewer
|  Virtual Printer (bundled) = /home/pi/OctoPrint/venv/lib/python2.7/site-packages/OctoPrint-1.2.13-py2.7.egg/octoprint/plugins/virtual_printer
2016-07-29 19:26:47,754 - octoprint.filemanager - INFO - Adding backlog items from all storage types to analysis queue...
2016-07-29 19:26:47,762 - octoprint.filemanager - INFO - Added 0 items from storage type "local" to analysis queue
2016-07-29 19:26:47,944 - octoprint.server - INFO - Reset webasset folder /home/pi/.octoprint/generated/webassets...
2016-07-29 19:26:47,954 - octoprint.server - INFO - Reset webasset folder /home/pi/.octoprint/generated/.webassets-cache...
2016-07-29 19:26:48,362 - octoprint.plugins.GPX - INFO - Connecting through x3g.
2016-07-29 19:26:48,365 - octoprint.plugins.GPX - INFO - GPXPrinter created, port: /dev/ttyACM0, baudrate: 115200
2016-07-29 19:26:50,473 - octoprint.plugins.pluginmanager - INFO - Loaded plugin repository data from http://plugins.octoprint.org/plugins.json
2016-07-29 19:26:50,541 - octoprint.plugins.discovery - INFO - Registered OctoPrint instance on raspberrypi for SSDP
2016-07-29 19:26:50,543 - octoprint.server - INFO - Listening on http://0.0.0.0:5000
2016-07-29 19:26:50,584 - octoprint.plugins.stlviewer - INFO - STL Viewer loaded!
2016-07-29 19:26:50,636 - octoprint.plugins.portlister - INFO - Port Lister () {}
2016-07-29 19:26:50,804 - octoprint.server - INFO - Preemptively caching / for {'query_string': 'en', 'path': '/', 'base_url': 'http://rheyes.co.uk/'}
2016-07-29 19:26:52,403 - octoprint.plugins.GPX - INFO - gpx.connect succeeded
2016-07-29 19:27:04,090 - octoprint.server.util.sockjs - INFO - New connection from client: 192.168.1.1
2016-07-29 19:27:04,109 - octoprint.server.util.sockjs - WARNING - Could not send message to client 192.168.1.1: 'utf8' codec can't decode byte 0x87 in position 1: invalid start byte
2016-07-29 19:27:07,549 - octoprint.util.pip - INFO - Found pip at /home/pi/OctoPrint/venv/bin/pip, version is 8.1.1
2016-07-29 19:27:07,615 - octoprint.plugins.softwareupdate - INFO - Saved version cache to disk
2016-07-29 19:27:08,453 - octoprint.server - INFO - Preemptively caching / for {'query_string': 'en', 'path': '/', 'base_url': 'http://80.229.11.1/'}
2016-07-29 19:27:08,848 - octoprint.server.util.sockjs - INFO - Client connection closed: 192.168.1.1
2016-07-29 19:27:10,405 - octoprint.server.util.sockjs - INFO - New connection from client: 192.168.1.1
2016-07-29 19:27:10,409 - octoprint.server.util.sockjs - WARNING - Could not send message to client 192.168.1.1: 'utf8' codec can't decode byte 0x87 in position 1: invalid start byte
2016-07-29 19:27:10,475 - octoprint.server.util.sockjs - INFO - New connection from client: 192.168.1.1
2016-07-29 19:27:10,478 - octoprint.server.util.sockjs - WARNING - Could not send message to client 192.168.1.1: 'utf8' codec can't decode byte 0x87 in position 1: invalid start byte
2016-07-29 19:27:10,484 - octoprint.server.util.sockjs - INFO - Client connection closed: 192.168.1.1
2016-07-29 19:27:10,986 - octoprint.plugins.cura - INFO - Path to CuraEngine has not been configured yet or does not exist (currently set to None), Cura will not be selectable for slicing
2016-07-29 19:27:11,172 - octoprint.server - INFO - Preemptively caching / for {'query_string': 'l10n=en', 'path': '/', 'base_url': 'http://rheyes.co.uk/'}
2016-07-29 19:27:11,344 - octoprint.server - INFO - Preemptively caching / for {'query_string': 'l10n=en', 'path': '/', 'base_url': 'http://80.229.11.1/'}
2016-07-29 19:27:11,531 - octoprint.server - INFO - Preemptively caching / for {'query_string': 'en', 'path': '/', 'base_url': 'http://127.0.0.1/'}
2016-07-29 19:27:13,736 - octoprint.server - INFO - Preemptively caching / for {'query_string': 'l10n=de', 'path': '/', 'base_url': 'http://rheyes.co.uk/'}
2016-07-29 19:27:15,778 - octoprint.server - INFO - Preemptively caching / for {'query_string': 'en', 'path': '/', 'base_url': 'http://www.qxqx11.com/'}
2016-07-29 19:27:17,759 - octoprint.server - INFO - Preemptively caching / for {'query_string': 'en', 'path': '/', 'base_url': 'http://www.558uu.com/'}
2016-07-29 19:27:19,823 - octoprint.server - INFO - Preemptively caching / for {'query_string': 'en', 'path': '/', 'base_url': 'http://www.165zz.com/'}
2016-07-29 19:27:22,036 - octoprint.server - INFO - Preemptively caching / for {'query_string': 'en', 'path': '/', 'base_url': 'http://www.250xx.com/'}
2016-07-29 19:27:42,836 - octoprint.plugins.softwareupdate - INFO - Saved version cache to disk
2016-07-29 19:27:47,959 - octoprint.plugins.softwareupdate - INFO - Saved version cache to disk
2016-07-29 19:29:10,214 - octoprint.plugins.GPX - INFO - Open /home/pi/.octoprint/data/GPX/gpx.ini
2016-07-29 19:29:10,216 - octoprint.plugins.GPX - INFO - Write /home/pi/.octoprint/data/GPX/gpx.ini
2016-07-29 19:29:14,903 - octoprint.plugins.softwareupdate - INFO - Saved version cache to disk
2016-07-29 19:29:14,920 - octoprint.plugins.cura - INFO - Path to CuraEngine has not been configured yet or does not exist (currently set to None), Cura will not be selectable for slicing
2016-07-29 19:30:52,420 - octoprint.filemanager.analysis - INFO - Starting analysis of local:18650_cell_-_Part_1.gcode
2016-07-29 19:31:01,454 - octoprint.server.api - INFO - Performing command: /home/pi/start-webcam.sh
2016-07-29 19:31:09,179 - octoprint.server.util.sockjs - INFO - New connection from client: 192.168.1.1
2016-07-29 19:31:09,181 - octoprint.server.util.sockjs - WARNING - Could not send message to client 192.168.1.1: 'utf8' codec can't decode byte 0x87 in position 1: invalid start byte
2016-07-29 19:31:09,187 - octoprint.server.util.sockjs - INFO - Client connection closed: 192.168.1.1
2016-07-29 19:31:09,340 - octoprint.plugins.cura - INFO - Path to CuraEngine has not been configured yet or does not exist (currently set to None), Cura will not be selectable for slicing
2016-07-29 20:00:49,504 - octoprint.filemanager.analysis - INFO - Starting analysis of local:18650_cell_-_Part_1.gcode
2016-07-30 00:54:30,280 - octoprint.server.util.sockjs - INFO - Client connection closed: 192.168.1.1
2016-07-30 00:54:30,536 - octoprint.server.util.sockjs - INFO - New connection from client: 192.168.1.1
2016-07-30 00:54:30,540 - octoprint.server.util.sockjs - WARNING - Could not send message to client 192.168.1.1: 'utf8' codec can't decode byte 0x87 in position 1: invalid start byte
2016-07-30 00:54:30,548 - octoprint.server.util.sockjs - INFO - Client connection closed: 192.168.1.1
2016-07-30 09:15:51,047 - octoprint.server.util.sockjs - INFO - New connection from client: 192.168.1.1
2016-07-30 09:15:51,049 - octoprint.server.util.sockjs - WARNING - Could not send message to client 192.168.1.1: 'utf8' codec can't decode byte 0x87 in position 1: invalid start byte
2016-07-30 09:15:51,223 - octoprint.plugins.cura - INFO - Path to CuraEngine has not been configured yet or does not exist (currently set to None), Cura will not be selectable for slicing
2016-07-30 09:15:52,320 - octoprint.plugins.announcements - INFO - Loaded channel _important from http://octoprint.org/feeds/important.xml in 0.33s
2016-07-30 09:16:50,992 - octoprint.plugins.GPX - INFO - Open /home/pi/.octoprint/data/GPX/gpx.ini
2016-07-30 09:16:50,994 - octoprint.plugins.GPX - INFO - Write /home/pi/.octoprint/data/GPX/gpx.ini
2016-07-30 09:16:51,192 - octoprint.plugins.cura - INFO - Path to CuraEngine has not been configured yet or does not exist (currently set to None), Cura will not be selectable for slicing
2016-07-30 09:16:52,004 - octoprint.plugins.softwareupdate - INFO - Saved version cache to disk
2016-07-30 09:16:58,360 - octoprint.plugins.softwareupdate - INFO - Starting update of octoprint to 1.2.15...
2016-07-30 09:17:14,592 - octoprint.plugins.softwareupdate - INFO - Update of octoprint to 1.2.15 successful!
2016-07-30 09:17:14,700 - octoprint.plugins.softwareupdate - INFO - Saved version cache to disk
2016-07-30 09:17:49,170 - octoprint.server.util.sockjs - INFO - Client connection closed: 192.168.1.1
2016-07-30 09:17:50,845 - octoprint.server - INFO - Shutting down...
2016-07-30 09:17:51,171 - octoprint.server - INFO - Goodbye!
2016-07-30 09:18:04,483 - octoprint.server - INFO - Starting OctoPrint 1.2.15.post1+gafdb98a (master branch)
2016-07-30 09:18:04,574 - octoprint.plugin.core - INFO - Loading plugins from /home/pi/.octoprint/plugins, /home/pi/OctoPrint/venv/lib/python2.7/site-packages/OctoPrint-1.2.15.post1_gafdb98a-py2.7.egg/octoprint/plugins and installed plugin packages...
2016-07-30 09:18:05,491 - octoprint.plugins.discovery - INFO - pybonjour is not installed, Zeroconf Discovery won't be available
2016-07-30 09:18:05,492 - octoprint.plugin.core - INFO - Found 14 plugin(s) providing 14 mixin implementations, 14 hook handlers
2016-07-30 09:18:05,497 - octoprint.filemanager.storage - INFO - Initializing the file metadata for /home/pi/.octoprint/uploads...
2016-07-30 09:18:05,615 - octoprint.filemanager.storage - INFO - ... file metadata for /home/pi/.octoprint/uploads initialized successfully.
2016-07-30 09:18:05,694 - octoprint.plugins.softwareupdate - INFO - Version cache was created for another version of OctoPrint, not using it
2016-07-30 09:18:07,530 - octoprint.util.pip - INFO - Found pip at /home/pi/OctoPrint/venv/bin/pip, version is 8.1.1
2016-07-30 09:18:07,533 - octoprint.plugin.core - INFO - Initialized 14 plugin implementation(s)
2016-07-30 09:18:07,634 - octoprint.plugin.core - INFO - 14 plugin(s) registered with the system:
|  Announcement Plugin (bundled) = /home/pi/OctoPrint/venv/lib/python2.7/site-packages/OctoPrint-1.2.15.post1_gafdb98a-py2.7.egg/octoprint/plugins/announcements
|  BQ Android App Companion (0.1.1) = /home/pi/OctoPrint/venv/local/lib/python2.7/site-packages/octoprint_bqappcompanion
|  CuraEngine (<= 15.04) (bundled) = /home/pi/OctoPrint/venv/lib/python2.7/site-packages/OctoPrint-1.2.15.post1_gafdb98a-py2.7.egg/octoprint/plugins/cura
|  Discovery (bundled) = /home/pi/OctoPrint/venv/lib/python2.7/site-packages/OctoPrint-1.2.15.post1_gafdb98a-py2.7.egg/octoprint/plugins/discovery
|  DisplayProgress (0.1.1) = /home/pi/OctoPrint/venv/local/lib/python2.7/site-packages/octoprint_displayprogress
|  GPX (2.5.4) = /home/pi/OctoPrint/venv/local/lib/python2.7/site-packages/octoprint_GPX
|  Navbar Temperature Plugin (0.8) = /home/pi/OctoPrint/venv/local/lib/python2.7/site-packages/octoprint_navbartemp
|  Plugin Manager (bundled) = /home/pi/OctoPrint/venv/lib/python2.7/site-packages/OctoPrint-1.2.15.post1_gafdb98a-py2.7.egg/octoprint/plugins/pluginmanager
|  PortLister (0.1.5) = /home/pi/OctoPrint/venv/local/lib/python2.7/site-packages/octoprint_portlister
|  Slack (0.2.1) = /home/pi/OctoPrint/venv/local/lib/python2.7/site-packages/octoprint_slack
|  Software Update (bundled) = /home/pi/OctoPrint/venv/lib/python2.7/site-packages/OctoPrint-1.2.15.post1_gafdb98a-py2.7.egg/octoprint/plugins/softwareupdate
|  Status Line (0.1.0) = /home/pi/OctoPrint/venv/local/lib/python2.7/site-packages/status_line
|  STL Viewer (0.3.1) = /home/pi/OctoPrint/venv/local/lib/python2.7/site-packages/octoprint_stlviewer
|  Virtual Printer (bundled) = /home/pi/OctoPrint/venv/lib/python2.7/site-packages/OctoPrint-1.2.15.post1_gafdb98a-py2.7.egg/octoprint/plugins/virtual_printer
2016-07-30 09:18:07,635 - octoprint.filemanager - INFO - Adding backlog items from all storage types to analysis queue...
2016-07-30 09:18:07,645 - octoprint.filemanager - INFO - Added 0 items from storage type "local" to analysis queue
2016-07-30 09:18:07,647 - octoprint.server - INFO - Reset webasset folder /home/pi/.octoprint/generated/webassets...
2016-07-30 09:18:07,657 - octoprint.server - INFO - Reset webasset folder /home/pi/.octoprint/generated/.webassets-cache...
2016-07-30 09:18:08,621 - octoprint.plugins.GPX - INFO - Connecting through x3g.
2016-07-30 09:18:08,624 - octoprint.plugins.GPX - INFO - GPXPrinter created, port: /dev/ttyACM0, baudrate: 115200
2016-07-30 09:18:10,641 - octoprint.plugins.pluginmanager - INFO - Loaded plugin repository data from disk, was still valid
2016-07-30 09:18:10,658 - octoprint.plugins.discovery - INFO - Registered OctoPrint instance on raspberrypi for SSDP
2016-07-30 09:18:10,660 - octoprint.server - INFO - Listening on http://0.0.0.0:5000
2016-07-30 09:18:10,681 - octoprint.plugins.stlviewer - INFO - STL Viewer loaded!
2016-07-30 09:18:10,694 - octoprint.plugins.portlister - INFO - Port Lister () {}
2016-07-30 09:18:10,731 - octoprint.server.util.sockjs - INFO - New connection from client: 192.168.1.1
2016-07-30 09:18:10,873 - octoprint.server - INFO - Preemptively caching / for {'query_string': 'en', 'path': '/', 'base_url': 'http://rheyes.co.uk/'}
2016-07-30 09:18:12,706 - octoprint.plugins.GPX - INFO - gpx.connect succeeded
2016-07-30 09:18:24,172 - octoprint.util.pip - INFO - Found pip at /home/pi/OctoPrint/venv/bin/pip, version is 8.1.1
2016-07-30 09:18:28,514 - octoprint.server - INFO - Preemptively caching / for {'query_string': 'en', 'path': '/', 'base_url': 'http://80.229.11.1/'}
2016-07-30 09:18:28,659 - octoprint.plugins.softwareupdate - INFO - Saved version cache to disk
2016-07-30 09:18:30,726 - octoprint.server - INFO - Preemptively caching / for {'query_string': 'l10n=en', 'path': '/', 'base_url': 'http://rheyes.co.uk/'}
2016-07-30 09:18:30,758 - octoprint.server - INFO - Preemptively caching / for {'query_string': 'l10n=en', 'path': '/', 'base_url': 'http://80.229.11.1/'}
2016-07-30 09:18:30,791 - octoprint.server - INFO - Preemptively caching / for {'query_string': 'en', 'path': '/', 'base_url': 'http://127.0.0.1/'}
2016-07-30 09:18:32,752 - octoprint.server - INFO - Preemptively caching / for {'query_string': 'en', 'path': '/', 'base_url': 'http://www.qxqx11.com/'}
2016-07-30 09:18:34,789 - octoprint.server - INFO - Preemptively caching / for {'query_string': 'l10n=de', 'path': '/', 'base_url': 'http://rheyes.co.uk/'}
2016-07-30 09:18:36,771 - octoprint.server - INFO - Preemptively caching / for {'query_string': 'en', 'path': '/', 'base_url': 'http://www.558uu.com/'}
2016-07-30 09:18:38,720 - octoprint.server - INFO - Preemptively caching / for {'query_string': 'en', 'path': '/', 'base_url': 'http://www.165zz.com/'}
2016-07-30 09:18:40,729 - octoprint.server - INFO - Preemptively caching / for {'query_string': 'en', 'path': '/', 'base_url': 'http://www.250xx.com/'}
2016-07-30 09:36:59,498 - tornado.application - ERROR - Uncaught exception GET /robots.txt (127.0.0.1)
HTTPServerRequest(protocol='http', host='rheyes.co.uk', method='GET', uri='/robots.txt', version='HTTP/1.0', remote_ip='127.0.0.1', headers={'Host': 'rheyes.co.uk', 'X-Forwarded-For': '108.59.8.70', 'Accept': '*/*', 'User-Agent': 'Mozilla/5.0 (compatible; MJ12bot/v1.4.5; http://www.majestic12.co.uk/bot.php?+)'})
Traceback (most recent call last):
  File "/home/pi/OctoPrint/venv/local/lib/python2.7/site-packages/tornado-4.0.1-py2.7-linux-armv7l.egg/tornado/web.py", line 1309, in _execute
    result = self.prepare()
  File "/home/pi/OctoPrint/venv/local/lib/python2.7/site-packages/OctoPrint-1.2.15.post1_gafdb98a-py2.7.egg/octoprint/server/util/tornado.py", line 195, in prepare
    self._fallback(self.request, b"")
  File "/home/pi/OctoPrint/venv/local/lib/python2.7/site-packages/OctoPrint-1.2.15.post1_gafdb98a-py2.7.egg/octoprint/server/util/tornado.py", line 474, in __call__
    response.extend(app_response)
  File "/home/pi/OctoPrint/venv/local/lib/python2.7/site-packages/Werkzeug-0.8.3-py2.7.egg/werkzeug/wsgi.py", line 569, in next
    data = self.file.read(self.buffer_size)
ValueError: I/O operation on closed file
2016-07-30 09:59:33,475 - octoprint.server.util.sockjs - INFO - Client connection closed: 192.168.1.1
2016-07-30 09:59:34,928 - octoprint.server.util.sockjs - INFO - New connection from client: 192.168.1.1
2016-07-30 09:59:35,095 - octoprint.plugins.cura - INFO - Path to CuraEngine has not been configured yet or does not exist (currently set to None), Cura will not be selectable for slicing
2016-07-30 09:59:38,915 - octoprint.server.api - INFO - Performing command: /home/pi/start-webcam.sh
2016-07-30 10:02:11,478 - octoprint.filemanager.analysis - INFO - Starting analysis of local:18650_chamber_-_triple_chamber.gcode
2016-07-30 11:13:48,729 - octoprint.filemanager.analysis - INFO - Starting analysis of local:18650_chamber_-_triple_chamber.gcode
2016-07-30 15:19:39,485 - octoprint.filemanager.analysis - INFO - Starting analysis of local:18650_chamber_-_triple_chamber.gcode
2016-07-30 16:33:54,399 - octoprint.server.util.sockjs - INFO - Client connection closed: 192.168.1.1
2016-07-30 16:33:54,576 - octoprint.server.util.sockjs - INFO - New connection from client: 192.168.1.1
2016-07-30 16:33:55,647 - octoprint.plugins.announcements - INFO - Loaded channel _important from http://octoprint.org/feeds/important.xml in 0.35s
2016-07-30 16:35:06,065 - octoprint.filemanager.analysis - INFO - Starting analysis of local:18650_chamber_-_triple_chamber.gcode

# Fixed code
def _estimatePrintTimeLeft(
    self,
    progress,
    printTime,
    cleanedPrintTime,
    statisticalTotalPrintTime,
    statisticalTotalPrintTimeType,
):
    """
    Tries to estimate the print time left for the print job

    This is somewhat horrible since accurate print time estimation is pretty much impossible to
    achieve, considering that we basically have only two data points (current progress in file and
    time needed for that so far - former prints or a file analysis might not have happened or simply
    be completely impossible e.g. if the file is stored on the printer's SD card) and
    hence can only do a linear estimation of a completely non-linear process. That's a recipe
    for inaccurate predictions right there. Yay.

    Anyhow, here's how this implementation works. This method gets the current progress in the
    printed file (percentage based on bytes read vs total bytes), the print time that elapsed,
    the same print time with the heat up times subtracted (if possible) and if available also
    some statistical total print time (former prints or a result from the GCODE analysis).

      1. First get an "intelligent" estimate based on the :class:`~octoprint.printer.estimation.TimeEstimationHelper`.
         That thing tries to detect if the estimation based on our progress and time needed for that becomes
         stable over time through a rolling window and only returns a result once that appears to be the
         case.
      2. If we have any statistical data (former prints or a result from the GCODE analysis)
         but no intelligent estimate yet, we'll use that for the next step. Otherwise, up to a certain percentage
         in the print we do a percentage based weighing of the statistical data and the intelligent
         estimate - the closer to the beginning of the print, the more precedence for the statistical
         data, the closer to the cut off point, the more precendence for the intelligent estimate. This
         is our preliminary total print time.
      3. If the total print time is set, we do a sanity check for it. Based on the total print time
         estimate and the time we already spent printing, we calculate at what percentage we SHOULD be
         and compare that to the percentage at which we actually ARE. If it's too far off, our total
         can't be trusted and we fall back on the dumb estimate. Same if the time we spent printing is
         already higher than our total estimate.
      4. If we do NOT have a total print time estimate yet but we've been printing for longer than
         a configured amount of minutes or are further in the file than a configured percentage, we
         also use the dumb estimate for now.

    Yes, all this still produces horribly inaccurate results. But we have to do this live during the print and
    hence can't produce to much computational overhead, we do not have any insight into the firmware implementation
    with regards to planner setup and acceleration settings, we might not even have access to the printed file's
    contents and such we need to find something that works "mostly" all of the time without costing too many
    resources. Feel free to propose a better solution within the above limitations (and I mean that, this solution
    here makes me unhappy).

    Args:
        progress (float or None): Current percentage in the printed file
        printTime (float or None): Print time elapsed so far
        cleanedPrintTime (float or None): Print time elapsed minus the time needed for getting up to temperature
            (if detectable).
        statisticalTotalPrintTime (float or None): Total print time of past prints against same printer profile,
            or estimated total print time from GCODE analysis.
        statisticalTotalPrintTimeType (str or None): Type of statistical print time, either "average" (total time
            of former prints) or "analysis"

    Returns:
        (2-tuple) estimated print time left or None if not proper estimate could be made at all, origin of estimation
    """

    if progress is None or printTime is None or cleanedPrintTime is None:
        return None

    dumbTotalPrintTime = printTime / progress
    estimatedTotalPrintTime = self._estimateTotalPrintTime(progress, cleanedPrintTime)
    totalPrintTime = estimatedTotalPrintTime

    printTimeLeftOrigin = "estimate"
    if statisticalTotalPrintTime is not None:
        if estimatedTotalPrintTime is None:
            # no estimate yet, we'll use the statistical total
            totalPrintTime = statisticalTotalPrintTime
            printTimeLeftOrigin = statisticalTotalPrintTimeType

        else:
            if progress < self._timeEstimationStatsWeighingUntil:
                # still inside weighing range, use part stats, part current estimate
                sub_progress = progress * (1 / self._timeEstimationStatsWeighingUntil)
                if sub_progress > 1.0:
                    sub_progress = 1.0
                printTimeLeftOrigin = "mixed-" + statisticalTotalPrintTimeType
            else:
                # use only the current estimate
                sub_progress = 1.0
                printTimeLeftOrigin = "estimate"

            # combine
            totalPrintTime = (
                1.0 - sub_progress
            ) * statisticalTotalPrintTime + sub_progress * estimatedTotalPrintTime

    printTimeLeft = None
    if totalPrintTime is not None:
        # sanity check current total print time estimate
        assumed_progress = cleanedPrintTime / totalPrintTime
        min_progress = progress - self._timeEstimationValidityRange
        max_progress = progress + self._timeEstimationValidityRange

        if (
            min_progress <= assumed_progress <= max_progress
            and totalPrintTime > cleanedPrintTime
        ):
            # appears sane, we'll use it
            printTimeLeft = totalPrintTime - cleanedPrintTime

        else:
            # too far from the actual progress or negative,
            # we use the dumb print time instead
            printTimeLeft = dumbTotalPrintTime - cleanedPrintTime
            printTimeLeftOrigin = "linear"

    else:
        printTimeLeftOrigin = "linear"
        if (
            progress > self._timeEstimationForceDumbFromPercent
            or cleanedPrintTime >= self._timeEstimationForceDumbAfterMin * 60
        ):
            # more than x% or y min printed and still no real estimate, ok, we'll use the dumb variant :/
            printTimeLeft = dumbTotalPrintTime - cleanedPrintTime

    if printTimeLeft is not None and printTimeLeft < 0:
        # shouldn't actually happen, but let's make sure
        printTimeLeft = None

    return printTimeLeft, printTimeLeftOrigin