Compare commits
6 Commits
v0.7.1
...
dependabot
Author | SHA1 | Date | |
---|---|---|---|
|
4858fc2450 | ||
|
42df47ae26 | ||
|
66deffb545 | ||
|
8a35b1696a | ||
|
17182ff311 | ||
|
645fad053d |
@@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
# PS5 DualSense controller over USB hidraw
|
# PS5 DualSense controller over USB hidraw
|
||||||
KERNEL=="hidraw*", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0ce6", MODE="0660", TAG+="uaccess"
|
KERNEL=="hidraw*", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0ce6", MODE="0660", TAG+="uaccess"
|
||||||
|
# PS5 DualSense Edge controller over USB hidraw
|
||||||
|
KERNEL=="hidraw*", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0df2", MODE="0660", TAG+="uaccess"
|
||||||
|
|
||||||
# PS5 DualSense controller over bluetooth hidraw
|
# PS5 DualSense controller over bluetooth hidraw
|
||||||
KERNEL=="hidraw*", KERNELS=="*054C:0CE6*", MODE="0660", TAG+="uaccess"
|
KERNEL=="hidraw*", KERNELS=="*054C:0CE6*", MODE="0660", TAG+="uaccess"
|
||||||
|
# PS5 DualSense Edge controller over bluetooth hidraw
|
||||||
|
KERNEL=="hidraw*", KERNELS=="*054C:0DF2*", MODE="0660", TAG+="uaccess"
|
||||||
|
969
poetry.lock
generated
969
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -6,4 +6,4 @@ from .enums import LedOptions, Brightness, PlayerID, PulseOptions, TriggerModes
|
|||||||
from .event_system import Event # noqa : F401
|
from .event_system import Event # noqa : F401
|
||||||
from .pydualsense import pydualsense, DSLight, DSState, DSTouchpad, DSTrigger, DSAudio # noqa : F401
|
from .pydualsense import pydualsense, DSLight, DSState, DSTouchpad, DSTrigger, DSAudio # noqa : F401
|
||||||
|
|
||||||
__version__ = "0.7.1"
|
__version__ = "0.7.3"
|
@@ -1,4 +1,5 @@
|
|||||||
import array
|
import array
|
||||||
|
from typing import List
|
||||||
|
|
||||||
# from South-River
|
# from South-River
|
||||||
# fmt: off
|
# fmt: off
|
||||||
@@ -39,10 +40,10 @@ hashTable = array.array('I', [
|
|||||||
# fmt:on
|
# fmt:on
|
||||||
|
|
||||||
|
|
||||||
def compute(buffer):
|
def compute(buffer: List[int]) -> int:
|
||||||
result = 0xEADA2D49
|
result: int = 0xEADA2D49
|
||||||
|
|
||||||
for i in range(0, 74):
|
for i in range(74):
|
||||||
result = hashTable[(result & 0xFF) ^ (buffer[i] & 0xFF)] ^ (result >> 8)
|
result = hashTable[(result & 0xFF) ^ (buffer[i] & 0xFF)] ^ (result >> 8)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
@@ -4,6 +4,7 @@ from enum import IntFlag
|
|||||||
class ConnectionType(IntFlag):
|
class ConnectionType(IntFlag):
|
||||||
BT = 0x0
|
BT = 0x0
|
||||||
USB = 0x1
|
USB = 0x1
|
||||||
|
ERROR = 0xFF
|
||||||
|
|
||||||
|
|
||||||
class LedOptions(IntFlag):
|
class LedOptions(IntFlag):
|
||||||
|
@@ -1,4 +1,8 @@
|
|||||||
class Event(object):
|
from typing import Any, Callable, List
|
||||||
|
|
||||||
|
|
||||||
|
# mypy: disable_error_code="type-arg"
|
||||||
|
class Event:
|
||||||
"""
|
"""
|
||||||
Base class for the event driven system
|
Base class for the event driven system
|
||||||
"""
|
"""
|
||||||
@@ -7,9 +11,9 @@ class Event(object):
|
|||||||
"""
|
"""
|
||||||
initialise event system
|
initialise event system
|
||||||
"""
|
"""
|
||||||
self._event_handler = []
|
self._event_handler: List[Callable] = []
|
||||||
|
|
||||||
def subscribe(self, fn):
|
def subscribe(self, fn: Callable) -> Any:
|
||||||
"""
|
"""
|
||||||
add a event subscription
|
add a event subscription
|
||||||
|
|
||||||
@@ -19,7 +23,7 @@ class Event(object):
|
|||||||
self._event_handler.append(fn)
|
self._event_handler.append(fn)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def unsubscribe(self, fn):
|
def unsubscribe(self, fn: Callable) -> Any:
|
||||||
"""
|
"""
|
||||||
delete event subscription fn
|
delete event subscription fn
|
||||||
|
|
||||||
@@ -29,7 +33,7 @@ class Event(object):
|
|||||||
self._event_handler.remove(fn)
|
self._event_handler.remove(fn)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __iadd__(self, fn):
|
def __iadd__(self, fn: Callable) -> Any:
|
||||||
"""
|
"""
|
||||||
add event subscription fn
|
add event subscription fn
|
||||||
|
|
||||||
@@ -39,7 +43,7 @@ class Event(object):
|
|||||||
self._event_handler.append(fn)
|
self._event_handler.append(fn)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __isub__(self, fn):
|
def __isub__(self, fn: Callable) -> Any:
|
||||||
"""
|
"""
|
||||||
delete event subscription fn
|
delete event subscription fn
|
||||||
|
|
||||||
@@ -49,9 +53,9 @@ class Event(object):
|
|||||||
self._event_handler.remove(fn)
|
self._event_handler.remove(fn)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __call__(self, *args, **keywargs):
|
def __call__(self, *args, **kwargs) -> None: # type: ignore[arg-type]
|
||||||
"""
|
"""
|
||||||
calls all event subscription functions
|
calls all event subscription functions
|
||||||
"""
|
"""
|
||||||
for eventhandler in self._event_handler:
|
for eventhandler in self._event_handler:
|
||||||
eventhandler(*args, **keywargs)
|
eventhandler(*args, **kwargs)
|
||||||
|
@@ -7,21 +7,23 @@ if platform.startswith("win32") and sys.version_info >= (3, 8):
|
|||||||
os.environ["PATH"] += os.pathsep + os.path.dirname(__file__)
|
os.environ["PATH"] += os.pathsep + os.path.dirname(__file__)
|
||||||
|
|
||||||
|
|
||||||
import hidapi
|
import threading
|
||||||
|
from copy import deepcopy
|
||||||
|
from typing import List, Tuple
|
||||||
|
|
||||||
|
import hidapi # type: ignore[import]
|
||||||
|
|
||||||
|
from .checksum import compute
|
||||||
from .enums import (
|
from .enums import (
|
||||||
|
BatteryState,
|
||||||
|
Brightness,
|
||||||
|
ConnectionType,
|
||||||
LedOptions,
|
LedOptions,
|
||||||
PlayerID,
|
PlayerID,
|
||||||
PulseOptions,
|
PulseOptions,
|
||||||
TriggerModes,
|
TriggerModes,
|
||||||
Brightness,
|
)
|
||||||
ConnectionType,
|
|
||||||
BatteryState,
|
|
||||||
) # type: ignore
|
|
||||||
import threading
|
|
||||||
from .event_system import Event
|
from .event_system import Event
|
||||||
from .checksum import compute
|
|
||||||
from copy import deepcopy
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
FORMAT = "%(asctime)s %(message)s"
|
FORMAT = "%(asctime)s %(message)s"
|
||||||
@@ -29,7 +31,7 @@ logging.basicConfig(format=FORMAT)
|
|||||||
logger.setLevel(logging.INFO)
|
logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
|
||||||
class pydualsense:
|
class pydualsense: # noqa: N801
|
||||||
OUTPUT_REPORT_USB = 0x02
|
OUTPUT_REPORT_USB = 0x02
|
||||||
OUTPUT_REPORT_BT = 0x31
|
OUTPUT_REPORT_BT = 0x31
|
||||||
|
|
||||||
@@ -49,7 +51,7 @@ class pydualsense:
|
|||||||
self.leftMotor = 0
|
self.leftMotor = 0
|
||||||
self.rightMotor = 0
|
self.rightMotor = 0
|
||||||
|
|
||||||
self.last_states = None
|
self.last_states: DSState = None # type: ignore[assignment]
|
||||||
|
|
||||||
self.register_available_events()
|
self.register_available_events()
|
||||||
|
|
||||||
@@ -113,7 +115,10 @@ class pydualsense:
|
|||||||
self.state = DSState() # controller states
|
self.state = DSState() # controller states
|
||||||
self.battery = DSBattery()
|
self.battery = DSBattery()
|
||||||
self.conType = self.determineConnectionType() # determine USB or BT connection
|
self.conType = self.determineConnectionType() # determine USB or BT connection
|
||||||
|
if self.conType is ConnectionType.ERROR:
|
||||||
|
raise Exception("Couldn't determine connection type")
|
||||||
self.ds_thread = True
|
self.ds_thread = True
|
||||||
|
self.connected = True
|
||||||
self.report_thread = threading.Thread(target=self.sendReport)
|
self.report_thread = threading.Thread(target=self.sendReport)
|
||||||
self.report_thread.start()
|
self.report_thread.start()
|
||||||
self.states = None
|
self.states = None
|
||||||
@@ -144,6 +149,8 @@ class pydualsense:
|
|||||||
self.output_report_length = 78
|
self.output_report_length = 78
|
||||||
return ConnectionType.BT
|
return ConnectionType.BT
|
||||||
|
|
||||||
|
return ConnectionType.ERROR
|
||||||
|
|
||||||
def close(self) -> None:
|
def close(self) -> None:
|
||||||
"""
|
"""
|
||||||
Stops the report thread and closes the HID device
|
Stops the report thread and closes the HID device
|
||||||
@@ -177,7 +184,7 @@ class pydualsense:
|
|||||||
detected_device: hidapi.Device = None
|
detected_device: hidapi.Device = None
|
||||||
devices = hidapi.enumerate(vendor_id=0x054C)
|
devices = hidapi.enumerate(vendor_id=0x054C)
|
||||||
for device in devices:
|
for device in devices:
|
||||||
if device.vendor_id == 0x054C and device.product_id == 0x0CE6:
|
if device.vendor_id == 0x054C and device.product_id in (0x0CE6, 0x0DF2):
|
||||||
detected_device = device
|
detected_device = device
|
||||||
|
|
||||||
if detected_device is None:
|
if detected_device is None:
|
||||||
@@ -227,42 +234,48 @@ class pydualsense:
|
|||||||
def sendReport(self) -> None:
|
def sendReport(self) -> None:
|
||||||
"""background thread handling the reading of the device and updating its states"""
|
"""background thread handling the reading of the device and updating its states"""
|
||||||
while self.ds_thread:
|
while self.ds_thread:
|
||||||
# read data from the input report of the controller
|
try:
|
||||||
inReport = self.device.read(self.input_report_length)
|
# read data from the input report of the controller
|
||||||
if self.verbose:
|
inReport = self.device.read(self.input_report_length)
|
||||||
logger.debug(inReport)
|
if self.verbose:
|
||||||
# decrypt the packet and bind the inputs
|
logger.debug(inReport)
|
||||||
self.readInput(inReport)
|
# decrypt the packet and bind the inputs
|
||||||
|
self.readInput(inReport)
|
||||||
|
|
||||||
# prepare new report for device
|
# prepare new report for device
|
||||||
outReport = self.prepareReport()
|
outReport = self.prepareReport()
|
||||||
|
|
||||||
# write the report to the device
|
# write the report to the device
|
||||||
self.writeReport(outReport)
|
self.writeReport(outReport)
|
||||||
|
except IOError:
|
||||||
|
self.connected = False
|
||||||
|
break
|
||||||
|
|
||||||
def readInput(self, inReport) -> None:
|
except AttributeError:
|
||||||
|
self.connected = False
|
||||||
|
break
|
||||||
|
|
||||||
|
def readInput(self, inReport : List[int]) -> None:
|
||||||
"""
|
"""
|
||||||
read the input from the controller and assign the states
|
read the input from the controller and assign the states
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
inReport (bytearray): read bytearray containing the state of the whole controller
|
inReport (bytearray): read bytearray containing the state of the whole controller
|
||||||
"""
|
"""
|
||||||
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
|
# 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[int] = list(inReport)[1:] if self.conType == ConnectionType.BT else list(inReport)
|
||||||
|
|
||||||
|
self.states: List[int] = states # type: ignore[assigment]
|
||||||
# states 0 is always 1
|
# states 0 is always 1
|
||||||
self.state.LX = states[1] - 128
|
self.state.LX = states[1] - 128
|
||||||
self.state.LY = states[2] - 128
|
self.state.LY = states[2] - 128
|
||||||
self.state.RX = states[3] - 128
|
self.state.RX = states[3] - 128
|
||||||
self.state.RY = states[4] - 128
|
self.state.RY = states[4] - 128
|
||||||
self.state.L2 = states[5]
|
self.state.L2 = bool(states[5])
|
||||||
self.state.R2 = states[6]
|
self.state.R2 = bool(states[6])
|
||||||
|
|
||||||
# state 7 always increments -> not used anywhere
|
# state 7 always increments -> not used anywhere
|
||||||
|
|
||||||
@@ -336,7 +349,7 @@ class pydualsense:
|
|||||||
|
|
||||||
# first call we dont have a "last state" so we create if with the first occurence
|
# first call we dont have a "last state" so we create if with the first occurence
|
||||||
if self.last_states is None:
|
if self.last_states is None:
|
||||||
self.last_states = deepcopy(self.state)
|
self.last_states: DSState = deepcopy(self.state) # type: ignore[assignment]
|
||||||
return
|
return
|
||||||
|
|
||||||
# send all events if neede
|
# send all events if neede
|
||||||
@@ -433,7 +446,7 @@ class pydualsense:
|
|||||||
|
|
||||||
# TODO: control mouse with touchpad for fun as DS4Windows
|
# TODO: control mouse with touchpad for fun as DS4Windows
|
||||||
|
|
||||||
def writeReport(self, outReport) -> None:
|
def writeReport(self, outReport : List[int]) -> None: # noqa: N803
|
||||||
"""
|
"""
|
||||||
write the report to the device
|
write the report to the device
|
||||||
|
|
||||||
@@ -442,18 +455,18 @@ class pydualsense:
|
|||||||
"""
|
"""
|
||||||
self.device.write(bytes(outReport))
|
self.device.write(bytes(outReport))
|
||||||
|
|
||||||
def prepareReport(self) -> None:
|
def prepareReport(self) -> List[int]:
|
||||||
"""
|
"""
|
||||||
prepare the output to be send to the controller
|
prepare the output to be send to the controller
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
list: report to send to controller
|
list: report to send to controller
|
||||||
"""
|
"""
|
||||||
|
outReport = (
|
||||||
|
[0] * self.output_report_length
|
||||||
|
) # create empty list with range of output report
|
||||||
|
|
||||||
if self.conType == ConnectionType.USB:
|
if self.conType == ConnectionType.USB:
|
||||||
outReport = (
|
|
||||||
[0] * self.output_report_length
|
|
||||||
) # create empty list with range of output report
|
|
||||||
# packet type
|
# packet type
|
||||||
outReport[0] = self.OUTPUT_REPORT_USB
|
outReport[0] = self.OUTPUT_REPORT_USB
|
||||||
|
|
||||||
@@ -516,9 +529,6 @@ class pydualsense:
|
|||||||
outReport[47] = self.light.TouchpadColor[2]
|
outReport[47] = self.light.TouchpadColor[2]
|
||||||
|
|
||||||
elif self.conType == ConnectionType.BT:
|
elif self.conType == ConnectionType.BT:
|
||||||
outReport = (
|
|
||||||
[0] * self.output_report_length
|
|
||||||
) # create empty list with range of output report
|
|
||||||
# packet type
|
# packet type
|
||||||
outReport[0] = self.OUTPUT_REPORT_BT # bt type
|
outReport[0] = self.OUTPUT_REPORT_BT # bt type
|
||||||
|
|
||||||
@@ -649,7 +659,7 @@ class DSState:
|
|||||||
self.gyro = DSGyro()
|
self.gyro = DSGyro()
|
||||||
self.accelerometer = DSAccelerometer()
|
self.accelerometer = DSAccelerometer()
|
||||||
|
|
||||||
def setDPadState(self, dpad_state: int):
|
def setDPadState(self, dpad_state: int) -> None:
|
||||||
"""
|
"""
|
||||||
Sets the dpad state variables according to the integers that was read from the controller
|
Sets the dpad state variables according to the integers that was read from the controller
|
||||||
|
|
||||||
@@ -684,7 +694,7 @@ class DSState:
|
|||||||
elif dpad_state == 5:
|
elif dpad_state == 5:
|
||||||
self.DpadUp = False
|
self.DpadUp = False
|
||||||
self.DpadDown = True
|
self.DpadDown = True
|
||||||
self.DpadLeft = False
|
self.DpadLeft = True
|
||||||
self.DpadRight = False
|
self.DpadRight = False
|
||||||
elif dpad_state == 6:
|
elif dpad_state == 6:
|
||||||
self.DpadUp = False
|
self.DpadUp = False
|
||||||
@@ -715,7 +725,7 @@ class DSLight:
|
|||||||
self.pulseOptions: PulseOptions = PulseOptions.Off
|
self.pulseOptions: PulseOptions = PulseOptions.Off
|
||||||
self.TouchpadColor = (0, 0, 255)
|
self.TouchpadColor = (0, 0, 255)
|
||||||
|
|
||||||
def setLEDOption(self, option: LedOptions):
|
def setLEDOption(self, option: LedOptions) -> None:
|
||||||
"""
|
"""
|
||||||
Sets the LED Option
|
Sets the LED Option
|
||||||
|
|
||||||
@@ -729,7 +739,7 @@ class DSLight:
|
|||||||
raise TypeError("Need LEDOption type")
|
raise TypeError("Need LEDOption type")
|
||||||
self.ledOption = option
|
self.ledOption = option
|
||||||
|
|
||||||
def setPulseOption(self, option: PulseOptions):
|
def setPulseOption(self, option: PulseOptions) -> None:
|
||||||
"""
|
"""
|
||||||
Sets the Pulse Option of the LEDs
|
Sets the Pulse Option of the LEDs
|
||||||
|
|
||||||
@@ -743,7 +753,7 @@ class DSLight:
|
|||||||
raise TypeError("Need PulseOption type")
|
raise TypeError("Need PulseOption type")
|
||||||
self.pulseOptions = option
|
self.pulseOptions = option
|
||||||
|
|
||||||
def setBrightness(self, brightness: Brightness):
|
def setBrightness(self, brightness: Brightness) -> None:
|
||||||
"""
|
"""
|
||||||
Defines the brightness of the Player LEDs
|
Defines the brightness of the Player LEDs
|
||||||
|
|
||||||
@@ -757,7 +767,7 @@ class DSLight:
|
|||||||
raise TypeError("Need Brightness type")
|
raise TypeError("Need Brightness type")
|
||||||
self.brightness = brightness
|
self.brightness = brightness
|
||||||
|
|
||||||
def setPlayerID(self, player: PlayerID):
|
def setPlayerID(self, player: PlayerID) -> None:
|
||||||
"""
|
"""
|
||||||
Sets the PlayerID of the controller with the choosen LEDs.
|
Sets the PlayerID of the controller with the choosen LEDs.
|
||||||
The controller has 4 Player states
|
The controller has 4 Player states
|
||||||
@@ -792,7 +802,7 @@ class DSLight:
|
|||||||
raise Exception("colors have values from 0 to 255 only")
|
raise Exception("colors have values from 0 to 255 only")
|
||||||
self.TouchpadColor = (r, g, b)
|
self.TouchpadColor = (r, g, b)
|
||||||
|
|
||||||
def setColorT(self, color: tuple) -> None:
|
def setColorT(self, color: Tuple[int, int, int]) -> None:
|
||||||
"""
|
"""
|
||||||
Sets the Color around the Touchpad as a tuple
|
Sets the Color around the Touchpad as a tuple
|
||||||
|
|
||||||
@@ -821,7 +831,7 @@ class DSAudio:
|
|||||||
self.microphone_mute = 0
|
self.microphone_mute = 0
|
||||||
self.microphone_led = 0
|
self.microphone_led = 0
|
||||||
|
|
||||||
def setMicrophoneLED(self, value):
|
def setMicrophoneLED(self, value: bool) -> None:
|
||||||
"""
|
"""
|
||||||
Activates or disables the microphone led.
|
Activates or disables the microphone led.
|
||||||
This doesnt change the mute/unmutes the microphone itself.
|
This doesnt change the mute/unmutes the microphone itself.
|
||||||
@@ -836,7 +846,7 @@ class DSAudio:
|
|||||||
raise TypeError("MicrophoneLED can only be a bool")
|
raise TypeError("MicrophoneLED can only be a bool")
|
||||||
self.microphone_led = value
|
self.microphone_led = value
|
||||||
|
|
||||||
def setMicrophoneState(self, state: bool):
|
def setMicrophoneState(self, state: bool) -> None:
|
||||||
"""
|
"""
|
||||||
Set the microphone state and also sets the microphone led accordingle
|
Set the microphone state and also sets the microphone led accordingle
|
||||||
|
|
||||||
@@ -868,7 +878,7 @@ class DSTrigger:
|
|||||||
# force parameters for the triggers
|
# force parameters for the triggers
|
||||||
self.forces = [0 for i in range(7)]
|
self.forces = [0 for i in range(7)]
|
||||||
|
|
||||||
def setForce(self, forceID: int = 0, force: int = 0):
|
def setForce(self, forceID: int = 0, force: int = 0) -> None:
|
||||||
"""
|
"""
|
||||||
Sets the forces of the choosen force parameter
|
Sets the forces of the choosen force parameter
|
||||||
|
|
||||||
@@ -888,7 +898,7 @@ class DSTrigger:
|
|||||||
|
|
||||||
self.forces[forceID] = force
|
self.forces[forceID] = force
|
||||||
|
|
||||||
def setMode(self, mode: TriggerModes):
|
def setMode(self, mode: TriggerModes) -> None:
|
||||||
"""
|
"""
|
||||||
Set the Mode for the Trigger
|
Set the Mode for the Trigger
|
||||||
|
|
||||||
|
@@ -1,10 +1,27 @@
|
|||||||
[build-system]
|
|
||||||
requires = ["poetry-core"]
|
[project]
|
||||||
build-backend = "poetry.core.masonry.api"
|
name = "pydualsense"
|
||||||
|
version = "0.7.3"
|
||||||
|
description = "use your DualSense (PS5) controller with python"
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.8,<4.0"
|
||||||
|
license = { text = "MIT License" }
|
||||||
|
authors = [{ name = "Florian (flok) K", email = "37000563+flok@users.noreply.github.com" }]
|
||||||
|
keywords = ['ps5', 'controller', 'dualsense', 'pydualsense']
|
||||||
|
|
||||||
|
classifiers = [
|
||||||
|
"License :: OSI Approved :: MIT License",
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
|
"Programming Language :: Python :: 3.8",
|
||||||
|
"Programming Language :: Python :: 3.9",
|
||||||
|
"Programming Language :: Python :: 3.10",
|
||||||
|
"Programming Language :: Python :: 3.11",
|
||||||
|
"Programming Language :: Python :: 3.12",
|
||||||
|
]
|
||||||
|
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "pydualsense"
|
name = "pydualsense"
|
||||||
version = "0.7.1"
|
version = "0.7.3"
|
||||||
description = "use your DualSense (PS5) controller with python"
|
description = "use your DualSense (PS5) controller with python"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://github.com/flok/pydualsense"
|
repository = "https://github.com/flok/pydualsense"
|
||||||
@@ -12,13 +29,23 @@ authors = ["Florian (flok) K"]
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
packages = [{include = "pydualsense"}]
|
packages = [{include = "pydualsense"}]
|
||||||
include = ["pydualsense/hidapi.dll"]
|
include = ["pydualsense/hidapi.dll"]
|
||||||
|
keywords = ['ps5', 'controller', 'dualsense', 'pydualsense']
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.7"
|
python = ">=3.8,<4.0"
|
||||||
hidapi-usb = "^0.3.1"
|
hidapi-usb = "^0.3.2"
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
|
python = ">=3.9,<4.0"
|
||||||
taskipy = "^1.12.2"
|
taskipy = "^1.12.2"
|
||||||
|
hidapi-usb = "^0.3.2"
|
||||||
|
sphinx = { version= "^7.3.7", python=">=3.9" }
|
||||||
|
furo = "^2024.5.6"
|
||||||
|
|
||||||
|
[tool.poetry.group.typing.dependencies]
|
||||||
|
mypy = "^1.3.0"
|
||||||
|
types-python-dateutil = "^2.8.19"
|
||||||
|
types-pytz = ">=2022.7.1.2"
|
||||||
|
|
||||||
[tool.taskipy.tasks]
|
[tool.taskipy.tasks]
|
||||||
clear = "find pydualsense/ -type f \\( -iname \\*.c -o -iname \\*.cpp -o -iname \\*.pyd -o -iname \\*.so \\) -delete"
|
clear = "find pydualsense/ -type f \\( -iname \\*.c -o -iname \\*.cpp -o -iname \\*.pyd -o -iname \\*.so \\) -delete"
|
||||||
@@ -29,8 +56,53 @@ post_test = "task clear"
|
|||||||
|
|
||||||
|
|
||||||
[tool.poetry_bumpversion.file."pydualsense/__init__.py"]
|
[tool.poetry_bumpversion.file."pydualsense/__init__.py"]
|
||||||
|
[tool.poetry_bumpversion.file."pyproject.toml"]
|
||||||
|
|
||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
|
fix = true
|
||||||
|
unfixable = [
|
||||||
|
"ERA", # do not autoremove commented out code
|
||||||
|
]
|
||||||
|
extend-select = [
|
||||||
|
"B", # flake8-bugbear
|
||||||
|
"C4", # flake8-comprehensions
|
||||||
|
"ERA", # flake8-eradicate/eradicate
|
||||||
|
"I", # isort
|
||||||
|
"N", # pep8-naming
|
||||||
|
"PIE", # flake8-pie
|
||||||
|
"PGH", # pygrep
|
||||||
|
"RUF", # ruff checks
|
||||||
|
"SIM", # flake8-simplify
|
||||||
|
"TCH", # flake8-type-checking
|
||||||
|
"TID", # flake8-tidy-imports
|
||||||
|
"UP", # pyupgrade
|
||||||
|
]
|
||||||
|
ignore = [
|
||||||
|
"B904", # use 'raise ... from err'
|
||||||
|
"B905", # use explicit 'strict=' parameter with 'zip()'
|
||||||
|
"N818", # Exception name should be named with an Error suffix
|
||||||
|
"RUF001",
|
||||||
|
"N816",
|
||||||
|
"ERA001",
|
||||||
|
"N802",
|
||||||
|
"N806"
|
||||||
|
]
|
||||||
|
target-version = "py38"
|
||||||
exclude = [".venv"]
|
exclude = [".venv"]
|
||||||
line-length = 120
|
line-length = 120
|
||||||
|
|
||||||
|
[tool.mypy]
|
||||||
|
strict = true
|
||||||
|
files = "pydualsense"
|
||||||
|
show_error_codes = true
|
||||||
|
pretty = true
|
||||||
|
warn_unused_ignores = true
|
||||||
|
enable_incomplete_feature = ["Unpack"]
|
||||||
|
exclude = [
|
||||||
|
"^docs\\.py$",
|
||||||
|
"^build\\.py$",
|
||||||
|
]
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["poetry-core"]
|
||||||
|
build-backend = "poetry.core.masonry.api"
|
18
setup.py
18
setup.py
@@ -1,18 +0,0 @@
|
|||||||
from setuptools import setup
|
|
||||||
import setuptools
|
|
||||||
|
|
||||||
with open("README.md", "r") as fh:
|
|
||||||
long_description = fh.read()
|
|
||||||
|
|
||||||
setup(
|
|
||||||
name='pydualsense',
|
|
||||||
version='0.7.0',
|
|
||||||
description='use your DualSense (PS5) controller with python',
|
|
||||||
long_description=long_description,
|
|
||||||
long_description_content_type="text/markdown",
|
|
||||||
url='https://github.com/flok/pydualsense',
|
|
||||||
author='Florian (flok) K',
|
|
||||||
license='MIT License',
|
|
||||||
packages=setuptools.find_packages(),
|
|
||||||
install_requires=['hidapi-usb>=0.3', 'cffi']
|
|
||||||
)
|
|
Reference in New Issue
Block a user