Welcome to mirror list, hosted at ThFree Co, Russian Federation.

DisplayProgressOnLCD.py « scripts « PostProcessingPlugin « plugins - github.com/Ultimaker/Cura.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: e39e69eff0c73c600f6752a7bbb52e3c8d129faa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# Cura PostProcessingPlugin
# Author:   Mathias Lyngklip Kjeldgaard, Alexander Gee, Kimmo Toivanen
# Date:     July 31, 2019
# Modified: Okt 22, 2020

# Description:  This plugin displays progress on the LCD. It can output the estimated time remaining and the completion percentage.

from ..Script import Script

import re
import datetime

class DisplayProgressOnLCD(Script):

    def __init__(self):
        super().__init__()

    def getSettingDataString(self):
        return """{
            "name": "Display Progress On LCD",
            "key": "DisplayProgressOnLCD",
            "metadata": {},
            "version": 2,
            "settings":
            {
                "time_remaining":
                {
                    "label": "Time Remaining",
                    "description": "Select to write remaining time to the display.Select to write remaining time on the display using M117 status line message (almost all printers) or using M73 command (Prusa and Marlin 2 if enabled).",
                    "type": "bool",
                    "default_value": false
                },
                "time_remaining_method":
                {
                    "label": "Time Reporting Method",
                    "description": "How should remaining time be shown on the display? It could use a generic message command (M117, almost all printers), or a specialised time remaining command (M73, Prusa and Marlin 2).",
                    "type": "enum",
                    "options": {
                        "m117":"M117 - All printers",
                        "m73":"M73 - Prusa, Marlin 2"
                    },
                    "enabled": "time_remaining",
                    "default_value": "m117"
                },
                "update_frequency":
                {
                    "label": "Update frequency",
                    "description": "Update remaining time for every layer or periodically every minute or faster.",
                    "type": "enum",
                    "options": {"0":"Every layer","15":"Every 15 seconds","30":"Every 30 seconds","60":"Every minute"},
                    "default_value": "0",
                    "enabled": "time_remaining"
                },
                "percentage":
                {
                    "label": "Percentage",
                    "description": "When enabled, set the completion bar percentage on the LCD using Marlin's M73 command.",
                    "type": "bool",
                    "default_value": false
                }
            }
        }"""

    # Get the time value from a line as a float.
    # Example line ;TIME_ELAPSED:1234.6789 or ;TIME:1337
    def getTimeValue(self, line):
        list_split = re.split(":", line)  # Split at ":" so we can get the numerical value
        return float(list_split[1])  # Convert the numerical portion to a float

    def outputTime(self, lines, line_index, time_left, mode):
        # Do some math to get the time left in seconds into the right format. (HH,MM,SS)
        time_left = max(time_left, 0)
        m, s = divmod(time_left, 60)
        h, m = divmod(m, 60)
        # Create the string
        if mode == "m117":
            current_time_string = "{:d}h{:02d}m{:02d}s".format(int(h), int(m), int(s))
            # And now insert that into the GCODE
            lines.insert(line_index, "M117 Time Left {}".format(current_time_string))
        else:  # Must be m73.
            mins = int(60 * h + m + s / 30)
            lines.insert(line_index, "M73 R{}".format(mins))

    def execute(self, data):
        output_time = self.getSettingValueByKey("time_remaining")
        output_time_method = self.getSettingValueByKey("time_remaining_method")
        output_frequency = int(self.getSettingValueByKey("update_frequency"))
        output_percentage = self.getSettingValueByKey("percentage")
        line_set = {}
        if output_percentage or output_time:
            total_time = -1
            previous_layer_end_percentage = 0
            previous_layer_end_time = 0
            for layer in data:
                layer_index = data.index(layer)
                lines = layer.split("\n")

                for line in lines:
                    if (line.startswith(";TIME:") or line.startswith(";PRINT.TIME:")) and total_time == -1:
                        # This line represents the total time required to print the gcode
                        total_time = self.getTimeValue(line)
                        line_index = lines.index(line)

                        # In the beginning we may have 2 M73 lines, but it makes logic less complicated
                        if output_time:
                            self.outputTime(lines, line_index, total_time, output_time_method)

                        if output_percentage:
                            # Emit 0 percent to sure Marlin knows we are overriding the completion percentage
                            lines.insert(line_index, "M73 P0")

                    elif line.startswith(";TIME_ELAPSED:"):
                        # We've found one of the time elapsed values which are added at the end of layers
                        
                        # If we have seen this line before then skip processing it. We can see lines multiple times because we are adding
                        # intermediate percentages before the line being processed. This can cause the current line to shift back and be
                        # encountered more than once
                        if line in line_set:
                            continue
                        line_set[line] = True

                        # If total_time was not already found then noop
                        if total_time == -1:
                            continue

                        current_time = self.getTimeValue(line)
                        line_index = lines.index(line)
                        
                        if output_time:
                            if output_frequency == 0:
                                # Here we calculate remaining time
                                self.outputTime(lines, line_index, total_time - current_time, output_time_method)
                            else:
                                # Here we calculate remaining time and how many outputs are expected for the layer
                                layer_time_delta = int(current_time - previous_layer_end_time)
                                layer_step_delta = int((current_time - previous_layer_end_time) / output_frequency)
                                # If this layer represents less than 1 step then we don't need to emit anything, continue to the next layer
                                if layer_step_delta != 0:
                                    # Grab the index of the current line and figure out how many lines represent one second
                                    step = line_index / layer_time_delta
                                    # Move new lines further as we add new lines above it
                                    lines_added = 1
                                    # Run through layer in seconds
                                    for seconds in range(1, layer_time_delta + 1):
                                        # Time from start to decide when to update
                                        line_time = int(previous_layer_end_time + seconds)
                                        # Output every X seconds and after last layer
                                        if line_time % output_frequency == 0 or line_time == total_time:
                                            # Line to add the output
                                            time_line_index = int((seconds * step) + lines_added)

                                            # Insert remaining time into the GCODE
                                            self.outputTime(lines, time_line_index, total_time - line_time, output_time_method)
                                            # Next line will be again lower
                                            lines_added = lines_added + 1

                                    previous_layer_end_time = int(current_time)

                        if output_percentage:
                            # Calculate percentage value this layer ends at
                            layer_end_percentage = int((current_time / total_time) * 100)

                            # Figure out how many percent of the total time is spent in this layer
                            layer_percentage_delta = layer_end_percentage - previous_layer_end_percentage
                            
                            # If this layer represents less than 1 percent then we don't need to emit anything, continue to the next layer
                            if layer_percentage_delta != 0:
                                # Grab the index of the current line and figure out how many lines represent one percent
                                step = line_index / layer_percentage_delta

                                for percentage in range(1, layer_percentage_delta + 1):
                                    # We add the percentage value here as while processing prior lines we will have inserted
                                    # percentage lines before the current one. Failing to do this will upset the spacing
                                    percentage_line_index = int((percentage * step) + percentage)

                                    # Due to integer truncation of the total time value in the gcode the percentage we 
                                    # calculate may slightly exceed 100, as that is not valid we cap the value here
                                    output = min(percentage + previous_layer_end_percentage, 100)
                                    
                                    # Now insert the sanitized percentage into the GCODE
                                    lines.insert(percentage_line_index, "M73 P{}".format(output))

                                previous_layer_end_percentage = layer_end_percentage

                # Join up the lines for this layer again and store them in the data array
                data[layer_index] = "\n".join(lines)
        return data