PyPS4-2ndScreen Documentation¶
PyPS4-2ndScreen¶
Description¶
A full Python implementation based on the Node.js package, ps4-waker, which is an unofficial API for the PS4 2nd Screen App.
This module is mainly targeted towards developers although the module does include a basic CLI.
Disclaimer: This project/module and I are not affiliated with or endorsed by Sony Interactive Entertainment LLC. As such this project may break at any time.
Features¶
This module can perform almost every feature found in the PS4 Second Screen App.
PS4 power and playing media state/status reporting
Remote control
Power on and standby control
Starting a specific game/media
Media information retrieval from the Playstation Store
Compatibility¶
Tested on:
Environment: Python 3.6/3.7/3.8
Operating System: Debian
Installation¶
Package can be installed with pip or from source.
It is advised to install the module in a virtual env.
Create virtual env first:
python -m venv .
source bin/activate
To install from pip:
pip install pyps4-2ndscreen
To install from source clone this repository and run from top-level:
pip install -r requirements.txt
python setup.py install
Protocol¶
UDP is used to get status updates and retrieve user credentials. TCP is used to send commands to the PS4 Console.
Ports¶
This module uses UDP port 1987 by default as the source port for polling the PS4.
PS4 listens on ports 987 (Priveleged) to fetch user PSN credentials.
In order to obtain user credentials, the Python Interpreter needs access to port 987 on the host system. The credential service pretends to be a PS4 console and will receive broadcast packets from the PS4 2nd Screen app on port 987.
Example:
sudo setcap 'cap_net_bind_service=+ep' /usr/bin/python3.5
This is so you do not need sudo/root priveleges to run.
Cover Art Issues¶
If you find that media art cannot be found. Please post an issue with your Region, Country, Title of game, an ID of game.
Known Issues¶
PS Command inconsistent.
On-Screen Keyboard is not implemented.
Credits¶
Thanks to hthiery for writing the underlying socket protocol in Python. https://github.com/hthiery/python-ps4
References¶
Usage¶
API should be accessed initially like the following examples.
Most functions can be accessed from the high-level PS4 object. You will need to pass in the IP address of your PS4 and your PSN credentials.
There are several async/asyncio coroutine functions in this module. These functions should be accessed with an Asyncio loop.
There are two versions of the Ps4 object/class: pyps4_2ndscreen.ps4.Ps4Legacy
and pyps4_2ndscreen.ps4.Ps4Async
. The pyps4_2ndscreen.ps4.Ps4Async
version is recommended over the pyps4_2ndscreen.ps4.Ps4Legacy
version which may be deprecated in the future.
The difference between the two is that the pyps4_2ndscreen.ps4.Ps4Legacy
class uses synchronous sockets (socket.socket) while the pyps4_2ndscreen.ps4.Ps4Async
class uses asyncio transports and protocols. If using the Async version, a running asyncio event loop is required.
pyps4_2ndscreen.ps4.Ps4Legacy
is suited for running single commands.
pyps4_2ndscreen.ps4.Ps4Async
is best suited for a runtime environment/application.
Using Ps4Async Example¶
Initializing¶
First start an asyncio event loop in the main thread.
import asyncio
task = asyncio.ensure_future(YourProgram())
loop = asyncio.get_event_loop()
loop.run_until_complete()
Next you need to init the Device Discovery Protocol. This will enable you to get regular status updates.
from pyps4_2ndscreen.ddp import async_create_ddp_endpoint
_, ddp_protocol = await async_create_ddp_endpoint()
Then you can instantiate the Ps4Async class and assign the ddp_protocol object to the ps4 object.
from pyps4_2ndscreen.ps4 import Ps4Async
ip_address = '192.168.0.3'
creds = 'yourcredentials'
ps4 = Ps4Async(ip_address, creds)
ps4.set_protocol(ddp_protocol)
Getting Status¶
Status messages include various details such as the PS4 Standby/On status and the current game playing.
To get the status of the PS4 simply call:
status = ps4.get_status()
When the PS4 console is on and you have assigned the DDP Protocol to the Ps4 instance, you can add a callback to be called when the PS4 status updates. The callback must be a callable with no arguments.
ps4.add_callback(YourCallback)
The DDP protocol will now handle polling the PS4 console. However, when the PS4 goes into standby or is turned off, you will have to poll the PS4 yourself.
Controlling¶
To turn on from standby call:
ps4.wakeup()
In order to control the PS4 in other ways, you have to login as a registered PSN user on your PS4.
First you should connect. This merely connects a TCP connection with the PS4. Sometimes the PS4 will refuse the connection, especially right after turning it on.
await ps4.async_connect()
Then you can login.
await ps4.login()
The following are supported actions. (Logging in should be handled automatically):
Turning Off
await ps4.standby()
Launching a game or an app
await ps4.start_title('CUS10000')
Navigation functions
await ps4.remote_control('ps')
To logout we simply drop the connection.
await ps4.close()
Getting Title Information¶
The PS4 object provides a coroutine to fetch information of a title from the PSN store. You will need the following information: - The title ID - The title name - PSN Region of title
The first two can be retreived from the status dictionary like so.
status = ps4.status
title_id = status.get('running-app-titleid')
title_name = status.get('running-app-name')
The PSN region needs to be a key in the following dictionary. You can verify like below:
from pyps4_2ndscreen.media_art import COUNTRIES
def check_region():
YourRegion = 'United States'
if YourRegion in COUNTRIES:
return True
return False
You can call the search coroutine now and retrieve info like the url for the cover:
result = await ps4.async_get_ps_store_data(title_name, title_id, YourRegion)
cover = result.cover_art
Getting Credentials¶
Your PSN Credentials can be generated by running a CLI command or by using the Python interpreter:
Terminal Command:
pyps4-2ndscreen credential
If your system does not have setcap utilities your may run the following command:
sudo ./bin/pyps4-2ndscreen credential
or
Python:
from pyps4_2ndscreen.credential import Credentials
creds = Credentials()
YourCredentials = creds.start()
This will start the credential service and will return the credentials for the PSN Account. You will need to get the PS4 Second Screen app for Android or iOS to do this. Once you have logged in with your acccount in the app and started the service, refresh the devices in the app and select the device named ‘pyps4-2ndscreen’.
Command Line¶
Usage: pyps4-2ndscreen [OPTIONS] COMMAND [ARGS]…
Pyps4-2ndscreen CLI. Allows for simple commands from terminal.
Example:
pyps4-2ndscreen -p 1234 start CUSA10000 -i 192.168.0.1 -c yourCredentials
- Options:
- --version
Show the version and exit.
- -v, --debug
Enable debug logging.
- -p, --port INTEGER
Local UDP Port to use.
- --help
Show this message and exit.
- Parameters:
- --ip_address, -i
IP Address of PS4.
- --credentials, -c
Credentials to use.
Commands¶
Command |
Description |
---|---|
credential |
Get PSN Credentials. |
link |
Configure/Link PS4. |
remote |
Send Remote Control. |
search |
Search for PS4 devices. |
standby |
Place PS4 in Standby. |
start |
Start title. |
status |
Get status of PS4. |
wakeup |
Wakeup PS4. |
interactive |
Toggle interactive mode for continuous control. |
Arguments¶
Argument |
Description |
---|---|
Title ID |
Title ID when using command start. |
Button |
Button when using command remote. |
Credential¶
The Credential module allows for fetching of PSN user credentials using the official PS4 2nd Screen App on iOS and Android.
Service¶
The pyps4_2ndscreen.credential.Credentials
class is a service to allow fetching of PSN credentials.
Note: The service requires port 987. This is a priveleged port so some operating systems will not allow you to use this port without root/sudo privileges. If you would like to use the service with normal privileges you can try the command below:
sudo setcap ‘cap_net_bind_service=+ep’ /usr/bin/python3.5
This command works for Debian based systems. The /usr/bin/python3.5 should be replaced with the absolute path to your Python interpreter.
-
class
pyps4_2ndscreen.credential.
Credentials
(device_name: Optional[str] = 'pyps4-2ndscreen', start: Optional[bool] = True)¶ Bases:
object
The PSN Credentials Service. Masquerades as a PS4 to get credentials.
Service listens on port 987 (Priveleged).
- Parameters
device_name – Name to display as
start – Start on init
-
listen
(timeout: Optional[int] = 120)¶ Listen and respond to requests.
- Parameters
timeout – Timeout in seconds
DDP (Device Discovery Protocol)¶
The DDP module allows for discovery of PS4 devices.
DDP Protocol¶
The pyps4_2ndscreen.ddp.DDPProtocol
is a handler for DDP/UDP messages. This class must be used in the event loop. It can handle multiple pyps4_2ndscreen.ps4.Ps4Async
objects.
-
class
pyps4_2ndscreen.ddp.
DDPProtocol
(max_polls=5)¶ Bases:
asyncio.protocols.DatagramProtocol
Async UDP Client.
-
set_max_polls
(poll_count: int)¶ Set number of unreturned polls neeeded to assume no status.
-
close
()¶ Close Transport.
-
add_callback
(ps4, callback)¶ Add callback to list. One per PS4 Object.
-
remove_callback
(ps4, callback)¶ Remove callback from list.
-
property
local_port
¶ Return local port.
-
property
remote_port
¶ Return remote port.
-
property
polls_disabled
¶ Return true if polls disabled.
-
-
async
ddp.
async_create_ddp_endpoint
(port=1987)¶ Create Async UDP endpoint.
PS4¶
The PS4 class is the main object for interfacing with a PS4 console. You should only call methods directly from this class.
There are two versions: pyps4_2ndscreen.ps4.Ps4Async
and pyps4_2ndscreen.ps4.Ps4Legacy
.
Base Version¶
The pyps4_2ndscreen.ps4.Ps4Base
class should not be used directly.
-
class
pyps4_2ndscreen.ps4.
Ps4Base
(host: str, credential: str, device_name: Optional[str] = 'pyps4-2ndscreen', port: Optional[int] = 0)¶ Bases:
object
The PS4 base object. Should not be initialized directly.
- Parameters
host – The host PS4 IP address
credential – The credentials of a PSN account
device_name – Name for client device
port – Local UDP Port to use
-
change_port
(port)¶ Change DDP Port.
-
get_status
() → dict¶ Return current status info.
-
async
async_get_ps_store_data
(title: str, title_id: str, region: str) → pyps4_2ndscreen.media_art.ResultItem¶ Return title data from PS Store.
-
property
port
¶ Return local port.
-
property
status_code
¶ Return status code.
-
property
is_running
¶ Return True if the PS4 is running.
-
property
is_standby
¶ Return True if the PS4 is in standby.
-
property
is_available
¶ Return True if the PS4 is available.
-
property
connected
¶ Return True if connected to PS4.
-
property
system_version
¶ Return the system version.
-
property
host_id
¶ Return the host id/MAC address.
-
property
host_name
¶ Return the host name.
-
property
running_app_titleid
¶ Return the title ID of the running application.
-
property
running_app_name
¶ Return the name of the running application.
-
property
running_app_ps_cover
¶ Return the URL for the title cover art.
-
property
running_app_ps_name
¶ Return the name fetched from PS Store.
Async Version¶
pyps4_2ndscreen.ps4.Ps4Async
is the recommended class. It is best suited for runtime applications. You should have an asyncio event loop running to call/await its coroutines.
-
class
pyps4_2ndscreen.ps4.
Ps4Async
(host: str, credential: str, device_name: Optional[str] = 'pyps4-2ndscreen', port: Optional[int] = 0)¶ Bases:
pyps4_2ndscreen.ps4.Ps4Base
Async Version of Ps4 Class.
- Parameters
host – The host PS4 IP address
credential – The credentials of a PSN account
device_name – Name for device
-
set_login_delay
(value: int)¶ Set delay for login.
-
set_protocol
(ddp_protocol: pyps4_2ndscreen.ddp.DDPProtocol)¶ Attach DDP protocol.
- Parameters
ddp_protocol –
- class
pyps4_2ndscreen.ddp.DDPProtocol
-
add_callback
(callback: callable)¶ Add status updated callback.
- Parameters
callback – Callback to call on status updated; No args
-
get_status
() → dict¶ Get current status info.
-
wakeup
(ignore_conflict=False)¶ Send Wakeup packet.
-
async
change_ddp_endpoint
(port: int, close_old: bool = False)¶ Return True if new endpoint is created.
-
async
get_ddp_endpoint
()¶ Return True if endpoint is created from socket.
-
async
login
(pin: Optional[str] = '')¶ Send Login Packet.
- Parameters
pin – Pin to send. Requred when linking.
-
async
standby
(ignore_conflict=False)¶ Send Standby Packet.
-
async
toggle
()¶ Toggle Power.
-
async
start_title
(title_id: str, running_id: Optional[str] = None)¶ Send start title packet.
Closes current title if title_id is running_id
- Parameters
title_id – Title to start; CUSA00000
running_id – Title currently running
-
async
remote_control
(button_name: str, hold_time: Optional[int] = 0)¶ Send remote control command packet. Is coroutine.
- Parameters
button_name – Button to send to PS4.
hold_time – Time to hold in millis. Only affects PS command.
-
async
close
()¶ Close Connection.
-
async
async_connect
(auto_login: Optional[bool] = True)¶ Connect.
- Parameters
auto_login – If true will login automatically if powering on.
-
property
login_delay
¶ Return login delay value.
Legacy Version¶
pyps4_2ndscreen.ps4.Ps4Legacy
is best suited for one-time commands.
-
class
pyps4_2ndscreen.ps4.
Ps4Legacy
(host: str, credential: str, device_name: Optional[str] = 'pyps4-2ndscreen', auto_close: Optional[bool] = True, port: Optional[int] = 0)¶ Bases:
pyps4_2ndscreen.ps4.Ps4Base
Legacy PS4 Class. Sync Version.
- Parameters
host – The host PS4 IP address
credential – The credentials of a PSN account
device_name – Name for device
-
close
()¶ Close the connection to the PS4.
-
wakeup
()¶ Send Wakeup Packet.
-
login
(pin: Optional[str] = '') → bool¶ Send Login Packet.
- Parameters
pin – Pin to send. Requred when linking.
-
standby
() → bool¶ Send Standby Packet.
-
start_title
(title_id, running_id: Optional[str] = None) → bool¶ Send Start title packet.
Close current title if title_id is running_id
- Parameters
title_id – Title to start; CUSA00000
running_id – Title currently running
-
remote_control
(button_name, hold_time: Optional[int] = 0) → bool¶ Send remote control command packet.
- Parameters
button_name – Button to send to PS4.
hold_time – Time to hold in millis. Only affects PS command.
-
send_status
() → bool¶ Send connection status ack to PS4.