-
Notifications
You must be signed in to change notification settings - Fork 60
Add WebUI #300
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Add WebUI #300
Conversation
|
we can't PR binary zip blobs, and PRs should not be placeholders. you should PR when you have something ready for actual review. |
|
Mistake? |
|
IMO it's OK for PRs to be placeholders for early review -- that's fine and useful for architectural commentary early, as well as filing issues to describe what you plan to implement -- but absolutely not binary zip blobs |
Yah, sorry about that. I just wanted to have something to start the pr. I have added the necessary files for it to run to this pr, and will hopefully add a x1plusd command to start/stop it, and a maybe a UI to enable/disable it. |
jwise
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am excited by the idea of a web UI!
Broadly, this needs a lot more work to fit into the X1Plus world. I left a bunch of comments for where I'd like to see it go. Maybe a good first start would be to put up a PR that integrates an aiohttpd into x1plusd (controlled by x1plus.settings), which just served a novnc? That seems like the simplest possible thing that woudl be making positive architectural steps, and we can do one thing at a time there -- then we can iterate on adding WebHMI features from there.
| # Script to be executed: | ||
| DAEMON="python3 /usr/etc/system/webhmi/little_webhmi.py" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WebHMI needs to be part of x1plusd, not running in the background as its own python service
| function set_heatbed_temp() { | ||
| temp=$1 | ||
| json="{ \ | ||
| \"print\":{\"command\":\"gcode_line\", \"sequence_id\":\"2002\", \"param\":\"M140 S$temp\"} \ | ||
| }" | ||
| mqtt_pub "$json" | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use x1plus.client commands to do this? Or pull in a MQTT client into x1plusd (I think @jphannifan was talking about an asyncio wrapper for paho)? I would like to avoid spawning shell scripts to the degree possible -- it seems like most of this stuff should really live in the x1plus.client library.
| import os | ||
|
|
||
| # Print the current working directory for debugging | ||
| print("Current working directory:", os.getcwd()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NB: X1Plus packages live in the /opt/x1plus/lib/python/ directory. So this probably should be x1plus.services.x1plusd.webhmi or something.
| async def update_current_job(): | ||
| global current_job_name | ||
| while True: | ||
| try: | ||
| with open('/userdata/print_ctx.json', 'r') as file: | ||
| data = json.load(file) | ||
| subtask_name = data['subtask_name'] | ||
| current_job_name = subtask_name | ||
| except Exception as e: | ||
| print(f"Error reading or parsing JSON file: {e}") | ||
| await asyncio.sleep(10) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we get these data either from DBus or MQTT instead of having to poll? Are these data broadcast on DBus as a signal?
| async def home_xyz_func(request): | ||
| global latest_message | ||
| subprocess.run(["/usr/bin/home_xyz.sh"], shell=False) | ||
| latest_message = 'Home XYZ' | ||
| raise web.HTTPFound('/') | ||
|
|
||
| async def preheat_100c(request): | ||
| global latest_message | ||
| subprocess.run(["/usr/bin/heatbed_set.sh", "-s", "100"], shell=False) | ||
| latest_message = 'Preheat Activated - 100c' | ||
| raise web.HTTPFound('/') | ||
|
|
||
| async def preheat_0c(request): | ||
| global latest_message | ||
| subprocess.run(["/usr/bin/heatbed_set.sh", "-s", "0"], shell=False) | ||
| latest_message = 'Preheat Deactivated' | ||
| raise web.HTTPFound('/') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing I am thinking about is that I would rather have a generic interface to the printer -- with logic run in a SPA in the browser -- than having one HTTP endpoint for each of a million little things. I was thinking that the generic interface to the printer really wanted to be a WebSocket with generic interfaces like 'submit Gcode', or 'submit MQTT request', or 'execute DBus RPC', with all the smarts on the client side.
| async def start_bbl_screen_vnc(request): | ||
| global latest_message | ||
| try: | ||
| latest_message = 'VNC Started' | ||
| subprocess.run(["/usr/bin/start_bbl_screen_vnc.sh"], shell=True, timeout=3) | ||
| except subprocess.TimeoutExpired: | ||
| latest_message = 'VNC Started' | ||
| raise web.HTTPFound('/') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is not correct for running vnc now
| if __name__ == '__main__': | ||
| web.run_app(app, host='0.0.0.0', port=5001) No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this needs to be configured by x1plus.settings
| # Start the background thread for updating the current job | ||
| threading.Thread(target=lambda: asyncio.run(update_current_job()), daemon=True).start() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this a Thread, not an asyncio task?
| var img = document.getElementById('modelImage'); | ||
| img.src = '/current_model_image?' + new Date().getTime(); | ||
| } | ||
| setInterval(refreshModelImage, 180000); // Refresh every 180000 milliseconds (3 minutes) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah this is a primo example of why one might want to use a websocket to push updates :)
|
|
||
| app.router.add_get('/', printer_hmi) | ||
| app.router.add_post('/home_xyz_func', home_xyz_func) | ||
| app.router.add_post('/preheat_100c', preheat_100c) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a very scary endpoint to have on the network with absolutely no authentication
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a very scary endpoint to have on the network with absolutely no authentication
Something that could be set to disabled by default and enabled by those on secure networks. I understand the concern, but for many (like myself) this would be a non-issue.
This will be the pr for webUI that @christophergault198 and I are making. I will be changing/adding/removing lots of stuff within the next couple of days. We are hoping to have a pr ready by Sunday or Monday at the latest. This will hopefully have a x1plusd command built in for starting/stopping, and we will try to use aiohttp instead of flask @jwise.