You are viewing the 3.0 documentation (Beta). Go to the current 2.0.x documentation.

Upgrading to 3.0 (preview)

Preview. Zequent 3.0 is not released yet. 2.0.x stays the current long-term-support line and its documentation is unchanged. This page describes what changes for a Client SDK integration when you move it to the 3.0 SDKs, which are available as preview builds. Names may still change before the release.

Upgrading an installation — platform, adapters, the order to do it in, and what keeps working — is described in Upgrading the platform to 3.0. Adapters move to the 3.0 Edge SDKs: Java · Python · Go.

What changes

In 2.x, the Client SDKs had one typed method per command (takeoff, goTo, openCover, …). The 3.0 SDKs have none of them: every action on an asset is a capability with a dotted command id (flight.takeoff, navigation.go_to, dock.open_cover, vendor.<vendor>.<name>) and JSON Schemas for its params and result. Every SDK has one way to run any of them:

JavaPythonGo
Entry pointzequent.commands()client.commandscontrol.New(conn)
What can this asset do?listCapabilities(assetSn)list_capabilities(asset_sn)ListCapabilities(ctx, sn, ...)
Run a commandexecuteCommand(assetSn, commandId, params) / executeCommand(CommandRequest)execute_command(asset_sn, command_id, params, ...)ExecuteCommand(ctx, sn, commandID, params, ...)
Run and wait for the outcomeexecuteAndWait(assetSn, commandId, params, wait)execute_and_wait(asset_sn, command_id, params, ...)ExecuteAndWait(ctx, sn, commandID, params, ...)
Follow a run / an assetwatchCommand(id, onEvent) / watchAsset(assetSn, onEvent)watch_command(id) / watch_asset(asset_sn)WatchCommand(ctx, id) / WatchAsset(ctx, sn)
Cancel a runcancelCommand(id, reason)cancel_command(id, reason)CancelCommand(ctx, id, reason)
Stick inputstreamManualControl(assetSn)stream_manual_control(asset_sn)StreamManualControl(ctx, sn)
Live telemetryzequent.telemetry().watchTelemetry(assetSns, minInterval, onSample, onSourceStatus)client.telemetry.watch_telemetry(asset_sns, min_interval=...)telemetry.New(conn).WatchTelemetry(ctx, sns, ...)
GuideCommands (Java)Commands (Python)Commands (Go)

A command a new adapter adds is usable the moment the adapter publishes it — no new SDK release.

Manual control

Stick input goes over one client-streaming session per asset (StreamManualControl): enter manual control with the command flight.manual.enter, open the session, send roll, pitch, yaw and throttle (-1..1, optionally a gimbal pitch) at your control rate, close it — the close answers with the number of inputs passed on to the asset — and leave with flight.manual.exit.

2.x3.0
Java remoteControl().startManualControlInput(sn, assetId)commands().streamManualControl(assetSn) → ManualControlStream: send(...), close(), done()
Python remote_control.start_manual_control_input(sn)commands.stream_manual_control(asset_sn) → ManualControlStream: async with, send(...), close(), cancel()
Go remotecontrol.Client.OpenManualControlInputStream(ctx)control.Client.StreamManualControl(ctx, sn) → Send(...), Close(); Send after Close is control.ErrManualControlClosed

Live telemetry

3.0 telemetry is one stream of samples and source status from live-data. A TelemetrySample has the fields every asset shares (position, relative altitude, heading, speeds, battery); everything device-specific is in its details, under the keys the asset declares in its capabilities' telemetry_fields. A SourceStatus reports each watched asset as online, stale or without data — first for every watched asset, then on each change. No asset watches every asset of the caller's organization; a dock's serial also brings its drone's samples. A minimum interval keeps at most one sample per asset per interval.

The platform sends heartbeats on a quiet stream; every SDK ends the watch with an error when neither a sample nor a heartbeat arrives within 35 s by default (configurable). No SDK reconnects a telemetry watch on its own — watch again.

2.x3.0
Java liveData().streamTelemetryData(...)telemetry().watchTelemetry(assetSns, minInterval, onSample, onSourceStatus) → TelemetryWatch
Python live_data.stream_telemetry(...)async for item in telemetry.watch_telemetry(asset_sns, min_interval=...)
Go livedata.Client.StreamTelemetry(ctx, sn, frequencyMs, durationSeconds)telemetry.New(conn).WatchTelemetry(ctx, sns, telemetry.WithMinInterval(...)) → Recv()
Java liveData().streamNotifications(...)telemetry().watchAlerts(assetSns, minSeverity, onAlert)
Python live_data.stream_notifications(...)async for alert in telemetry.watch_alerts(asset_sns, min_severity=...)
Go livedata.Client.StreamNotifications(...) / StreamDetections(...)WatchAlerts(ctx, sns, telemetry.WithMinSeverity(...)) / WatchDetections(ctx, sns)
Java liveData().startLiveStream / stopLiveStream, Python live_data.start_live_stream / stop_live_stream, Go StartLiveStream / StopLiveStreamthe commands stream.start / stream.stop (params from the asset's capability)

Every command run has a command execution id and a state: ACCEPTED / RUNNING while underway, then one of SUCCEEDED, FAILED, REJECTED (refused before it started), CANCELLED or TIMED_OUT. A command whose reply is its outcome (open a cover) comes back finished; one that takes time (takeoff, go-to, return home) comes back ACCEPTED and its outcome follows as a command event.

Waiting for the outcome: executeAndWait

All three SDKs wait the same way:

  1. They open a watch on the asset's command events before they send the command, so a run that finishes right away is not missed.
  2. They follow only the execution id that call started; events of other runs on the asset are ignored.
  3. Only SUCCEEDED is success. REJECTED, FAILED, CANCELLED and TIMED_OUT all end in the SDK's command error, carrying the final result.
  4. Giving up the wait (the Java wait duration, asyncio.timeout in Python, the ctx deadline in Go) does not stop the command on the platform. Cancel it explicitly.

Watching a run yourself after executeCommand has returned can miss the end of a fast run; wait with executeAndWait instead.

What stays the same

  • Configuration, environment variables and the ZQNT_CLIENT_TOKEN client credential. The 3.0 command service is served by remote-control next to the 2.x service, on the same host and port.
  • Connector and Mission Autonomy (Applications, Skill executions, schedulers) keep their 2.x contracts in the 3.0 SDKs. The 2.x Remote Control and Live Data clients are gone: commands, telemetry, detections and alerts are 3.0 calls.
  • navigation.go_to's altitude is metres above the takeoff point (left out = 40 m), as in 2.x.
  • Leave a param out when you have no value. The platform reads a missing coordinate as "not given"; sending 0 means latitude 0 / longitude 0 / ground level. Java and Python drop null / None values for you.

Installing the 3.0 SDK previews

From 3.0 the Edge and Client SDK of each language live in one repository — zequent/zqnt-sdk-java, zequent/zqnt-sdk-python, zequent/zqnt-sdk-go — and every SDK is versioned 3.0.0. They take their generated contracts from the public Zequent API (zequent/zqnt-api, Apache 2.0), which replaces the zqnt-utils-* packages of 2.x:

Package2.x3.0
Java Client SDKcom.zqnt.sdk:client-java-sdk (Zequent/zqnt-client-sdk-java)com.zqnt:zqnt-sdk-java-client (Zequent/zqnt-sdk-java) — same Java packages
Java Edge SDKcom.zqnt.sdk:edge-java-sdk (Zequent/zqnt-edge-sdk-java)com.zqnt:zqnt-sdk-java-edge (Zequent/zqnt-sdk-java) — same Java packages
Java contractscom.zqnt:zqnt-utils-javacom.zqnt:zqnt-api (Zequent/zqnt-api) — same Java packages, no import changes
Python Client SDKzqnt-client-sdk from zqnt-client-sdk-pythonzqnt-client-sdk from zqnt-sdk-python, subdirectory = "client" — same modules
Python Edge SDKedge-python-sdk from zqnt-edge-sdk-pythonedge-python-sdk from zqnt-sdk-python, subdirectory = "edge" — same modules
Python contractszqnt-utils (zqnt_utils.…)zqnt-api from zqnt-api, subdirectory = "python" (zqnt_api.…, e.g. zqnt_api.generated.zqnt.telemetry.v3)
Go Client SDKgithub.com/Zequent/zqnt-client-sdk-go/v2github.com/zequent/zqnt-sdk-go/v3/client/...
Go Edge SDKgithub.com/Zequent/zqnt-edge-sdk-go/v2github.com/zequent/zqnt-sdk-go/v3/edge/... (package still edgesdk)
Go contractsgithub.com/zequent/zqnt-utils-golang/v2 (private)github.com/zequent/zqnt-api/go/v3 (public), same package paths below gen/
SDKPreview
Javacom.zqnt:zqnt-sdk-java-client preview builds on GitHub Packages (https://maven.pkg.github.com/Zequent/zqnt-sdk-java), 3.0.0-PR<n>-<sha>-SNAPSHOT (at the time of writing 3.0.0-PR13-f96c80a-SNAPSHOT); it pulls a com.zqnt:zqnt-api 3.0.0 preview build from https://maven.pkg.github.com/Zequent/zqnt-api. See Commands (Java).
PythonGit branch feature/v3-agentic of zqnt-sdk-python, subdirectory = "client", under [tool.uv.sources]; it brings zqnt-api at the revision it pins. See Commands (Python).
GoModule github.com/zequent/zqnt-sdk-go/v3 (/v3, lower-case owner): go get github.com/zequent/zqnt-sdk-go/v3@feature/v3-agentic. Its generated types come from the public module github.com/zequent/zqnt-api/go/v3. See Commands (Go).

Preview builds are for trying 3.0 against a 3.0 platform, not for production. Each moves to a 3.0.0 release once 3.0 ships.

Running against 2.x platforms

The 3.0 command, manual-control and telemetry APIs need a platform that runs 3.0. A 2.x platform does not serve them, and every call fails with the gRPC status UNIMPLEMENTED:

SDKHow it shows
Javathe future fails with CommandException, getStatus() = UNIMPLEMENTED, category ERROR_CATEGORY_NOT_FOUND
PythonCommandError, status = grpc.StatusCode.UNIMPLEMENTED, category ERROR_CATEGORY_NOT_FOUND
Gostatus.Code(err) == codes.Unimplemented

The 3.0 Client SDKs have no 2.x command calls: the typed per-command methods, the 2.x manual-control session and the 2.x Live Data client (Java remoteControl() / liveData(), Python client.remote_control / client.live_data, Go packages remotecontrol / livedata) are removed. An application that has to command both 2.x and 3.0 platforms keeps the 2.0 SDK for the 2.x ones and decides per platform which SDK to use — for example from configuration, or by treating UNIMPLEMENTED from listCapabilities as "this platform is still on 2.x":

boolean platformServes3(ZequentClient zequent, String assetSn) {
    try {
        zequent.commands().listCapabilities(assetSn).join();
        return true;
    } catch (CompletionException failure) {
        CommandException error = CommandException.from(failure);
        if (error.getStatus() == io.grpc.Status.Code.UNIMPLEMENTED) return false; // 2.x: use the 2.0 SDK
        throw error;
    }
}

Moving the platform itself to 3.0 is a separate upgrade: see Upgrading the platform to 3.0.

Typed call → command id

The 2.x typed calls are removed in the 3.0 SDKs; this table is the migration aid. listCapabilities on an asset is authoritative for the commands and params it accepts. These are the ids and params of the built-in commands the Zequent adapters share:

2.x Java (remoteControl())2.x Python (remote_control)2.x Go (remotecontrol)Command idParams
takeofftakeoffTakeOffflight.takeofflatitude, longitude, altitude
goTogo_toGoTonavigation.go_tolatitude, longitude, altitude (above the takeoff point; left out = 40 m)
goTo(request, true)go_to(request, no_fly_zone_override=True)GoToWithOptions(..., GoToOptions{NoFlyZoneOverride: true})navigation.go_toas above, plus the no-fly zone override option of the 3.0 call
returnToHomereturn_to_homeReturnToHomeflight.return_to_homealtitude (optional)
lookAtlook_atLookAtgimbal.look_atlatitude, longitude, altitude, locked, payloadIndex
enterManualControl / exitManualControlenter_manual_control / exit_manual_controlEnterManualControl / ExitManualControlflight.manual.enter / flight.manual.exitnone
openCoveropen_coverOpenCoverdock.open_covernone
closeCoverclose_coverCloseCoverdock.close_coverforce (boolean, optional)
startCharging / stopChargingstart_charging / stop_chargingStartCharging / StopChargingdock.start_charging / dock.stop_chargingnone
rebootAssetreboot_assetRebootAssetasset.rebootnone
bootSubAssetboot_sub_assetBootSubAssetasset.boot_sub_assetenabled (boolean: true boots, false shuts down)
debugModedebug_modeSetRemoteDebugModeasset.remote_debugenabled (boolean)
changeAcModechange_ac_modeChangeAcModeasset.change_ac_modemode (one of the values in the capability's schema)
takePhoto—CapturePhotocamera.take_photonone
liveStreamSplitScreen—LiveStreamSplitScreenstream.split_screenenabled (boolean)
liveData().changeCameraLenslive_data.change_lensChangeLenscamera.change_lenslens, videoId
liveData().changeCameraZoomlive_data.change_zoomChangeZoomcamera.change_zoomlens, payloadIndex, zoom
getCapabilities(sn)—GetCapabilities—use listCapabilities / list_capabilities / ListCapabilities
sendCustomCommand(...)—SendCustomCommandthe capability's command idthe same params; the 2.x capability target becomes the 3.0 call's target option

Responses and errors

2.x3.0
success / has_errors on the responseThe result's state: SUCCEEDED, FAILED, … — or, with executeAndWait, the SUCCEEDED result or the SDK's command error
error code and message on the responseThe result's error: category, a stable code (e.g. flight.not_airborne, command.invalid_params), message, retryable
a refused call (gRPC status)Java CommandException / Python CommandError with the gRPC status; Go keeps the gRPC status on the error
progress on the responseCommand events: progress, remaining, message, and the final result
tidThe command execution id: watch it, cancel it
a custom command's result mapThe result payload: Java Structs.toMap(...), Python to_dict(...), Go GetResult().AsMap()

One difference between the SDKs: from a plain executeCommand, Java and Python return a run that started and failed as a result in state FAILED, while Go returns it as a *control.CommandError. All three raise their command error for a REJECTED command, and all three treat only SUCCEEDED as success in executeAndWait.

New on 3.0, per call: a reason (required for commands rated COMMAND_RISK_CRITICAL), an idempotency key (the same key sent twice runs the command once), a timeout that replaces the capability's default, and a target for a sub-asset, payload or component.

Go: module path

Go callers change their import paths once — the client packages move into the client/ tree of the github.com/zequent/zqnt-sdk-go/v3 module (lower-case owner) and the generated types move to github.com/zequent/zqnt-api/go/v3, with the same package paths below gen/:

grep -rl zqnt-client-sdk-go/v2 --include='*.go' . | xargs sed -i \
  -e 's#github.com/Zequent/zqnt-client-sdk-go/v2/gen/#github.com/zequent/zqnt-api/go/v3/gen/#g' \
  -e 's#github.com/Zequent/zqnt-client-sdk-go/v2/#github.com/zequent/zqnt-sdk-go/v3/client/#g'
go get github.com/zequent/zqnt-sdk-go/v3@feature/v3-agentic && go mod tidy

Was this page helpful?