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 discover, connect, RemoteOperation
from playdirector.credentials import JsonCredentialStorage

async def main():
    storage = JsonCredentialStorage()

    # Find the console (pass ip= to target a specific address)
    device = await discover(ip="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
    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.

PS5

You'll need your NPSSO token from the PSN website and the 8-digit PIN shown on the console under Settings → System → Remote Play → Link 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())

PS4

import asyncio
from playdirector.pairing import pair_ps4_remoteplay
from playdirector.credentials import JsonCredentialStorage

async def main():
    cred = await pair_ps4_remoteplay(
        ip="192.168.1.100",
        pin="12345678",
        npsso="your-npsso",
    )
    JsonCredentialStorage().save(cred)

asyncio.run(main())

API

Discovery

from playdirector import discover
from playdirector.discovery import DeviceStatus

# Discover all devices on the network
async for device in discover(timeout=5):
    print(device.device_type, device.host, device.status)

# Target a specific IP
device = await discover(ip="192.168.1.50")

DiscoveredDevice fields:

Field Type Description
host str IP address
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 connect, wake
from playdirector.packets import RemoteOperation

# Wake from standby (no full session needed)
await wake(device, cred)

# Full session — send button inputs (PS4)
async with connect(device, cred) as session:
    await session.send_keys([RemoteOperation.PS])
    await session.send_keys([RemoteOperation.UP, RemoteOperation.ENTER])
    await session.standby()

# Navigate PS5 to home screen
from playdirector import go_home
await go_home(device, cred)

Available Buttons (RemoteOperation)

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 PlayActorError, LoginError, UnsupportedDeviceError

try:
    async with connect(device, cred) as session:
        ...
except LoginError:
    print("Bad credentials")
except UnsupportedDeviceError:
    print("Operation not supported on this console")
except PlayActorError as e:
    print("Protocol 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.1.1.tar.gz (75.4 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.1.1-py3-none-any.whl (72.1 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for playdirector-0.1.1.tar.gz
Algorithm Hash digest
SHA256 41517c969a19c2e2fc83fe13e8f6e101c69bd80818d48d326dc8bc375ace615a
MD5 d0bd1f138d5f2ee79ad786f06d3210c8
BLAKE2b-256 a598581c750a2a3a583b4228730724afea1b0c9025e8e0e689fb6a9597aa06f3

See more details on using hashes here.

Provenance

The following attestation bundles were made for playdirector-0.1.1.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.1.1-py3-none-any.whl.

File metadata

  • Download URL: playdirector-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 72.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.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 b1abe7d64826d9fcc7dac15ac070c76ac75105ae2bc636a37559d0e49ffced7b
MD5 7b1cfb8a6cda77210b754721eaa7b797
BLAKE2b-256 0a8cc00c96ba30167a78dfdc5f0e67093f997651d9b4cccab5bcf43f81fc9d4a

See more details on using hashes here.

Provenance

The following attestation bundles were made for playdirector-0.1.1-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