Maslow Home Maslow Community Garden Newsletter

Python developers: practical implementation of web server in ground control

#1

One thing I thought would be handy is to be able to use my smartphone to control certain screens on ground control… a good example is the “set sprockets vertical” screen. Right now, I carry my wireless mouse over to the particular motor and try to move the mouse over buttons of a 20-inch monitor over 10 feet away. It’s challenging. So I was wondering if we could add a web server to process requests from a web browser (running on my phone or tablet) and activate the same functions that the actual kivy buttons call. I’m not a python web developer by any means, but with a little guidance I might be able to figure it out. Any suggestions on how to approach this?

2 Likes
#2

I would check out Flask. It’s a very lightweight web framework.

#3

This is similar to the software on the Shapeoko. It spins up a server and serves a page to control things. The problem is if something else is serving a server in the same port the conflict throws errors and shuts the program down. On the other hand I’ve requested this before they also bind keyboard keys to the buttons. So a cheap 10 key key pad can run everything form 30 ft away.

My 2 cents

Thank you

#4

A terrible idea that sounds kinda fun: if we expose some features via http endpoints it should be pretty easy to hook up Alexa or Siri (maybe via Home Assistant). Then you could yell things at your Maslow and it would do them. Again this is probably a bad idea

4 Likes
#5

I did actually get a framework working… don’t like it, but it’s simple. I’m not a web developer but I think if I keep the page simple, I imagine it will do the job. Each button does a submit and the server calls a function and then returns the same webpage. I don’t know how to wire it up differently.

It’s in my repo under webserver branch

3 Likes
#6

Dam you John!

Now I have a vision of Rube Goldberging the Maslow to hold a bottle of Bourbon with a long rubber strip to act as a sliding “cork” and a tilt hinge once it’s free of the cork to pour into a High ball glass.

Alexa - Have Maslow pour me a drink!

Thanks a lot - I’m going to be engineering it in my sleep.

5 Likes
#7

I managed to put together a decent proof of concept and it’s not all that embarrassing. I didn’t want to use jquery so I did everything I needed in plain javascript. I did ultimately manage to incorporate external stylesheets and javascript files and put the content into html files (hey, it’s my first web server so cut me some slack). The only page really working is the front page and that only has the “Home” button on it.

Basically (and simply), the main app keeps track of what widget is on the screen and when you go to the webpage (e.g., 127.0.0.1:8000), the web handler queries the app for the current widget and then serves the correct page for that widget. When you push a button, it does a XMLHTTPRequest and sends the widget name and command name. The web handler then does a lookup in a dictionary and has the widget initiate that command.

I did incorporate a safety feature so that the buttons are disabled when you load the webpage. You have to hold enable for 1 second and then the buttons become enabled for up to 10 seconds. If you doubleclick enable, the buttons stay enabled until you refresh the page. I did this because sometimes when a butterfly flaps its wings in China, it makes my phone dial people. I didn’t want it to hit stop or do a move unless I told it specifically to do it.

It’s on my github repo under the webserver branch.

2 Likes
#8

I should mention that the branch is based off the optical calibration branch which includes lots of changes to groundcontrol and firmware. So, don’t download it and expect it to work with the current firmware.

1 Like
#9

Screenshot from my Pixel XL… AwesomeFonts doesn’t have icons for the diagonal arrows… so these will have to do.

5 Likes
#10

Oh wow this looks great! Neat that it serves the correct page based on which widget is available. Do you want to split this out into a separate change set that could be merged independently of the Optical Calibration stuff? We could potentially get this in before optical calibration stuff is baked

2 Likes
#11

I was thinking about that and it’s probably a good idea. There’s really nothing affected in the current code other than main.py … and that change is minor… everything else is stuck in the WebService directory.

1 Like
#12

I’m happy to turn that into a separate PR sometime this weekend. Is it in a place you think it’s good to go?

2 Likes
#13

Probably this weekend it will… I’m still wiring up the buttons and I want to do the Z-Axis still. I need to tweak actions on the phone/tablet vs. computer. I was wanting to use a long-press on the enable button and I used onmousedown and onmouseup with a timer to make it work (thanks stackoverflow) but the mobile browser I guess use onpointerdown and onpointerup and even though I switched it, it seems a bit flaky.

I wanted to keep it fairly light so I didn’t use bootstrap/jquery etc. where I could have maybe used a different control. I tried “Bulma” as a css framework and it seems to make things look pretty and responsive, but it’s just styling.

And thanks for the help offer… I’ll definitely take you up on it :slight_smile:

#14

You’re welcome! Just let me know when you feel good about it. And try your best to keep commits for the web stuff separate from commits for the optical calibration. I can pull it all out into a separate branch when you feel like it’s ready

1 Like
#15

I see some odd behavior from this. When I click the button on the front page to open the Z-Axis popup, it pops up with no problem. However, when I send the command from the web handler to the front page class to issue the exact same command the button does, it opens but I get some errors about gridlayout objects having no cols or rows set and layout not being triggered. The screen that comes up in gc sometimes looks good, but other times some of the buttons are all white. Everything “works”, it’s just that the kivy screen can get messed up unless it’s called via a kivy button.

Edit: little more info. The first time you open the zaxis popup from the web handler, the screen will have some white buttons and you’ll get the error messages in the console. But the next time, and any subsequent times, it will appear correctly on the screen… but you always get the error messages:

[WARNING] <kivy.uix.gridlayout.GridLayout object at 0x10B9AE68> have no cols or rows set, layout is not triggered.
[WARNING] <kivy.uix.gridlayout.GridLayout object at 0x10BA57D8> have no cols or rows set, layout is not triggered.
[WARNING] <kivy.uix.gridlayout.GridLayout object at 0x10BA57D8> have no cols or rows set, layout is not triggered.
[WARNING] <kivy.uix.gridlayout.GridLayout object at 0x10BA57D8> have no cols or rows set, layout is not triggered.
[WARNING] <kivy.uix.gridlayout.GridLayout object at 0x10BA57D8> have no cols or rows set, layout is not triggered.
[WARNING] <kivy.uix.gridlayout.GridLayout object at 0x10C2FF80> have no cols or rows set, layout is not triggered.
[WARNING] <kivy.uix.gridlayout.GridLayout object at 0x10BA57D8> have no cols or rows set, layout is not triggered.
[WARNING] <kivy.uix.gridlayout.GridLayout object at 0x10C47D88> have no cols or rows set, layout is not triggered.
[WARNING] <kivy.uix.gridlayout.GridLayout object at 0x10BA57D8> have no cols or rows set, layout is not triggered.
[WARNING] <kivy.uix.gridlayout.GridLayout object at 0x10C47D88> have no cols or rows set, layout is not triggered.
[WARNING] <kivy.uix.gridlayout.GridLayout object at 0x10BA57D8> have no cols or rows set, layout is not triggered.
[WARNING] <kivy.uix.gridlayout.GridLayout object at 0x10C65B90> have no cols or rows set, layout is not triggered.
[WARNING] <kivy.uix.gridlayout.GridLayout object at 0x10BA57D8> have no cols or rows set, layout is not triggered.
[WARNING] <kivy.uix.gridlayout.GridLayout object at 0x10C65B90> have no cols or rows set, layout is not triggered.
[WARNING] <kivy.uix.gridlayout.GridLayout object at 0x10BA57D8> have no cols or rows set, layout is not triggered.
[WARNING] <kivy.uix.gridlayout.GridLayout object at 0x10C81688> have no cols or rows set, layout is not triggered.
[WARNING] <kivy.uix.gridlayout.GridLayout object at 0x10B9AE68> have no cols or rows set, layout is not triggered.

#16

And more information… apparently the only appearance problem is that the background color of some of the buttons come out white instead of the dark gray. The text is still being produced, but since it defaults to white, you can’t read it… I changed “Done” to blue in the picture below. Either I’m doing something wrong, or its a kivy bug.

#17

Hmm I wonder if there’s some kind of ‘draw’ or ‘update’ or ‘layout’ method that needs to get called when triggering these things manually.

#18

The way I’m looking at it is that if you push the button on your phone/tablet to bring up a particular screen, then what it looks like on the computer screen isn’t that big of a deal. But it seems that if you bring up any screen manually first, then things render ok from that point on… for instance, if you click actions and then close it, you are good to go (even though those error messages print to the console).

This has turned into a bit of work but I think I’ve managed through it. Trying to wire-in a web function to a kivy app is probably never been done before (at least no one has asked about it on stackoverflow that I can find). I wonder if maybe the whole interface should migrate from kivy over to a web interface. It certainly would make this easier, allow for headless operation, and could all be migrated to a small device like a raspberry pi. Something to ponder.

1 Like
#19

I had to reset my chains last night and it was so much “less unenjoyable” using my cell phone to control the motors. I’m going to make a few tweaks. This layout was off on my phone (the buttons were too big). I’m also going to change the timer to reset after every time you press a button. So once you enable it, you get 10 seconds to press a button when you do, it resets the timer back to 10 seconds… Having the timer disable the interface I think is a nice safety feature as I had to concerns about sliding the phone in my pocket.

2 Likes
#20

So are you thinking this is ready to be turned into a pull request? I can probably find some time to do it later this week, just let me know when it’s ready!

2 Likes