25 Commits

Author SHA1 Message Date
Florian Kaiser
f5529f1463 Add state for microphone button 2021-03-07 21:40:55 +01:00
Florian Kaiser
b3ff9fd375 Update 0.5.2
- Added Microphone mute
- changed MicrphoneLED function to boolean instead of int parameter
- using diffrent hidapi library for interacting with c library to get length of reports from device for bt support later
2021-03-07 21:21:01 +01:00
Flo
98b13798cd Merge pull request #19 from nougator/master
Fixed verbose
2021-01-17 21:10:33 +01:00
Nougator
b51c8b49f6 Fixed verbose. 2021-01-17 20:55:59 +01:00
Nougator
cdbe03ad56 Merge pull request #1 from flok/master
e
2021-01-17 20:55:19 +01:00
Flo
3a14ab3e7a Update setup.py 2021-01-10 14:53:56 +01:00
Flo
32f9042abb Merge pull request #16 from flok/hidapi_rewrite
Refactor hidapi
2021-01-10 14:08:31 +01:00
Florian Kaiser
4c86d71633 Refactor hidapi 2021-01-10 14:06:53 +01:00
Flo
9c79d961f1 Merge pull request #15 from TheComputerDan/master
Adapting Platform Agnostic Practices
2021-01-07 10:13:15 +01:00
Dan
c1c10e4eac Remove self reference 2021-01-06 18:25:15 -05:00
Dan
04ce807bc0 Added platform check for add_dll_directory 2021-01-03 22:16:31 -05:00
Dan
71a49da5d2 Removing accidently merged imports 2021-01-02 23:29:59 -05:00
Dan
f4e1d73dd3 Merge remote-tracking branch 'upstream/master'
Updating Fork with Master
2021-01-02 23:25:19 -05:00
Florian K
e766dca70f Deleting mypy action
Mypy gives weird results on github. Lets only work with it locally
2021-01-01 23:42:29 +01:00
Florian K
1e0b23da41 Update python-mypy.yml 2021-01-01 23:41:15 +01:00
Florian K
ff01788c89 Mypy enums import error fix 2021-01-01 23:39:54 +01:00
Florian K
c07b975bc5 Merge pull request #13 from nougator/patch-1
Update README.md
2021-01-01 23:16:08 +01:00
Nougator
7b0270fa7d Update README.md 2021-01-01 20:56:57 +01:00
Florian Kaiser
d76717c163 Fix missing import 2021-01-01 20:34:42 +01:00
Florian Kaiser
786657cc90 Merge branch 'master' of https://github.com/flok/pydualsense into master 2021-01-01 20:33:39 +01:00
Florian Kaiser
11e78fbece Fix Python > 3.8 dll import 2021-01-01 20:32:55 +01:00
Florian K
a3f697866b Changed place for hidapi.dll
Adding dlls to your System32 is not a good idea. Place the dll into your Workspace
2021-01-01 19:01:30 +01:00
Florian K
1530c79dd7 Update install instructions
Updated the install instructions with the hidapi download and placement.
2021-01-01 11:36:35 +01:00
Dan
83a37750d1 linting 2021-01-01 00:28:46 -05:00
Dan
bc0eb35c3c Moving winreg check to support other OSes 2020-12-31 20:39:50 -05:00
8 changed files with 85 additions and 71 deletions

View File

@@ -1,21 +0,0 @@
name: Mypy
on: [push]
jobs:
build:
runs-on: ubuntu-latest
name: Mypy
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install mypy
- name: mypy
run: |
mypy pydualsense/

3
.gitignore vendored
View File

@@ -149,6 +149,9 @@ dmypy.json
!.vscode/extensions.json !.vscode/extensions.json
*.code-workspace *.code-workspace
### pycharm ###
.idea/*
# End of https://www.toptal.com/developers/gitignore/api/python,vscode # End of https://www.toptal.com/developers/gitignore/api/python,vscode
pydualsense/interface.py pydualsense/interface.py

View File

@@ -1,9 +1,9 @@
# pydualsense # 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 receive and update the controller. control your dualsense through python. using the hid library this package implements the report features for controlling your new PS5 controller.
# install # install
Just install the package from [pypi](https://pypi.org/project/pydualsense/) Download [hidapi](https://github.com/libusb/hidapi/releases) and place the x64 .dll file into your Workspace. After that install the package from [pypi](https://pypi.org/project/pydualsense/).
```bash ```bash
pip install pydualsense pip install pydualsense
@@ -12,7 +12,7 @@ pip install pydualsense
```python ```python
from pydualsense import pydualsense from pydualsense import pydualsense, TriggerModes
ds = pydualsense() # open controller ds = pydualsense() # open controller
ds.init() # initialize controller ds.init() # initialize controller
@@ -22,7 +22,7 @@ ds.triggerL.setForce(1, 255)
ds.close() # closing the controller ds.close() # closing the controller
``` ```
See ``examples`` folder for some more ideas See [examples](https://github.com/flok/pydualsense/tree/master/examples) folder for some more ideas
# Help wanted # Help wanted
@@ -30,7 +30,7 @@ Help wanted from people that want to use this and have feature requests. Just op
# dependecies # dependecies
- hid >= 1.0.4 - hidapi-usb >= 0.2.6
# Credits # Credits

View File

@@ -5,8 +5,8 @@ dualsense = pydualsense()
dualsense.init() dualsense.init()
# set color around touchpad to red # set color around touchpad to red
dualsense.light.setColorI(255,0,0) dualsense.light.setColorI(255,0,0)
# enable microphone indicator # mute microphone
dualsense.audio.setMicrophoneLED(1) dualsense.audio.setMicrophoneMute(True)
# set all player 1 indicator on # set all player 1 indicator on
dualsense.light.setPlayerID(PlayerID.player1) dualsense.light.setPlayerID(PlayerID.player1)
# sleep a little to see the result on the controller # sleep a little to see the result on the controller

View File

@@ -1,5 +1,8 @@
from enum import IntFlag from enum import IntFlag
class ConnectionType(IntFlag):
BT = 0x0,
USB = 0x1
class LedOptions(IntFlag): class LedOptions(IntFlag):
Off=0x0, Off=0x0,
PlayerLedBrightness=0x1, PlayerLedBrightness=0x1,

View File

@@ -0,0 +1,18 @@
import winreg
import sys
def check_hide() -> bool:
"""check if hidguardian is used and controller is hidden
"""
if sys.platform.startswith('win32'):
try:
access_reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
access_key = winreg.OpenKey(access_reg, 'SYSTEM\CurrentControlSet\Services\HidGuardian\Parameters', 0, winreg.KEY_READ)
affected_devices = winreg.QueryValueEx(access_key, 'AffectedDevices')[0]
if "054C" in affected_devices and "0CE6" in affected_devices:
return True
return False
except OSError as e:
pass
return False

View File

@@ -1,17 +1,17 @@
from os import device_encoding
import hid # type: ignore # needed for python > 3.8
from .enums import (LedOptions, PlayerID, import os, sys
PulseOptions, TriggerModes, Brightness) if sys.platform.startswith('win32') and sys.version_info >= (3,8):
os.add_dll_directory(os.getcwd())
import hidapi
from .enums import (LedOptions, PlayerID, PulseOptions, TriggerModes, Brightness, ConnectionType) # type: ignore
import threading import threading
import sys
import winreg
class pydualsense: class pydualsense:
def __init__(self, verbose: bool = False) -> None:# def __init__(self, verbose: bool = False) -> None:#
# TODO: maybe add a init function to not automatically allocate controller when class is declared # TODO: maybe add a init function to not automatically allocate controller when class is declared
self.verbose = verbose self.verbose = verbose
self.receive_buffer_size = 64
self.send_report_size = 48
self.leftMotor = 0 self.leftMotor = 0
self.rightMotor = 0 self.rightMotor = 0
@@ -20,7 +20,7 @@ class pydualsense:
def init(self): def init(self):
"""initialize module and device states """initialize module and device states
""" """
self.device: hid.Device = self.__find_device() self.device: hidapi.Device = self.__find_device()
self.light = DSLight() # control led light of ds self.light = DSLight() # control led light of ds
self.audio = DSAudio() # ds audio setting self.audio = DSAudio() # ds audio setting
self.triggerL = DSTrigger() # left trigger self.triggerL = DSTrigger() # left trigger
@@ -28,13 +28,25 @@ class pydualsense:
self.state = DSState() # controller states self.state = DSState() # controller states
self.conType = self.determineConnectionType() # determine USB or BT connection
# thread for receiving and sending # thread for receiving and sending
self.ds_thread = True self.ds_thread = 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.init = True def determineConnectionType(self) -> ConnectionType:
if self.device._device.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:
self.input_report_length = 78
self.output_report_length = 78
return ConnectionType.BT
def close(self): def close(self):
""" """
@@ -44,24 +56,8 @@ class pydualsense:
self.report_thread.join() self.report_thread.join()
self.device.close() self.device.close()
def _check_hide(self) -> bool:
"""check if hidguardian is used and controller is hidden
"""
if sys.platform.startswith('win32'):
try:
access_reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
access_key = winreg.OpenKey(access_reg, 'SYSTEM\CurrentControlSet\Services\HidGuardian\Parameters', 0, winreg.KEY_READ)
affected_devices = winreg.QueryValueEx(access_key, 'AffectedDevices')[0]
if "054C" in affected_devices and "0CE6" in affected_devices:
return True
return False
except OSError as e:
print(e)
return False def __find_device(self) -> hidapi.Device:
def __find_device(self) -> hid.Device:
""" """
find HID device and open it find HID device and open it
@@ -74,19 +70,21 @@ class pydualsense:
""" """
# TODO: detect connection mode, bluetooth has a bigger write buffer # TODO: detect connection mode, bluetooth has a bigger write buffer
# TODO: implement multiple controllers working # TODO: implement multiple controllers working
if self._check_hide(): if sys.platform.startswith('win32'):
raise Exception('HIDGuardian detected. Delete the controller from HIDGuardian and restart PC to connect to controller') import pydualsense.hidguardian as hidguardian
detected_device: hid.Device = None if hidguardian.check_hide():
devices = hid.enumerate(vid=0x054c) raise Exception('HIDGuardian detected. Delete the controller from HIDGuardian and restart PC to connect to controller')
detected_device: hidapi.Device = None
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 == 0x0CE6:
detected_device = device detected_device = device
if detected_device == None: if detected_device == None:
raise Exception('No device detected') raise Exception('No device detected')
dual_sense = hid.Device(vid=detected_device['vendor_id'], pid=detected_device['product_id']) dual_sense = hidapi.Device(vendor_id=detected_device.vendor_id, product_id=detected_device.product_id)
return dual_sense return dual_sense
def setLeftMotor(self, intensity: int): def setLeftMotor(self, intensity: int):
@@ -131,10 +129,10 @@ class pydualsense:
"""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 # read data from the input report of the controller
inReport = self.device.read(self.receive_buffer_size) inReport = self.device.read(self.input_report_length)
if self.verbose:
print(inReport)
# decrypt the packet and bind the inputs # decrypt the packet and bind the inputs
self.readInput(inReport) self.readInput(inReport)
@@ -187,6 +185,7 @@ class pydualsense:
misc2 = states[10] misc2 = states[10]
self.state.ps = (misc2 & (1 << 0)) != 0 self.state.ps = (misc2 & (1 << 0)) != 0
self.state.touchBtn = (misc2 & 0x02) != 0 self.state.touchBtn = (misc2 & 0x02) != 0
self.state.micBtn = (misc2 & 0x04) != 0
# trackpad touch # trackpad touch
@@ -229,7 +228,8 @@ class pydualsense:
Returns: Returns:
list: report to send to controller list: report to send to controller
""" """
outReport = [0] * 48 # create empty list with range of output report
outReport = [0] * self.output_report_length # create empty list with range of output report
# packet type # packet type
outReport[0] = 0x2 outReport[0] = 0x2
@@ -263,6 +263,8 @@ class pydualsense:
# set Micrphone LED, setting doesnt effect microphone settings # set Micrphone LED, setting doesnt effect microphone settings
outReport[9] = self.audio.microphone_led # [9] outReport[9] = self.audio.microphone_led # [9]
outReport[10] = 0x10 if self.audio.microphone_mute == True else 0x00
# add right trigger mode + parameters to packet # add right trigger mode + parameters to packet
outReport[11] = self.triggerR.mode.value outReport[11] = self.triggerR.mode.value
outReport[12] = self.triggerR.forces[0] outReport[12] = self.triggerR.forces[0]
@@ -484,15 +486,24 @@ class DSAudio:
This doesnt change the mute/unmutes the microphone itself. This doesnt change the mute/unmutes the microphone itself.
Args: Args:
value (int): On or off microphone LED value (bool): On or off microphone LED
Raises: Raises:
Exception: false state for the led Exception: false state for the led
""" """
if value > 1 or value < 0: if not isinstance(value, bool):
raise Exception('Microphone LED can only be on or off (0 .. 1)') raise TypeError('MicrophoneLED can only be a bool')
self.microphone_led = value self.microphone_led = value
def setMicrophoneMute(self, state):
if not isinstance(state, bool):
raise TypeError('state needs to be bool')
self.setMicrophoneLED(state) # set led accordingly
self.microphone_mute = state
class DSTrigger: class DSTrigger:
def __init__(self) -> None: def __init__(self) -> None:
# trigger modes # trigger modes
@@ -534,4 +545,4 @@ class DSTrigger:
if not isinstance(mode, TriggerModes): if not isinstance(mode, TriggerModes):
raise TypeError('Trigger mode parameter needs to be of type `TriggerModes`') raise TypeError('Trigger mode parameter needs to be of type `TriggerModes`')
self.mode = mode self.mode = mode

View File

@@ -6,7 +6,7 @@ with open("README.md", "r") as fh:
setup( setup(
name='pydualsense', name='pydualsense',
version='0.4.1', version='0.5.2.5',
description='use your DualSense (PS5) controller with python', description='use your DualSense (PS5) controller with python',
long_description=long_description, long_description=long_description,
long_description_content_type="text/markdown", long_description_content_type="text/markdown",
@@ -14,5 +14,5 @@ setup(
author='Florian K', author='Florian K',
license='MIT License', license='MIT License',
packages=setuptools.find_packages(), packages=setuptools.find_packages(),
install_requires=['hid>=1.0.4'] install_requires=['hidapi-usb', 'cffi']
) )