Does a remote MDI terminal/interface exist?

Hi all,

Apologies if this has been addressed - I’ve done some hunting around here, don’t think I’ve seen this answered.

Basically, I’m looking for the functionality of the MDI tab, but accessible through SSH or web API.

I have a few different use cases that ultimately boil down to this: I’d like to be able send arbitrary gcode commands between running programs, all initiated from scripts and/or custom UI on a remote computer.

I believe I can manage the program control with the handlers identified in the 1F controller github repo ( OneFinityCNC ). But as best I can tell, MDI isn’t accessible here.

Any suggestions?


It sounds like you may be referring to Macros — pre-defined snippets that need to be run frequently, often at the touch/click of a button. This is a feature that has been requested many times, but does not seem to be of much interest to the Onefinity team. It was implemented in the original Buildbotics repo at a later date but (to my understanding) Buildbotics changed their license agreement which prevents Onefinity from using any further enhancements, so they must now do their own development.

I briefly started working on a Chrome extension for this purpose, but it has fallen to the back burner. It is capable of sending commands via web sockets. I can hard-code Macros into the extension source and run them from the web interface, but there is currently no UI for creating/editing Macros within the browser itself. If this is something people are interested in, I may be able to put some work in or share the basic concept for others to develop. I have not tested it on the controller instance itself, only from a remote browser instance.

Hey Greg,

when considering the Onefinity manufacturer’s efforts to further develop their onefinity-firmware, I don’t think I would use Onefinity’s fork to further develop the Buildbotics controller. I would rather join upstream development and get involved in the Buildbotics CNC controller in buildbotics/bbctrl-firmware. As you can see on the onefinity-firmware 1.0.9 source code, Joseph Coffland is still the author in the (free) licence at the top of every py file for the raspi, as well in every c file for the AVR microcontroller. You could contact the author of the Buildbotics CNC Controller (jcoffland at directly and tell them you want to contribute.

What I think the Buildbotics CNC Controller needs, besides the capability of adjusting feed rate on the fly and more sophisticated methods to probe a workpiece, is more hardware buttons. The only hardware button that has an effect to the software is the “estop” pin on 25-pin I/O interface, that makes the system enter the “estopped mode” that is also available on the Big Red-Yellow button icon on the top right of the Web User Interface (not on the Big Red-Yellow Button Onefinity black box!) and that stops not only the steppers, but also the spindle or the router. What I would program first, is a hardware “Pause” and “Stop” button. And, as you suggested, a good api. Maybe there are points to trigger actions that you can find if you dive into the code, but contacting the author and getting involved into development upstream would be easier than trying this alone.

The last time I had a look at the recent version of the web interface py file of Onefinity’s fork, I really would not like to work on it. They change the programming style all over.

I have a working Onefinity Controller that I leave at version 1.0.9 of onefinity-firmware. And by the way, I don’t plan to use it as the CNC Controller for my own machine.

– Source: What is the 1F future? We need to know – Post #11 by Aiph5u

See also

1 Like

Hey Matticustard,

you have not been here a while, welcome back!

Macros are available on the Controller (see here)

The CERN OHL is an accepted free content licence according to the Free Cultural Works definition[14] and version 2 is approved by the Open Source Initiative[15].

– Source: CERN Open Hardware Licence – Wikipedia

1 Like

It’s inevitable, sooner or later, I write a book!

@Matticustard Thanks for your input. In some of the reading in the forum in the past weeks, I had seen your discussion about your project and was intrigued. I agree, macros are sorely needed feature. While they might, in some cases cover what I’m looking for, I’m looking for something even more flexible, where the gcode content will vary at run time. So predefined macros very often won’t work.

@Aiph5u I might have tried too hard on being brief and done a bad job of explaining what I’m looking for - unless your point was that I should jump into the BBCtrl development and help create what I’m looking for. :wink: in which case, my kung-fu may not be at that level yet.

For the sake of simplicity, let’s just say I’m using a WW X50 to do some larger format work that I used to do on a smaller, woodpecker / grbl controller based CNC with a connection from a remote PC running mostly unattended scripts and/or “job UI” developed in-house.

As such I could easily issue a collection of arbitrary commands. A variety of dynamic adjustments and tweaks could be made to the CNC based on a number of factors not known prior to starting the job. Then, the remote UI could kick-off a sequence of CNC program (either canned, or fed to the controller). In some cases making [mainly] move adjustments and dynamic pauses between operations mid-program. (In my case constant feed rates are fine).

When looking into the WW X50 and what I understood of the 1F controller, I recognized this would present some challenges and I accepted that. In the short term, my need for being operational at day one meant I would go w/ the 1F controller. In some cases, I’ve leveraged more complex programs leaning more on parameters, conditionals, etc.

But for comparable unattended capability, I still need a way to feed arbitrary parameter values remotely, and ideally send a few odd gcode commands. The general concept behind Matticustard’s browser extension is close, but my hope was to add some minimal interface funcitonality to our in-house UI and scipts. Not rewrite them as a browser extension for accessing the 1F controller’s web interface.

Again, I appreciate your feedback and any new insight you might have.



I fully understand that your needs may differ. The underlying point I was attempting to convey is that it is possible to send commands using websockets. The implementation does not have to be limited to a browser extension. And while this may not be fully sufficient for your needs, it seemed it might potentially be compatible with this statement.

Basically, I’m looking for the functionality of the MDI tab, but accessible through SSH or web API.

Python proof of concept.

In this case, I took the cookie value directly from a browser. This would need to be addressed in a stand-alone solution. But it does work to send GCode to the controller.

EDIT: Modified example to remove need for cookie, thanks to @suprak.

import asyncio
import websockets

async def hello():
    uri = "ws://"
    async with websockets.connect(uri) as websocket:
        command = "G0 X100 Y100"
        await websocket.send(command)
        print(f">>> {command}")
        message = await websocket.recv()
        print(f"<<< {message}")



PS C:\Users\Matthew\scripts> py ./
>>> G0 X100 Y100
<<< {"bitDiameter": 6.35, "9va": 0, "2lw": 2, "qvt": 0, "a_min": 0, "fvv": 0, "0sa": 1.8, "1tc": 1, "8vt": 0, "selected_time": 1699413186.581628, "plan_time": 0, "evv": 0, "0me": true, "3h": true, "1me": true, "3xs": 0, "3max": 44.1325, "3ls": 0, "0zb": 0.9, "6vr": 0, "motor_overload": false, "shunt_overload": false, "v": 0, "3ho": 4, "2tv": 1.997, "0tv": 1.997, "uvv": 0, "fvt": 0, "3tm": 0, "5vv": 0, "2sa": 1.8, "eom": 0, "3lm": 8, "ovt": 0, "pwr_flags": 0, "1tm": 816, "1df": 0, "nvv": 0, "avr": 0, "gvr": 0, "xc": 66, "0xs": 0, "cva": 0, "motor_voltage_sense_error": false, "offset_a": 0, "1om": 0, "kvv": 0, "dva": 0, "3me": true, "metric": true, "1dc": 2.8, "power_shutdown": false, "vf": 0, "0vt": 0, "mvv": 0, "2vm": 10, "1homed": 1.0, "7vv": 0, "3tn": -160, "load1_shutdown": false, "speed": 0, "svr": 0, "5va": 0, "2df": 0, "hvt": 0, "0tr": 16, "kvt": 0, "2om": 0, "fo": 1000, "kva": 0, "5vt": 0, "8va": 0, "1lv": 0.1, "3jm": 1000, "load1": 0.0, "lvr": 0, "mva": 0, "1tn": 0, "qvr": 0, "dvt": 0, "0lv": 0.1, "0sp": 200, "c_max": 0, "1vm": 10, "bp": 0, "3am": 750, "uvt": 0, "2xs": 0, "cp": 0, "2sp": 200, "messages": [], "xp": 0, "svt": 0, "0min": 0.0, "jva": 0, "2xw": 2, "bvr": 0, "kvr": 0, "dos": 2, "imperial": false, "over_current": false, "vva": 0, "offset_b": 0, "4vv": 0, "1sa": 1.8, "pa": 3.133, "3lw": 2, "0lw": 2, "2sv": 1.688, "mvr": 0, "dvr": 0, "offset_z": 0, "max_arc_error": 0.005, "vdd": 0.7, "1am": 750, "2lb": 5, "9vr": 0, "demo": false, "pt": 1, "if": 0.01, "0vr": 0, "yp": 0, "so": 1000, "0h": true, "5vr": 0, "uva": 0, "0mi": 16, "er": "OK", "over_voltage": false, "hb": false, "0tm": 1220, "fos": 2, "2vt": 0, "2mi": 16, "motor": 0.62, "vvv": 0, "0home": 0.0, "sva": 0, "3va": 0, "2lv": 0.1, "1an": 1, "qva": 0, "1tv": 1.997, "hm": 0, "avt": 0, "cvt": 0, "6vt": 0, "ma": 0, "hvv": 0, "1min": 0.0, "1os": 2, "7va": 0, "0lm": 8, "shunt_error": false, "evt": 0, "pvt": 0, "7vr": 0, "0vm": 10, "qvv": 0, "sc": 250, "avv": 0, "pv": 10, "3vt": 0, "1vv": 0, "svv": 0, "3rv": false, "pvr": 0, "2dc": 2.8, "3sa": 1.8, "b_min": 0, "vin": 37.05, "dp": true, "6va": 0, "2os": 2, "evr": 0, "gvt": 0, "fom": 0, "xx": "READY", "vvt": 0, "0ho": 3, "load2_shutdown": false, "uvr": 0, "1lb": 5, "0vv": 0, "2rv": false, "tvr": 0, "0va": 0, "lvv": 0, "rva": 0, "0tn": 0, "2me": true, "cr": 0, "lvt": 0, "c_min": 0, "0sv": 1.688, "sid": "d6fb31a0-f1fd-47bf-8df8-c73f6eb52cc9", "gvv": 0, "1vt": 0, "mw": false, "9vt": 0, "2zb": 1.5, "jvt": 0, "1lm": 8, "1jm": 1000, "1vr": 0, "st": 2, "hid": "363033375539-05-0010-000a", "1rv": false, "2lm": 8, "3tr": 10, "3vr": 0, "pw": 1, "cvr": 0, "2ho": 3, "fa": false, "offset_y": 0, "ava": 0, "lva": 0, "0ls": 0, "2ic": 1, "1va": 0, "4vt": 0, "0tc": 1, "1ic": 1, "2h": false, "a_max": 0, "sx": 24000, "2va": 0, "ovv": 0, "3an": 2, "tos": 2, "jvv": 0, "eoa": false, "et": 1, "nvt": 0, "3df": 0, "toa": false, "0lb": 5, "4va": 0, "load1_sense_error": false, "offset_x": 0, "hx": 400, "doa": false, "nva": 0, "7vt": 0, "3zb": 1, "un": 0, "3tc": 1, "2jm": 1000, "b_max": 0, "gva": 0, "motor_under_voltage": false, "tom": 0, "dvv": 0, "sr": true, "feed": 100.0, "2an": 1, "tva": 0, "2tr": 10, "offset_c": 0, "2tn": 0, "3lb": 5, "2tc": 1, "0max": 409.57853661380545, "2ls": 0, "1zb": 7.184, "pvv": 0, "tvt": 0, "3vm": 7, "sd": 5, "3tv": 1.997, "ovr": 0, "eos": 2, "dom": 0, "8vr": 0, "hi": 1, "3vv": 0, "3sp": 200, "mx": 1, "8vv": 0, "1xw": 2, "hvr": 0, "0homed": 1.0, "1ho": 3, "md": 99.99, "1ls": 0, "0xw": 2, "jvr": 0, "1home": 0.0, "1max": 381.00383496421756, "1oa": false, "0jm": 1000, "vvr": 0, "2homed": false, "nvr": 0, "hq": 3000, "1h": true, "id": 16, "1sv": 1.688, "bvv": 0, "2vr": 0, "load2": 0.0, "ivv": 0, "sm": 6000, "pva": 0, "3lv": 0.1, "selected": "air-handler-base.ngc", "2vv": 0, "pi": false, "3mi": 16, "3homed": 1.0, "4vr": 0, "0am": 750, "0ic": 1, "0an": 0, "3sv": 0.675, "rpi_temp": 52, "ew": 1, "tvv": 0, "fva": 0, "es": false, "rvt": 0, "ap": 0, "3ic": 1, "rvv": 0, "ivr": 0, "3xw": 2, "3dc": 2.8, "1sp": 200, "ivt": 0, "0dc": 2.8, "cycle": "idle", "rvr": 0, "ss": 0, "bvt": 0, "nd": 1, "vdd_current_sense_error": false, "3home": 0.0, "foa": false, "load2_sense_error": false, "6vv": 0, "cvv": 0, "under_voltage": false, "2am": 750, "temp": 28, "mvt": 0, "files": ["air-handler-base.ngc", "filter-base.ngc", "lanterns-8910.ngc", "plugs.ngc"], "dt": 0, "1lw": 2, "line": 1, "zp": 0, "3min": 0.0, "sense_error": false, "1tr": 10, "0rv": false, "pr": "Switch found", "2tm": 816, "tool": 0, "2oa": false, "pwr_version": 6, "s": 0, "eva": 0, "0df": 0, "fvr": 0, "vout": 37.06, "iva": 0, "1mi": 16, "hva": 0, "9vv": 0, "mb": 0, "ova": 0, "bva": 0, "1xs": 0, "motor_current_sense_error": false}
1 Like

FYI, I was playing with this in dotnet,

  • The websockets url to use is ws://onefinity/websocket, where “onefinity” can be the IP
  • Cookie is not needed when using above url

You can listen to the socket to receive machine status (temperature, heartbeat, etc).
Or you can send commands in JSON format.

I am working on a custom app for my pen plotter idea, so will report back if folks are interested.

* The above is true for my OF BB v1.1.1, YMMV


@Matticustard Whoops, I should have asked for clarification. I initially wondered if that’s what you were using the websockets for. But based on the screenshot with the controller Web UI augmented with your macro buttons, I assumed you were automating interaction with the Web UI itself.

I stand corrected - And you are absolutely right, I believe that should give me exactly what I need. Example code very much appreciated.

Thanks for your patience and persistence.

  • Greg

Hey all,

if you have a web interface, as is the case with the buildbotics-based controller, this is always a way to control it. But I don’t like it, I know this from getting online banking software to work when they skipped HBCI support and it was not fun because they changed websites all the time. If I was interested in improving the buildbotics platform, I would dive into the py scripts and trigger the actions directly.