This Repository contains Python examples for DroidPad Android app
git clone https://github.com/umer0586/droidpad-python-examples
pip install -r requirements.txt
cd droidpad-python-examples/servers
-
python websocket-server.py 8080
-
python tcp-server.py 8081
-
python udp-server.py 8082
- On Windows, use the
ipconfig
command. - On Linux, use the
ifconfig
command.
Create a new controller in DroidPad. Then, navigate to the connection settings and specify the IP address and port number. Once connected, and you should see JSON messages being printed in the console.
DroidPad functions as a BLE peripheral and sends notifications containing CSV
strings to connected client through the characteristic UUID: dc3f5274-33ba-48de-8246-43bf8985b323
.
-
Start the GATT Server on DroidPad:
- Open a control pad with BLE connection and tap the Play button to initialize the GATT server and start advertising.
-
Subscribe Using the Python Client:
-
Navigate to the
BLEClient
directory in the DroidPad Python examples repository. -
Run the
subscribe.py
script:python subscribe.py
-
This script performs the following:
- Scans for nearby BLE devices advertising the service UUID:
4fbfc1d7-f509-44ab-afe1-62ea40a4b111
. - Subscribes to notifications from the characteristic UUID:
dc3f5274-33ba-48de-8246-43bf8985b323
.
- Scans for nearby BLE devices advertising the service UUID:
-
-
View Notifications:
- Once the script connects to DroidPad, it displays
CSV
strings in the console. - These notifications are triggered by interactions with items on the control pad.
- Once the script connects to DroidPad, it displays
Configurable Server (by imsamuka)
This server is configured with a TOML file, and supports multiple TCP/UDP droidpad servers simultaneosly. Theres's a documented default config file to use as a reference. There are other examples in the configServer folder.
# Enter configServer directory
cd configServer
python config-server.py [CONFIG_FILE]
# Examples:
python config-server.py default.toml
python config-server.py linux/mouse-x11.toml
The configuration is always composed of a [pad_name]
and [pad_name.rules]
. You can have more than one pad per file, but each one has to have these 2 sections.
In [pad_name]
you declare the global configuration for this particular pad:
[example]
host = "0.0.0.0"
port = 8080
type = "UDP"
default_eval = "sh"
call_sync = "threaded_async"
fstring_sim = true
format_map = true
The meaning of each field is explained in the default configuration file. It's recommended for Windows users to change default_eval
to py
, cmd
or powershell
.
In [pad_name.rules]
you declare all rules about the pad elements themselves.
[example.rules]
ctl_id-dp_press = "echo {id} {button} pressed"
ctl_id-dp_release = "echo {id} {button} released"
ctl_id-dp_click = "echo {id} {button} clicked"
Each rule field is composed of three parts separated by a -
character, and a command or list of commands:
ELEMENTID-RULETYPE-EVALTYPE = "COMMAND"
ELEMENTID-RULETYPE-EVALTYPE = ["COMMAND_1", "COMMAND_2"]
ELEMENTID-RULETYPE-EVALTYPE = """
MULTILINE_COMMAND
"""
-
ELEMENTID
: Is the ID you configure in the DroidPad App for a control element. -
RULETYPE
: Determines the type of element and when the rule will activate. The possible choices for this part can be found in the default configuration file. -
EVALTYPE
: Determines which program will be used to executeCOMMAND
. For example:-bash
will runbash -c "COMMAND"
-py
will runpython -c "COMMAND"
If
-EVALTYPE
is missing, then the eval type declared in thedefault_eval
configuration field is used instead. -
COMMAND
: How it will be interpreted depends on the eval type.- If
format_map = true
, substrings like{id} {type} {state} {button}
will be substituited by their values in the event received. For example, if a dpad left button was pressed,{button}
will be substituited byLEFT
and{state}
byPRESS
. Normal python formatting works, for example in a slider with value0.9
,{value:%}
will be90%
. - If
fstring_sim = true
, substrings inside__{ }__
will be interpreted like a python f-string. This means you can run python code BEFORE the actual command runs. All event fields are in scope, and a dictionarymemo
may be used to store other variables. - In the case of eval type
exec
, it expects a list of arguments instead of a single string, for example["echo", "Element {id} sent a event"]
. If you want multiple commands, you need to use a list inside a list.
- If
# After tapping a button with id 'turnoff'
# run the command: sh -c shutdown
turnoff-click-sh = "shutdown"
# After pressing/release button with id `mousebtn1`
# run the program 'xdotool' with default_eval
# to press/release the mouse left button
mousebtn1-press = "xdotool mousedown 1"
mousebtn1-release = "xdotool mouseup 1"
# The same as above, using __{}__ substitution
# uses `fstring_sim = true`
mousebtn1-button = "xdotool mouse__{'down' if state == 'PRESS' else 'up'}__ 1"
# When a joystick with id 'radius' sends a event
# Run a python script to print the calculated radius in degrees
radius-joy-py = """
import math
x = {x} # <-- uses `format_map = true` here
y = {y}
print('Radius: ', math.atan2(y, x) * 180.0 / math.pi)
"""
# Change the volume of the current media using a slider with id 'volume'
# Echo the current volume as a percentage
# uses `format_map = true`
volume-slider-sh = 'playerctl volume {value}; echo "Volume at {value:%}"'
# Convert every button press on a dpad with id 'arrows' to keyboard arrows
# __{button.title()}__ converts "RIGHT" to "Right"
arrows-dp_button = "xdotool key__{'down' if state == 'PRESS' else 'up'}__ __{button.title()}__"