Klipper remote pendant attempt. need some help with a few particulars

WARNING: not YBR.

tldr: Q1 can you help me fix my service so it will start automagically and actually work. Q2, should I be threading this or somehow triggering on a request to pair from the wii rather than using a button to initiate pairing with the bluetooth device?

So with all the discussion on the pendant for the jackpot, I have managed to sort of make one for my klipper setup. Currently it is very difficult to use and clunky to get started, but from the pendant, I can run macros in klipper and potentially have it basically do anything a macro can do in klipper which is anything… but one thing at a time. I had a similar setup on my maslow with a wii remote and it worked awesome until the wii controller just died one day. Fast forward and I can pick them up off ebay for like $7 now, so lets just say there might be a few spares.

The layout:

klipper runs on raspberry pi 3B+. The pi is set up as an mcu so that exposes the GPIO on the board for input and indication output. Ive put in macro cfg files for an ssd1306 oled and for a 3d printed custom staples EZ button that starts the connect process


the wii shows up in bluetoothctl on the zero as Device 00:19:1D:CB:71:09 Nintendo RVL-CNT-01. If you try this, be sure when you type in the pair with the mac address command to press the red sync button on the remote and it won’t ask for a password, it will just work.

To start the connect process, the macro in klipper does a curl http post command to the nearby raspberry pi zero. The raspberry pi zero is running a python flask server on port 5000 that accepts the post and indicates its status with a tricolor LED.

what you are seeing is the crowsnest camera mounted over my LR4 which I filmed from another room - but before you go all fireman on my post, I’m not running the spindle from the other room, just testing colors from the couch. the LED program and wii pairing were done manually from 2 ssh terminals. one for LED and one for sending the curl command:

curl -X POST -H “Content-Type: application/json” -d ‘{“red”: 0, “green”: 1, “blue”: 0}’ http://localhost:5000/enable_pendant
and waited for the pairing that sometimes takes a few seconds. All commands are 2 button sequences to avoid accidentally triggering something stupid. A+direction, B+ direction, etc… the +/- change the battery light and serve as a distance option for movement small, med, largee, etc.)
It works by activatingthe bluetooth on a second raspberry pi (zero) because bluetooth on the main pi3 running klipper is not allowed due to interferes with the real-time process timing or something like that. So once bluetooth turns on and assuming you pressed the wii-mote buttons to turn it on, then it will pair and give a rumble to let you know it is ready and the battery light will go to #3. Pressing button sequences on the wii remote will call an http post request to klipper using the json script option then run the macro or gcode or if via json-rpc, get position or whatever info from it (lots of info in the klipper docs).

I have a couple other plans that aren’t yet working:

  1. the .91” oled via I2C connected to the rpi mcu (with klipper) is supposed to be showing real time updates of xyz positions via an update macro. the first oled was broken and I think the second one is too. (may have to go with a 2x16 character display or something similar…) This is a tiny screen that would sit on the core as an indicator for initial positioning with the pendant.

  2. when certain commands are sent from the pendant, the led will change color or pulse or blink. This works partially, but all of the commands are not yet input and colors have not yet been assigned.

  3. If I can get this connection thing ironed out, It might be worthwhile to move to a switch pro controller or an xbox wireless…

The issues: it has been challenging to get the right program structure to make this all work in a seamless simple way. On the zero, I’m using the python cwiid library and it connects to bluetooth when you instantiate the controller object, so I have that run as a subprocess from the led code that I’m trying to run as a service on the zero. If I manually start the led code, it works.


When I can send the curl command from the zero locally or from the klipper macro button and it will start the wii subprocess and pair with the remote. Whenever I try to run the same code from a service at boot, it fails.

Aug 30 23:46:34 pendant (EZled.sh)[630]: EZled.service: Failed at step EXEC spawning /home/pi/wp/EZled.sh: Exec format error
Aug 30 23:46:34 pendant systemd[1]: Started EZled.service - EZ LED daemon.
Aug 30 23:46:34 pendant systemd[1]: EZled.service: Main process exited, code=exited, status=203/EXEC
Aug 30 23:46:34 pendant systemd[1]: EZled.service: Failed with result 'exit-code'.

here are my EZled config files for the linux service. It won’t run if it isn’t root. The sh files are set with correct permissions (777) and then some so that shouldn’t be the issue.

pi@pendant$ ls EZl*

EZled.py  EZled-restart.sh  EZled.service  EZled.sh  EZled-start.sh  EZled-stop.sh

pi@pendant$ cat EZled.sh

#!/bin/bash

/usr/bin/python3 /home/pi/wp/EZled.py

pi@pendant$ cat EZled.service

[Unit] 
Description=EZ LED daemon 
After=network.target

[Service] 
Type=forking 
ExecStart=/home/pi/wp/EZled.sh 
WorkingDirectory=/home/pi/wp
StandardOutput=tty 
TTYPath=/dev/tty1
Restart=always 
user=root

[Install]
WantedBy=sysinit.target

I’m not ready to share the actual led code, but I have a more structural question as well:

Would it be better to run the LED flask server and the cwiid bluetooth connection as separate threads spawned from the same program? AI has been helping me see what that could potentially look like. The issue is I can’t leave the bluetooth on because without a controller, the object doesn’t work, so you have to create it when the controller is around…
The reason a thread seems better has to do with the macro from klipper. When the macro sends a curl http post command to the zero, klipper halts and waits for the bluetooth connection to finish before it will respond again and this can be minutes. If the pendant was running as a thread, a variable flag could be set and the flask server could return with a code and klipper won’t care anymore.

any thoughts or help would be appreciated. I have only recently had a few minutes in the evening to try a few things, so it moves slowly, but could be fun to get it working well.

Edited service file with suggestions from below

3 Likes

This should be #!/bin/bash. It doesn’t know to run this .sh in bash. When you run from the terminal, you are running it in a shell, which is bash.

Threading is a complex question. Ideally, yes, thing that are orthogonal should be running asynchronously. As for what to do when the BT controller isn’t there, is there a way to ask cwiid if the controller is there and just poll (in a thread) for the controller?

1 Like

+1 for the shebang. That was part of it. The other part was the restart specified in the .service file. has to be “no” or “always” or one of the allowed states, but “never” doesn’t work. the journal and status now say running, but the curl connection is rejected, so closer, but not quite there.

after some iteration, I got the code all put in one program.

The base code is a flask server starts a thread that idles (rather than a subprocess) until a pair command is given and then it instantiates the wii object and can connect with the remote and communicate with klipper. Was simpler than I anticipated… just moved the subprocess code to the thread code. This solves the klipper or post pairing delay. Still need to figure out the auto pairing.

2 Likes

Button on klipper pi works
Service on pi zero works
Remote pairs
Remote runs klipper macros
Remote can be disabled and service continues to run for the process to repeat

Now to verify and test all features…

3 Likes