תחילת העבודה עם Fleet Engine

Fleet Engine On-demand Rides and Deliveries API מאפשר לכם לנהל נסיעות ואת מצב הרכב עבור אפליקציות הנסיעה ו-Order Progress הוא מטפל בטרנזקציות בין Driver SDK, Consumer SDK והשירות לקצה העורפי שלכם – שיכול לתקשר עם Fleet Engine באמצעות קריאות ל-gRPC או ל-REST.

דרישות מוקדמות

לצורכי פיתוח, ודאו שאתם מתקינים את ה-SDK של Cloud (gcloud) ושהפרויקט שלכם מאומת.

מעטפת

gcloud auth login

אמורה להופיע הודעת הצלחה כמו:

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

צריך לוודא שממשקי ה-API של Rides and Deliveries Solution Fleet Engine מוגדרים כראוי.

מעטפת

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

אם הפקודה הזו גורמת לשגיאה, עליכם לפנות לאדמין של הפרויקט ולנציג התמיכה של Google כדי לקבל גישה.

רישום ביומן

Feet Engine יכול לכתוב הודעות ביומן לגבי קריאות ל-API שהוא מקבל ב יומנים של Google Cloud Platform. סקירה כללית על אופן הקריאה והניתוח של יומנים זמינה במאמרי העזרה של Cloud Logging.

יכול להיות שהרישום לא יפעל כברירת מחדל לפרויקטים שנוצרו לפני 10 בפברואר 2022. למידע נוסף, תוכלו לקרוא את משאבי העזרה בנושא רישום ביומן.

ספריות לקוח

אנחנו מפרסמים ספריות לקוח בכמה שפות תכנות נפוצות. הספריות האלה יעזרו לספק חוויית מפתח טובה יותר בהשוואה ל-REST או gRPC גולמיים. כדי לקבל הוראות לקבלת ספריות לקוח לאפליקציית השרת, קראו את המאמר ספריות לקוח.

דוגמאות Java במסמך הזה מבוססות על היכרות עם gRPC.

אימות והרשאה

אפשר להגדיר את היכולות שמסופקות על ידי Trip ו-Order Progress באמצעות מסוף Google Cloud. כדי להשתמש בממשקי ה-API ובערכות ה-SDK האלה, צריך להשתמש באסימוני אינטרנט מסוג JSON שנחתמו באמצעות חשבונות שירות שנוצרו ממסוף Cloud.

הגדרת פרויקט ב-Cloud

כדי להגדיר את הפרויקט בענן, קודם צריך ליצור את הפרויקט ולאחר מכן ליצור חשבונות שירות.

כדי ליצור פרויקט ב-Google Cloud:

  1. יצירת פרויקט ב-Google Cloud באמצעות מסוף Google Cloud.
  2. באמצעות ממשקי ה-API והשירותים, מפעילים את Local Rides and Deliveries API.

חשבונות שירות משויכים לתפקיד אחד או יותר. הם משמשים ליצירת אסימוני אינטרנט מסוג JSON שמעניקים קבוצות שונות של הרשאות, בהתאם לתפקידים. בדרך כלל, כדי לצמצם את האפשרות של התנהלות פוגעת, אפשר ליצור כמה חשבונות שירות, שבכל אחד מהם יש את מערך התפקידים המינימלי הנדרש.

'התקדמות הנסיעה' ו'ההזמנה' משתמשת בתפקידים הבאים:

תפקידתיאור
משתמש SDK לצרכן של Fleet Engine

roles/fleetengine.consumerSdkUser
הענקת הרשאה לחיפוש כלי רכב ולאחזור מידע על רכבים ונסיעות. אסימונים שנוצרו על ידי חשבון שירות עם התפקיד הזה משמשים בדרך כלל ממכשירים ניידים של אפליקציות לצרכנים פרטיים שמשמשים לשיתוף נסיעות או למסירה.
משתמש ב-Flet Engine Driver SDK

roles/fleetengine.driverSdkUser
הענקת הרשאה לעדכון מיקומים ומסלולים של כלי רכב ולאחזור מידע על רכבים ונסיעות. אסימונים שנוצרו על ידי חשבון שירות בתפקיד הזה משמשים בדרך כלל ממכשירים ניידים של אפליקציית שיתוף הנסיעה או הנהג.
משתמש-על בשירות של Fleet Engine

roles/fleetengine.serviceSuperUser
מעניקה הרשאה לכל ממשקי ה-API של הרכבים והנסיעות. אסימונים שנוצרו על ידי חשבון שירות עם התפקיד הזה משמשים בדרך כלל מהשרתים העורפיים שלך.

לדוגמה, אפשר ליצור חשבון שירות לכל אחד משלושת התפקידים ולהקצות להם את התפקידים המתאימים.

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

ערכות ה-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 משתמש באסימוני JWT (JSON Web Tokens) כדי להגביל את הגישה לממשקי ה-API של Fleet Engine. ספריית Fleet Engine Auth החדשה זמינה ב-GitHub מאפשרת ליצור בקלות אסימוני JWT של Fleet Engine וחותמת עליהם בצורה מאובטחת.

הספרייה מציעה את היתרונות הבאים:

  • מפשט את תהליך היצירה של אסימוני Fleet Engine.
  • מספקת מנגנוני חתימה של אסימונים מלבד שימוש בקובצי פרטי כניסה (כמו התחזות לחשבון שירות).
  • צירוף אסימונים חתומים לבקשות יוצאות שנשלחות מ-stub של gRPC או מלקוח GAPIC.

יצירת אסימון אינטרנט מסוג JSON (JWT) להרשאה

כשלא משתמשים בספריית Fleet Engine Auth, צריך ליצור את אסימוני האינטרנט JSON (JWT) ישירות ב-codebase. לשם כך נדרשת הבנה עמוקה לגבי אסימוני JWT ואיך הם קשורים ל-Flet Engine. לכן אנחנו ממליצים מאוד לנצל את ספריית Fleet Engine Auth.

בתוך Fleet Engine, אסימוני JWT (JSON Web Tokens) מספקים אימות לטווח קצר ומוודאים שהמכשירים יכולים לשנות רק כלי רכב, נסיעות או משימות שעבורם הם מורשים. אסימוני JWT מכילים כותרת וקטע של תלונה. קטע הכותרת כולל מידע כמו המפתח הפרטי לשימוש (שמתקבל מחשבונות השירות) ואלגוריתם ההצפנה. הקטע של הצהרת הבעלות כולל מידע כמו זמן היצירה של האסימון, זמן החיים של האסימונים, השירותים שאליהם הוא דורש גישה ומידע אחר להרשאה להיקף הגישה, לדוגמה, מזהה הרכב.

קטע של כותרת JWT מכיל את השדות הבאים:

שדהתיאור
alg האלגוריתם שבו צריך להשתמש. 'RS256'.
typ סוג האסימון. 'JWT'.
ילד מזהה המפתח הפרטי של חשבון השירות שלך. הערך הזה מופיע בשדה 'private_key_id' בקובץ ה-JSON של חשבון השירות. חשוב להשתמש במפתח מחשבון שירות עם רמת ההרשאות הנכונה.

קטע של תלונות JWT מכיל את השדות הבאים:

שדהתיאור
iss כתובת האימייל של חשבון השירות שלכם.
sub כתובת האימייל של חשבון השירות שלכם.
אודיו SERVICE_NAME של חשבון השירות שלך, במקרה הזה https://fleetengine.googleapis.com/
Iat חותמת הזמן של מועד יצירת האסימון, שצוינה בשניות שחלפו מ-00:00:00 UTC, 1 בינואר 1970. יש להמתין 10 דקות לפני הטיה. אם חותמת הזמן רחוקה מדי בעבר או בעתיד, השרת עשוי לדווח על שגיאה.
exp חותמת הזמן של מועד פקיעת התוקף של האסימון, שמצוינת בשניות שחלפו מ-00:00:00 UTC, 1 בינואר 1970. הבקשה תיכשל אם חותמת הזמן היא יותר משעה אחת בעתיד.
הרשאה בהתאם לתרחיש לדוגמה, ייתכן שהוא מכיל 'vehicleid' או 'tripid'.

יצירת אסימון JWT פירושה חתימה עליו. להוראות ולדוגמאות קוד ליצירה ולחתימה של ה-JWT, קראו את המאמר הרשאה לחשבון שירות ללא OAuth. לאחר מכן תוכלו לצרף אסימון חתום לשיחות gRPC או לשיטות אחרות לגישה אל Fleet Engine.

הצהרות JWT

כשיוצרים את המטען הייעודי (payload) של JWT, מוסיפים הצהרה נוספת בקטע ההרשאה, כשהמפתח vehicleid או tripid מוגדר לערך של מזהה הרכב או של מזהה הנסיעה שעבורם מתבצעת השיחה.

ב-SDK של הנהג תמיד נעשה שימוש בהצהרה vehicleid, לא משנה אם הוא פועל בנסיעה או ברכב. באמצעות הקצה העורפי של Fleet Engine אפשר לוודא שהרכב משויך לנסיעה המבוקשת לפני ביצוע השינוי.

ב-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"
   }
}

באיור שלמטה מוצג אסימון לדוגמה של אפליקציה לנהג:

{
  "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 בכותרת, מציינים את מזהה המפתח הפרטי של חשבון השירות. הערך הזה מופיע בשדה private_key_id בקובץ ה-JSON של חשבון השירות.
  • בשדות iss ו-sub מציינים את כתובת האימייל של חשבון השירות. הערך הזה מופיע בשדה client_email בקובץ ה-JSON של חשבון השירות.
  • בשדה aud, יש לציין https://SERVICE_NAME/.
  • בשדה iat, יש להשתמש בחותמת הזמן של מועד יצירת האסימון, שצוין כשניות שחלפו מאז 00:00:00 UTC, 1 בינואר 1970. יש להמתין 10 דקות לפני הטיה. אם חותמת הזמן רחוקה מדי בעבר, או בעתיד, השרת עשוי לדווח על שגיאה.
  • בשדה exp, יש להשתמש בחותמת הזמן של מועד פקיעת התוקף של האסימון, שצוין כשניות מאז 00:00:00 UTC, 1 בינואר 1970. הערך המקסימלי המותר הוא iat + 3600.

כשחותמים על ה-JWT שיועבר למכשיר נייד, חשוב להשתמש בחשבון השירות לתפקיד ה-Driver או 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 הוא הזמן הנוכחי במספר השניות לאחר תקופה של זמן מערכת (epoch), ואפשר לאחזר אותו על ידי הרצת date +%s בטרמינל. המאפיין exp הוא זמן התפוגה במספר השניות לאחר תקופה של זמן מערכת (epoch), וניתן לחשב אותו על ידי הוספת 3600 ל-iat. מועד התפוגה לא יכול להיות יותר משעה אחת בעתיד.

{
  "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

JWT חתום בקידוד Base64 אמור להיות שמור בקובץ signed_token.jwt. האסימון יהיה תקף לשעה הקרובה.

עכשיו אפשר לבדוק את האסימון על ידי הרצת פקודת curl על נקודת הקצה של List Vehicles ב-REST:

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

כלי רכב ומחזור החיים שלהם

הרכב הוא הישות שמייצגת צמד נהג-רכב. בשלב הזה, לא ניתן לעקוב בנפרד אחרי נהג/ת וכלי רכב. ספק שיתוף הנסיעה או המסירה יוצר רכב באמצעות מזהה ספק (שחייב להיות זהה למזהה הפרויקט של הפרויקט ב-Google Cloud, שמכיל את חשבון השירות המשמש לקריאה לממשקי ה-API של Fleet Engine) ומזהה רכב בבעלות ספק שיתוף הנסיעה או ספק המשלוחים.

רכב שלא עודכן דרך UpdateVehicle אחרי שבעה ימים יימחק באופן אוטומטי. זו שגיאה בקריאה ל-CreateVehicle עם צמד מזהה ספק/מזהה רכב שכבר קיים. במקרה של כלי רכב שלא מתעדכנים לעיתים קרובות, אפשר לטפל בשתי דרכים: לבצע קריאה תכופה ל-CreateVehicle עם צמד צפוי של מזהה ספק/מזהה רכב, וביטול השגיאה אם הרכב כבר קיים, או, הפעלה של CreateVehicle אחרי UpdateVehicle שחוזרת עם השגיאה NOT_FOUND.

עדכונים לגבי מיקום הרכב

על מנת ליהנות מהביצועים הטובים ביותר עם Fleet Engine, מומלץ לספק לו זרם של עדכוני מיקום של הרכב. אפשר לספק את העדכונים האלה באחת מהדרכים הבאות:

  1. השתמשו ב-SDK של מנהל ההתקן – Android, iOS -- האפשרות הפשוטה ביותר.
  2. השתמשו בקוד מותאם אישית – שימושי אם המיקומים מועברים דרך הקצה העורפי, או אם אתם משתמשים במכשירים שאינם Android או iOS.

סוגים של כלי רכב

ישות הרכב מכילה את שדה החובה VehicleType, שמכיל ערך של טיפוסים בני Category שאפשר לציין כ-AUTO, TAXI, TRUCK, TWO_WHEELER, BICYCLE או PEDESTRIAN. סוג הרכב יכול לשמש כקריטריון לסינון ב-SearchVehicles וב-ListVehicles.

כל הניתובים של כלי רכב ישתמשו ב-RouteTravelMode המתאים אם הקטגוריה מוגדרת לערך AUTO, TWO_WHEELER, BICYCLE או PEDESTRIAN. אם הקטגוריה מוגדרת לערך TAXI או TRUCK, הניתוב מטופל באופן זהה למצב AUTO.

מאפייני הרכב

ישות הרכב מכילה שדה חוזר של VehicleAttribute. המאפיינים האלה לא מפורשים על ידי Fleet Engine. ה-API SearchVehicles כולל שדה שמחייב התאמה של Vehicles להכיל את כל המאפיינים הכלולים שמוגדרים לערך שצוין.

שימו לב ששדה המאפיין מתווסף למספר שדות נתמכים אחרים בהודעה של Vehicle, כמו vehicle_type ו-supported_trip_types.

ציוני דרך שנותרים ברכב

ישות הרכב מכילה שדה חוזר של TripWaypoint (RPC | REST), שנקרא waypoints(RPC | REST). השדה הזה כולל את שאר ציוני הדרך בנסיעות, לפי הסדר שבו הרכב מגיע אליהם. Fleet Engine מחשב את השדה הזה כשנסיעות מוקצות לרכב, ומעדכן אותו כשהנסיעות משנות את הסטטוס שלהן. ניתן לזהות את ציוני הדרך האלה באמצעות השדה TripId והשדה WaypointType.

הרחבת הזכאות של רכב להצגת התאמות

בדרך כלל, השירותים של שיתוף הנסיעה או ספק המשלוחים אחראים על התאמת בקשות הנסיעה לרכבים. השירות יכול להשתמש במאפייני הרכב כדי לכלול רכב במספר גדול יותר של חיפושים. לדוגמה, הספק יכול להטמיע קבוצה של מאפיינים בהתאם לרמות ההטבות או היכולות שמספקות הרכב. לדוגמה, שלוש רמות יכולות להיות קבוצת מאפיינים עם ערכים בוליאניים: is_bronze_level, is_silver_level ו-is_gold_level. כלי רכב יכול לעמוד בדרישות של כל שלושת השירותים. כשמנוע Fleet מקבל בקשה לנסיעה שמחייבת יכולות ברמת כסף, החיפוש כולל את הרכב הזה. דוגמה לשימוש במאפיינים האלה כוללת כלי רכב עם מגוון יכולות.

יש שתי דרכים לעדכן את מאפייני הרכב. אחד מהם הוא UpdateVehicle API. כשמשתמשים ב-API הזה, כל מאפייני הרכב מוגדרים לערך. אין אפשרות לעדכן רק מאפיין אחד. השיטה השנייה היא UpdateVehicleAttributes API. בשיטה הזו צריך רק את המאפיינים לעדכון. המאפיינים הכלולים בבקשה יוגדרו לערך החדש או יתווספו. מאפיינים שלא צוינו לא ישתנו.

איך ליצור כלי רכב

צריך ליצור ישות Vehicle לכל רכב שאפשר לעקוב אחריו ב-Fleet.

כדי ליצור כלי רכב, משתמשים בנקודת הקצה CreateVehicle עם CreateVehicleRequest.

השדה provider_id ב-Vehicle חייב להיות מזהה הפרויקט (למשל my-on-demand-project) של הפרויקט ב-Google Cloud שמכיל את חשבונות השירות שישמשו להתקשרות אל Fleet Engine. שימו לב: למרות שניתן לגשת ל-Flet Engine באמצעות כמה חשבונות שירות עבור אותו ספק של נסיעות משותפות או מסירה, ב-Flit Engine אין כרגע תמיכה בחשבונות שירות מכמה פרויקטים ב-Google Cloud שניגשים לאותו Vehicles.

אפשר ליצור את Vehicle במצב OFFLINE או ONLINE. אם יוצרים את השדה ONLINE, יכול להיות שהוא יוחזר מיד בתגובה לשאילתות SearchVehicles.

ייתכן שהשיחה עם CreateVehicle תכלול last_location ראשונית. למרות שמותר, אין ליצור Vehicle במצב ONLINE בלי last_location.

פרטים על השדה של סוג הרכב מופיעים בקטע סוגי רכב.

פרטים נוספים על שדה המאפיינים מופיעים בקטע מאפייני רכב.

הערך שהוחזר מ-CreateVehicle הוא היישות Vehicle שנוצרה.

דוגמה

מעטפת

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 כותב רשומה ביומן באמצעות היומנים של פלטפורמת Google Cloud כשמקבלת קריאה לנקודת הקצה CreateVehicle. הרשומה ביומן כוללת מידע על הערכים בבקשה CreateVehicle. אם השיחה תסתיים, יופיע גם מידע על Vehicle שהחזרה.

מעטפת

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 כשנוצר רכב חדש. על מנת לקבל את ההתראות האלה, יש לפעול לפי ההוראות המפורטות כאן.

איך עושים את זה: עדכון מיקום של רכב

אם לא משתמשים ב-Drive SDK כדי לעדכן את מיקום הרכב, אפשר לבצע שיחה ישירה אל Fleet Engine באמצעות מיקום הרכב. בכל כלי רכב פעיל, Fleet Engine מצפה לעדכון מיקום לפחות פעם בדקה ופעם אחת לכל 5 שניות. לעדכונים האלה נדרשות רק הרשאות משתמש של Fleet Engine Driver SDK.

דוגמה

מעטפת

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.

HOW-TO: עדכון שדות אחרים בכלי רכב

עדכונים למאפיינים אחרים של מצב הרכב מתרחשים בתדירות נמוכה יותר מאשר עדכוני המיקום. לעדכונים למאפיינים שהם לא last_location מחייבות הרשאות של משתמש-על ב-Fleet Engine.

השדה UpdateVehicleRequest כולל update_mask כדי לציין אילו שדות צריך לעדכן. התנהגות השדה זהה לזו שמופיעה במסמכי התיעוד של Protobuf לגבי מסכות שדות.

כפי שצוין במאפייני רכב, כדי לעדכן את השדה attributes צריך לכתוב את כל המאפיינים. אי אפשר לעדכן רק את הערך של צמד מפתח/ערך אחד בקריאה ל-UpdateVehicle. כדי לעדכן ערכים של מאפיינים ספציפיים, אפשר להשתמש ב-API UpdateVehicleAttributes.

דוגמה

הדוגמה הזו מפעילה את back_to_back.

מעטפת

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 לעדכוני רכב

Fleet Engine API כותב רשומה ביומן באמצעות היומנים של פלטפורמת Google Cloud כשמקבלת קריאה לנקודת הקצה UpdateVehicle. הרשומה ביומן כוללת מידע על הערכים בבקשה UpdateVehicle. אם השיחה תסתיים, יופיע גם מידע על Vehicle שהחזרה.

מעטפת

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 כשרכב קיים מתעדכן. על מנת לקבל את ההתראות האלה, יש לפעול לפי ההוראות המפורטות כאן.

HOW-TO: חיפוש כלי רכב

Fleet Engine תומך בחיפוש כלי רכב. בעזרת ה-API של SearchVehicles אפשר למצוא נהגים זמינים בסביבה שהכי מתאימים לביצוע משימה כמו מתן שירות לנסיעה או בקשת מסירה. ה-API של SearchVehicles מחזיר רשימה מדורגת של נהגים שתואמים למאפייני המשימה עם המאפיינים של הרכבים בצי שלכם. למידע נוסף, ראו חיפוש נהגים בקרבת מקום.

דוגמה

כשמחפשים רכבים זמינים, Fleet Engine מחריגה כלי רכב בנסיעות פעילות כברירת מחדל. השירותים של ספק שיתוף הנסיעה או הספק צריכים לכלול אותם במפורש בבקשות חיפוש. הדוגמה הבאה ממחישה איך לכלול את הרכבים האלה בחיפוש אחר כלי רכב שתואמים לנסיעה מהקניון גרנד אינדונזיה מזרח למרכז הכנסים בלאי סידאנג ג'קרטה.

מעטפת

קודם כול צריך לעדכן את המיקום של הרכב שיצרנו בשלבים הקודמים, כדי שהוא יעמוד בדרישות. בעולם האמיתי, זה נעשה באמצעות Driver SDK שפועל ברכב עם Android או iOS.

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;
}

שאילתה בנושא סינון רכב

SearchVehicles ו-ListVehicles תומכים בסינון לפי מאפייני רכב באמצעות שאילתת סינון. למידע על התחביר של שאילתות סינון, ראו AIP-160 לדוגמאות.

שימו לב ששאילתות סינון תומכות רק בסינון לפי מאפייני רכב, ואי אפשר להשתמש בהן בשדות אחרים. שאילתת הסינון פועלת כסעיף AND עם אילוצים אחרים, כמו minimum_capacity או vehicle_types ב-SearchVehiclesRequest.

HOW-TO: הצגת רשימה של כלי רכב

SearchVehicles מותאם לאיתור מספר קטן של כלי רכב לפי סדר במהירות רבה, והוא משמש בעיקר למציאת נהגים בקרבת מקום שהכי מתאימים למשימה. עם זאת, לפעמים רוצים למצוא את כל כלי הרכב שעומדים בקריטריונים מסוימים, גם אם צריך לדפדף בין התוצאות. ListVehicles מיועד לתרחיש לדוגמה הזה.

בעזרת ה-API של ListVehicles אפשר למצוא את כל הרכבים שעונים על אפשרויות מסוימות של בקשות. ה-API ListVehicles מחזיר רשימה מעומדת של כלי רכב בפרויקט שעומדים בדרישות מסוימות.

כדי לסנן לפי מאפייני רכב, קראו את המאמר שאילתת סינון רכב.

דוגמה

בדוגמה הזו מתבצע סינון לפי vehicle_type ומאפיינים באמצעות המחרוזת filter.

מעטפת

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;
}

נסיעות ומחזור החיים שלהם

ה-API של Trip ומחזור החיים דומים ל-Vehicle API ולמחזור החיים. ספק שיתוף הנסיעות אחראי על יצירת נסיעות באמצעות הממשק של Fleet Engine. Fleet Engine מספק גם שירות RPC וגם TripService וגם משאבי REST, provider.trips . הממשקים האלה מאפשרים ליצור ישויות של 'נסיעה', לבקש מידע, את פונקציונליות החיפוש ואת יכולות העדכון.

ל-Trip יש שדה סטטוס למעקב אחרי ההתקדמות שלו במחזור החיים. הערכים עוברים מ-NEW ל-COMPLETE וגם מ-CANCELED ו-UNKNOWN_TRIP_STATUS . ראו trip_status ל-RPC או TripStatus ל-REST.

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

השירות שלך יכול לעדכן את הנסיעה אל CANCELED מכל אחד מהסטטוסים האלה. כשהשירות יוצר נסיעה, המנוע מגדיר את הסטטוס כ-NEW. הערך vehicle_id הוא אופציונלי. בדומה לכלי רכב, השירותים מוחקים נסיעות באופן אוטומטי אחרי שבעה ימים בלי עדכון. אם השירות ינסה ליצור נסיעה עם מזהה שכבר קיים, תוחזר שגיאה. נסיעה נחשבת כ'פעילה' אם היא בסטטוס שאינו COMPLETE או CANCELED. ההבחנה הזו חשובה בשדה active_trips בישות 'רכב' ובשדה SearchTripsRequest.

השירות יכול לשנות את vehicle_id שהוקצה לנסיעה רק כשהסטטוס הוא NEW או CANCELED. אם נהג מבטל נסיעה במהלך המסלול, צריך להגדיר את סטטוס הנסיעה כ-NEW או כ-CANCELED לפני שמשנים או מוחקים את vehicle_id.

הסטטוס חשוב כשמטמיעים תמיכה הלוך ושוב. התמיכה הזו מאפשרת לספק להקצות נסיעה חדשה לרכב בזמן שהרכב נמצא בנסיעה פעילה. הקוד ליצירת נסיעה הלוך ושוב זהה לקוד של נסיעה יחידה, וכולל את אותו מזהה רכב. ה-Flet Engine מוסיף את המוצא והיעד של הנסיעה החדשה לציוני הדרך של הרכב. למידע נוסף על נסיעות הלוך ושוב, ראו יצירת נסיעות מרובות נקודות יעד.

נקודות העצירה של שארית הנסיעה

ישות הנסיעה מכילה שדה חוזר של TripWaypoint (RPC | REST), שנקרא remainingWaypoints(RPC | REST). השדה הזה כולל את כל ציוני הדרך שהרכב צריך לנסוע בהם לפי הסדר לפני נקודת ההורדה הסופית של הנסיעה. החישוב הזה מתבצע על סמך ציוני הדרך שנותרו של הרכב. בתרחישים לדוגמה של 'חזרה אחורה' ו'קארפול', הרשימה הזו מכילה ציוני דרך מנסיעות אחרות שיתבצעו לפני הנסיעה, אבל לא ציוני דרך אחרי הנסיעה. אפשר לזהות את ציון הדרך ברשימה לפי TripId ו-WaypointType.

הקשר בין סטטוס הנסיעה ונקודות העצירה של כלי הרכב

נקודות העצירה שנותרו ברכב (RPC | REST) יעודכנו כאשר Fleet Engine יקבל בקשה לשינוי סטטוס הנסיעה. ציון הדרך הקודם יוסר מרשימת ציוני הדרך שנותרו של הרכב אחרי שהסטטוס של tripStatus(RPC | REST) ישתנה מסטטוס אחר ל-ENROUTE_TO_XXX. כלומר, כשסטטוס הנסיעה משתנה מ-ENROUTE_TO_PICKUP ל-ARROUTE_TO_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.
  • trip_id - מחרוזת שנוצרה על ידי ספק שיתוף הנסיעות.
  • trip - קונטיינר עם מטא-נתונים בסיסיים שמתארים את הנסיעה.
    • trip_type – ספירה שמייצגת אם יכולים להיות בנסיעה נוסעים אחרים מנקודת מוצא ומיעד שונים באותו רכב (SHARED) או רק לצד אחד (EXCLUSIVE).
    • pickup_point – TerminalLocation שמייצג את נקודת המוצא של הנסיעה. ראו הפניה ל-RPC או חומר עזר ל-REST

כשיוצרים נסיעה, אפשר לספק את number_of_passengers, dropoff_point ו-vehicle_id. אמנם לא חובה להזין את השדות האלה, אבל אם תספקו אותם, הם יישמרו. המערכת מתעלמת משאר שדות הנסיעה. לדוגמה, כל הנסיעות מתחילות ב-trip_status של NEW, גם אם עוברים ב-trip_status של CANCELED בבקשת היצירה.

דוגמה

הדוגמה הבאה יוצרת נסיעה לקניון גראנד אינדונזיה מזרח. הנסיעה היא לשני נוסעים, והיא בלעדית. הערך provider_id של Trip חייב להיות זהה למזהה הפרויקט. בדוגמה, ספק שיתוף הנסיעות יצר את הפרויקט ב-Google Cloud, project-id. לפרויקט הזה צריכים להיות חשבונות השירות שמשמשים לקרוא ל-Flet Engine. הסטטוס של הנסיעה הוא NEW.

בהמשך, אחרי שהשירות יתאים את הנסיעה לרכב, השירות יכול להתקשר אל UpdateTrip ולשנות את vehicle_id כשהנסיעה מוקצית לרכב.

מעטפת

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 כותב רשומה ביומן באמצעות היומנים של פלטפורמת Google Cloud כשמקבלת קריאה לנקודת הקצה CreateTrip. הרשומה ביומן כוללת מידע על הערכים בבקשה CreateTrip. אם השיחה תסתיים, יופיע גם מידע על Trip שהוחזר.

איך עושים את זה: עדכון נסיעה

הישות של Trip מכילה שדות שמאפשרים מעקב באמצעות השירות, וכן לדיווח על התקדמות הנסיעה על ידי Driver SDK ועל ידי Consumer SDK. כדי לעדכן את המאפיינים צריך להשתמש בהודעה UpdateTripRequest. הפעולה הזו מעדכנת את שדות הנסיעה בהתאם לfield_mask של הבקשה. פרטים נוספים מופיעים כאן: UpdateTripRequest.

ספק שיתוף הנסיעות אחראי לעדכן את המאפיינים הבאים:

  • סטטוס הנסיעה.
  • מזהה הרכב. בזמן היצירה או אחרי התאמת הרכב לנסיעה.
  • שינויים באיסוף, בהחזרה או בציוני הדרך.

Fleet Engine מעדכן באופן אוטומטי את השדות הבאים כשמשתמשים בתכונה 'שיתוף מסע' דרך Driver SDK או Consumer SDK:

  • מסלולים
  • זמן הגעה משוער
  • המרחק שנותר
  • מיקום הרכב
  • ציוני דרך שנותרו

קראו את המאמר Tripב-RPC או Resource.Trip ב-REST.

יומני Google Cloud Platform של עדכוני נסיעה

Fleet Engine API כותב רשומה ביומן באמצעות היומנים של פלטפורמת Google Cloud כשמקבלת קריאה לנקודת הקצה UpdateTrip. הרשומה ביומן כוללת מידע על הערכים בבקשה UpdateTrip. אם השיחה מצליחה, היא תכלול גם מידע על Trip שהוחזר.

איך עושים את זה: חיפוש נסיעות

Fleet Engine תומך בחיפוש נסיעות. כפי שצוין בעבר, נסיעה נמחקת אוטומטית אחרי שבעה ימים, ולכן SearchTrips לא חושף את ההיסטוריה המלאה של כל הנסיעות.

SearchTrips הוא API גמיש, אבל ברשימה הבאה יש שני תרחישים לדוגמה.

  • קביעת נסיעות פעילות של רכב – הספק יכול לזהות את הנסיעות הפעילות הנוכחיות של הרכב. בתוך SearchTripsRequest, vehicle_id מוגדר לרכב שנמצא בבדיקה, וצריך להגדיר את active_trips_only כ-true.

  • התאמה בין מצב המנוע של הספק לבין המצב של Fleet Engine – הספק יכול להשתמש ב-SearchTrips כדי להבטיח את מצב הנסיעה שלו ואת המצב של Fleet Engine. הדבר חשוב במיוחד לגבי TripStatus. אם מצב הנסיעה שהוקצתה לרכב לא מוגדר בצורה נכונה כ-COMPLETE או כ-CANCELED, הרכב לא ייכלל על ידי SearchVehicles.

כדי להשתמש ב-SearchTrips בצורה הזו, צריך להשאיר את השדה vehicle_id ריק, להגדיר את active_trips_only לערך true ולהגדיר ב-minimum_staleness פרק זמן ארוך יותר מרוב משך הנסיעה. לדוגמה, אפשר לציין שעה אחת. התוצאות כוללות נסיעות שלא הסתיימו או מבוטלות, ולא עודכנו במשך יותר משעה. על הספק לבדוק את הנסיעות האלה כדי לוודא שהסטטוס שלהן ב-Flet Engine מעודכן כראוי.

פתרון בעיות

במקרה של שגיאת DEADLINE_EXCEEDED, המצב של Fleet Engine לא ידוע. הספק צריך להפעיל שוב את CreateTrip, פעולה שתחזיר שגיאת 201 (CREATED) או 409 (הפעולה). במקרה השני, הבקשה הקודמת בוצעה בהצלחה לפני DEADLINE_EXCEEDED. במדריכים של Consumer API תוכלו למצוא מידע נוסף על טיפול בשגיאות שקשורות לנסיעות: Android או iOS.

תמיכה בנסיעות ב-Carpool

אפשר להקצות מספר נסיעות של SHARED לרכב עם תמיכה בTripType.SHARED. עליך לציין את הסדר של כל נקודות העצירה שלא עברו לכל הנסיעות שהוקצו לרכב המשותף הזה דרך Trip.vehicle_waypoints, כאשר מקצים את vehicle_id לנסיעה משותפת (בבקשת CreateTrip או UpdateTrip). ראו vehicle_waypoints ל-RPC או vehicleWaypoints ל-REST.

תמיכה במספר יעדים

זיהוי יעד ביניים

השדה intermediateDestinations והשדה intermediateDestinationIndex ב-Trip (RPC | REST) משולבים יחד כדי לציין את היעד.

עדכון יעד הביניים

אפשר לעדכן את יעדי הביניים דרך UpdateTrip. כשמעדכנים את יעדי הביניים, צריך לספק רשימה מלאה של יעדי הביניים, כולל היעדים שביקרת בהם, ולא רק אלה שנוספו או שצריך לשנות. כשה-intermediateDestinationIndex מצביע על מדד אחרי המיקום של יעד ביניים שנוסף או עודכן, יעד הביניים החדש או המעודכן לא יתווסף ל-waypoints של הרכב או ל-remainingWaypoints של הנסיעה. הסיבה לכך היא שכל יעדי ביניים לפני intermediateDestinationIndex מוגדרים כיעדים שכבר ביקרתם בהם.

שינויים בסטטוס הנסיעה

השדה intermediateDestinationsVersion ב-(RPC | REST) נדרש בבקשת העדכון של סטטוס הנסיעה שנשלחת אל Fleet Engine כדי לציין שיעד ביניים חלף. יעד הביניים המטורגט מצוין בשדה intermediateDestinationIndex. כשהערך בשדה tripStatus (RPC | 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;
}

איך להירשם: הרשמה להודעות התראה מ-Feet Engine API

Feet Engine API משתמש ב- Google Cloud Pub/Sub כדי לפרסם התראות בנושא שנוצר על ידי פרויקט Google Cloud לצרכנים. כברירת מחדל, Pub/Sub לא מופעל ב-Feet Engine בפרויקט Google Cloud שלכם. צריך להגיש בקשת תמיכה או לפנות למהנדס הלקוח כדי להפעיל את Pub/Sub.

כדי ליצור נושא לפרויקט Cloud, פועלים לפי ההוראות האלה. מזהה הנושא חייב להיות 'fleet_engine_notifications'.

צריך ליצור את הנושא באותו פרויקט ב-Cloud שקורא לממשקי API של Fleet Engine.

אחרי יצירת הנושא, תצטרכו להעניק ל-Feet Engine API את ההרשאה לפרסם אותו. כדי לעשות את זה, לחצו על הנושא שיצרתם כרגע והוסיפו הרשאה חדשה. יכול להיות שתצטרכו ללחוץ על SHOW INFO PANEL כדי לפתוח את עורך ההרשאות. חשבון המשתמש צריך להיות geo-fleet-engine@system.gserviceaccount.com והתפקיד צריך להיות Pub/Sub publisher.

כדי להגדיר את הפרויקט ב-Cloud להרשמה להתראות, צריך לפעול לפי ההוראות האלה.

Fleet Engine API תפרסם כל התראה בשני פורמטים שונים של נתונים, protobuf ו-json. פורמט הנתונים של כל התראה מצוין במאפיינים של PubsubMessage, כאשר המפתח הוא data_format והערך הוא protobuf או json.

סכימת התראות:

פרוטובוף

// 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"
    }
  }
}