ReferenceClientRead Data

Reading Data

Learn how to read data from channels in Synnax, including real-time streaming and historical reads.

This guide covers reading channel data from Synnax. For real-time data acquisition and monitoring, streaming is the recommended approach. Historical reads are useful for analyzing data that has already been recorded.

If you’d like a conceptual overview of how reads work in Synnax, check out the reads concepts guide.

Streaming Data

Streaming data is useful for real-time processing, visualization, and monitoring. If you’d like a conceptual overview of how streaming works in Synnax, check out the streams page.

Opening a Streamer

To start streaming data, call the open_streamer method on the client and provide a list of channels to stream.

Python

TypeScript

# Python's context manager is recommended
with client.open_streamer(["ch1", "ch2"]) as streamer:
    for frame in streamer:
        # Process the frame

# Alternative method
# (requires explicit closing)
streamer = client.open_streamer(["ch1", "ch2"])

Downsampling Option

To stream data at a lower rate, use the downsample_factor parameter. The streamer will skip the specified number of samples in each series before returning the next frame. Note that this does not average values—it skips samples.

Python

TypeScript

# Read every 2nd sample
streamer = client.open_streamer(
    channels=["temperature", "pressure"],
    downsample_factor=2,
)

Using an Async Streamer

Python

TypeScript

For asyncio support, use open_async_streamer. It has the same interface as the synchronous streamer:

async with await client.open_async_streamer(["ch1", "ch2"]) as streamer:
    async for frame in streamer:
        # Process the frame

Reading Frames

To read the next incoming frame, call the read method on the streamer.

Python

TypeScript

frame = streamer.read()

This call will block until a new frame is available. Note that a frame may not contain data for every channel—see Handling Partial Frames for details.

For more on working with frames, see Series and Frames.

Using a For Loop

The streamer implements an iterator, allowing you to use a for loop to continuously process incoming frames.

Python

TypeScript

# Process frames synchronously

for frame in streamer:
    print(frame.at(-1))

Handling Partial Frames

When reading frames from a streamer, it’s important to note that a frame may not contain data for every channel specified when opening the streamer. For example, when reading from two sensors, temperature and pressure, that are being sampled by different devices at different rates, a frame may contain data only for the first channel, followed by a frame containing only data for the second channel.

Python

TypeScript

streamer = client.open_streamer(["temperature", "pressure"])

frame = streamer.read()
print(frame[-1])
# Output: {"temperature": 25.0}

frame = streamer.read()
print(frame[-1])
# Output: {"pressure": 1013.25}

frame = streamer.read()
print(frame[-1])
# Output: {"temperature": 25.1, "pressure": 1013.25}

# Check if a frame contains data for a specific channel
if "temperature" in frame:
    print(frame["temperature"])

Specifying a Timeout

Python

TypeScript

Add a timeout parameter to the read method. If the timeout is reached before a new frame is available, the method returns None.

# Wait for 5 seconds
frame = streamer.read(timeout=5)

# A `TimeSpan` object can also be used
frame = streamer.read(timeout=5 * sy.TimeSpan.SECOND)

if frame is None:
    print("Timed out waiting for a frame")

Updating the Channel List

To update the list of channels being streamed, call the update*channels method on the streamer. This will _replace* the current list of channels, not add to it.

Python

TypeScript

streamer.update_channels(["temperature", "pressure", "humidity"])

Closing the Streamer

After you’re done streaming, it’s essential that you call the close method on the streamer to release the network connection and other related resources.

Python

TypeScript

streamer.close()

Using structured cleanup patterns ensures the streamer is always closed, even if an exception is thrown.

Python

TypeScript

# Using the streamer as a context manager ensures
# the streamer is always closed correctly.

with client.open_streamer(["temperature1", "temperature2"]) as streamer:
    for frame in streamer:
        # Process the frame

Historical Reads

Historical reads are useful for analyzing data that has already been recorded. Use these patterns when working with past data rather than live streams.

Reading from a Channel

The simplest way to read historical data from Synnax is to use the read method on a Channel.

Python

TypeScript

channel = client.channels.retrieve("my_temp_sensor")
start = sy.TimeStamp("2025-02-12 12:30:00")
end = sy.TimeStamp("2025-02-12 14:30:00")

data = channel.read(start, end)

The returned data is a Series object, which contains the time-range occupied by the data. Notably, the Series can be treated exactly like a numpy.ndarray.

data = data - 273.15
tr = data.time_range

Reading from Multiple Channels

The returned data is an instance of the Frame class.

Python

TypeScript

Access the Series object using the [] operator. The Frame can also be converted to a pandas.DataFrame by calling the to_df method.

import synnax as sy

start = sy.TimeStamp("2025-02-12 12:30:00")
end = sy.TimeStamp("2025-02-12 14:30:00")

frame = client.read(start, end, ["my_sensor", "sensor_index"])

data = frame["my_sensor"]
df = frame.to_df()

Reading the Latest Data

The readLatest method allows you to read the latest N samples from one or more channels:

Python

TypeScript

# Read the latest sample from a channel
latest_value = client.read_latest("my_tc", n=1)

# Read the latest 10 samples from a channel
latest_samples = client.read_latest("my_tc", n=10)

# Read the latest 5 samples from multiple channels
frame = client.read_latest(["my_tc", "my_sg", "my_pt"], n=5)

The returned data follows the same conventions as regular reads - a Series for single channels or a Frame for multiple channels.