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

Fleet Engine On-demand Rides and Deliveries API מאפשר לנהל את הנסיעות ומצב הרכב באפליקציות שלכם לנסיעה ולהתקדמות בהזמנה. הוא מטפל בטרנזקציות בין Driver SDK, ה-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 של Fleet Engine בפתרונות Fleet Engine הם על פי דרישה.

מעטפת

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

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

רישום ביומן

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

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

ספריות לקוח

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

בדוגמאות של Java בתיעוד הזה, ההנחה היא שיש לכם היכרות עם gRPC.

אימות והרשאה

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

הגדרת פרויקט בענן

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

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

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

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

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

תפקידתיאור
משתמש SDK לצרכנים ב-Fleet Engine

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

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

roles/fleetengine.ondemandAdmin
התפקיד הזה מאפשר לקרוא ולכתוב את כל מקורות המידע לגבי רכבים ונסיעות. חשבונות משתמשים עם התפקיד הזה לא צריכים להשתמש באסימוני JWT, ובמקום זאת הם צריכים להשתמש ב-Application Default Credentials. המערכת מתעלמת מהצהרות JWT מותאמות אישית. יש להגביל את התפקיד הזה לסביבות מהימנות (הקצה העורפי של הלקוח).
FleetEngine Service Super User **(הוצא משימוש)**

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

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

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 Library, יש ליצור אסימוני אינטרנט JSON (JWT) ישירות בתוך ה-codebase שלכם. כדי לעשות את זה, צריכה להיות לכם הבנה עמוקה לגבי אסימוני JWT ואיך הם קשורים ל-Fleet Engine. לכן אנחנו ממליצים מאוד להשתמש ב-Fleet Engine Auth.

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

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

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

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

שדהתיאור
iss כתובת האימייל של חשבון השירות שלכם.
sub כתובת האימייל של חשבון השירות שלכם.
אוד SERVICE_NAME של חשבון השירות שלך, במקרה הזה https://fleetengine.googleapis.com/
iat חותמת הזמן שבה נוצר האסימון, צוינה בשניות שחלפו מ-1 בינואר 1970 ב-00:00:00 (שעון UTC). ממתינים 10 דקות להטיה. אם חותמת הזמן רחוקה מדי בעבר או בעתיד, השרת עשוי לדווח על שגיאה.
exp חותמת הזמן של תפוגת האסימון, צוינה בשניות שחלפו מ-1 בינואר 1970 ב-00:00:00 (שעון UTC). הבקשה תיכשל אם המועד של חותמת הזמן יהיה של יותר משעה אחת בעתיד.
הרשאה בהתאם לתרחיש לדוגמה, יכול להיות שהמאפיין '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"
   }
}

הטבלה הבאה מציגה אסימון לדוגמה עבור אפליקציית Drive:

{
  "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 משתמשים בחותמת הזמן כשפג תוקף האסימון (בשניות החל מ-1 בינואר 1970 ב-00:00:00 UTC). הערך המקסימלי המותר הוא iat + 3600.

כשחותמים על ה-JWT להעברה למכשיר נייד, צריך להשתמש בחשבון השירות של התפקידים Driver או Consumer SDK. אחרת, במכשיר הנייד תהיה אפשרות לשנות את המצב שלא אמור להיות בו.

באופן דומה, כשחותמים על ה-JWT לשימוש לקריאות עם הרשאות, הקפידו להשתמש בחשבון השירות עם תפקיד ה-Super User. אחרת, הפעולה תיכשל.

יצירת 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 הוא זמן התפוגה במספר שניות אחרי 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 על נקודת הקצה ל-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. שימוש ב-Driver SDK – האפשרות הפשוטה ביותר – Android, iOS.
  2. כדאי להשתמש בקוד מותאם אישית – שימושי אם המיקומים מועברים דרך הקצה העורפי, או אם אתם משתמשים במכשירים אחרים שאינם Android או iOS.

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

ישות הרכב מכילה שדה חובה של VehicleType, שמכיל טיפוסים בני מנייה (enum) של 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 Engine מקבל בקשה לנסיעה שנדרשת ממנה יכולות של רמת כסף, החיפוש כולל את הרכב הזה. השימוש במאפיינים בדרך הזו כולל כלי רכב עם מגוון יכולות.

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

איך: יצירת רכב

צריך ליצור ישות Vehicle לכל רכב שיהיה מעקב אחריו בכלל.

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

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

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

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

בקטע Vehicle types (סוגי רכב) מופיעים פרטים בשדה 'סוג הרכב'.

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

הערך שהוחזר מ-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 ליצירת רכב

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

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

אם אתם לא משתמשים ב-Driver 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.

איך: עדכון שדות אחרים של רכבים

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

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

איך: חיפוש כלי רכב

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

דוגמה

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

מעטפת

קודם מעדכנים את המיקום של הרכב שיצרנו בשלבים הקודמים כדי שהוא יהיה כשיר. בעולם האמיתי, הפעולה הזו תתבצע על ידי 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 ומחזור החיים דומים ל-Automotive API ולמחזור החיים. ספק Rideshare אחראי על יצירת הנסיעות באמצעות הממשקים של 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 שהוקצה לנסיעה רק כשהנסיעה פעילה. לדוגמה, אפשר לעשות את זה כשנהג מבטל נסיעה במהלך הנסיעה, והנסיעה מועברת לרכב אחר.

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

ציוני הדרך שנותרו בנסיעה

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

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

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

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

דוגמה

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

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

איך: עדכון נסיעה

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

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

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

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

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

אפשר לקרוא מידע נוסף על Tripב-RPC או על Resource.Trip ב-REST.

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

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

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

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

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

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

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

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

פתרון בעיות

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

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

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

תמיכה ביעדים מרובים

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

המערכת משלבת את השדה intermediateDestinations והשדה intermediateDestinationIndex ב'נסיעה' (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;
}

איך: הרשמה לקבלת התראות מ-Fleet Engine API

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

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

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

אחרי שיוצרים את הנושא, צריך לתת ל-Fleet Engine API את ההרשאה כדי לפרסם בנושא. כדי לעשות את זה, לוחצים על הנושא שיצרתם ומוסיפים הרשאה חדשה. יכול להיות שתצטרכו ללחוץ על הצגת חלונית המידע כדי לפתוח את עורך ההרשאות. חשבון המשתמש צריך להיות 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"
    }
  }
}