diff --git a/README.md b/README.md index 8070517..4c4f4d7 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # pydualsense -control your dualsense through python. using the hid library this module implements the sending report for controlling you new PS5 controller. It creates a background thread to constantly update the controller. +control your dualsense through python. using the hid library this module implements the sending report for controlling you new PS5 controller. It creates a background thread to constantly receive and update the controller. # install diff --git a/examples/leds.py b/examples/leds.py new file mode 100644 index 0000000..285c0e5 --- /dev/null +++ b/examples/leds.py @@ -0,0 +1,15 @@ +from pydualsense import * + +# get dualsense instance +dualsense = pydualsense() +# set color around touchpad to red +dualsense.setColor(0,0,255) +# enable microphone indicator +dualsense.setMicrophoneLED(1) +# set all player indicators on +dualsense.setPlayer(PlayerID.all) +# sleep a little to see the result on the controller +# this is not needed in normal usage +import time; time.sleep(2) +# terminate the thread for message and close the device +dualsense.close() \ No newline at end of file diff --git a/examples/trigger_effects.py b/examples/trigger_effects.py new file mode 100644 index 0000000..72c06b4 --- /dev/null +++ b/examples/trigger_effects.py @@ -0,0 +1,12 @@ +from pydualsense import * + +# get dualsense instance +dualsense = pydualsense() +# set left trigger mode to rigid and put some force values on it +dualsense.setLeftTriggerMode(TriggerModes.Rigid) +dualsense.setLeftTriggerForce(1, 255) +# sleep a little to see the result on the controller +# this is not needed in normal usage +import time; time.sleep(2) +# terminate the thread for message and close the device +dualsense.close() \ No newline at end of file diff --git a/pydualsense/enums.py b/pydualsense/enums.py index eecc75d..060a692 100644 --- a/pydualsense/enums.py +++ b/pydualsense/enums.py @@ -1,6 +1,6 @@ from enum import IntFlag -class LedOptions(IntFlag): +class LedOptions(IntFlag): Off=0x0, PlayerLedBrightness=0x1, UninterrumpableLed=0x2, @@ -25,12 +25,12 @@ class PlayerID(IntFlag): all = 31 class TriggerModes(IntFlag): - Off =0x0, # no resistance - Rigid =0x1, # continous resistance - Pulse =0x2, # section resistance - Rigid_A=0x1 | 0x20, - Rigid_B=0x1 | 0x04, - Rigid_AB=0x1 | 0x20 | 0x04, + Off = 0x0, # no resistance + Rigid = 0x1, # continous resistance + Pulse = 0x2, # section resistance + Rigid_A = 0x1 | 0x20, + Rigid_B = 0x1 | 0x04, + Rigid_AB = 0x1 | 0x20 | 0x04, Pulse_A = 0x2 | 0x20, Pulse_B = 0x2 | 0x04, Pulse_AB = 0x2 | 0x20 | 0x04, diff --git a/pydualsense/pydualsense.py b/pydualsense/pydualsense.py index 0052a8a..ddbe05e 100644 --- a/pydualsense/pydualsense.py +++ b/pydualsense/pydualsense.py @@ -5,9 +5,14 @@ import threading class pydualsense: - def __init__(self) -> None: + def __init__(self, verbose: bool = False) -> None: # TODO: maybe add a init function to not automatically allocate controller when class is declared + self.verbose = verbose + self.device: hid.Device = self.__find_device() + + + self.light = DSLight() # control led light of ds self.audio = DSAudio() self.triggerL = DSTrigger() @@ -15,6 +20,7 @@ class pydualsense: self.color = (0,0,255) # set color around touchpad to blue + self.receive_buffer_size = 64 self.send_report_size = 48 # controller states @@ -28,6 +34,7 @@ class pydualsense: def close(self): self.ds_thread = False self.report_thread.join() + self.device.close() def __find_device(self): devices = hid.enumerate(vid=0x054c) @@ -41,10 +48,10 @@ class pydualsense: if len(found_devices) != 1: raise Exception('no dualsense controller detected') - + dual_sense = hid.Device(vid=found_devices[0]['vendor_id'], pid=found_devices[0]['product_id']) return dual_sense - + # color stuff def setColor(self, r: int, g:int, b:int): @@ -102,8 +109,10 @@ class pydualsense: # TODO: audio # audio stuff def setMicrophoneLED(self, value): - self.audio.microphoneLED = value + self.audio.microphone_led = value + def setPlayer(self, player : PlayerID): + self.light.playerNumber = player def sendReport(self): """background thread handling the reading of the device and updating its states @@ -112,7 +121,7 @@ class pydualsense: # read data from the input report of the controller inReport = self.device.read(self.receive_buffer_size) - + # decrypt the packet and bind the inputs self.readInput(inReport) @@ -184,10 +193,9 @@ class pydualsense: # print(f'2Active = {self.state.trackPadTouch1.isActive}') # print(f'X2: {self.state.trackPadTouch1.X} Y2: {self.state.trackPadTouch1.Y}') # print(f'DPAD {self.state.DpadLeft} {self.state.DpadUp} {self.state.DpadRight} {self.state.DpadDown}') - + # TODO: implement gyrometer and accelerometer # TODO: control mouse with touchpad for fun as DS4Windows - def writeReport(self, outReport): @@ -206,7 +214,7 @@ class pydualsense: :rtype: list """ outReport = [0] * 48 # create empty list with range of output report - # packet type + # packet type outReport[0] = 0x2 @@ -216,7 +224,7 @@ class pydualsense: # 0x04 set the right trigger motor # 0x08 set the left trigger motor # 0x10 modification of audio volume - # 0x20 toggling of internal speaker while headset is connected + # 0x20 toggling of internal speaker while headset is connected # 0x40 modification of microphone volume outReport[1] = 0xff # [1] @@ -227,11 +235,11 @@ class pydualsense: # 0x08 will actively turn all LEDs off? Convenience flag? (if so, third parties might not support it properly) # 0x10 toggling white player indicator LEDs below touchpad # 0x20 ??? - # 0x40 adjustment of overall motor/effect power (index 37 - read note on triggers) + # 0x40 adjustment of overall motor/effect power (index 37 - read note on triggers) # 0x80 ??? outReport[2] = 0x1 | 0x2 | 0x4 | 0x10 | 0x40 # [2] - - outReport[3]= 0 # left low freq motor 0-255 # [3] + + outReport[3] = 0 # left low freq motor 0-255 # [3] outReport[4] = 0 # right low freq motor 0-255 # [4] # outReport[5] - outReport[8] audio related @@ -265,7 +273,8 @@ class pydualsense: outReport[45] = self.color[0] outReport[46] = self.color[1] outReport[47] = self.color[2] - + if self.verbose: + print(outReport) return outReport class DSTouchpad: @@ -341,7 +350,7 @@ class DSLight: make it simple, no get or set functions. quick and dirty """ def __init__(self) -> None: - self.brightness: Brightness = Brightness.low # sets + self.brightness: Brightness = Brightness.low # sets self.playerNumber: PlayerID = PlayerID.player1 self.ledOption : LedOptions = LedOptions.Both self.pulseOptions : PulseOptions = PulseOptions.Off @@ -353,7 +362,7 @@ class DSLight: if player > 5: raise Exception('only 5 players supported. choose 1-5') - + class DSAudio: def __init__(self) -> None: