Hello community!
I wanted to share a Python script I put together for monitoring the thermal status of Ouster sensors.
While you can always poll the HTTP telemetry API to check sensor temperatures, polling too frequently can create unnecessary network and processing overhead. This script takes a different approach by reading the thermal flags embedded directly inside the incoming UDP LiDAR data packets.
By utilizing the PacketFormat class within the Ouster SDK, this script extracts the exact shot-limiting and thermal-shutdown states, as well as their respective countdown timers, directly from the packet stream.
Refer to:
-
Thermal Integration Guide: Thermal Integration Guide — Ouster Sensor Docs documentation
-
Sensor Data Guide: Sensor Data — Ouster Sensor Docs documentation
This script has been fully tested and verified using the following environment:
Ouster SDK Version: 0.16.2
Sensor Firmware Versions: 3.1.0 and 3.2.0
#!/usr/bin/env python3
import argparse
import time
from contextlib import closing
from ouster.sdk import core, sensor
def enum_name(enum_cls, code: int) -> str:
try:
return enum_cls(code).name
except Exception:
return f"UNKNOWN({code})"
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("hostname", help="Sensor hostname or IP")
parser.add_argument("--lidar-port", type=int, default=7502)
parser.add_argument("--imu-port", type=int, default=7503)
args = parser.parse_args()
kwargs = {
"timeout": 1.0,
"buffer_time_sec": 1.0,
}
if args.lidar_port is not None:
kwargs["lidar_port"] = args.lidar_port
if args.imu_port is not None:
kwargs["imu_port"] = args.imu_port
with closing(sensor.SensorPacketSource(args.hostname, **kwargs)) as source:
pf = core.PacketFormat(source.sensor_info[0])
last_state = None
for sensor_idx, packet in source:
if not isinstance(packet, core.LidarPacket):
continue
shot_code = pf.shot_limiting(packet.buf)
therm_code = pf.thermal_shutdown(packet.buf)
shot_countdown = pf.countdown_shot_limiting(packet.buf)
therm_countdown = pf.countdown_thermal_shutdown(packet.buf)
state = (shot_code, therm_code, shot_countdown, therm_countdown)
# Print on change, instead of spamming every lidar packet.
if state != last_state:
print(
f"{time.strftime('%Y-%m-%d %H:%M:%S')} "
f"shot_limiting={enum_name(core.ShotLimitingStatus, shot_code)}({shot_code}) "
f"shot_countdown={shot_countdown} "
f"thermal_shutdown={enum_name(core.ThermalShutdownStatus, therm_code)}({therm_code}) "
f"thermal_countdown={therm_countdown}"
)
last_state = state
if shot_code != int(core.ShotLimitingStatus.NORMAL):
print("WARNING: lidar is in, or approaching, shot limiting")
if __name__ == "__main__":
main()
Sample Output of this script
python3 monitor_thermal.py 192.168.2.229
[2026-05-26 15:32:25.746] [ouster::sensor] [info] Opening port: 7502
[2026-05-26 15:32:25.746] [ouster::sensor] [info] Opening port: 7503
2026-05-26 15:32:25 shot_limiting=NORMAL(0) shot_countdown=0 thermal_shutdown=NORMAL(0) thermal_countdown=0