Edge SDK — Connector Service
The ConnectorService interface gives an edge adapter access to the platform's asset registry over gRPC. It covers what an adapter itself needs — pairing and updating its own asset(s), reading schedules, reporting the commands it supports to the Skill Registry, and registering media files it uploaded. The 1.3 Mission and Task methods are gone: work reaches an adapter as commands (see Edge Adapter — Custom Commands).
Full method-by-method reference: Connector API Reference.
Table of Contents
- Overview
- Asset Management
- Asset Payloads
- Skill Registry
- Media Files
- Schedulers
- Capabilities
- Error Handling
- Configuration
- Usage Examples
Overview
From the edge adapter, you use ConnectorService to:
- Make sure your asset exists when the adapter starts — pairing it with a one-time code if the platform doesn't know it yet.
- Update asset state as it changes.
- Read a schedule's definition.
- Report the commands your adapter supports to the Skill Registry.
- Register a media file the device uploaded.
- Store and retrieve asset payloads (arbitrary versioned metadata blobs, e.g. calibration data).
- Report which commands your adapter currently supports, by implementing
getCapabilitiesonEdgeAdapterService— this is what lets the Admin Console show only the controls an asset actually implements.
The SDK provides a ready-to-use implementation (ConnectorServiceImpl) that handles gRPC communication and Proto-to-DTO mapping; your adapter creates it (see Quickstart — Wire the SDK).
Asset Management
Pair the Asset at Startup
An adapter does not create assets. Its asset is either created in the Admin Console, or paired
with a one-time pairing code (Admin Console, Assets page, Pairing codes). ensureAsset covers both:
it looks the serial number up, and redeems the code only if the asset is unknown — a code is single-use,
so after the first pairing there is nothing left to redeem.
connectorService.ensureAsset(asset, pairingCode) // pairingCode may be null
.thenAccept(found -> log.info("Asset: {}", found == null ? "not on the platform yet" : found.getId()));
redeemAssetClaim(code, asset)trades a code for an asset directly. The organization the asset lands in comes from the code, never fromasset. It completes withnullfor every refusal alike — unknown, expired, revoked, exhausted, or not valid for this kind of device.describeAssetClaim(code)returns the name of the organization a code would pair into, without spending it — so a device can ask its operator to confirm first.registerAssetis deprecated: it creates an asset with no organization, which no tenant can see.
See Usage Examples for a complete startup class.
Get Asset by Serial Number / ID
connectorService.getAssetBySn("YOUR_DEVICE_SN")
.thenAccept(asset -> log.info("Found asset: {} (ID: {})", asset.getName(), asset.getId()));
connectorService.getAssetById("550e8400-e29b-41d4-a716-446655440000")
.thenAccept(asset -> log.info("Asset SN: {}", asset.getSn()));
Get Sub-Asset by Serial Number
Retrieve a sub-asset (e.g. the drone paired to a dock):
connectorService.getSubAssetBySn("YOUR_DEVICE_SNXXX")
.thenAccept(subAsset -> log.info("Sub-asset model: {}", subAsset.getModel()));
Update an Asset
AssetDTO update = AssetDTO.builder()
.sn("YOUR_DEVICE_SN")
.name("Dock Alpha -- Updated")
.build();
connectorService.updateAsset("550e8400-e29b-41d4-a716-446655440000", update)
.thenAccept(updated -> log.info("Asset updated"));
Deregister an Asset
deRegisterAsset(id) deletes the asset record. Do not call it on shutdown: a paired asset would have
to be paired again with a new code.
Asset Payloads
Report the hardware mounted on an asset or sub-asset — a camera, gimbal or sensor, with its slot, model and firmware.
connectorService.upsertAssetPayload("YOUR_DEVICE_SN", null, payloadDTO)
.thenAccept(saved -> log.info("Payload stored: {}", saved.getId()));
Schedulers
A schedule defines when a Skill or a single command runs, and on which asset. Schedules are created and changed in the Admin Console; an adapter can read one:
connectorService.getSchedulerById("scheduler-uuid")
.thenAccept(scheduler -> log.info("Scheduler: {}", scheduler));
Capabilities
An adapter reports which commands it supports by implementing getCapabilities(String sn) on
EdgeAdapterService, returning a CurrentCapabilities of Capability entries. The platform calls
this when it needs to know what an asset can do — for example so the Admin Console can hide
controls an asset does not support, rather than failing at execution time.
@Override
public CompletableFuture<CurrentCapabilities> getCapabilities(String sn) {
Capability takeoff = new Capability("takeOff", "Take off to a target point",
true, null, Map.of("source", "adapter"));
takeoff.setTargetType(CapabilityTargetType.CAPABILITY_TARGET_TYPE_ASSET);
takeoff.setInputSchema(Map.of("type", "object"));
return CompletableFuture.completedFuture(
CurrentCapabilities.of(sn, AssetTypeEnum.ASSET_TYPE_AIRCRAFT, Set.of(takeoff)));
}
Return CurrentCapabilities.empty(sn) for an asset you do not recognise. See
Edge Adapter for the full EdgeAdapterService surface.
Skill Registry
Beyond the live getCapabilities snapshot, an adapter can report its commands to the platform's
persisted Skill Registry — one entry per (command_id, schema_version), which Skill authors build on:
| Method | Purpose |
|---|---|
observeSkillContract(contract) | Add a contract, or refresh one already known |
listSkillContracts(status, commandId) | List the registry; with commandId, that command's version history |
setSkillContractStatus(id, status) | Move a contract through ACTIVE / DRAFT / DEPRECATED / RETIRED |
setSkillContractPermissions(id, requiredPermissions) | Replace its required permissions (stored, not yet enforced) |
See the Connector reference.
Media Files
registerMediaFile(request) records a file the device uploaded to the platform's inbox bucket. The
platform attributes it to the execution that was running on the asset and files it under its
organization. Reporting the same object twice is harmless.
Error Handling
All ConnectorServiceImpl methods follow a consistent error handling pattern:
- The gRPC response includes a
hasErrorsflag. - If
hasErrorsistrue, the method logs the error and returnsnull(for entity methods) orfalse(for delete methods). - If the gRPC call itself fails (network error, timeout), the
CompletableFuturecompletes exceptionally.
connectorService.getAssetBySn("SOME_SN")
.thenAccept(asset -> {
if (asset == null) {
log.warn("Asset not found or server error");
return;
}
// use asset
})
.exceptionally(err -> {
log.error("gRPC call failed", err);
return null;
});
Configuration
The Connector address is grpc.client.connector.host / .port (CONNECTOR_SERVICE_HOST /
CONNECTOR_SERVICE_PORT, default port 8010). See the Configuration Guide.
Usage Examples
Startup Pairing Pattern
package com.example.edge;
import com.zqnt.sdk.edge.connector.application.ConnectorService;
import com.zqnt.utils.asset.domains.AssetDTO;
import com.zqnt.utils.common.proto.AssetTypeEnum;
import com.zqnt.utils.common.proto.AssetVendor;
import io.quarkus.runtime.StartupEvent;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import java.util.Optional;
@Slf4j
@ApplicationScoped
public class AssetPairing {
private final ConnectorService connectorService;
@ConfigProperty(name = "zequent.edge.sn")
String sn;
// One-time pairing code from the Admin Console; only needed for a device the platform doesn't know yet
@ConfigProperty(name = "zqnt.claim-code")
Optional<String> claimCode;
public AssetPairing(ConnectorService connectorService) {
this.connectorService = connectorService;
}
void onStart(@Observes StartupEvent event) {
AssetDTO asset = AssetDTO.builder()
.sn(sn)
.name("Dock Alpha")
.type(AssetTypeEnum.ASSET_TYPE_DOCK)
.vendor(AssetVendor.ASSET_VENDOR_DJI)
.build();
connectorService.ensureAsset(asset, claimCode.orElse(null))
.thenAccept(found -> {
if (found == null) {
log.warn("Asset {} is not on the platform yet: create it in the console or set a pairing code", sn);
} else {
log.info("Asset {} is {}", sn, found.getId());
}
})
.exceptionally(err -> {
log.error("Asset lookup failed", err);
return null;
});
}
}
zqnt.claim-code reads ZQNT_CLAIM_CODE. Once the asset is paired, the code can be removed.
See also
- Connector API Reference — every method
- Edge Adapter — Custom Commands — how work reaches your adapter in 2.0