Skip to main content

Async Python library for PS4/PS5 second-screen control (wake, standby, button input)

Project description

playdirector

An async Python library for controlling PS4 and PS5 consoles over your local network — wake from standby, send button inputs, navigate home, and more.

PyPI version Python License: MIT

Features

  • Discover PS4/PS5 consoles on your local network via UDP broadcast
  • Wake a console from standby without a full session
  • Connect and send button inputs (PS4), navigate to home (PS5)
  • Pair with a PS5 using your PSN credentials (NPSSO token)
  • Credential storage — JSON files persisted to ~/.config/playdirector/
  • Fully async/await — built on asyncio and aiohttp

Requirements

  • Python 3.11+
  • PS4 (firmware ≥ 8.0) or PS5
  • Console and computer on the same local network

Installation

pip install playdirector

Quick Start

import asyncio
from playdirector import find, connect, RemoteOperation
from playdirector.credentials import JsonCredentialStorage

async def main():
    storage = JsonCredentialStorage()

    # Probe a known IP
    device = await find("192.168.1.50")
    if device is None:
        print("Console not found")
        return

    # Load previously paired credentials
    cred = storage.load(device.device_id)
    if cred is None:
        print("No credentials — run pairing first")
        return

    # Connect and send the PS button (PS4)
    async with connect(device, cred) as session:
        await session.send_keys([RemoteOperation.PS])

asyncio.run(main())

Pairing

Before connecting you need to pair with the console once to obtain credentials. The pair() function detects whether the console is a PS4 or PS5 and runs the correct flow automatically.

You'll need:

  • Your NPSSO token from the PSN website
  • The 8-digit PIN shown on the console:
    • PS5 — Settings → System → Remote Play → Link Device
    • PS4 — Settings → Remote Play Connection Settings → Add Device
import asyncio
from playdirector import pair
from playdirector.credentials import JsonCredentialStorage

async def main():
    cred = await pair(
        ip="192.168.1.50",
        pin="12345678",      # 8-digit PIN from console
        npsso="your-npsso", # from https://ca.account.sony.com/api/v1/ssocookie
    )
    JsonCredentialStorage().save(cred)
    print("Paired:", cred.device_id)

asyncio.run(main())

API

Discovery

from playdirector import scan, find

# Scan the network — yields all responding devices
async for device in scan(timeout=5):
    print(device.device_type, device.ip, device.status)

# Probe a specific IP — returns one device or None
device = await find("192.168.1.50")

DiscoveredDevice fields:

Field Type Description
ip str IP address
name str Console name
device_type DeviceType PS4 or PS5
status DeviceStatus AWAKE or STANDBY
device_id str Unique device identifier
running_app_name str | None Currently running app (if awake)
running_app_titleid str | None Title ID of running app

Control

from playdirector import find, wake, connect, standby, send_buttons, go_home
from playdirector.packets import RemoteOperation

device = await find("192.168.1.50")

# Wake from standby (UDP only — no session, call before connecting)
await wake(device, cred)

# Put into standby (PS4 + PS5)
await standby(device, cred)

# Send button inputs (PS4 only)
await send_buttons(device, cred, [RemoteOperation.PS])
await send_buttons(device, cred, [RemoteOperation.UP, RemoteOperation.ENTER])

# Navigate PS5 to home screen (PS5 only)
await go_home(device, cred)

# Open a session manually for multiple operations without reconnecting
async with connect(device, cred) as session:
    await session.send_keys([RemoteOperation.UP])
    await session.send_keys([RemoteOperation.ENTER])
    await session.standby()

Note: send_buttons is supported on PS4 only. The PS5 Remote Play protocol does not expose button input — only wake(), standby(), and go_home() are available for PS5.

Available Buttons (RemoteOperation) — PS4 only

UP · DOWN · LEFT · RIGHT · ENTER · BACK · OPTION · PS · CANCEL

Multiple buttons can be combined: RemoteOperation.UP | RemoteOperation.LEFT

Credential Storage

from playdirector.credentials import JsonCredentialStorage

storage = JsonCredentialStorage()           # defaults to ~/.config/playdirector/
storage = JsonCredentialStorage("/my/dir") # custom path

storage.save(cred)                         # saves to <dir>/<device_id>.json
cred = storage.load(device_id)             # returns None if not found
storage.delete(device_id)
ids = storage.list_device_ids()

Error Handling

from playdirector import (
    PlayDirectorConnectionError,
    PlayDirectorCredentialsError,
    PlayDirectorDeviceError,
    PlayDirectorNotSupportedError,
)

try:
    async with connect(device, cred) as session:
        await session.standby()
except PlayDirectorConnectionError as e:
    # Can't reach the device — check IP and network
    print("Device unreachable:", e)
except PlayDirectorDeviceError as e:
    # Device is online but refused the operation — another session may be active
    print("Device refused request:", e)
except PlayDirectorCredentialsError as e:
    # Credentials rejected — re-pair with the console
    print("Bad credentials:", e)
except PlayDirectorNotSupportedError as e:
    # Wrong device type for this operation
    print("Not supported:", e)
except PlayDirectorError as e:
    # Catch-all for any other library error
    print("playdirector error:", e)

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

playdirector-0.3.0.tar.gz (80.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

playdirector-0.3.0-py3-none-any.whl (76.1 kB view details)

Uploaded Python 3

File details

Details for the file playdirector-0.3.0.tar.gz.

File metadata

  • Download URL: playdirector-0.3.0.tar.gz
  • Upload date:
  • Size: 80.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for playdirector-0.3.0.tar.gz
Algorithm Hash digest
SHA256 2ed2d1591f9a8431fc63246b9cd609d31906966e8c6b968e2663367d2529e6c1
MD5 d534cc8f0b0b0057d834672c7544b9ad
BLAKE2b-256 09f3fd1698e519f7f497a5310fe0e9086a8050334e4c828ee7c0aab99eb11205

See more details on using hashes here.

Provenance

The following attestation bundles were made for playdirector-0.3.0.tar.gz:

Publisher: publish.yml on JackJPowell/playdirector

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file playdirector-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: playdirector-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 76.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for playdirector-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9e06914e5fa02dba608c2776ee2aaf9f36ee6698f46c871dc5f74c0e2d848d5c
MD5 62df5f729609ab146ed434fb7ba7b025
BLAKE2b-256 e3df8d8e4925daf11bb6dd7336373ba37b3a8a26bc1d3aa6f05ca9e62eaed963

See more details on using hashes here.

Provenance

The following attestation bundles were made for playdirector-0.3.0-py3-none-any.whl:

Publisher: publish.yml on JackJPowell/playdirector

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page