Live Image Streaming

The Seestar continuously stacks frames during observation and makes the progressively-improving image available over a binary socket on port 4800. The stream module lets you grab single frames or stream them in real time.

Peek at the current stack

The lowest-friction way to see what the Seestar is currently imaging — one line, no file written, just a matplotlib window:

from seestarpy import stream

stream.show_current_stack()

The frame is auto-stretched with a midtone transfer function so faint nebulosity is visible. The window title shows the Seestar IP, resolution, frame number, and whether it’s a stacked or preview image.

For multiple Seestars, pass ips="all" (or a list) and all frames are fetched in parallel and tiled into a single subplot-grid figure:

from seestarpy import connection as conn

conn.find_available_ips(3)
stream.show_current_stack(ips="all")
stream.show_current_stack(ips=[1, 2])         # specific scopes
stream.show_current_stack(port=stream.IMAGE_PORT_WIDE)  # wide camera

Returns (header, arr8) for a single scope or {ip: (header, arr8)} for many — handy if you want to keep the displayed pixels for further processing.

Grabbing a single live image

The simplest use case — download the latest stacked image and save it as a stretched PNG that reveals faint nebulosity:

from seestarpy import stream

stream.get_live_image(filename="latest.png")

That’s it. The IP address is auto-discovered via mDNS, and the PNG is auto-stretched with a midtone transfer function so faint structure is visible.

If you want a lossless 16-bit FITS file instead (for further processing in PixInsight, Siril, etc.), just change the extension:

stream.get_live_image(filename="latest.fits")

Note

FITS output requires astropy. Install it with pip install astropy.

Working with the raw pixel data

If you want to manipulate the image in Python directly, use decode_payload():

from seestarpy import stream

header, payload = stream.get_live_image()
pixels = stream.decode_payload(payload, header)

print(pixels.shape)   # (3840, 2160, 3) on S50 in 4K mode
print(pixels.dtype)   # uint16

The array is (height, width, 3) with 16-bit RGB values. The header dict contains useful metadata:

print(header['width'], header['height'])  # 2160 3840
print(header['img_type'])                 # 5 = stacked, 1 = preview
print(header['image_id'])                 # sequential frame counter
print(header['hfd'])                      # half-flux diameter (focus quality)

Multi-Seestar usage

For multiple Seestars, pass the IP explicitly:

from seestarpy import connection as conn

conn.find_available_ips(3)

for name, ip in conn.AVAILABLE_IPS.items():
    stream.get_live_image(ip=ip, filename=f"{name}.png")

Preview vs stacked image

By default get_live_image requests the accumulated stacked image. To grab a single unstacked preview frame instead:

header, payload = stream.get_live_image(method="get_current_img")

Live display with matplotlib

The easiest way to watch the stacked image build up in real time — one line:

from seestarpy import stream

stream.start_stream(with_matplotlib=True)

This opens a matplotlib window showing each new stacked frame as it arrives, auto-stretched to reveal faint nebulosity. The window title shows the Seestar IP, resolution, frame number, and image type. Close the window to stop streaming.

Note

The Seestar sends a new stacked frame every time it finishes integrating, so during active observation the display updates every few seconds.

You can combine the live display with your own callback — for example, to save every frame to disk while also watching:

def save_each(header, payload):
    stream.save_image(payload, header, f"frame_{header['image_id']:04d}.png")

stream.start_stream(on_image=save_each, with_matplotlib=True)

If you need full control over the display, call show() directly:

session = stream.start_stream()
# ... do other setup ...
session.show()   # blocks until window closed, then stops stream

RTSP video stream

The Seestar also has an RTSP video feed (live viewfinder, not the stacked image). This is useful for aiming, focusing, and monitoring in real time:

url = stream.build_rtsp_url()        # telephoto camera
# 'rtsp://192.168.1.246:4554/stream'

You can open this with ffplay, VLC, or OpenCV:

ffplay rtsp://192.168.1.246:4554/stream

Or in Python with OpenCV:

import cv2
cap = cv2.VideoCapture(stream.build_rtsp_url())
while cap.isOpened():
    ret, frame = cap.read()
    if ret:
        cv2.imshow("Seestar Live", frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
cap.release()