Skip to content

irjudson/seestar-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

seestar

Async Python client library for ZWO Seestar smart telescopes. Reverse-engineered from the publicly-distributed Android app and the on-device ASCOM Alpaca server; MIT-licensed.

Disclaimer. This library is not affiliated with, endorsed by, or sponsored by ZWO. It is an independent, reverse-engineered client for the Seestar JSON-RPC protocol, developed from observation of the publicly-distributed Android app. Use at your own risk; may void your device warranty. Contributions and test reports across firmware versions are welcome — see CONTRIBUTING.md.

Install

pip install -e .

Quick Start

import asyncio
import seestar

SEESTAR_HOST = "192.168.x.x"  # your device IP

async def main():
    # Or discover devices on the network
    devices = await seestar.discover(timeout=5.0)
    host = devices[0].host if devices else SEESTAR_HOST

    # Connect and control
    async with seestar.SeestarClient(host) as client:
        state = await client.get_device_state()
        print(f"{state.device.name} - FW {state.device.firmware_ver_string}")
        print(f"Battery: {state.pi_status.battery_capacity}%")

        coord = await client.mount.get_equ_coord()
        print(f"RA: {coord.ra:.4f}h  Dec: {coord.dec:.4f}°")

        # Goto a target and stack
        await client.view.start(mode="star", target_name="M42",
                                target_ra_dec=[5.588 / 15, -5.39])
        await client.stack.start(restart=True)

asyncio.run(main())

Command Subsystems

All commands are organized into subsystems on the client:

Subsystem Access Examples
Mount client.mount get_equ_coord(), goto(), park(), speed_move()
Camera client.camera start_exposure(), set_control_value(), save_image()
Focuser client.focuser move(), start_auto_focus(), get_position()
Filter Wheel client.wheel set_position(), calibrate(), get_slot_names()
View client.view start(), stop(), get_state()
Stacking client.stack start(), start_batch(), get_stacked_img()
Plate Solve client.solve start(), get_result()
Images client.image get_files(), get_thumbnail(), start_annotate()
Streaming client.stream start(), stop(), start_record_avi()
Polar Align client.polar_align start(), stop(), get_polar_axis()
System client.system get_setting(), shutdown(), station_scan()
Planning client.plan list_plans(), set_plan(), import_plan()
Sensors client.sensor start_compass_calibration(), get_compass_state()
Photometry client.photometry check(), get_result(), get_stars()
Calib Frames client.calib start_create_dark(), start_create_hpc()
Dither client.dither get(), set()
Remote client.remote join(), disjoin(), disconnect()
Object Lists client.lists add_list(), add_obj(), get_list()
Catalog client.catalog get_planet_position(), start_scan_planet()
Voice client.voice state(), state_download()

Firmware version awareness

The client detects the device's firmware on connect (via get_device_state) and exposes it as client.firmware_version. Methods whose availability depends on firmware are gated — calling one on an unsupported firmware raises NotImplementedOnFirmwareError before anything hits the wire:

from seestar import NotImplementedOnFirmwareError

async with seestar.SeestarClient(host) as client:
    print(client.firmware_version)   # e.g. 7.32

    # Available on firmware ≥ 6.45 only
    await client.system.check_internet()          # OK on 7.32
    await client.image.remove_file("/path/a.png") # OK on 7.32

    try:
        # Removed after firmware 5.97
        await client.image.get_annotate_result()
    except NotImplementedOnFirmwareError as exc:
        print(exc)
        # 'get_annotate_result' not available on this device — was removed
        # after firmware 5.97; current firmware is 7.32

Verified firmware range: 5.50 → 7.32. Older and newer versions are likely to work but are not continuously tested.

Events

async with seestar.SeestarClient(host) as client:
    client.events.on("AutoGoto", lambda e: print(f"Goto: {e.state}"))
    client.events.on("Stack", lambda e: print(f"Stack: {e.state}"))
    client.events.on_category(seestar.EventCategory.DEVICE_STATE, handler)
    client.events.on_all(lambda e: print(f"[{e.Event}] {e.state}"))

ASCOM Alpaca

The Seestar also runs an ASCOM Alpaca REST server. Use it as an alternative:

async with seestar.AlpacaClient(host) as alpaca:
    telescope = alpaca.telescope()
    ra = await telescope.get_ra()
    await telescope.slew_to_coordinates_async(ra=5.588, dec=-5.39)

Protocol

Communication is line-delimited JSON over TCP port 4700 with \r\n terminators. Connection requires an RSA handshake, followed by a heartbeat every 4 seconds. See docs/seestar-api-reference.md for the full protocol specification covering 150+ commands, 33 event types, and the complete device state model.

Port Purpose
4700 Command/response (JSON over TCP)
4720 UDP discovery broadcast
4800 Live image stream (telephoto)
4804 Live image stream (wide-angle)
4554/4555 RTMP video streams
4801 File transfer
80 ASCOM Alpaca REST API

About

Async Python client library for the ZWO Seestar S50 telescope API — enables full programmatic control.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages