Merge pull request #42 from triveria/add-bluetooth-readout
Add bluetooth readout
This commit is contained in:
11
70-ps5-controller.rules
Normal file
11
70-ps5-controller.rules
Normal file
@@ -0,0 +1,11 @@
|
||||
# ref.: https://boilingsteam.com/the-dualsense-is-making-even-more-sense/
|
||||
# copy this file to /etc/udev/rules.d
|
||||
# reload udev rules with:
|
||||
# udevadm control --reload-rules
|
||||
# udevadm trigger
|
||||
|
||||
# PS5 DualSense controller over USB hidraw
|
||||
KERNEL=="hidraw*", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0ce6", MODE="0660", TAG+="uaccess"
|
||||
|
||||
# PS5 DualSense controller over bluetooth hidraw
|
||||
KERNEL=="hidraw*", KERNELS=="*054C:0CE6*", MODE="0660", TAG+="uaccess"
|
10
README.md
10
README.md
@@ -17,7 +17,15 @@ pip install --upgrade pydualsense
|
||||
|
||||
## Linux
|
||||
|
||||
On Linux based system you first need to install the hidapi through your package manager of your system.
|
||||
On Linux based system you first need to add a udev rule to let the user access the PS5 controller without requiring root privileges.
|
||||
|
||||
```bash
|
||||
sudo cp 70-ps5-controller.rules /etc/udev/rules.d
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger
|
||||
```
|
||||
|
||||
Then install the hidapi through your package manager of your system.
|
||||
|
||||
On an Ubuntu system the package ```libhidapi-dev``` is required.
|
||||
|
||||
|
53
examples/read_all_input_channels.py
Normal file
53
examples/read_all_input_channels.py
Normal file
@@ -0,0 +1,53 @@
|
||||
import curses
|
||||
import time
|
||||
from pydualsense import *
|
||||
|
||||
|
||||
def print_states(stdscr):
|
||||
curses.curs_set(0)
|
||||
curses.use_default_colors()
|
||||
stdscr.nodelay(1)
|
||||
while True:
|
||||
stdscr.erase()
|
||||
pretty_states = [f"{state:03}" for state in dualsense.states]
|
||||
|
||||
stdscr.addstr(f"epoch: {time.time():.2f}\n")
|
||||
stdscr.addstr(f"states[0:10]: {pretty_states[0:10]}\n")
|
||||
stdscr.addstr(f"states[10:20]: {pretty_states[10:20]}\n")
|
||||
stdscr.addstr(f"states[20:30]: {pretty_states[20:30]}\n")
|
||||
stdscr.addstr(f"states[30:40]: {pretty_states[30:40]}\n")
|
||||
stdscr.addstr(f"states[40:50]: {pretty_states[40:50]}\n")
|
||||
stdscr.addstr(f"states[50:60]: {pretty_states[50:60]}\n")
|
||||
stdscr.addstr(f"states[60:70]: {pretty_states[60:70]}\n")
|
||||
stdscr.addstr(f"states[70:78]: {pretty_states[70:78]}\n")
|
||||
stdscr.addstr("\n")
|
||||
stdscr.addstr(f"square: {dualsense.state.square!s:>5} \t triangle: {dualsense.state.triangle!s:>5} \t circle: {dualsense.state.circle!s:>5} \t cross: {dualsense.state.cross!s:>5}\n")
|
||||
stdscr.addstr(f"DpadUp: {dualsense.state.DpadUp!s:>5} \t DpadDown: {dualsense.state.DpadDown!s:>5} \t DpadLeft: {dualsense.state.DpadLeft!s:>5} \t DpadRight: {dualsense.state.DpadRight!s:>5}\n")
|
||||
stdscr.addstr(f"L1: {dualsense.state.L1!s:>5} \t L2: {dualsense.state.L2:3} \t L2Btn: {dualsense.state.L2Btn!s:>5} \t L3: {dualsense.state.L3!s:>5} \t R1: {dualsense.state.R1!s:>5} \t R2: {dualsense.state.R2:3d} \t R2Btn: {dualsense.state.R2Btn!s:>5} \t R3: {dualsense.state.R3!s:>5}\n")
|
||||
stdscr.addstr(f"share: {dualsense.state.share!s:>5} \t options: {dualsense.state.options!s:>5} \t ps: {dualsense.state.ps!s:>5} \t touch1: {dualsense.state.touch1!s:>5} \t touch2: {dualsense.state.touch2!s:>5} \t touchBtn: {dualsense.state.touchBtn!s:>5} \t touchRight: {dualsense.state.touchRight!s:>5} \t touchLeft: {dualsense.state.touchLeft!s:>5}\n")
|
||||
stdscr.addstr(f"touchFinger1: {dualsense.state.touchFinger1} \t touchFinger2: {dualsense.state.touchFinger2}\n")
|
||||
stdscr.addstr(f"micBtn: {dualsense.state.micBtn!s:>5}\n")
|
||||
stdscr.addstr(f"RX: {dualsense.state.RX:4} \t RY: {dualsense.state.RY:4} \t LX: {dualsense.state.LX:4} \t LY: {dualsense.state.LY:4}\n")
|
||||
stdscr.addstr(f"trackPadTouch0: ID: {dualsense.state.trackPadTouch0.ID} \t isActive: {dualsense.state.trackPadTouch0.isActive!s:>5} \t X: {dualsense.state.trackPadTouch0.X:4d} \t Y: {dualsense.state.trackPadTouch0.Y:4d}\n")
|
||||
stdscr.addstr(f"trackPadTouch1: ID: {dualsense.state.trackPadTouch1.ID} \t isActive: {dualsense.state.trackPadTouch1.isActive!s:>5} \t X: {dualsense.state.trackPadTouch1.X:4d} \t Y: {dualsense.state.trackPadTouch1.Y:4d}\n")
|
||||
stdscr.addstr(f"gyro: roll: {dualsense.state.gyro.Roll:6} \t pitch: {dualsense.state.gyro.Pitch:6} \t yaw: {dualsense.state.gyro.Yaw:6}\n")
|
||||
stdscr.addstr(f"acc: X: {dualsense.state.accelerometer.X:6} \t Y: {dualsense.state.accelerometer.Y:6} \t Z: {dualsense.state.accelerometer.Z:6}\n")
|
||||
stdscr.addstr("\n")
|
||||
stdscr.addstr("Exit script with 'q'\n")
|
||||
|
||||
stdscr.refresh()
|
||||
if stdscr.getch() == ord('q'):
|
||||
break
|
||||
|
||||
|
||||
dualsense = pydualsense()
|
||||
dualsense.init()
|
||||
|
||||
while dualsense.states is None:
|
||||
print("Waiting until connection is established...")
|
||||
print(f"epoch: {time.time():.0f}")
|
||||
time.sleep(0.5)
|
||||
|
||||
|
||||
curses.wrapper(print_states)
|
||||
dualsense.close()
|
@@ -98,33 +98,34 @@ class pydualsense:
|
||||
self.triggerL = DSTrigger() # left trigger
|
||||
self.triggerR = DSTrigger() # right trigger
|
||||
self.state = DSState() # controller states
|
||||
|
||||
if platform.startswith('Windows'):
|
||||
self.conType = self.determineConnectionType() # determine USB or BT connection
|
||||
else:
|
||||
# set for usb manually
|
||||
self.input_report_length = 64
|
||||
self.output_report_length = 64
|
||||
|
||||
self.conType = self.determineConnectionType() # determine USB or BT connection
|
||||
self.ds_thread = True
|
||||
self.report_thread = threading.Thread(target=self.sendReport)
|
||||
self.report_thread.start()
|
||||
self.states = None
|
||||
|
||||
def determineConnectionType(self) -> ConnectionType:
|
||||
"""
|
||||
Determine the connection type of the controller. eg USB or BT.
|
||||
|
||||
Currently only USB is supported.
|
||||
We ask the controller for an input report with a length up to 100 bytes
|
||||
and afterwords check the lenght of the received input report.
|
||||
The connection type determines the length of the report.
|
||||
|
||||
This way of determining is not pretty but it works..
|
||||
|
||||
Returns:
|
||||
ConnectionType: Detected connection type of the controller.
|
||||
"""
|
||||
|
||||
if self.device._device.input_report_length == 64:
|
||||
dummy_report = self.device.read(100)
|
||||
input_report_length = len(dummy_report)
|
||||
|
||||
if input_report_length == 64:
|
||||
self.input_report_length = 64
|
||||
self.output_report_length = 64
|
||||
return ConnectionType.USB
|
||||
elif self.device._device.input_report_length == 78:
|
||||
elif input_report_length == 78:
|
||||
self.input_report_length = 78
|
||||
self.output_report_length = 78
|
||||
return ConnectionType.BT
|
||||
@@ -228,7 +229,15 @@ class pydualsense:
|
||||
Args:
|
||||
inReport (bytearray): read bytearray containing the state of the whole controller
|
||||
"""
|
||||
states = list(inReport) # convert bytes to list
|
||||
if self.conType == ConnectionType.BT:
|
||||
# the reports for BT and USB are structured the same,
|
||||
# but there is one more byte at the start of the bluetooth report.
|
||||
# We drop that byte, so that the format matches up again.
|
||||
states = list(inReport)[1:] # convert bytes to list
|
||||
else: # USB
|
||||
states = list(inReport) # convert bytes to list
|
||||
|
||||
self.states = states
|
||||
# states 0 is always 1
|
||||
self.state.LX = states[1] - 127
|
||||
self.state.LY = states[2] - 127
|
||||
|
Reference in New Issue
Block a user