# Asynchronous Python API for Synology DSM
[![](https://github.com/mib1185/py-synologydsm-api/workflows/Tests/badge.svg)](https://github.com/mib1185/py-synologydsm-api/actions?query=workflow%3ATests+branch%3Amaster)
[![Library version](https://img.shields.io/pypi/v/py-synologydsm-api.svg)](https://pypi.org/project/py-synologydsm-api)
[![Supported versions](https://img.shields.io/pypi/pyversions/py-synologydsm-api.svg)](https://pypi.org/project/py-synologydsm-api)
[![Downloads](https://pepy.tech/badge/py-synologydsm-api)](https://pypi.org/project/py-synologydsm-api)
[![Formated with Black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
# Installation
```bash
[sudo] pip install py-synologydsm-api
```
# Usage
You can import the module as `synology_dsm`.
## Constructor
```python
SynologyDSM(
session,
dsm_ip,
dsm_port,
username,
password,
use_https=False,
timeout=10,
device_token=None,
debugmode=False,
)
```
For `session` a valid `aiohttp.ClientSession` needs to be provided. If ssl verification should be truned off, configure the session accordingly (eq. `aiohttp.ClientSession(connector=aiohttp.TCPConnector(verify_ssl=False)`)
`device_token` should be added when using a two-step authentication account, otherwise DSM will ask to login with a One Time Password (OTP) and requests will fail (see the login section for more details).
Default `timeout` is 10 seconds. `SynologyDSM` also takes a `aiohttp.ClientTimeout` as `timeout`.
## Login
Use the `login()` function to authenticate first, otherwise a `SynologyDSMNotLoggedInException` is raised.
It will return a boolean if it successed or faild to authenticate to DSM.
If your account need a two-step authentication (2SA), `login()` will raise `SynologyDSMLogin2SARequiredException`.
Call the function again with a One Time Password (OTP) as parameter, like `login("123456")` (better to be a string to handle first zero).
Store the `device_token` property so that you do not need to reconnect with password the next time you open a new `SynologyDSM` session.
## Code example
Every API has an `update()` function that is needed to get the first data, then the data is cached and updated at the next `update()` call.
The `SynologyDSM` class can also `update()` all APIs at once.
```python
import asyncio
import aiohttp
from synology_dsm import SynologyDSM
async def main():
print("Creating Valid API")
async with aiohttp.ClientSession(
connector=aiohttp.TCPConnector(verify_ssl=False)
) as session:
await do(session)
async def do(session: aiohttp.ClientSession):
api = SynologyDSM(session, "<IP/DNS>", "<port>", "<username>", "<password>")
await api.login()
print("=== Information ===")
await api.information.update()
print("Model: " + str(api.information.model))
print("RAM: " + str(api.information.ram) + " MB")
print("Serial number: " + str(api.information.serial))
print("Temperature: " + str(api.information.temperature) + " °C")
print("Temp. warning: " + str(api.information.temperature_warn))
print("Uptime: " + str(api.information.uptime))
print("Full DSM version:" + str(api.information.version_string))
print("--")
print("=== Utilisation ===")
await api.utilisation.update()
print("CPU Load: " + str(api.utilisation.cpu_total_load) + " %")
print("Memory Use: " + str(api.utilisation.memory_real_usage) + " %")
print("Net Up: " + str(api.utilisation.network_up()))
print("Net Down: " + str(api.utilisation.network_down()))
print("--")
print("=== Storage ===")
await api.storage.update()
for volume_id in api.storage.volumes_ids:
print("ID: " + str(volume_id))
print("Status: " + str(api.storage.volume_status(volume_id)))
print("% Used: " + str(api.storage.volume_percentage_used(volume_id)) + " %")
print("--")
for disk_id in api.storage.disks_ids:
print("ID: " + str(disk_id))
print("Name: " + str(api.storage.disk_name(disk_id)))
print("S-Status: " + str(api.storage.disk_smart_status(disk_id)))
print("Status: " + str(api.storage.disk_status(disk_id)))
print("Temp: " + str(api.storage.disk_temp(disk_id)))
print("--")
print("=== Shared Folders ===")
await api.share.update()
for share_uuid in api.share.shares_uuids:
print("Share name: " + str(api.share.share_name(share_uuid)))
print("Share path: " + str(api.share.share_path(share_uuid)))
print("Space used: " + str(api.share.share_size(share_uuid, human_readable=True)))
print("Recycle Bin Enabled: " + str(api.share.share_recycle_bin(share_uuid)))
print("--")
if __name__ == "__main__":
asyncio.run(main())
```
## Download Station usage
```python
import asyncio
import aiohttp
from synology_dsm import SynologyDSM
async def main():
print("Creating Valid API")
async with aiohttp.ClientSession(
connector=aiohttp.TCPConnector(verify_ssl=False)
) as session:
await do(session)
async def do(session: aiohttp.ClientSession):
api = SynologyDSM(session, "<IP/DNS>", "<port>", "<username>", "<password>")
await api.login()
if "SYNO.DownloadStation.Info" in api.apis:
await api.download_station.get_info()
await api.download_station.get_config()
# The download list will be updated after each of the following functions:
# You should have the right on the (default) directory that the download will be saved, or you will get a 403 or 406 error
await api.download_station.create("http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4")
await api.download_station.pause("dbid_1")
# Like the other function, you can eather pass a str or a list
await api.download_station.resume(["dbid_1", "dbid_2"])
await api.download_station.delete("dbid_3")
# Manual update
await api.download_station.update()
if __name__ == "__main__":
asyncio.run(main())
```
## File Station usage
### List folders and files in specific folder
```python
import asyncio
import aiohttp
from synology_dsm import SynologyDSM
async def main():
print("Creating Valid API")
async with aiohttp.ClientSession(
connector=aiohttp.TCPConnector(verify_ssl=False)
) as session:
await do(session)
async def do(session: aiohttp.ClientSession):
api = SynologyDSM(session, "<IP/DNS>", "<port>", "<username>", "<password>")
await api.login()
shared_folders = await api.file.get_shared_folders()
for folder in shared_folders:
print(f"############### {folder.name} ###############")
print(f"path: {folder.path}")
print(f"freespace: {folder.additional.volume_status.freespace}")
print(f"totalspace: {folder.additional.volume_status.totalspace}")
print(f"readonly: {folder.additional.volume_status.readonly}")
files = await api.file.get_files(path="/home")
for file in files:
print(f"path: {file.path}")
print(f"size: {file.additional.size}")
print(f"is dir: {file.is_dir}")
print(f"owner user: {file.additional.owner.user}")
if __name__ == "__main__":
asyncio.run(main())
```
### Upload, Download and Delete files
```python
import asyncio
import aiohttp
from synology_dsm import SynologyDSM
async def main():
print("Creating Valid API")
async with aiohttp.ClientSession(
connector=aiohttp.TCPConnector(verify_ssl=False)
) as session:
await do(session)
async def do(session: aiohttp.ClientSession):
api = SynologyDSM(session, "<IP/DNS>", "<port>", "<username>", "<password>")
await api.login()
# upload file direct from local
await api.file.upload_file(path="/home", filename="myfile.name", source="/workspace/myfile.name")
# upload file direct from local, create parent folder(s) if none exist.
await api.file.upload_file(path="/home/new_folder", filename="myfile.name", source="/workspace/myfile.name", create_parents=True)
# upload file from a stream reader
await api.file.upload_file(path="/home", filename="myfile.name", source=open("/workspace/myfile.name", "rb"))
# upload file from an AsyncIterator[bytes]
loop = asyncio.get_running_loop()
async def send_backup() -> AsyncIterator[bytes]:
f = await loop.run_in_executor(None, open, "/workspace/myfile.name", "rb")
try:
while chunk := await loop.run_in_executor(None, f.read, 2**20):
yield chunk
finally:
await loop.run_in_executor(None, f.close)
async def open_backup() -> AsyncIterator[bytes]:
return send_backup()
await api.file.upload_file(path="/home", filename="myfile.name", source=await open_backup())
# download file direct to local
await api.file.download_file(path="/home", filename="myfile.name", target_file="/tmp/download.file")
# download file via stream reader
stream_reader = await api.file.download_file(path="/home", filename="myfile.name")
with open("/tmp/download.file", "wb") as fh:
async for data in stream_reader.iter_chunked(8192):
fh.write(data)
await api.file.delete_file(path="/home", filename="myfile.name")
if __name__ == "__main__":
asyncio.run(main())
```
## External USB storage usage
```python
import asyncio
import aiohttp
from synology_dsm import SynologyDSM
async def main():
print("Creating Valid API")
async with aiohttp.ClientSession(
connector=aiohttp.TCPConnector(verify_ssl=False)
) as session:
await do(session)
async def do(session: aiohttp.ClientSession):
api = SynologyDSM(session, "<IP/DNS>", "<port>", "<username>", "<password>")
await api.login()
await api.external_usb.update()
for device in api.external_usb.get_devices.values():
print("Name: " + str(device.device_name))
print("Size: " + str(device.device_size_total(human_readable=True))
print("Size in mb: " + str(device.device_size_total())
print("Partitions size total: " + str(device.partitions_all_size_total(human_readable=True)))
print("Partitions size used: " + str(device.partitions_all_size_used(human_readable=True)))
print("Partitions % Used: " + str(device.partitions_all_percentage_used ) + " %")
print(" === Partitions ===")
for part in device.device_partitions.values():
print(" Share name: " + str(part.share_name))
print(" Filesystem: " + str(part.filesystem))
print(" Size: " + str(part.partition_size_total(human_readable=True)))
print(" Used: " + str(part.partition_size_used(human_readable=True)))
print(" % Used: " + str(part.partition_percentage_used) + " %")
if __name__ == "__main__":
asyncio.run(main())
```
## Photos usage
```python
import asyncio
import aiohttp
from synology_dsm import SynologyDSM
async def main():
print("Creating Valid API")
async with aiohttp.ClientSession(
connector=aiohttp.TCPConnector(verify_ssl=False)
) as session:
await do(session)
async def do(session: aiohttp.ClientSession):
api = SynologyDSM(session, "<IP/DNS>", "<port>", "<username>", "<password>")
await api.login()
albums = await api.photos.get_albums()
# download each item of each album
for album in albums:
print(f"'{album.name}' has {album.item_count} items")
items = await api.photos.get_items_from_album(album)
for item in items:
print(f"{item.file_name}")
with open(item.file_name, "wb") as fh:
fh.write(await api.photos.download_item(item))
# search for items and download them
items = await api.photos.get_items_from_search("pinky and the brain")
for item in items:
with open(item.file_name, "wb") as fh:
fh.write(await api.photos.download_item(item))
if __name__ == "__main__":
asyncio.run(main())
```
## Surveillance Station usage
```python
import asyncio
import aiohttp
from synology_dsm import SynologyDSM
async def main():
print("Creating Valid API")
async with aiohttp.ClientSession(
connector=aiohttp.TCPConnector(verify_ssl=False)
) as session:
await do(session)
async def do(session: aiohttp.ClientSession):
api = SynologyDSM(session, "<IP/DNS>", "<port>", "<username>", "<password>")
await api.login()
surveillance = api.surveillance_station
await surveillance.update() # First update is required
# Returns a list of cached cameras available
cameras = surveillance.get_all_cameras()
# Assuming there's at least one camera, get the first camera_id
camera_id = cameras[0].camera_id
# Returns cached camera object by camera_id
camera = surveillance.get_camera(camera_id)
# Returns cached motion detection enabled
motion_setting = camera.is_motion_detection_enabled
# Return bytes of camera image
await surveillance.get_camera_image(camera_id)
# Updates all cameras/motion settings and cahce them
await surveillance.update()
# Gets Home Mode status
home_mode_status = await surveillance.get_home_mode_status()
# Sets home mode - true is on, false is off
await surveillance.set_home_mode(True)
if __name__ == "__main__":
asyncio.run(main())
```
## System usage
```python
import asyncio
import aiohttp
from synology_dsm import SynologyDSM
async def main():
print("Creating Valid API")
async with aiohttp.ClientSession(
connector=aiohttp.TCPConnector(verify_ssl=False)
) as session:
await do(session)
async def do(session: aiohttp.ClientSession):
api = SynologyDSM(session, "<IP/DNS>", "<port>", "<username>", "<password>")
await api.login()
system = api.system
# Reboot NAS
await system.reboot()
# Shutdown NAS
await system.shutdown()
# Manual update system information
await system.update()
# Get CPU information
system.cpu_clock_speed
system.cpu_cores
system.cpu_family
system.cpu_series
# Get NTP settings
system.enabled_ntp
system.ntp_server
# Get system information
system.firmware_ver
system.model
system.ram_size
system.serial
system.sys_temp
system.time
system.time_zone
system.time_zone_desc
system.up_time
# Get list of all connected USB devices
system.usb_dev
if __name__ == "__main__":
asyncio.run(main())
```
## Upgrade usage
```python
import asyncio
import aiohttp
from synology_dsm import SynologyDSM
async def main():
print("Creating Valid API")
async with aiohttp.ClientSession(
connector=aiohttp.TCPConnector(verify_ssl=False)
) as session:
await do(session)
async def do(session: aiohttp.ClientSession):
api = SynologyDSM(session, "<IP/DNS>", "<port>", "<username>", "<password>")
await api.login()
upgrade = api.upgrade
# Manual update upgrade information
await upgrade.update()
# check if DSM update is available
if upgrade.update_available:
do something ...
# get available version string (return None if no update available)
upgrade.available_version
# get need of reboot (return None if no update available)
upgrade.reboot_needed
# get need of service restarts (return None if no update available)
upgrade.service_restarts
if __name__ == "__main__":
asyncio.run(main())
```
## Virtual Machine Manager usage
### Show information about all existing guests
```python
import asyncio
import aiohttp
from synology_dsm import SynologyDSM
async def main():
print("Creating Valid API")
async with aiohttp.ClientSession(
connector=aiohttp.TCPConnector(verify_ssl=False)
) as session:
await do(session)
async def do(session: aiohttp.ClientSession):
api = SynologyDSM(session, "<IP/DNS>", "<port>", "<username>", "<password>")
await api.login()
await api.virtual_machine_manager.update()
guests = api.virtual_machine_manager.get_all_guests()
for guest in guests:
print(f"############### {guest.name} ###############")
print(f"autorun: {guest.autorun}")
print(f"description: {guest.description}")
print(f"guest_id: {guest.guest_id}")
print(f"status: {guest.status}")
print(f"vcpu_num: {guest.vcpu_num}")
print(f"vram_size: {guest.vram_size / 1024} MiBytes")
print(f"host_cpu_usage: {guest.host_cpu_usage / 10} %")
print(f"host_ram_usage: {round(guest.host_ram_usage / 1024,1)} MiBytes")
if __name__ == "__main__":
asyncio.run(main())
```
### Perform power actions on guests
```python
import asyncio
import aiohttp
from synology_dsm import SynologyDSM
async def main():
print("Creating Valid API")
async with aiohttp.ClientSession(
connector=aiohttp.TCPConnector(verify_ssl=False)
) as session:
await do(session)
async def do(session: aiohttp.ClientSession):
api = SynologyDSM(session, "<IP/DNS>", "<port>", "<username>", "<password>")
await api.login()
await api.virtual_machine_manager.update()
# start a guest
await api.virtual_machine_manager.guest_poweron("{guest.guest_id}")
# power off a guest
await api.virtual_machine_manager.guest_poweroff("{guest.guest_id}")
# graceful shutdown a guest (needs working guest-agent, else it is not graceful)
await api.virtual_machine_manager.guest_shutdown("{guest.guest_id}")
# graceful restart a guest (needs working guest-agent, else it is not graceful)
await api.virtual_machine_manager.guest_restart("{guest.guest_id}")
if __name__ == "__main__":
asyncio.run(main())
```
# Credits / Special Thanks
- [@florianeinfalt](https://github.com/florianeinfalt)
- [@tchellomello](https://github.com/tchellomello)
- [@Quentame](https://github.com/Quentame) (Multiple API addition & tests)
- [@aaska](https://github.com/aaska) (DSM 5 tests)
- [@chemelli74](https://github.com/chemelli74) (2SA tests)
- [@snjoetw](https://github.com/snjoetw) (Surveillance Station library)
- [@shenxn](https://github.com/shenxn) (Surveillance Station tests)
- [@Gestas](https://github.com/Gestas) (Shared Folders)
- [@lodesmets](https://github.com/lodesmets) (Synology Photos)
Found Synology API "documentation" on this repo : https://github.com/kwent/syno/tree/master/definitions
# Official references
- [Calendar API documentation (2015-2019)](https://global.download.synology.com/download/Document/Software/DeveloperGuide/Package/Calendar/2.4/enu/Synology_Calendar_API_Guide_enu.pdf)
- [Download Station API documentation (2012-2014)](https://global.download.synology.com/download/Document/Software/DeveloperGuide/Package/DownloadStation/All/enu/Synology_Download_Station_Web_API.pdf)
- [File Station API documentation (2013-2019)](https://global.download.synology.com/download/Document/Software/DeveloperGuide/Package/FileStation/All/enu/Synology_File_Station_API_Guide.pdf)
- [Surveillance Station API documentation (2012-2020)](https://global.download.synology.com/download/Document/Software/DeveloperGuide/Package/SurveillanceStation/All/enu/Surveillance_Station_Web_API.pdf)
- [Virtual Machine Manager API documentation (2015-2019)](https://global.download.synology.com/download/Document/Software/DeveloperGuide/Package/Virtualization/All/enu/Synology_Virtual_Machine_Manager_API_Guide.pdf)
Raw data
{
"_id": null,
"home_page": "https://github.com/mib1185/py-synologydsm-api#readme",
"name": "py-synologydsm-api",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "synology-dsm, synology",
"author": "Michael Brussk (mib1185), Quentin POLLET (Quentame), FG van Zeelst (ProtoThis)",
"author_email": null,
"download_url": null,
"platform": null,
"description": "# Asynchronous Python API for Synology DSM\n\n[![](https://github.com/mib1185/py-synologydsm-api/workflows/Tests/badge.svg)](https://github.com/mib1185/py-synologydsm-api/actions?query=workflow%3ATests+branch%3Amaster)\n[![Library version](https://img.shields.io/pypi/v/py-synologydsm-api.svg)](https://pypi.org/project/py-synologydsm-api)\n[![Supported versions](https://img.shields.io/pypi/pyversions/py-synologydsm-api.svg)](https://pypi.org/project/py-synologydsm-api)\n[![Downloads](https://pepy.tech/badge/py-synologydsm-api)](https://pypi.org/project/py-synologydsm-api)\n[![Formated with Black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)\n\n# Installation\n\n```bash\n[sudo] pip install py-synologydsm-api\n```\n\n# Usage\n\nYou can import the module as `synology_dsm`.\n\n## Constructor\n\n```python\nSynologyDSM(\n session,\n dsm_ip,\n dsm_port,\n username,\n password,\n use_https=False,\n timeout=10,\n device_token=None,\n debugmode=False,\n)\n```\n\nFor `session` a valid `aiohttp.ClientSession` needs to be provided. If ssl verification should be truned off, configure the session accordingly (eq. `aiohttp.ClientSession(connector=aiohttp.TCPConnector(verify_ssl=False)`)\n\n`device_token` should be added when using a two-step authentication account, otherwise DSM will ask to login with a One Time Password (OTP) and requests will fail (see the login section for more details).\n\nDefault `timeout` is 10 seconds. `SynologyDSM` also takes a `aiohttp.ClientTimeout` as `timeout`.\n\n## Login\n\nUse the `login()` function to authenticate first, otherwise a `SynologyDSMNotLoggedInException` is raised.\n\nIt will return a boolean if it successed or faild to authenticate to DSM.\n\nIf your account need a two-step authentication (2SA), `login()` will raise `SynologyDSMLogin2SARequiredException`.\nCall the function again with a One Time Password (OTP) as parameter, like `login(\"123456\")` (better to be a string to handle first zero).\nStore the `device_token` property so that you do not need to reconnect with password the next time you open a new `SynologyDSM` session.\n\n## Code example\n\nEvery API has an `update()` function that is needed to get the first data, then the data is cached and updated at the next `update()` call.\n\nThe `SynologyDSM` class can also `update()` all APIs at once.\n\n```python\nimport asyncio\nimport aiohttp\nfrom synology_dsm import SynologyDSM\n\nasync def main():\n print(\"Creating Valid API\")\n async with aiohttp.ClientSession(\n connector=aiohttp.TCPConnector(verify_ssl=False)\n ) as session:\n await do(session)\n\nasync def do(session: aiohttp.ClientSession):\n api = SynologyDSM(session, \"<IP/DNS>\", \"<port>\", \"<username>\", \"<password>\")\n await api.login()\n\n print(\"=== Information ===\")\n await api.information.update()\n print(\"Model: \" + str(api.information.model))\n print(\"RAM: \" + str(api.information.ram) + \" MB\")\n print(\"Serial number: \" + str(api.information.serial))\n print(\"Temperature: \" + str(api.information.temperature) + \" \u00b0C\")\n print(\"Temp. warning: \" + str(api.information.temperature_warn))\n print(\"Uptime: \" + str(api.information.uptime))\n print(\"Full DSM version:\" + str(api.information.version_string))\n print(\"--\")\n\n print(\"=== Utilisation ===\")\n await api.utilisation.update()\n print(\"CPU Load: \" + str(api.utilisation.cpu_total_load) + \" %\")\n print(\"Memory Use: \" + str(api.utilisation.memory_real_usage) + \" %\")\n print(\"Net Up: \" + str(api.utilisation.network_up()))\n print(\"Net Down: \" + str(api.utilisation.network_down()))\n print(\"--\")\n\n print(\"=== Storage ===\")\n await api.storage.update()\n for volume_id in api.storage.volumes_ids:\n print(\"ID: \" + str(volume_id))\n print(\"Status: \" + str(api.storage.volume_status(volume_id)))\n print(\"% Used: \" + str(api.storage.volume_percentage_used(volume_id)) + \" %\")\n print(\"--\")\n\n for disk_id in api.storage.disks_ids:\n print(\"ID: \" + str(disk_id))\n print(\"Name: \" + str(api.storage.disk_name(disk_id)))\n print(\"S-Status: \" + str(api.storage.disk_smart_status(disk_id)))\n print(\"Status: \" + str(api.storage.disk_status(disk_id)))\n print(\"Temp: \" + str(api.storage.disk_temp(disk_id)))\n print(\"--\")\n\n print(\"=== Shared Folders ===\")\n await api.share.update()\n for share_uuid in api.share.shares_uuids:\n print(\"Share name: \" + str(api.share.share_name(share_uuid)))\n print(\"Share path: \" + str(api.share.share_path(share_uuid)))\n print(\"Space used: \" + str(api.share.share_size(share_uuid, human_readable=True)))\n print(\"Recycle Bin Enabled: \" + str(api.share.share_recycle_bin(share_uuid)))\n print(\"--\")\n\nif __name__ == \"__main__\":\n asyncio.run(main())\n```\n\n## Download Station usage\n\n```python\nimport asyncio\nimport aiohttp\nfrom synology_dsm import SynologyDSM\n\nasync def main():\n print(\"Creating Valid API\")\n async with aiohttp.ClientSession(\n connector=aiohttp.TCPConnector(verify_ssl=False)\n ) as session:\n await do(session)\n\nasync def do(session: aiohttp.ClientSession):\n api = SynologyDSM(session, \"<IP/DNS>\", \"<port>\", \"<username>\", \"<password>\")\n await api.login()\n\n if \"SYNO.DownloadStation.Info\" in api.apis:\n\n await api.download_station.get_info()\n await api.download_station.get_config()\n\n # The download list will be updated after each of the following functions:\n # You should have the right on the (default) directory that the download will be saved, or you will get a 403 or 406 error\n await api.download_station.create(\"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4\")\n await api.download_station.pause(\"dbid_1\")\n # Like the other function, you can eather pass a str or a list\n await api.download_station.resume([\"dbid_1\", \"dbid_2\"])\n await api.download_station.delete(\"dbid_3\")\n\n # Manual update\n await api.download_station.update()\n\nif __name__ == \"__main__\":\n asyncio.run(main())\n```\n\n## File Station usage\n\n### List folders and files in specific folder\n\n```python\nimport asyncio\nimport aiohttp\nfrom synology_dsm import SynologyDSM\n\nasync def main():\n print(\"Creating Valid API\")\n async with aiohttp.ClientSession(\n connector=aiohttp.TCPConnector(verify_ssl=False)\n ) as session:\n await do(session)\n\nasync def do(session: aiohttp.ClientSession):\n api = SynologyDSM(session, \"<IP/DNS>\", \"<port>\", \"<username>\", \"<password>\")\n await api.login()\n\n shared_folders = await api.file.get_shared_folders()\n for folder in shared_folders:\n print(f\"############### {folder.name} ###############\")\n print(f\"path: {folder.path}\")\n print(f\"freespace: {folder.additional.volume_status.freespace}\")\n print(f\"totalspace: {folder.additional.volume_status.totalspace}\")\n print(f\"readonly: {folder.additional.volume_status.readonly}\")\n\n files = await api.file.get_files(path=\"/home\")\n for file in files:\n print(f\"path: {file.path}\")\n print(f\"size: {file.additional.size}\")\n print(f\"is dir: {file.is_dir}\")\n print(f\"owner user: {file.additional.owner.user}\")\n\nif __name__ == \"__main__\":\n asyncio.run(main())\n```\n\n### Upload, Download and Delete files\n\n```python\nimport asyncio\nimport aiohttp\nfrom synology_dsm import SynologyDSM\n\nasync def main():\n print(\"Creating Valid API\")\n async with aiohttp.ClientSession(\n connector=aiohttp.TCPConnector(verify_ssl=False)\n ) as session:\n await do(session)\n\nasync def do(session: aiohttp.ClientSession):\n api = SynologyDSM(session, \"<IP/DNS>\", \"<port>\", \"<username>\", \"<password>\")\n await api.login()\n\n # upload file direct from local\n await api.file.upload_file(path=\"/home\", filename=\"myfile.name\", source=\"/workspace/myfile.name\")\n\n # upload file direct from local, create parent folder(s) if none exist.\n await api.file.upload_file(path=\"/home/new_folder\", filename=\"myfile.name\", source=\"/workspace/myfile.name\", create_parents=True)\n\n # upload file from a stream reader\n await api.file.upload_file(path=\"/home\", filename=\"myfile.name\", source=open(\"/workspace/myfile.name\", \"rb\"))\n\n # upload file from an AsyncIterator[bytes]\n loop = asyncio.get_running_loop()\n async def send_backup() -> AsyncIterator[bytes]:\n f = await loop.run_in_executor(None, open, \"/workspace/myfile.name\", \"rb\")\n try:\n while chunk := await loop.run_in_executor(None, f.read, 2**20):\n yield chunk\n finally:\n await loop.run_in_executor(None, f.close)\n\n async def open_backup() -> AsyncIterator[bytes]:\n return send_backup()\n await api.file.upload_file(path=\"/home\", filename=\"myfile.name\", source=await open_backup())\n\n # download file direct to local\n await api.file.download_file(path=\"/home\", filename=\"myfile.name\", target_file=\"/tmp/download.file\")\n\n # download file via stream reader\n stream_reader = await api.file.download_file(path=\"/home\", filename=\"myfile.name\")\n with open(\"/tmp/download.file\", \"wb\") as fh:\n async for data in stream_reader.iter_chunked(8192):\n fh.write(data)\n\n await api.file.delete_file(path=\"/home\", filename=\"myfile.name\")\n\nif __name__ == \"__main__\":\n asyncio.run(main())\n```\n\n## External USB storage usage\n\n```python\nimport asyncio\nimport aiohttp\nfrom synology_dsm import SynologyDSM\n\nasync def main():\n print(\"Creating Valid API\")\n async with aiohttp.ClientSession(\n connector=aiohttp.TCPConnector(verify_ssl=False)\n ) as session:\n await do(session)\n\nasync def do(session: aiohttp.ClientSession):\n api = SynologyDSM(session, \"<IP/DNS>\", \"<port>\", \"<username>\", \"<password>\")\n await api.login()\n\n await api.external_usb.update()\n for device in api.external_usb.get_devices.values():\n print(\"Name: \" + str(device.device_name))\n print(\"Size: \" + str(device.device_size_total(human_readable=True))\n print(\"Size in mb: \" + str(device.device_size_total())\n print(\"Partitions size total: \" + str(device.partitions_all_size_total(human_readable=True)))\n print(\"Partitions size used: \" + str(device.partitions_all_size_used(human_readable=True)))\n print(\"Partitions % Used: \" + str(device.partitions_all_percentage_used ) + \" %\")\n print(\" === Partitions ===\")\n for part in device.device_partitions.values():\n print(\" Share name: \" + str(part.share_name))\n print(\" Filesystem: \" + str(part.filesystem))\n print(\" Size: \" + str(part.partition_size_total(human_readable=True)))\n print(\" Used: \" + str(part.partition_size_used(human_readable=True)))\n print(\" % Used: \" + str(part.partition_percentage_used) + \" %\")\n\nif __name__ == \"__main__\":\n asyncio.run(main())\n```\n\n## Photos usage\n\n```python\nimport asyncio\nimport aiohttp\nfrom synology_dsm import SynologyDSM\n\nasync def main():\n print(\"Creating Valid API\")\n async with aiohttp.ClientSession(\n connector=aiohttp.TCPConnector(verify_ssl=False)\n ) as session:\n await do(session)\n\nasync def do(session: aiohttp.ClientSession):\n api = SynologyDSM(session, \"<IP/DNS>\", \"<port>\", \"<username>\", \"<password>\")\n await api.login()\n\n albums = await api.photos.get_albums()\n\n # download each item of each album\n for album in albums:\n print(f\"'{album.name}' has {album.item_count} items\")\n\n items = await api.photos.get_items_from_album(album)\n for item in items:\n print(f\"{item.file_name}\")\n with open(item.file_name, \"wb\") as fh:\n fh.write(await api.photos.download_item(item))\n\n # search for items and download them\n items = await api.photos.get_items_from_search(\"pinky and the brain\")\n for item in items:\n with open(item.file_name, \"wb\") as fh:\n fh.write(await api.photos.download_item(item))\n\nif __name__ == \"__main__\":\n asyncio.run(main())\n```\n\n## Surveillance Station usage\n\n```python\nimport asyncio\nimport aiohttp\nfrom synology_dsm import SynologyDSM\n\nasync def main():\n print(\"Creating Valid API\")\n async with aiohttp.ClientSession(\n connector=aiohttp.TCPConnector(verify_ssl=False)\n ) as session:\n await do(session)\n\nasync def do(session: aiohttp.ClientSession):\n api = SynologyDSM(session, \"<IP/DNS>\", \"<port>\", \"<username>\", \"<password>\")\n await api.login()\n\n surveillance = api.surveillance_station\n await surveillance.update() # First update is required\n\n # Returns a list of cached cameras available\n cameras = surveillance.get_all_cameras()\n\n # Assuming there's at least one camera, get the first camera_id\n camera_id = cameras[0].camera_id\n\n # Returns cached camera object by camera_id\n camera = surveillance.get_camera(camera_id)\n\n # Returns cached motion detection enabled\n motion_setting = camera.is_motion_detection_enabled\n\n # Return bytes of camera image\n await surveillance.get_camera_image(camera_id)\n\n # Updates all cameras/motion settings and cahce them\n await surveillance.update()\n\n # Gets Home Mode status\n home_mode_status = await surveillance.get_home_mode_status()\n\n # Sets home mode - true is on, false is off\n await surveillance.set_home_mode(True)\n\nif __name__ == \"__main__\":\n asyncio.run(main())\n```\n\n## System usage\n\n```python\nimport asyncio\nimport aiohttp\nfrom synology_dsm import SynologyDSM\n\nasync def main():\n print(\"Creating Valid API\")\n async with aiohttp.ClientSession(\n connector=aiohttp.TCPConnector(verify_ssl=False)\n ) as session:\n await do(session)\n\nasync def do(session: aiohttp.ClientSession):\n api = SynologyDSM(session, \"<IP/DNS>\", \"<port>\", \"<username>\", \"<password>\")\n await api.login()\n\n system = api.system\n\n # Reboot NAS\n await system.reboot()\n\n # Shutdown NAS\n await system.shutdown()\n\n # Manual update system information\n await system.update()\n\n # Get CPU information\n system.cpu_clock_speed\n system.cpu_cores\n system.cpu_family\n system.cpu_series\n\n # Get NTP settings\n system.enabled_ntp\n system.ntp_server\n\n # Get system information\n system.firmware_ver\n system.model\n system.ram_size\n system.serial\n system.sys_temp\n system.time\n system.time_zone\n system.time_zone_desc\n system.up_time\n\n # Get list of all connected USB devices\n system.usb_dev\n\nif __name__ == \"__main__\":\n asyncio.run(main())\n```\n\n## Upgrade usage\n\n```python\nimport asyncio\nimport aiohttp\nfrom synology_dsm import SynologyDSM\n\nasync def main():\n print(\"Creating Valid API\")\n async with aiohttp.ClientSession(\n connector=aiohttp.TCPConnector(verify_ssl=False)\n ) as session:\n await do(session)\n\nasync def do(session: aiohttp.ClientSession):\n api = SynologyDSM(session, \"<IP/DNS>\", \"<port>\", \"<username>\", \"<password>\")\n await api.login()\n upgrade = api.upgrade\n\n # Manual update upgrade information\n await upgrade.update()\n\n # check if DSM update is available\n if upgrade.update_available:\n do something ...\n\n # get available version string (return None if no update available)\n upgrade.available_version\n\n # get need of reboot (return None if no update available)\n upgrade.reboot_needed\n\n # get need of service restarts (return None if no update available)\n upgrade.service_restarts\n\nif __name__ == \"__main__\":\n asyncio.run(main())\n```\n\n## Virtual Machine Manager usage\n\n### Show information about all existing guests\n\n```python\nimport asyncio\nimport aiohttp\nfrom synology_dsm import SynologyDSM\n\n\nasync def main():\n print(\"Creating Valid API\")\n async with aiohttp.ClientSession(\n connector=aiohttp.TCPConnector(verify_ssl=False)\n ) as session:\n await do(session)\n\n\nasync def do(session: aiohttp.ClientSession):\n api = SynologyDSM(session, \"<IP/DNS>\", \"<port>\", \"<username>\", \"<password>\")\n await api.login()\n\n await api.virtual_machine_manager.update()\n\n guests = api.virtual_machine_manager.get_all_guests()\n\n for guest in guests:\n print(f\"############### {guest.name} ###############\")\n print(f\"autorun: {guest.autorun}\")\n print(f\"description: {guest.description}\")\n print(f\"guest_id: {guest.guest_id}\")\n print(f\"status: {guest.status}\")\n print(f\"vcpu_num: {guest.vcpu_num}\")\n print(f\"vram_size: {guest.vram_size / 1024} MiBytes\")\n print(f\"host_cpu_usage: {guest.host_cpu_usage / 10} %\")\n print(f\"host_ram_usage: {round(guest.host_ram_usage / 1024,1)} MiBytes\")\n\n\nif __name__ == \"__main__\":\n asyncio.run(main())\n```\n\n### Perform power actions on guests\n\n```python\nimport asyncio\nimport aiohttp\nfrom synology_dsm import SynologyDSM\n\n\nasync def main():\n print(\"Creating Valid API\")\n async with aiohttp.ClientSession(\n connector=aiohttp.TCPConnector(verify_ssl=False)\n ) as session:\n await do(session)\n\n\nasync def do(session: aiohttp.ClientSession):\n api = SynologyDSM(session, \"<IP/DNS>\", \"<port>\", \"<username>\", \"<password>\")\n await api.login()\n\n await api.virtual_machine_manager.update()\n\n # start a guest\n await api.virtual_machine_manager.guest_poweron(\"{guest.guest_id}\")\n\n # power off a guest\n await api.virtual_machine_manager.guest_poweroff(\"{guest.guest_id}\")\n\n # graceful shutdown a guest (needs working guest-agent, else it is not graceful)\n await api.virtual_machine_manager.guest_shutdown(\"{guest.guest_id}\")\n\n # graceful restart a guest (needs working guest-agent, else it is not graceful)\n await api.virtual_machine_manager.guest_restart(\"{guest.guest_id}\")\n\nif __name__ == \"__main__\":\n asyncio.run(main())\n```\n\n# Credits / Special Thanks\n\n- [@florianeinfalt](https://github.com/florianeinfalt)\n- [@tchellomello](https://github.com/tchellomello)\n- [@Quentame](https://github.com/Quentame) (Multiple API addition & tests)\n- [@aaska](https://github.com/aaska) (DSM 5 tests)\n- [@chemelli74](https://github.com/chemelli74) (2SA tests)\n- [@snjoetw](https://github.com/snjoetw) (Surveillance Station library)\n- [@shenxn](https://github.com/shenxn) (Surveillance Station tests)\n- [@Gestas](https://github.com/Gestas) (Shared Folders)\n- [@lodesmets](https://github.com/lodesmets) (Synology Photos)\n\nFound Synology API \"documentation\" on this repo : https://github.com/kwent/syno/tree/master/definitions\n\n# Official references\n\n- [Calendar API documentation (2015-2019)](https://global.download.synology.com/download/Document/Software/DeveloperGuide/Package/Calendar/2.4/enu/Synology_Calendar_API_Guide_enu.pdf)\n- [Download Station API documentation (2012-2014)](https://global.download.synology.com/download/Document/Software/DeveloperGuide/Package/DownloadStation/All/enu/Synology_Download_Station_Web_API.pdf)\n- [File Station API documentation (2013-2019)](https://global.download.synology.com/download/Document/Software/DeveloperGuide/Package/FileStation/All/enu/Synology_File_Station_API_Guide.pdf)\n- [Surveillance Station API documentation (2012-2020)](https://global.download.synology.com/download/Document/Software/DeveloperGuide/Package/SurveillanceStation/All/enu/Surveillance_Station_Web_API.pdf)\n- [Virtual Machine Manager API documentation (2015-2019)](https://global.download.synology.com/download/Document/Software/DeveloperGuide/Package/Virtualization/All/enu/Synology_Virtual_Machine_Manager_API_Guide.pdf)\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Python API for communication with Synology DSM",
"version": "2.6.1",
"project_urls": {
"Changelog": "https://github.com/mib1185/py-synologydsm-api/releases",
"Documentation": "https://github.com/mib1185/py-synologydsm-api#readme",
"Homepage": "https://github.com/mib1185/py-synologydsm-api#readme",
"Repository": "https://github.com/mib1185/py-synologydsm-api"
},
"split_keywords": [
"synology-dsm",
" synology"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "9aa5be966ce859a44d5f66730b73bfedb93d8171a71de78cb545f96864031b93",
"md5": "478cce1a807483c335eda857a653625d",
"sha256": "671b9dcf3cf27a6bb1370ec3431a233ddce904ed090ded006bc4206258b4a3b0"
},
"downloads": -1,
"filename": "py_synologydsm_api-2.6.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "478cce1a807483c335eda857a653625d",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 41865,
"upload_time": "2025-01-25T10:49:49",
"upload_time_iso_8601": "2025-01-25T10:49:49.635253Z",
"url": "https://files.pythonhosted.org/packages/9a/a5/be966ce859a44d5f66730b73bfedb93d8171a71de78cb545f96864031b93/py_synologydsm_api-2.6.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-01-25 10:49:49",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "mib1185",
"github_project": "py-synologydsm-api#readme",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "py-synologydsm-api"
}