-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathidx.html
295 lines (276 loc) · 17.5 KB
/
idx.html
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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="pragma" content="no-cache; charset=utf-8" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>OctoControl Terminal</title>
<style type="text/css">
body {background-color:#FFFFDD}
//td {vertical-align:top;padding:0px;margin:0px}
p {text-align:justify;margin-bottom:0px}
td.gchord {font-size:75%;font-weight:bold;padding:0px;margin:0px;padding-top:0px;padding-right:3px;text-align:left;font-family:verdana,arial;color:#888888;position:relative;top:3px}
td.gtxt {text-align:left}
.dettitle {border-bottom:1px lightgray dashed}
.dettitle2 {border-bottom:1px lightgray dashed}
h2 {margin-top:20px; background-color:xgray}
h3 {background-color:xyellow;margin-top:30px;text-decoration:underline}
h4 {padding-left:0px;margin-left:0px;text-decoration:underline;color:#333333}
ul {margin-top:0px;padding-top:0px}
.ref {color:gray}
.gr {color:gray}
.grsm {color:gray;font-size:80%}
.err {color:red;font-weight:bold}
a {text-color:blue;text-decoration:underline}
a:HOVER {border-bottom:1px blue;color:red}
a.index {text-decoration:none}
a.index:HOVER {text-decoration:underline;color:red}
.preFile {background-color:lightgray;padding:0.5em}
td.imgthumb {vertical-align:top;padding:5px;font-size:80%}
img.ico {width:12px;height:12px;overflow:visible;position:relative;margin-top:-5px}
.imginc {max-width:100%;max-height:80vh}
.imginccap {text-align:left;padding-bottom:0.5em}
div.code {margin:0px;padding:0px;padding-left:30px;}
.code {font-family:courier,fixed;color:green;}
.cmd {font-family:courier,fixed;color:red;background-color:#FFEEDD;font-weight:bold;white-space:pre-wrap;padding-left:0.5em;;padding-right:0.5em;padding-top:0.5em;padding-bottom:0.5em}
.cmd::first-line {color:darkred;}
.cmd::before {content:'> ';}
.cmdresp {font-family:courier,fixed;color:blue;background-color:#EEEEFF;white-space:pre-wrap;padding-left:0.5em;;padding-right:0.5em;}
.cmdresp::first-line {color:darkblue;}
.cmdresp::before {content:' ';}
.comm {font-family:courier,fixed;color:red;background-color:#FFEEDD;font-weight:bold;white-space:pre-wrap;padding-left:0.5em;;padding-right:0.5em;}
.comm::first-line {color:darkred;}
.comm::before {content:'> ';}
.commresp {font-family:courier,fixed;color:blue;background-color:#EEEEFF;white-space:pre-wrap;padding-left:0.5em;;padding-right:0.5em;}
.commresp::first-line {color:darkblue;}
.commresp::before {content:'< ';}
.bang {font-weight:bold;color:red}
// unsupported by everything except apple, so far
//@media screen and (inverted-colors: inverted) {
//.cmd {background-color:#0000CC;color:lightblue;}
//.cmd::first-line: {color:blue}
//.cmdresp {background-color:#CC0000;color:lightred}
//.cmdresp::first-line: {color:red}
//}
@media print{
body {font-size:80%}
.noprint {display:none;visibility:hidden}
.xnopbr {page-break-inside:avoid}
td.gchord: {color:black}
.nopbr {}
.preFile {background-color:white;border:1px dotted black}
}
</style>
<meta property="og:title" content="OctoControl Terminal" />
<meta property="og:type" content="website" />
<meta property="og:x-url" content="http://:" />
<meta property="og:description" content="8term/8mon, interactive monitoring and controlling of OctoPrint server" />
<meta property="og:image" content="http://th.8term-screenshot2.png" />
</head>
<body>
<h1>OctoControl Terminal</h1><hr class="noprint" /><div class="noprint"><a title="Click here to enlarge" href="8term-screenshot2.png"><img src="th.8term-screenshot2.png" width="640" height="375" align="right" style="padding-left:20px" />
</a>
<a class="index indexlev2" href="#Problem" title="">Problem</a><br /><a class="index indexlev2" href="#Solutionapproach" title="Solution approach">Solution approach</a><br /><a class="index indexlev2" href="#basics" title="basics">basics</a><br /> <small><a class="index indexlev3" href="#config" title="basics.config">config</a></small><br /> <small><a class="index indexlev3" href="#websocket" title="basics.websocket">websocket</a></small><br /> <small><a class="index indexlev3" href="#RESTAPI" title="basics.REST API">REST API</a></small><br /><a class="index indexlev2" href="#8mon.py" title="8mon.py">8mon.py</a><br /> <small><a class="index indexlev3" href="#usage" title="8mon.py.usage">usage</a></small><br /> <small><a class="index indexlev4" href="#options" title="8mon.py.usage.options">options</a></small><br /> <small><a class="index indexlev4" href="#example" title="8mon.py.usage.example">example</a></small><br /><a class="index indexlev2" href="#8term.py" title="8term.py">8term.py</a><br /> <small><a class="index indexlev3" href="#8term.py.usage" title="8term.py.usage">usage</a></small><br /> <small><a class="index indexlev4" href="#8term.py.usage.options" title="8term.py.usage.options">options</a></small><br /> <small><a class="index indexlev4" href="#keys" title="8term.py.usage.keys">keys</a></small><br /> <small><a class="index indexlev4" href="#commands" title="8term.py.usage.commands">commands</a></small><br /> <small><a class="index indexlev3" href="#weakness" title="8term.py.weakness">weakness</a></small><br /><a class="index indexlev2" href="#Download" title="Download">Download</a><br /><a class="index indexlev2" href="#TODO" title="TODO">TODO</a><br /><a class="index indexlev2" href="#Screenshots" title="Screenshots">Screenshots</a><br /></div><hr /><a name="Problem"></a><h2>Problem
</h2>
<p>
<a class="a" href="http://octoprint.org/" title="remote link: http://octoprint.org/" target="_blank">OctoPrint</a> is a neat software used as a web-operated printserver
for <a class="w" href="https://en.wikipedia.org/wiki/3D_printers" title="Wikipedia link: 3D printers" target="_blank">3D printers</a>.
</p>
<p>
Sometimes, however, a commandline control is desired.
</p>
<p>
For command by command noninteractive work, <a class="P" href="https://www.improwis.com/projects/8control" title="local project" target="_blank">8control</a> suite was written in bash.
</p>
<p>
However, the commands do not provide the server's response. Which is occasionally needed.
</p>
<hr /><a name="Solutionapproach"></a><h2>Solution approach
</h2>
<p>
The OctoPrint server comes with a powerful <a class="w" href="https://en.wikipedia.org/wiki/Representational_state_transfer" title="Wikipedia link: Representational state transfer" target="_blank">REST</a> <a class="w" href="https://en.wikipedia.org/wiki/Application_programming_interface" title="Wikipedia link: Application programming interface" target="_blank">API</a> accessible
over the <a class="w" href="https://en.wikipedia.org/wiki/HTTP" title="Wikipedia link: HTTP" target="_blank">HTTP</a> protocol and extensively using <a class="w" href="https://en.wikipedia.org/wiki/JSON" title="Wikipedia link: JSON" target="_blank">JSON</a> format for the data.
The production version API documentation is <a class="a" href="https://docs.octoprint.org/en/master/api/index.html" title="remote link: https://docs.octoprint.org/en/master/api/index.html" target="_blank">here</a>.
</p>
<p>
There is also a <a class="w" href="https://en.wikipedia.org/wiki/websocket" title="Wikipedia link: websocket" target="_blank">websocket</a> API. This is documented <a class="a" href="https://docs.octoprint.org/en/master/api/push.html" title="remote link: https://docs.octoprint.org/en/master/api/push.html" target="_blank">here</a>.
</p>
<p>
Python was chosen for this level of complexity, as the startup time penalty is not worth the necessary cost of not spending
too much time writing it all in C and bash is too weak.
</p>
<hr /><a name="basics"></a><h2> basics
</h2>
<a name="config"></a><h3> config
</h3>
<p>
Both 8mon and 8term use the same configuration file format as the 8control suite. The file is located at <span class="code">/etc/octocmd.conf</span>
and is in JSON format. An example is here:
<pre class=""> "OctoAPI_KEY": "0C59XXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"OctoPrint_URL": "http://printer:5000"
}
</pre></p>
<p>
The API key can be provided by the Octoprint UI.
The URL is the address of the machine. Can be domain name, can be a raw IP address.
</p>
<p>
The URL is converted to the websocket one by replacing <span class="code">http://</span> with <span class="code">ws://</span>.
</p>
<a name="websocket"></a><h3> websocket
</h3>
<p>
The websocket data come in the form of JSON blocks. A fairly large amount of data flows in, with every state change
the server reports to the web browser interface.
</p>
<p>
The gcode logs, of Send and Recv streams, arrive in the <span class="code"> ['current']['logs'] </span> array.
</p>
<p>
The machine events arrive in the <span class="code"> ['events'] </span> array.
</p>
<p>
The data come in fixed intervals. More than one gcode line can come in the same event.
</p>
<p>
The websocket access is done via <a class="a" href="https://websockets.readthedocs.io/" title="remote link: https://websockets.readthedocs.io/" target="_blank">websockets</a> library.
</p>
<a name="RESTAPI"></a><h3> REST API
</h3>
<p>
The API is needed for handling the login, and eventual other commands. The commands get submitted
to the server via a HTTP request. The command responses are retrieved via websocket.
</p>
<p>
The API access is done via <a class="a" href="https://pypi.org/project/requests/" title="remote link: https://pypi.org/project/requests/" target="_blank">requests</a> library.
</p>
<hr /><a name="8mon.py"></a><h2> 8mon.py
</h2>
<p>
8mon.py is the noninteractive websocket/REST client.
</p>
<p>
The command can provide monitoring of the gcode communication, the events,
or the entire communication (which gets pretty spammy).
</p>
<p>
It can also send a command to the machine, and display its response.
</p>
<p>
CAVEAT: the code compares the command sent in with content of the Sent: line, then shows everything from that to Recv: ok.
Octoprint rewrites/substitutes some G/M codes. In these cases, the code won't return data and will be killed by a timeout.
</p>
<a name="usage"></a><h3> usage
</h3>
<p>
On startup, 8mon reads the config file, connects to the websocket of the server mentioned there,
authorizes itself with the API key, subscribes to events and current streams on websocket, and
shows the incoming data.
</p>
<p>
If told, also sends a command.
The commands are converted to uppercase. (Beware, some commands like M117 and G7 have case-sensitive
data. This will break them.)
</p>
<a name="options"></a><h4> options
</h4>
<pre class="preFile">Usage: ./8mon.py [-a] [-s] [-v] [-v] [-v] [-tTIMEOUT] [-C/config/file] [command]
Parameters:
-a show all messages
-s show separators between messages
-v increase verbosity, up to 2 times
-t<num> timeout in seconds
-C/file config file location, default /etc/octocmd.conf
-h this help
--help this help
command gcode command to get the response
</pre><p>
For easier parsing, there are no spaces between option and value.
</p>
<a name="example"></a><h4> example
</h4>
<div class="cmd"> 8mon.py m114</div><div class="cmdresp"> Send: M114</div><div class="cmdresp"> {'event': {'type': 'PositionUpdate', 'payload': {'reason': None, 'e': 0.0, 'x': 68.06, 'y': 62.24, 'f': 367.3464610996, 't': 0, 'z': 0.0}}}</div><div class="cmdresp"> Recv: X:68.06 Y:62.24 Z:0.00 E:0.00 Count X: 32156 Y:21476 Z:0</div><div class="cmdresp"> Recv: ok</div><div class="cmd"> 8mon.py</div><div class="cmdresp"> ### Opening websocket to: ws://laser:5000/sockjs/websocket</div><div class="cmdresp"> ### waiting for events, gcode</div><div class="cmdresp"> ### Opened connection</div><div class="cmdresp"> Recv: echo:busy: processing</div><div class="cmdresp"> Recv: echo:busy: processing</div><div class="cmdresp"> Recv: ok</div><div class="cmdresp"> Recv: echo:endstops hit: Y:5.90</div><div class="cmdresp"> Send: N5 G0 X0.8954578544 Y0.0000000000 Z0.0000000000 F261.9211735748*58</div><div class="cmdresp"> Recv: ok</div><div class="cmdresp"> Send: N6 G0 X3.5309134035 Y0.0000000000 Z0.0000000000 F220.2485759381*52</div><div class="cmdresp"> Recv: ok</div><div class="cmdresp"> Send: N7 G0 X4.2839007032 Y0.0000000000 Z0.0000000000 F220.2485759381*59</div><div class="cmdresp"> Recv: ok</div><div class="cmdresp"> Send: N8 G0 X5.0816629578 Y0.0000000000 Z0.0000000000 F233.3452377916*62</div><div class="cmdresp"> Recv: ok</div><div class="cmdresp"> Send: N9 G0 X5.9771208121 Y0.0000000000 Z0.0000000000 F261.9211735748*60</div><div class="cmdresp"> Recv: ok</div><div class="cmdresp"> ^C### ERROR: <class 'KeyboardInterrupt'></div><div class="cmdresp"> ### closed ###</div><hr /><a name="8term.py"></a><h2> 8term.py
</h2>
<p>
8term.py is an interactive terminal for the gcode, the console somewhat equivalent of the "Terminal" window of the web interface.
The terminal has color syntax highlighting.
</p>
<p>
The code uses the same general approach as 8mon does, with <a class="a" href="https://python-prompt-toolkit.readthedocs.io/en/master/" title="remote link: https://python-prompt-toolkit.readthedocs.io/en/master/" target="_blank">prompt_toolkit</a> library
for general interactive screens, and <a class="a" href="https://pygments.org/" title="remote link: https://pygments.org/" target="_blank">pygments</a> as lexer and syntax highlighter.
</p>
<p>
The modified gcode lexer and the associated color style were integrated to the main file, to avoid multifile dependencies
and allow easy portability.
</p>
<a name="8term.py.usage"></a><h3> usage
</h3>
<p>
On startup, 8term reads the config file, connects to the websocket of the server mentioned there,
authorizes itself with the API key, subscribes to events and current streams on websocket, and
shows the incoming data on the top window.
</p>
<p>
The bottom window acts as the input console. A command entered there is sent via the REST API.
</p>
<p>
If the first command letter is lowercase, the command as a whole is converted to uppercase.
Beware, some commands like M117 and G7 have case-sensitive data. This will break them.
An uppercase G or M (or other letter) will signal to the software it should not translate case.
</p>
<p>
Command sent as parameter from the console will be uppercased regardless. (TODO: address.)
</p>
<a name="8term.py.usage.options"></a><h4> options
</h4>
<pre class="preFile">Usage: ./8term.py [-a] [-s] [-v] [-v] [-v] [-tTIMEOUT] [-C/config/file] [command]
Parameters:
-v increase verbosity, up to 2 times
-C/file config file location, default /etc/octocmd.conf
-h this help
--help this help
command gcode command to get the response
</pre><p>
For easier parsing, there are no spaces between option and value.
</p>
<a name="keys"></a><h4> keys
</h4>
<ul><li> <span class="code">Ctrl-C</span>, <span class="code">Ctrl-D</span> - quit
</li><li> <span class="code">Tab</span>, <span class="code">Ctrl-W</span> - switch between top and bottom window
</li><li> <span class="code">PgUp</span>, <span class="code">PgDn</span> - if the top window is focused, scroll through the history
</li></ul><a name="commands"></a><h4> commands
</h4>
<ul><li> process
</li><ul><li> <span class="code">/start</span> - starts job
</li><li> <span class="code">/pause</span> - pauses running job
</li><li> <span class="code">/resume</span> - resumes running job
</li><li> <span class="code">/cancel</span> - cancels running job
</li></ul><li> position
</li><ul><li> <span class="code">/home</span> - G28, homes the machine
</li></ul><li> machine
</li><ul><li> <span class="code">/on</span> - M80, power-on the machine
</li><li> <span class="code">/off</span> - M81, power-off the machine
</li></ul></ul><a name="weakness"></a><h3> weakness
</h3>
<p>
The code gets slower at too many thousand gcode lines.
</p>
<hr /><a name="Download"></a><h2>Download
</h2>
<ul><li> <a class="F" href="8mon.py" title="local file">8mon.py</a>
</li><li> <a class="F" href="8term.py" title="local file">8term.py</a>
</li></ul><hr /><a name="TODO"></a><h2>TODO
</h2>
<ul><li> more commands
</li><li> better error handling
</li><li> find out why slow, or add manual clearing of the console
</li><li> file upload/run handling
</li><li> case handling for commands
</li><li> logfile load/save with filenames
</li></ul><hr /><a name="Screenshots"></a><h2>Screenshots
</h2>
<table class="images" border="0"><tr>
<td valign="top" class="imgthumb" width="640"><a title="Click here to enlarge" href="8term-screenshot1.png"><img src="th.8term-screenshot1.png" width="640" height="376" /></a><br/></td><td valign="top" class="imgthumb" width="640"><a title="Click here to enlarge" href="8term-screenshot3.png"><img src="th.8term-screenshot3.png" width="640" height="375" /></a><br/></td><td></td><td></td></tr></table><!-- feedback -->
<!-- /feedback -->
</body>
</html>