Fleet Engine を使ってみる

Fleet Engine On-demand Rides and Deliveries API を使用すると、ルートと注文状況のアプリケーションのルートと車両の状態を管理できます。Driver SDK、Consumer SDK、バックエンド サービス間のトランザクションを処理します。バックエンド サービスは、gRPC または REST 呼び出しを使用して Fleet Engine と通信できます。

前提条件

開発の場合は、Cloud SDK をインストール(gcloud)し、プロジェクトで認証されていることを確認します。

shell

gcloud auth login

次のような成功メッセージが表示されます。

You are now logged in as [my-user@example.com].
Your current project is [project-id].  You ...

On-demand Rides and Deliveries Solution Fleet Engine API が適切に設定されていることを確認します。

shell

gcloud --project=project-id services enable fleetengine.googleapis.com

このコマンドでエラーが発生した場合は、プロジェクト管理者と Google サポート担当者にアクセス権の取得を依頼してください。

ロギング

Fleet Engine は、受信した API 呼び出しに関するログメッセージを Google Cloud Platform ログに書き込むことができます。ログの読み取りと分析方法の概要については、Cloud Logging のドキュメントをご覧ください。

2022 年 2 月 10 日より前に作成されたプロジェクトでは、ロギングがデフォルトで有効になっていない場合があります。詳細については、ロギングのドキュメントをご覧ください。

クライアント ライブラリ

クライアント ライブラリは、いくつかの一般的なプログラミング言語で公開されています。これらのライブラリは、未加工の REST や gRPC よりも優れたデベロッパー エクスペリエンスを提供するのに役立ちます。サーバー アプリケーション用のクライアント ライブラリを取得する手順については、クライアント ライブラリをご覧ください。

このドキュメントの Java の例は、gRPC に精通していることを前提としています。

認証と認可

「移動」と「注文状況」によって提供される機能は、Google Cloud コンソールで構成できます。これらの API と SDK では、Cloud コンソールから作成されたサービス アカウントを使用して署名された JSON Web Token を使用する必要があります。

Cloud プロジェクトの設定

クラウド プロジェクトを設定するには、まずプロジェクトを作成してから、サービス アカウントを作成します。

Google Cloud プロジェクトを作成するには:

  1. Google Cloud コンソールを使用して Google Cloud プロジェクトを作成する。
  2. API とサービス ダッシュボードを使用して、Local Rides and Deliveries API を有効にします。

サービス アカウントは 1 つ以上のロールに関連付けられます。これらは、ロールに応じて異なる一連の権限を付与する JSON Web Token を作成するために使用されます。通常、不正使用の可能性を減らすために、必要最小限のロールセットを持つ複数のサービス アカウントを作成できます。

移動と注文の進捗状況は次のロールを使用します。

ロール説明
Fleet Engine Consumer SDK ユーザー

roles/fleetengine.consumerSdkUser
車両を検索する権限と、車両とルートに関する情報を取得する権限を付与します。このロールを持つサービス アカウントによって作成されたトークンは、通常、ライドシェアリングまたは宅配のコンシューマ アプリのモバイル デバイスで使用されます。
Fleet Engine Driver SDK ユーザー

roles/fleetengine.driverSdkUser
車両の位置情報とルートを更新する権限と、車両とルートに関する情報を取得する権限を付与します。通常、このロールを持つサービス アカウントによって作成されたトークンは、配車サービスや配達ドライバー アプリのモバイル デバイスで使用されます。
Fleet Engine サービス スーパー ユーザー

roles/fleetengine.serviceSuperUser
すべての車両とルートの API に権限を付与します。このロールを持つサービス アカウントによって作成されたトークンは、通常、バックエンド サーバーから使用されます。

たとえば、3 つのロールのそれぞれにサービス アカウントを作成し、それぞれのロールを割り当てます。

gcloud --project=project-id iam service-accounts create fleet-engine-consumer-sdk
gcloud projects add-iam-policy-binding project-id \
       --member=serviceAccount:fleet-engine-consumer-sdk@project-id.iam.gserviceaccount.com \
       --role=roles/fleetengine.consumerSdkUser

gcloud --project=project-id iam service-accounts create fleet-engine-driver-sdk
gcloud projects add-iam-policy-binding project-id \
       --member=serviceAccount:fleet-engine-driver-sdk@project-id.iam.gserviceaccount.com \
       --role=roles/fleetengine.driverSdkUser

gcloud --project=project-id iam service-accounts create fleet-engine-su
gcloud projects add-iam-policy-binding project-id \
       --member=serviceAccount:fleet-engine-su@project-id.iam.gserviceaccount.com \
       --role=roles/fleetengine.serviceSuperUser

Driver SDK と Consumer SDK は、これらの標準的なロールを中心に構築されています。

また、カスタムロールを作成して、任意の権限セットをバンドルすることもできます。必要な権限がないと、ドライバ SDK とコンシューマ SDK でエラー メッセージが表示されます。そのため、カスタムロールは使用しないことを強くおすすめします。

利便性のため、信頼できないクライアント用の JWT トークンを作成する必要がある場合は、サービス アカウント トークン作成者ロールにユーザーを追加すると、そのユーザーは gcloud コマンドライン ツールでトークンを作成できます。

gcloud projects add-iam-policy-binding project-id \
       --member=user:my-user@example.com \
       --role=roles/iam.serviceAccountTokenCreator

ここで、my-user@example.com は gcloud での認証に使用するメールアドレス(gcloud auth list --format='value(account)')です。

Fleet Engine 認証ライブラリ

Fleet Engine は、JSON Web Token(JWT)を使用して Fleet Engine API へのアクセスを制限します。新しい Fleet Engine Auth Library(GitHub で入手可能)を使用すると、Fleet Engine JWT の構成を簡素化し、安全に署名できます。

このライブラリには次のようなメリットがあります。

  • Fleet Engine トークンの作成プロセスを簡素化します。
  • 認証情報ファイルを使用する以外のトークン署名メカニズム(サービス アカウントの権限借用など)を提供します。
  • 署名付きトークンを gRPC スタブまたは GAPIC クライアントから送信された送信リクエストに追加します。

認可用の JSON Web Token(JWT)の作成

Fleet Engine 認証ライブラリを使用しない場合は、コードベース内で JSON Web Token(JWT)を直接作成する必要があります。そのためには、JWT と Fleet Engine との関連性の両方について深く理解している必要があります。そのため、Fleet Engine 認証ライブラリを利用することを強くおすすめします。

Fleet Engine 内では、JSON Web Token(JWT)が有効期間の短い認証を提供し、デバイスが承認された車両、ルート、タスクのみを変更できるようにします。JWT にはヘッダーとクレーム セクションが含まれます。ヘッダー セクションには、使用する秘密鍵(サービス アカウントから取得)や暗号化アルゴリズムなどの情報が含まれています。クレーム セクションには、トークンの作成時間、トークンの有効期間、アクセスを申請しているサービス、ダウン アクセスのスコープを設定するためのその他の認可情報(車両 ID など)が含まれます。

JWT ヘッダー セクションには次のフィールドがあります。

項目説明
alg 使用するアルゴリズム。「RS256」。
typ トークンのタイプ。JWT。
子供 サービス アカウントの秘密鍵 ID。この値は、サービス アカウント JSON ファイルの private_key_id フィールドで確認できます。適切なレベルの権限を持つサービス アカウントの鍵を使用してください。

JWT クレームのセクションには次のフィールドがあります。

項目説明
iss サービス アカウントのメールアドレス。
sub サービス アカウントのメールアドレス。
AUD サービス アカウントの SERVICE_NAME(この場合は https://fleetengine.googleapis.com/)
iat トークンが作成されたときのタイムスタンプ。1970 年 1 月 1 日 00:00:00 UTC からの経過秒数で指定します。スキューのために 10 分間待ちます。タイムスタンプが過去にさかのぼって、または未来の日付になっている場合、サーバーがエラーを報告する可能性があります。
exp トークンが期限切れになるタイムスタンプ。1970 年 1 月 1 日 00:00:00 UTC からの経過秒数で指定します。タイムスタンプが 1 時間以上先である場合、リクエストは失敗します。
authorization ユースケースに応じて、「vehicleid」または「tripid」を含めることができます。

JWT トークンを作成するということは、それに署名することです。JWT の作成と署名の手順とコードサンプルについては、OAuth を使用しないサービス アカウントの認証をご覧ください。その後、署名付きトークンを gRPC 呼び出し、または Fleet Engine へのアクセスに使用するその他のメソッドにアタッチできます。

JWT クレーム

JWT ペイロードを作成するときに、認証セクションにクレームを追加し、キー vehicleid または tripid を呼び出し対象の車両 ID またはルート ID の値に設定します。

Driver SDK は、運転しているルートがルートか車両かにかかわらず、常に vehicleid クレームを使用します。Fleet Engine のバックエンドは、変更を行う前に、リクエストされたルートに車両が関連付けられていることを確認します。

Consumer SDK では常に tripid クレームが使用されます。

配車サービス プロバイダまたは配達プロバイダは、vehicleid または tripid を「*」とともに使用して、すべての車両とルートに一致させる必要があります。JWT には、不要な場合でも両方のトークンを含めることができるため、トークン署名の実装が簡素化される場合があります。

JWT のユースケース

プロバイダ サーバーのトークンの例を次に示します。

{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "private_key_id_of_provider_service_account"
}
.
{
  "iss": "provider@yourgcpproject.iam.gserviceaccount.com",
  "sub": "provider@yourgcpproject.iam.gserviceaccount.com",
  "aud": "https://fleetengine.googleapis.com/",
  "iat": 1511900000,
  "exp": 1511903600,
  "authorization": {
     "vehicleid": "*",
     "tripid": "*"
   }
}

一般ユーザー向けアプリのトークンの例を次に示します。

{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "private_key_id_of_consumer_service_account"
}
.
{
  "iss": "consumer@yourgcpproject.iam.gserviceaccount.com",
  "sub": "consumer@yourgcpproject.iam.gserviceaccount.com",
  "aud": "https://fleetengine.googleapis.com/",
  "iat": 1511900000,
  "exp": 1511903600,
  "authorization": {
     "tripid": "trip_54321"
   }
}

以下は、Driver app のトークンの例です。

{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "private_key_id_of_driver_service_account"
}
.
{
  "iss": "driver@yourgcpproject.iam.gserviceaccount.com",
  "sub": "driver@yourgcpproject.iam.gserviceaccount.com",
  "aud": "https://fleetengine.googleapis.com/",
  "iat": 1511900000,
  "exp": 1511903600,
  "authorization": {
     "vehicleid": "driver_12345"
   }
}
  • ヘッダーの kid フィールドに、サービス アカウントの秘密鍵 ID を指定します。この値は、サービス アカウント JSON ファイルの private_key_id フィールドにあります。
  • iss フィールドと sub フィールドに、サービス アカウントのメールアドレスを指定します。この値は、サービス アカウント JSON ファイルの client_email フィールドにあります。
  • aud フィールドに https://SERVICE_NAME/ を指定します。
  • iat フィールドには、トークンが作成されたときのタイムスタンプを、1970 年 1 月 1 日 00:00:00 UTC からの経過秒数として指定します。スキューのために 10 分間待ちます。タイムスタンプが古すぎる、または未来のものであると、サーバーがエラーを報告する可能性があります。
  • exp フィールドには、トークンが期限切れになるときのタイムスタンプ(1970 年 1 月 1 日 00:00:00 UTC からの経過秒数)を使用します。指定できる最大値は iat + 3,600 です。

モバイル デバイスに渡す JWT に署名する場合は、Driver SDK または Consumer SDK のロールのサービス アカウントを使用してください。それ以外の場合、モバイル デバイスは設定すべきでない状態を変更できます。

同様に、特権呼び出しに使用する JWT に署名する場合は、スーパー ユーザーのロールを持つサービス アカウントを使用してください。そうしないと、オペレーションが失敗します。

テスト用の JWT の生成

テスト時には、ターミナルからトークンを生成すると便利です。

以下の手順を行うには、ユーザー アカウントにサービス アカウント トークン作成者のロールが必要です。

gcloud projects add-iam-policy-binding project-id \
       --member=user:my-user@example.com \
       --role=roles/iam.serviceAccountTokenCreator

次の内容の新しいファイルを unsigned_token.json という名前で作成します。iat プロパティは、エポックからの現在の時刻(秒単位)です。これは、ターミナルで date +%s を実行することで取得できます。exp プロパティは、エポックからの経過秒数(秒単位)です。これは、iat に 3, 600 を足して計算できます。有効期限は今後 1 時間以上にする必要があります。

{
  "aud": "https://fleetengine.googleapis.com/",
  "iss": "super-user-service-account@project-id.iam.gserviceaccount.com",
  "sub": "super-user-service-account@project-id.iam.gserviceaccount.com",
  "iat": iat,
  "exp": exp,
  "authorization": {
     "vehicleid": "*",
     "tripid": "*"
   }
}

次に、次の gcloud コマンドを実行して、スーパー ユーザー サービス アカウントに代わってトークンに署名します。

gcloud beta iam service-accounts sign-jwt --iam-account=super-user-service-account@project-id.iam.gserviceaccount.com unsigned_token.json signed_token.jwt

これで、署名付きの Base64 エンコード JWT が signed_token.jwt ファイル内に格納されているはずです。トークンは 1 時間有効です。

これで、List Vehicles REST エンドポイントに対して curl コマンドを実行して、トークンをテストできるようになりました。

curl -X GET "https://fleetengine.googleapis.com/v1/providers/project-id/vehicles" -H "Authorization: Bearer $(cat signed_token.jwt)"

車両とそのライフサイクル

Vehicle は、ドライバーと車両のペアを表すエンティティです。現時点では、ドライバーと車両を個別に追跡することはできません。ライドシェア プロバイダまたはデリバリー プロバイダは、プロバイダ ID(Fleet Engine API の呼び出しに使用されるサービス アカウントを含む Google Cloud プロジェクトのプロジェクト ID と同じである必要がある)と、ライドシェア プロバイダまたはデリバリー プロバイダが所有する車両 ID を使用して車両を作成します。

7 日後に UpdateVehicle を介して更新されなかった車両は自動的に削除されます。既存のプロバイダ ID/車両 ID のペアで CreateVehicle を呼び出すとエラーが発生します。頻繁に更新されない車両の場合は、想定されるプロバイダ ID/車両 ID のペアで CreateVehicle を頻繁に呼び出し、車両がすでに存在する場合はエラーを破棄するか、または UpdateVehicle の後に CreateVehicle を呼び出すと NOT_FOUND エラーが返されるかの 2 つの方法で対処できます。

車両位置情報の更新

Fleet Engine で最高のパフォーマンスを得るには、車両位置情報の更新のストリームを提供します。次のいずれかの方法で最新情報を提供します。

  1. Driver SDK を使用します(AndroidiOS)。最もシンプルなオプションです。
  2. カスタムコードを使用します。これは、位置情報がバックエンド経由でリレーされる場合や、Android または iOS 以外のデバイスを使用している場合に役立ちます。

車種

Vehicle エンティティには VehicleType という必須フィールドがあり、このフィールドに AUTOTAXITRUCKTWO_WHEELERBICYCLEPEDESTRIAN のいずれかとして指定できる Category 列挙型が含まれています。車両タイプは、SearchVehiclesListVehicles でフィルタ条件として機能します。

カテゴリが AUTOTWO_WHEELERBICYCLEPEDESTRIAN のいずれかに設定されている場合、車両のすべてのルーティングで、対応する RouteTravelMode が使用されます。カテゴリが TAXI または TRUCK に設定されている場合、ルーティングは AUTO モードと同様に扱われます。

車両属性

Vehicle エンティティには VehicleAttribute の繰り返しフィールドが含まれています。これらの属性は、Fleet Engine によって解釈されません。SearchVehicles API には、一致した Vehicles に、指定された値に設定されたすべての属性を含めることを要求するフィールドがあります。

属性フィールドは、Vehicle メッセージでサポートされる他のいくつかのフィールド(vehicle_typesupported_trip_types など)に追加されることに注意してください。

車両の残りの地点

Vehicle エンティティには、waypointsRPC | REST)という TripWaypointRPC | REST)の繰り返しフィールドが含まれています。このフィールドには、ルートの残りのウェイポイントが、車両が到着する順序で含まれます。Fleet Engine はルートが車両に割り当てられるとこのフィールドを計算し、ルートのステータスが変化するとこのフィールドを更新します。これらの地点は、TripId フィールドと WaypointType フィールドで識別できます。

車両のマッチングの対象を拡大する

通常、配車サービスまたは配達プロバイダのサービスが、ルート リクエストを車両と照合します。このサービスでは車両属性を使用して、より多くの検索に車両を含めることができます。たとえば、車両が提供する特典や機能のレベルに対応する属性のセットを実装できます。たとえば、is_bronze_levelis_silver_levelis_gold_level の 3 つのレベルは、ブール値を持つ属性セットです。車両はこの 3 つすべてに要件を満たすことができます。フリート エンジンがシルバーレベルの機能を必要とするルートのリクエストを受信すると、検索にその車両が含まれます。この方法で属性を使用する場合、さまざまな機能を提供する車両が含まれます。

車両属性を更新する方法は 2 つあります。1 つは UpdateVehicle API です。この API を使用すると、車両属性のセット全体がこの値に設定されます。1 つの属性だけを更新することはできません。もう一つのメソッドは UpdateVehicleAttributes API です。このメソッドは、更新する属性のみを受け取ります。リクエストに含まれる属性は、新しい値または追加された値に設定されます。指定されていない属性は変更されません。

手順: 車両を作成する

フリート内で追跡する車両ごとに、Vehicle エンティティを作成する必要があります。

CreateVehicle エンドポイントを CreateVehicleRequest とともに使用して、車両を作成します。

Vehicleprovider_id は、Fleet Engine を呼び出すために使用されるサービス アカウントを含む Google Cloud プロジェクトのプロジェクト ID(例: my-on-demand-project)にする必要があります。複数のサービス アカウントは同じライドシェアまたは配信プロバイダの Fleet Engine にアクセスできますが、Fleet Engine は現在、同じ Vehicles にアクセスする複数の Google Cloud プロジェクトのサービス アカウントをサポートしていません。

Vehicle は、OFFLINE 状態または ONLINE 状態で作成できます。ONLINE が作成されると、SearchVehicles クエリに応答して直ちに返されます。

最初の last_locationCreateVehicle 呼び出しに含めることができます。許可されている場合、Vehiclelast_location なしで ONLINE 状態で作成できません。

車両タイプ フィールドの詳細については、車両タイプをご覧ください。

属性フィールドの詳細については、車両属性をご覧ください。

CreateVehicle から返される値は、作成された Vehicle エンティティです。

shell

curl -X POST \
  "https://fleetengine.googleapis.com/v1/providers/project-id/vehicles?vehicleId=vid-8241890" \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  --data-binary @- << EOM
{
    "vehicleState": "OFFLINE",
    "supportedTripTypes": ["EXCLUSIVE"],
    "maximumCapacity": 4,
    "vehicleType": {"category": "AUTO"},
    "attributes": [{"key": "on_trip", "value": "false"}]
}
EOM

providers.vehicles.create リファレンスをご覧ください。

Java

static final String PROJECT_ID = "project-id";

VehicleServiceBlockingStub vehicleService =
    VehicleService.newBlockingStub(channel);

String parent = "providers/" + PROJECT_ID;
Vehicle vehicle = Vehicle.newBuilder()
    .setVehicleState(VehicleState.OFFLINE)  // Initial state
    .addSupportedTripTypes(TripType.EXCLUSIVE)
    .setMaximumCapacity(4)
    .setVehicleType(VehicleType.newBuilder().setCategory(VehicleType.Category.AUTO))
    .addAttributes(VehicleAttribute.newBuilder()
        .setKey("on_trip").setValue("false"))  // Opaque to the Fleet Engine
    // Add .setBackToBackEnabled(true) to make this vehicle eligible for trip
    // matching while even if it is on a trip.  By default this is disabled.
    .build();

CreateVehicleRequest createVehicleRequest =
    CreateVehicleRequest.newBuilder()  // no need for the header
        .setParent(parent)
        .setVehicleId("vid-8241890")  // Vehicle ID assigned by Rideshare or Delivery Provider
        .setVehicle(vehicle)  // Initial state
        .build();

// In this case, the Vehicle is being created in the OFFLINE state and
// no initial position is being provided.  When the Driver App checks
// in with the Rideshare or Delivery Provider, the state can be set to ONLINE and
// the Driver App will update the Vehicle Location.

try {
  Vehicle createdVehicle =
      vehicleService.createVehicle(createVehicleRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
    case ALREADY_EXISTS:
      break;
    case PERMISSION_DENIED:
      break;
  }
  return;
}
// If no Exception, Vehicle created successfully.

車両作成の Google Cloud Platform ログ

Fleet Engine API は、CreateVehicle エンドポイントの呼び出しを受信すると、Google Cloud Platform ログを介してログエントリを書き込みます。ログエントリには、CreateVehicle リクエストの値に関する情報が含まれています。呼び出しが成功すると、返された Vehicle に関する情報も含まれます。

shell

gcloud --project=project-id logging read --freshness=1h '
  jsonPayload.request.vehicleId="vid-8241890"
  jsonPayload.@type="type.googleapis.com/maps.fleetengine.v1.CreateVehicleLog"
'

次のようなレコードが出力されます。

---
insertId: c2cf4d3a180251c1bdb892137c14f022
jsonPayload:
  '@type': type.googleapis.com/maps.fleetengine.v1.CreateVehicleLog
  request:
    vehicle:
      attributes:
      - key: on_trip
        value: 'false'
      maximumCapacity: 4
      state: VEHICLE_STATE_OFFLINE
      supportedTrips:
      - EXCLUSIVE_TRIP
      vehicleType:
        vehicleCategory: AUTO
    vehicleId: vid-8241890
  response:
    attributes:
    - key: on_trip
      value: 'false'
    availableCapacity: 4
    currentRouteSegmentHandle: AdSiwAwCO9gZ7Pw5UZZimOXOo41cJTjg/r3SuwVPQmuuaV0sU3+3UCY+z53Cl9i6mWHLoCKbBt9Vsj5PMRgOJ8zX
    maximumCapacity: 4
    name: providers/project-id/vehicles/vid-8241890
    state: VEHICLE_STATE_OFFLINE
    supportedTrips:
    - EXCLUSIVE_TRIP
    vehicleType:
      vehicleCategory: AUTO
labels:
  vehicle_id: vid-8241890
logName: projects/project-id/logs/fleetengine.googleapis.com%2Fcreate_vehicle
receiveTimestamp: '2021-09-22T03:25:16.361159871Z'
resource:
  labels:
    location: global
    resource_container: projects/project-id
  type: fleetengine.googleapis.com/Fleet
timestamp: '2021-09-22T03:25:15.724998Z'

車両作成に関する Cloud Pub/Sub 通知

Fleet Engine API は、新しい車両が作成されると Cloud Pub/Sub 経由で通知をパブリッシュします。これらの通知を受け取るには、こちらの手順に沿って操作してください。

手順: 車両の位置情報を更新する

Driver SDK を使用して車両の位置情報を更新していない場合は、車両の位置情報を指定して Fleet Engine を直接呼び出すことができます。アクティブな車両について、Fleet Engine は少なくとも 1 分に 1 回、最大で 5 秒に 1 回、位置情報の更新があると想定します。これらの更新には、Fleet Engine Driver SDK ユーザー権限のみが必要です。

shell

curl -X PUT \
  "https://fleetengine.googleapis.com/v1/providers/project-id/vehicles/vid-8241890?updateMask=last_location" \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  --data-binary @- << EOM
{
    "supplementalLocation": {"latitude": 12.1, "longitude": 14.5},
    "supplementalLocationTime": "$(date -u --iso-8601=seconds)",
    "supplementalLocationSensor": "CUSTOMER_SUPPLIED_LOCATION",
    "supplementalLocationAccuracy": 15
}
EOM

providers.vehicles.update リファレンスをご覧ください。

Java

static final String PROJECT_ID = "project-id";
static final String VEHICLE_ID = "vid-8241890";

VehicleServiceBlockingStub vehicleService = VehicleService.newBlockingStub(channel);

String vehicleName = "providers/" + PROJECT_ID + "/vehicles/" + VEHICLE_ID;
Vehicle updatedVehicle = Vehicle.newBuilder()
    .setLastLocation(VehicleLocation.newBuilder()
        .setSupplementalLocation(LatLng.newBuilder()
            .setLatitude(37.3382)
            .setLongitude(121.8863))
        .setSupplementalLocationTime(now())
        .setSupplementalLocationSensor(LocationSensor.CUSTOMER_SUPPLIED_LOCATION)
        .setSupplementalLocationAccuracy(DoubleValue.of(15.0)))  // Optional)
    .build();

UpdateVehicleRequest updateVehicleRequest = UpdateVehicleRequest.newBuilder()
    .setName(vehicleName)
    .setVehicle(updatedVehicle)
    .setUpdateMask(FieldMask.newBuilder()
        .addPaths("last_location"))
    .build();

try {
  Vehicle updatedVehicle =
      vehicleService.updateVehicle(updateVehicleRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
    case NOT_FOUND:
      // Most implementations will call CreateVehicle in this case
      break;
    case PERMISSION_DENIED:
      break;
  }
  return;
}
// If no Exception, Vehicle updated successfully.

手順: 他の車両フィールドを更新する

車両状態の他の属性の更新は、位置情報の更新よりも頻度が低くなります。last_location 以外の属性を更新するには、Fleet Engine のスーパー ユーザー権限が必要です。

UpdateVehicleRequest には、更新するフィールドを示す update_mask が含まれています。フィールドの動作は、フィールド マスクに関する Protobuf ドキュメントに記載されています。

車両属性で説明したように、attributes フィールドを更新するには、保持するすべての属性を書き込む必要があります。UpdateVehicle 呼び出しで 1 つの Key-Value ペアの値を更新することはできません。特定の属性の値を更新するには、UpdateVehicleAttributes API を使用できます。

この例では、back_to_back を有効にします。

shell

curl -X PUT \
  "https://fleetengine.googleapis.com/v1/providers/project-id/vehicles/vid-8241890?updateMask=vehicle_state,attributes,back_to_back_enabled" \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  --data-binary @- << EOM
{
    "vehicleState": "ONLINE",
    "attributes": [
      {"key": "on_trip", "value": "true"},
      {"key": "cash_only", "value": "false"}
    ],
    "backToBackEnabled": true
}
EOM

providers.vehicles.update リファレンスをご覧ください。

Java

static final String PROJECT_ID = "project-id";
static final String VEHICLE_ID = "vid-8241890";

VehicleServiceBlockingStub vehicleService = VehicleService.newBlockingStub(channel);

String vehicleName = "providers/" + PROJECT_ID + "/vehicles/" + VEHICLE_ID;
Vehicle updatedVehicle = Vehicle.newBuilder()
    .setVehicleState(VehicleState.ONLINE)
    .addAllAttributes(ImmutableList.of(
        VehicleAttribute.newBuilder().setKey("on_trip").setValue("true").build(),
        VehicleAttribute.newBuilder().setKey("cash_only").setValue("false").build()))
    .setBackToBackEnabled(true)
    .build();

UpdateVehicleRequest updateVehicleRequest = UpdateVehicleRequest.newBuilder()
    .setName(vehicleName)
    .setVehicle(updatedVehicle)
    .setUpdateMask(FieldMask.newBuilder()
        .addPaths("vehicle_state")
        .addPaths("attributes")
        .addPaths("back_to_back_enabled"))
    .build();

// Attributes and vehicle state are being updated, so both are
// included in the field mask.  Note that of on_trip were
// not being updated, but rather cash_only was being changed,
// the desired value of "on_trip" would still need to be written
// as the attributes are completely replaced in an update operation.

try {
  Vehicle updatedVehicle =
      vehicleService.updateVehicle(updateVehicleRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
    case NOT_FOUND:
      // Most implementations will call CreateVehicle in this case
      break;
    case PERMISSION_DENIED:
      break;
  }
  return;
}
// If no Exception, Vehicle updated successfully.

車両の更新情報に関する Google Cloud Platform のログ

Fleet Engine API は、UpdateVehicle エンドポイントの呼び出しを受信すると、Google Cloud Platform ログを介してログエントリを書き込みます。ログエントリには、UpdateVehicle リクエストの値に関する情報が含まれています。呼び出しが成功すると、返された Vehicle に関する情報も含まれます。

shell

gcloud --project=project-id logging read --freshness=1h '
  jsonPayload.request.vehicleId="vid-8241890"
  jsonPayload.@type="type.googleapis.com/maps.fleetengine.v1.UpdateVehicleLog"
'

車両の更新情報に関する Cloud Pub/Sub 通知

Fleet Engine API は、既存の車両が更新されると Cloud Pub/Sub 経由で通知をパブリッシュします。これらの通知を受け取るには、こちらの手順に沿って操作してください。

手順: 車両を検索する

Fleet Engine は車両の検索をサポートしています。SearchVehicles API を使用すると、配車サービスや配達リクエストなどのタスクに最適な、近くのドライバーを検索できます。SearchVehicles API は、タスク属性とフリート内の車両属性に一致するドライバーのランク付けされたリストを返します。詳細については、付近のドライバーを探すをご覧ください。

利用可能な車両を検索する際、Fleet Engine はデフォルトで、有効なルートの車両を除外します。ライドシェア プロバイダのサービスまたは配達プロバイダのサービスは、検索リクエストに明示的に含める必要があります。次の例は、グランド インドネシア イースト モールからバライ シダン ジャカルタ コンベンション センターへのルートに一致する車両の検索にこれらの車両を含める方法を示しています。

shell

まず、前の手順で作成した車両の位置を更新して、この機能が有効になるようにします。実際には、これは車内の Android デバイスまたは iOS デバイスで実行される Driver SDK によって行われます。

curl -X PUT \
  "https://fleetengine.googleapis.com/v1/providers/project-id/vehicles/vid-8241890?updateMask=last_location,attributes" \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  --data-binary @- << EOM
{
  "lastLocation": {
    "updateTime": "$( date -u +"%Y-%m-%dT%H:%M:%SZ" )",
    "location": {
      "latitude": "-6.195139",
      "longitude": "106.820826"
    }
  },
  "attributes": [{"key": "on_trip", "value": "false"}]
}
EOM

検索を実行すると、少なくともその車両が取得されます。

curl -X POST \
  "https://fleetengine.googleapis.com/v1/providers/project-id/vehicles:search" \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  --data-binary @- << EOM
{
  "pickupPoint": {
    "point": {"latitude": "-6.195139", "longitude": "106.820826"}
  },
  "dropoffPoint": {
    "point": {"latitude": "-6.1275", "longitude": "106.6537"}
  },
  "pickupRadiusMeters": 2000,
  "count": 10,
  "minimumCapacity": 2,
  "tripTypes": ["EXCLUSIVE"],
  "vehicleTypes": [{"category": "AUTO"}],
  "filter": "attributes.on_trip=\"false\"",
  "orderBy": "PICKUP_POINT_ETA",
  "includeBackToBack": true
}
EOM

providers.vehicles.search リファレンスをご覧ください。

Java

static final String PROJECT_ID = "project-id";

VehicleServiceBlockingStub vehicleService = VehicleService.newBlockingStub(channel);

String parent = "providers/" + PROJECT_ID;
SearchVehiclesRequest searchVehiclesRequest = SearchVehiclesRequest.newBuilder()
    .setParent(parent)
    .setPickupPoint( // Grand Indonesia East Mall
        TerminalLocation.newBuilder().setPoint(
            LatLng.newBuilder().setLatitude(-6.195139).setLongitude(106.820826)))
    .setDropoffPoint( // Balai Sidang Jakarta Convention Center
        TerminalLocation.newBuilder().setPoint(
            LatLng.newBuilder().setLatitude(-6.213796).setLongitude(106.807195)))
    .setPickupRadiusMeters(2000)
    .setCount(10)
    .setMinimumCapacity(2)
    .addTripTypes(TripType.EXCLUSIVE)
    .addVehicleTypes(VehicleType.newBuilder().setCategory(VehicleType.Category.AUTO))
    .setFilter("attributes.on_trip=\"false\"")
    .setOrderBy(VehicleMatchOrder.PICKUP_POINT_ETA)
    .setIncludeBackToBack(true) // Fleet Engine includes vehicles that are en route.
    .build();

// Error handling
// If matches are returned and the authentication passed, the request completed
// successfully

try {
  SearchVehiclesResponse searchVehiclesResponse =
      vehicleService.searchVehicles(searchVehiclesRequest);

  // Search results: Each vehicle match contains a vehicle entity and information
  // about the distance and ETA to the pickup point and dropoff point.
  List<VehicleMatch> vehicleMatches = searchVehiclesResponse.getMatchesList();
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
    case NOT_FOUND:
      break;
    case PERMISSION_DENIED:
      break;
  }
  return;
}

車両フィルタリング クエリ

SearchVehiclesListVehicles は、フィルタクエリを使用した車両属性のフィルタリングをサポートしています。フィルタクエリの構文については、AIP-160 で例をご覧ください。

フィルタクエリは、車両属性のフィルタリングのみをサポートしています。他のフィールドには使用できません。フィルタクエリは、SearchVehiclesRequestminimum_capacityvehicle_types など、他の制約とともに AND 句として機能します。

手順: 車両を一覧表示する

SearchVehicles は、ランク付けされた順序で少数の車両をすばやく見つけるために最適化されており、主に、タスクに最適な近くのドライバーを見つけるために使用されます。しかし、結果をページ分けする必要があったとしても、特定の条件を満たすすべての車両を検出したい場合もあります。ListVehicles はそのユースケース向けに設計されています。

ListVehicles API を使用すると、特定のリクエスト オプションを満たすすべての車両を検索できます。ListVehicles API は、要件に一致するプロジェクト内の車両のページ分けされたリストを返します。

車両属性をフィルタリングするには、車両フィルタリング クエリをご覧ください。

この例では、filter 文字列を使用して、vehicle_type と属性にフィルタリングを行います。

shell

curl -X POST \
  "https://fleetengine.googleapis.com/v1/providers/project-id/vehicles:list" \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  --data-binary @- << EOM
{
  "vehicleTypes": [{"category": "AUTO"}],
  "filter": "attributes.on_trip=\"false\"",
}
EOM

providers.vehicles.list リファレンスをご覧ください。

Java

static final String PROJECT_ID = "project-id";

VehicleServiceBlockingStub vehicleService = VehicleService.newBlockingStub(channel);

String parent = "providers/" + PROJECT_ID;
ListVehiclesRequest listVehiclesRequest = ListVehiclesRequest.newBuilder()
    .setParent(parent)
    .addTripTypes(TripType.EXCLUSIVE)
    .addVehicleTypes(VehicleType.newBuilder().setCategory(VehicleType.Category.AUTO))
    .setFilter("attributes.on_trip=\"false\"")
    .setIncludeBackToBack(true) // Fleet Engine includes vehicles that are en route.
    .build();

// Error handling
// If matches are returned and the authentication passed, the request completed
// successfully

try {
  ListVehiclesResponse listVehiclesResponse =
      vehicleService.listVehicles(listVehiclesRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
    case NOT_FOUND:
      break;
    case PERMISSION_DENIED:
      break;
  }
  return;
}

ルートとそのライフサイクル

Trip API とライフサイクルは、Vehicle API とライフサイクルに似ています。ライドシェア プロバイダは、Fleet Engine インターフェースを使用してルートを作成します。Fleet Engine は、RPC サービス TripService と REST リソース provider.trips の両方を提供します。これらのインターフェースにより、ルート エンティティの作成、情報リクエスト、検索機能、更新機能が有効になります。

Trip には、ライフサイクル全体での進捗状況を追跡するステータス フィールドがあります。値は NEW から COMPLETE に加えて CANCELEDUNKNOWN_TRIP_STATUS に移行します。RPC の場合は trip_statusREST の場合は TripStatus をご覧ください。

  • NEW
  • ENROUTE_TO_PICKUP
  • ARRIVED_AT_PICKUP
  • ENROUTE_TO_INTERMEDIATE_DESTINATION
  • ARRIVED_AT_INTERMEDIATE_DESTINATION
  • ENROUTE_TO_DROPOFF
  • COMPLETE

CANCELED 行きのルートは、次のいずれかのステータスから更新できます。サービスがルートを作成すると、エンジンによってステータスが NEW に設定されます。vehicle_id は省略可能です。車両と同様に、サービスは 7 日後に更新なしにルートを自動的に削除します。サービスがすでに存在する ID でルートを作成しようとすると、エラーが返されます。ルートのステータスが COMPLETE または CANCELED 以外の場合、そのルートは「アクティブ」と見なされます。この区別は、Vehicle エンティティの active_trips フィールドと SearchTripsRequest では重要です。

サービスは、ステータスが NEW または CANCELED の場合にのみ、Trip に割り当てられた vehicle_id を変更できます。ドライバーがルートの途中でルートをキャンセルした場合は、vehicle_id を変更またはクリアする前に、ルート ステータスを NEW または CANCELED に設定する必要があります。

連続ルートのサポートを実装する場合、このステータスは重要です。このサポートにより、プロバイダは、車両がアクティブなルートにあるときに、新しいルートを車両に割り当てることができます。Back-to-Back ルートを作成するコードは 1 つのルートと同じで、同じ車両 ID を使用します。Fleet Engine は、新しいルートの出発地と目的地を車両のウェイポイントに追加します。連続するルートについて詳しくは、複数の地点を経由するルートを作成するをご覧ください。

ルートの残りの地点

Trip エンティティには、remainingWaypointsRPC | REST)という TripWaypointRPC | REST)の繰り返しフィールドが含まれます。このフィールドには、このルートの最終降車地点までに車両が順番に移動する必要があるすべての地点が含まれます。車両の残りの地点から計算されます。Back-to-Back と Carpool のユースケースでは、このリストには、このルートの前に通過する他のルートのウェイポイントが含まれますが、このルートの後に通過するウェイポイントは除外されます。リスト内の地点は TripIdWaypointType で識別できます。

移動状況と車両の残りの地点の関係

Fleet Engine がルート ステータスの変更リクエストを受信すると、車両の残りの地点RPC | REST)が更新されます。tripStatusRPC | REST)が他のステータスから ENROUTE_TO_XXX に変更されると、前のウェイポイントは車両の残りのウェイポイント リストから削除されます。つまり、ルート ステータスが ENROUTE_TO_PICKUP から ARRIVED_AT_PICKUP に変更された場合、ルートの乗車ポイントは車両の残りの地点リストに残りますが、ルート ステータスが ENROUTE_TO_INTERMEDIATE_DESTINATION または ENROUTE_TO_DROPOFF に変更されると、車両の残りの乗車地点が削除されます。

これは、ARRIVED_AT_INTERMEDIATE_DESTINATION と ENROUTE_TO_INTERMDEDIATE_DESTINATION についても同様です。ARRIVED_AT_INTERMEDIATE_DESTINATION の場合、現在の中間目的地は、次のウェイポイントに到着したことを車両が報告するまで、車両の残りのウェイポイント リストから削除されません。

ルートのステータスが COMPLETED に変更されると、このルートの地点は車両の残りの地点リストに含まれません。

手順: ルートを作成する

各ルート リクエストを追跡してフリート内の車両と照合するには、Trip エンティティを作成する必要があります。CreateTrip エンドポイントを CreateTripRequest とともに使用してルートを作成します。

ルートを作成するには、次の属性が必要です。

  • parent - Google Cloud プロジェクトの作成時に作成されたプロバイダ ID を含む文字列。
  • trip_id - ライドシェア プロバイダによって作成された文字列。
  • trip - ルートを記述する基本的なメタデータを含むコンテナ。
    • trip_type - 同じ車両(SHARED)で出発地と目的地が異なる他の乗客がいる可能性があるかどうか(EXCLUSIVE の場合)を表す列挙型。
    • pickup_point - ルートの出発地を表す TerminalLocation。RPC リファレンスまたは REST リファレンスをご覧ください。

ルートを作成する際には、number_of_passengersdropoff_pointvehicle_id を指定できます。これらのフィールドは必須ではありませんが、指定すると保持されます。その他の Trip フィールドはすべて無視されます。たとえば、すべてのルートは、作成リクエストで CANCELEDtrip_status を渡しても、NEWtrip_status で開始されます。

次の例では、グランド インドネシア イースト モールへのルートを作成します。このルートは乗客 2 名で、排他的です。Tripprovider_id は、プロジェクト ID と同じにする必要があります。この例では、ライドシェア プロバイダが Google Cloud プロジェクト project-id を作成しました。このプロジェクトには、Fleet Engine を呼び出すために使用されるサービス アカウントが必要です。ルートのステータスは NEW です。

その後、ルートを車両と照合した後、UpdateTrip を呼び出して、ルートが車両に割り当てられると vehicle_id を変更できます。

shell

curl -X POST \
  "https://fleetengine.googleapis.com/v1/providers/project-id/trips?tripId=tid-1f97" \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  --data-binary @- << EOM
{
  "tripType": "EXCLUSIVE",
  "numberOfPassengers": 2,
  "pickupPoint": {
    "point": {"latitude": "-6.195139", "longitude": "106.820826"}
  },
  "dropoffPoint": {
    "point": {"latitude": "-6.1275", "longitude": "106.6537"}
  }
}
EOM

providers.trips.create リファレンスをご覧ください。

Java

static final String PROJECT_ID = "project-id";

TripServiceBlockingStub tripService = TripService.newBlockingStub(channel);

String parent = "providers/" + PROJECT_ID;
Trip trip = Trip.newBuilder()
    .setTripType(TripType.EXCLUSIVE) // Use TripType.SHARED for carpooling
    .setPickupPoint(                 // Grand Indonesia East Mall
        TerminalLocation.newBuilder().setPoint(
            LatLng.newBuilder().setLatitude(-6.195139).setLongitude(106.820826)))
    // Provide the number of passengers if available.
    .setNumberOfPassengers(2)
    // Provide the drop-off point if available.
    .setDropoffPoint(
        TerminalLocation.newBuilder().setPoint(
            LatLng.newBuilder().setLatitude(-6.1275).setLongitude(106.6537)))
    .build();

CreateTripRequest createTripRequest =
    CreateTripRequest.newBuilder()  // no need for the header
        .setParent(parent)
        .setTripId("tid-1f97")  // Trip ID assigned by the Provider
        .setTrip(trip)              // Initial state
        .build();

// Error handling
// If Fleet Engine does not have trip with that id and the credentials of the
// requestor pass, the service creates the trip successfully.

try {
  Trip createdTrip =
      tripService.createTrip(createTripRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
    case ALREADY_EXISTS:
      break;
    case PERMISSION_DENIED:
      break;
  }
  return;
}

ルート作成の Google Cloud Platform ログ

Fleet Engine API は、CreateTrip エンドポイントの呼び出しを受信すると、Google Cloud Platform ログを使用してログエントリを書き込みます。ログエントリには、CreateTrip リクエストの値に関する情報が含まれています。呼び出しが成功すると、返された Trip に関する情報も含まれます。

手順: ルートを更新する

Trip エンティティには、サービスによる追跡を可能にするフィールドと、Driver SDK とコンシューマ SDK にルートの進捗状況を報告するためのフィールドが含まれます。プロパティを更新するには、UpdateTripRequest メッセージを使用します。これにより、リクエストの field_mask に応じて Trip フィールドが更新されます。UpdateTripRequest を参照してください。

ライドシェア プロバイダは、次の属性の更新を担当します。

  • ルートの状況。
  • 車両 ID。作成時、または車両とルートのマッチング後。
  • 乗車、降車、地点の変更。

Driver SDK または Consumer SDK で移動経路の共有機能を使用すると、Fleet Engine は次のフィールドを自動的に更新します。

  • ルート
  • 到着予定
  • 残りの距離
  • 車両の位置
  • 残りの地点

RPC の Trip または REST の Resource.Trip をご覧ください。

ルート更新情報の Google Cloud Platform ログ

Fleet Engine API は、UpdateTrip エンドポイントの呼び出しを受信すると、Google Cloud Platform ログを使用してログエントリを書き込みます。ログエントリには、UpdateTrip リクエストの値に関する情報が含まれています。呼び出しが成功した場合は、返された Trip に関する情報も含まれます。

手順: ルートを検索する

Fleet Engine ではルートの検索がサポートされています。前述のように、Trip は 7 日後に自動的に削除されます。したがって、SearchTrips はすべての Trips の完全な履歴を公開しません。

SearchTrips は柔軟な API ですが、以下のリストでは 2 つのユースケースを考慮しています。

  • 車両のアクティブなルートの特定 - プロバイダは、車両の現在アクティブなルートを特定できます。SearchTripsRequest 内で、vehicle_id は検討中の車両に設定し、active_trips_onlytrue に設定します。

  • プロバイダとフリート エンジンの状態の調整 - プロバイダは SearchTrips を使用して、ルート状態と Fleet Engine の状態を一致させることができます。これは、TripStatus の場合に特に重要です。車両に割り当てられたルートのステータスが COMPLETE または CANCELED に正しく設定されていない場合、その車両は SearchVehicles に含まれません。

この方法で SearchTrips を使用するには、vehicle_id を空のままにして、active_trips_onlytrue に設定し、minimum_staleness には、ほとんどのルートの所要時間よりも長い時間を設定します。たとえば、1 時間を指定します。結果には、COMPLETE でも CANCELED でもなく、1 時間以上更新されていない Trips が含まれます。プロバイダはこれらのルートを調べて、Fleet Engine でのステータスが正しく更新されていることを確認する必要があります。

トラブルシューティング

DEADLINE_EXCEEDED エラーの場合、Fleet Engine の状態は不明です。プロバイダは CreateTrip を再度呼び出す必要があります。これにより、201(CREATED)または 409(CONFLICT)が返されます。後者の場合、前のリクエストは DEADLINE_EXCEEDED の前に成功しています。トリップエラーの処理について詳しくは、Consumer API ガイド(Android または iOS)をご覧ください。

相乗りのサポート

TripType.SHARED をサポートする車両に複数の SHARED ルートを割り当てることができます。(CreateTrip または UpdateTrip リクエストで)共有ルートに vehicle_id を割り当てる際に、この共有配車内の車両に割り当てられたすべてのルートについて、通過しなかったウェイポイントの順序を Trip.vehicle_waypoints を介して指定する必要があります。RPC の場合は vehicle_waypointsREST の場合は vehicleWaypoints をご覧ください。

複数の宛先のサポート

中間宛先を特定する

Trip(RPC | REST)のフィールド intermediateDestinations とフィールド intermediateDestinationIndex を組み合わせて、目的地を示すために使用されます。

中間デスティネーションを更新する

中間デスティネーションは UpdateTrip で更新できます。中間デスティネーションを更新する場合は、新しく追加または変更されるデスティネーションだけでなく、訪問済みデスティネーションも含め、中間デスティネーションの完全なリストを指定する必要があります。intermediateDestinationIndex が新たに追加または変更された中間デスティネーションの位置より後のインデックスを指している場合、新規または更新された中間デスティネーションは車両の waypoints またはルートの remainingWaypoints に追加されません。intermediateDestinationIndex より前の中間デスティネーションは訪問済みとして扱われるためです。

ルート状況の変更

中間目的地が過ぎたことを通知するため、Fleet Engine に送信されるルート ステータス更新リクエストで(RPC | REST)フィールド intermediateDestinationsVersion が必要です。対象の中間デスティネーションは、intermediateDestinationIndex フィールドで指定されます。tripStatusRPC | REST)が ENROUTE_TO_INTERMEDIATE_DESTINATION の場合、[0..N-1] の数値は、車両が次に通過する中間目的地を示します。tripStatus が ARRIVED_AT_INTERMEDIATE_DESTINATION の場合、[0..N-1] の数字は車両がどの中間目的地にあるかを示します。

次のコード例は、複数の目的地を経由するルートを作成し、そのルートが乗車地点を過ぎていると仮定して、ルートのステータスを更新して、最初の中間目的地に向かう方法を示しています。

Java

static final String PROJECT_ID = "project-id";
static final String TRIP_ID = "multi-destination-trip-A";

String tripName = "providers/" + PROJECT_ID + "/trips/" + TRIP_ID;
Trip trip = …; // Fetch trip object from FleetEngine or your storage.

TripServiceBlockingStub tripService = TripService.newBlockingStub(channel);

// Trip settings to update.
Trip trip = Trip.newBuilder()
    // Trip status cannot go back to a previous status once it is passed
    .setTripStatus(TripStatus.ENROUTE_TO_INTERMEDIATE_DESTINATION)
    // Enrouting to the first intermediate destination.
    .setIntermediateDestinationIndex(0)
    // intermediate_destinations_version MUST be provided to ensure you
    // have the same picture on intermediate destinations list as FleetEngine has.
    .setIntermediateDestinationsVersion(
        trip.getIntermediateDestinationsVersion())
    .build();

// Trip update request
UpdateTripRequest updateTripRequest =
    UpdateTripRequest.newBuilder()
        .setName(tripName)
        .setTrip(trip)
        .setUpdateMask(
            FieldMask.newBuilder()
                .addPaths("trip_status")
                .addPaths("intermediate_destination_index")
                // intermediate_destinations_version must not be in the
                // update mask.
                .build())
        .build();

// Error handling
try {
  Trip updatedTrip = tripService.updateTrip(updateTripRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
    case NOT_FOUND:  // Trip does not exist.
      break;
    case FAILED_PRECONDITION:  // The given trip status is invalid, or the
                                // intermediate_destinations_version
                                // doesn’t match FleetEngine’s.
      break;
    case PERMISSION_DENIED:
      break;
  }
  return;
}

方法: Fleet Engine API からの通知メッセージをサブスクライブする

Fleet Engine API は、 Google Cloud Pub/Sub を使用して、コンシューマの Google Cloud プロジェクトによって作成されたトピックに関する通知をパブリッシュします。デフォルトでは、Google Cloud プロジェクトの Fleet Engine で Pub/Sub が有効になっていません。サポートケースを登録するか、カスタマー エンジニアに連絡して Pub/Sub を有効にしてください。

Cloud プロジェクトにトピックを作成するには、こちらの手順に従ってください。トピック ID は「fleet_engine_notifications」にする必要があります。

トピックは、Fleet Engine API を呼び出すのと同じ Cloud プロジェクトに作成する必要があります。

トピックを作成したら、トピックで公開する権限を Fleet Engine API に付与する必要があります。これを行うには、作成したトピックをクリックして新しい権限を追加します。場合によっては、[情報パネルを表示] をクリックして権限エディタを開く必要があります。 プリンシパルは geo-fleet-engine@system.gserviceaccount.com、ロールは Pub/Sub publisher にする必要があります。

通知を受信するように Cloud プロジェクトを設定するには、こちらの手順に沿ってください。

Fleet Engine API は、protobufjson の 2 種類のデータ形式で各通知を公開します。各通知のデータ形式は、PubsubMessage 属性で示されています。キーは data_format、値は protobuf または json です。

通知スキーマ:

Protobuf

// A batch of notifications that is published by the Fleet Engine service using
// Cloud Pub/Sub in a single PubsubMessage.
message BatchNotification {
  // Required. At least one notification must exist.
  // List of notifications containing information related to changes in
  // Fleet Engine data.
  repeated Notification notifications = 1;
}

// A notification related to changes in Fleet Engine data.
// The data provides additional information specific to the type of the
// notification.
message Notification {
  // Required. At least one type must exist.
  // Type of notification.
  oneof type {
    // Notification related to changes in vehicle data.
    VehicleNotification vehicle_notification = 1;
  }
}

// Notification sent when a new vehicle was created.
message CreateVehicleNotification {
  // Required.
  // Vehicle must contain all fields that were set when it was created.
  Vehicle vehicle = 1;
}

// Notification sent when an existing vehicle is updated.
message UpdateVehicleNotification {
  // Required.
  // Vehicle must only contain name and fields that are present in the
  // field_mask field below.
  Vehicle vehicle = 1;

  // Required.
  // Contains vehicle field paths that were specifically requested
  // by the Provider.
  google.protobuf.FieldMask field_mask = 2;
}

// Notification related to changes in vehicle data.
message VehicleNotification {
  // Required. At least one type must be set.
  // Type of notification.
  oneof type {
    // Notification sent when a new vehicle was created.
    CreateVehicleNotification create_notification = 1;
    // Notification sent when an existing vehicle is updated.
    UpdateVehicleNotification update_notification = 2;
  }
}

JSON

BatchNotification: {
  "description": "A batch of notifications that is published by the Fleet Engine service using Cloud Pub/Sub in a single PubsubMessage.",
  "type": "object",
  "required": ["notifications"],
  "properties": {
    "notifications": {
      "description": "At least one notification must exist. List of notifications containing information related to changes in Fleet Engine data.",
      "type": "Notification[]"
    }
  }
}

Notification: {
  "description": "A notification related to changes in Fleet Engine data. The data provides additional information specific to the type of the notification.",
  "type": "object",
  "properties": {
    "vehicleNotification": {
      "description": "Notification related to changes in vehicle data.",
      "type": "VehicleNotification"
    }
  }
}

VehicleNotification: {
  "description": "Notification related to changes in vehicle data.",
  "type": "object",
  "properties": {
    "createNotification": {
      "description": "Notification sent when a new vehicle was created.",
      "type": "CreateVehicleNotification"
    },
    "updateNotification": {
      "description": "Notification sent when an existing vehicle is updated.",
      "type": "UpdateVehicleNotification"
    }
  }
}

CreateVehicleNotification: {
  "description": "Notification sent when a new vehicle was created.",
  "type": "object",
  "required": ["vehicle"],
  "properties": {
    "vehicle": {
      "description": "Vehicle must contain all fields that were set when it was created.",
      "type": "Vehicle"
    }
  }
}

UpdateVehicleNotification: {
  "description": "Notification sent when an existing vehicle is updated.",
  "type": "object",
  "required": ["vehicle", "fieldMask"],
  "properties": {
    "vehicle": {
      "description": "Vehicle must only contain name and fields that are present in the fieldMask field below.",
      "type": "Vehicle"
    },
    "fieldMask": {
      "description": "Contains vehicle field paths that were specifically requested by the Provider.",
      "type": "FieldMask"
    }
  }
}