Telegram Bot Menemukan Lokasi Peta dan Rute dengan Google Map (GAS II-11)

11 menit saja |

Kita mulai materi lagi ya, bermain-main dengan koordinat menyenangkan bersama Dora. Ya, dimana kitaa? Kita perlu peta πŸ˜‚

Mari berpetualang bersama Dora di Telegram!

"Dora dan Teman"

Pendahuluan

Niat awal mo aku lanjutin welcome bot, tapi kawatir bosan udah 3 video berturut-turut dan cukup panjang kan. Saya sendiri agak mual bahas lagi haha.. kita ganti materi dulu, beralih dari welcome bot ke sesuatu yang baru dan mungkin akan menarik semuanya.

Yakni bermain-main dengan google map.

Yak cocok sekali, dengan fitur bot yang ini bisa dijadikan sebagai service bot umum.

Pra Materi

Ya, seperti biasa ya.. musti udah belajar sebelum-sebelumnya. Gak perlu lagi disebutin ulang lah yaaak.

Tingkat Kesulitan

Level materi ini adalah: middle - advanced

Tingkat kesulitan materi agak sulit ya, bisa dibilang untuk yang sudah belajar sampai ke yang advance buat nambahin referensi pemrogramannya.

Namun, sekali jangan takut. Meski kamu seorang beginner.. tidak selamanya jadi beginner kok. Manusia akan terus berkembang, asal jangan putus asa dan menyerah!

Penulisan

Materi ini di tulis sejak 11 Januari 2021.

Fokus

"Dora dan Teman"

Dora ikutan belajar ya, teman-teman.

Fokus bahasan kali ini, relatif agak panjang juga. Ada 3 poin utama yang ingin disampaikan:

  1. Cara membaca koordinat yang dikirim posisi user
  2. Mencari lokasi yang diminta user
  3. Terakhir mencari rute

Tiga poin ini semoga lebih dari cukup untuk belajar tentang bagaimana powerfull nya bot telegram dipergunakan untuk bermain-main dengan lokasi yak. Nyok mulai? Nyoook..

OK Lets Go!

"Dora dan Teman"

Dora mulai serius membaca dan praktek

1. Posisi User

Ini adalah yang paling simple, yakni ketika user mengirim posisinya bot akan membaca dan menginfokan koordinatnya. Selanjutnya tentu terserah Anda, mau dimanfaatkan gimana, dicatet atau diapa-apain.

Tujuan saya di poin pertama ini adalah, teman-teman belajar cara bot membaca dari user dan menghasilkan koordinatnya. Itu saja ya..

user: (kirim lokasi)
bot : πŸ“ Posisi kamu di koordinat: xxx, yyy.

Coding

Seperti biasa, kita buat trigger sejajar dengan if (msg.txt) pada file proses.gs ya.

Sekali lagi, bagi teman-teman yang kurang paham naruh codingnya dimana, bisa lihat di videonya. Jangan asal tempel yak.

// mendeteksi pesan yang dikirim mengandung lokasi
if (msg.location) {
    // penyederhanaan variable
    var location = msg.location;

    // penyusunan teks untuk dikirim
    var teks = `πŸ“ Posisi kamu di koordinat: <code>${location.latitude}, ${location.longitude}</code>.`;
    return tg.sendMsg(msg, teks, 'HTML', false, msg.message_id);
}

Dalam koding di atas, untuk membaca lokasi yang dikirim user, hanya diperlukan path pada json location, kemudian diambilah koordinatnya latitude dan longitude.

Perhatikan juga, bagaimana cara penulisan variable teks. Di sini saya menggunakan petik satu kebalik. Agar bisa menyisipkan variable baru dengan metode ${namaVariable}.

Silakan di test, dan semestinya sudah bisa berjalan dengan baik.

Sederhana bukan?

Pemanfaatannya untuk apa? Yap, silakan dikembangkan sendiri yak. Karena masing-masing dari kalian tentu memiliki niat dan tujuan berbeda-beda.

2. Mencari Lokasi

"Dora dan Teman"

Tujuan kali ini, kita akan menemukan lokasi yang dicari user. User menyebutkan lokasi sesuai objek POI (Point of Interest) suatu tempat. Misalnya menyebut nama kota, nama jalan, nama daerah, nama bangunan, nama toko, dan lain sebagainya.

geoCoder

Di sini kita akan memanfaatkan API bawaan dari Google App Script, yakni Map GeoCoder.

Ada banyak class method yang ada di sana, serta parameter-parameter apa saja teman-teman bisa pelajari sendiri ya.

"Geocoder Class"

Ketika saya cek posisi Simpang Lima Gumul hasil JSON nya adalah sebagai berikut :

{"status":"OK","results":[{"formatted_address":"Tugurejo, Kec. Ngasem, Kediri, Jawa Timur 64182, Indonesia","types":["establishment","point_of_interest","tourist_attraction"],"geometry":{"location_type":"GEOMETRIC_CENTER","location":{"lng":112.0623289,"lat":-7.815697799999999},"viewport":{"northeast":{"lat":-7.814348819708497,"lng":112.0636778802915},"southwest":{"lng":112.0609799197085,"lat":-7.817046780291501}}},"place_id":"ChIJMdqcXxdXeC4Rs0rkYwVhIzE","plus_code":{"compound_code":"53M6+PW Tugurejo, Kediri, Jawa Timur, Indonesia","global_code":"6P4J53M6+PW"},"address_components":[{"short_name":"Tugurejo","types":["administrative_area_level_5","political"],"long_name":"Tugurejo"},{"long_name":"Tugurejo","types":["administrative_area_level_4","political"],"short_name":"Tugurejo"},{"short_name":"Kec. Ngasem","long_name":"Kecamatan Ngasem","types":["administrative_area_level_3","political"]},{"long_name":"Kediri","types":["administrative_area_level_2","political"],"short_name":"Kediri"},{"long_name":"Jawa Timur","short_name":"Jawa Timur","types":["administrative_area_level_1","political"]},{"types":["country","political"],"short_name":"ID","long_name":"Indonesia"},{"long_name":"64182","short_name":"64182","types":["postal_code"]}]}]}

Jika bingung bacanya, silakan dicopas dan dimasukkan ke JSON Path Finder.

Dari sini kita lihat ada status = OK, jika tidak berarti ada error.

Errornya bisa bermacam-macam, salah satunya kena LIMIT aksesnya atau jatah requestnya habis. So, bijak-bijak dalam penggunaannya ya.

"Geocoder Class"

Result Status Code

Code

"Dora dan Teman"

Swiper ketakutan, bakal ditemukan terus

Oke mari kita implementasikan pada bot.

Gambarannya seperti ini:

user: !lokasi simpang lima gumul, kediri
bot : (mengirim data yang ditemukan dan koordinatnya)

Buat trigger codenya:

// geoCode
// syntax !lokasi (teks minimal 3 huruf)
var pola = /^[\/!](lok|loc|location|lokasi|posisi) ([\w\s,\.]{3,})/i;
if (cocok = pola.exec(msg.text)) {
    // geo untuk dapatkan lokasi

    // pertama: kita setup ke dalam bahasa Indonesia
    var geocoder = Maps.newGeocoder().setLanguage('id');
    // kedua: kita cari lokasi nya sesuai request
    var response = geocoder.geocode(cocok[2]);

    // periksa hasilnya, jika tidak ketemu keluarkan pesan error
    if (response.status !== 'OK') return tg.sendMsg(msg, "🚫 Lokasi tidak Ketemu.", 'HTML', false, msg.message_id);

    // jika ketemu, ambil aja data pertama
    
    // penyederhanaan variable untuk geo data pertama
    var Lokasi = response.results[0];
    
    var address = Lokasi.formatted_address;
    var latitude = Lokasi.geometry.location.lat;
    var longitude = Lokasi.geometry.location.lng;

    // untuk title, saya bingung dikasih apa
    // diisi koordinatnya aja deh      
    var title = latitude + ", " + longitude;

    // kirim Venue, ada di dokumentasi Lib V2
    // tg.sendVenue(chat_id, latitude, longitude, title, address, foursquare_id, foursquare_type, disable_notification, reply_to_message_id, reply_markup)

    return tg.sendVenue(msg.chat.id, latitude, longitude, title, address, false, false, false, msg.message_id)
        
    // --> akhir cek geoCode
}

Untuk pola lokasi kita batasi minimal 3 karakter ya. Biar gak sedikit-sedikit diproses.

Sedangkan pengiriman peta, kita bisa menggunakan sendLocation atau sendVenue.

Bedanya, klo sendVenue bisa memberikan info keterangan tambahan seperti nama alamat jalan dan lain sebagainya.

Maka, disini saya memilih sendVenue karena lebih banyak pilihan.

OK, Yang ini relatif mudah juga kan!

3. Reverse GeoCode

"Dora dan Teman"

Dora keasyikan, menghias karyanya

Sekarang kita balik, dari koordinat kita kirimkan penjelasan lokasi.

user: !lokasi -7.815697799999999, 112.0623289
bot : (mengirim lokasi yang diminta)

reverseGeocode

Di sini kita pake method reverseGeocode nya API Google Maps.

Syntax nya adalah :

reverseGeocode(latitude, longitude)

dengan hasil berupa object JSON.

Jika kita test lokasi koordinat Simpang Lima Gumul, maka hasil yang di dapatkan serupa dengan geoCode, namun sangat panjang.

Code

Karena formatnya lebih spesifik, harus berupa koordinat:

Karena POLA KEYWORDnya SAMA, MAKA pastikan lokasi triggernya di atas geocode!

Kalau tidak, pola yang ini tidak akan bekerja. Atau teman-teman bisa bedakan pola keywordnya, misalnya jadi !koordinat.

// cari lokasi berdasarkan koordinat, reverse Geocode
// syntax: !lokasi lat, long

var pola = /^[\/!](?:lok|loc|location|lokasi|posisi) (-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)$/i;
if (cocok = pola.exec(msg.text)) {
    // geo untuk dapatkan lokasi

    // pertama: kita setup ke dalam bahasa Indonesia
    var geocoder = Maps.newGeocoder().setLanguage('id');
    // kedua: kita cari lokasi nya sesuai request
    var response = geocoder.reverseGeocode(cocok[1], cocok[2]);

    // periksa hasilnya, jika tidak ketemu keluarkan pesan error
    if (response.status !== 'OK') return tg.sendMsg(msg, "🚫 Lokasi koordinat tidak Ketemu.", 'HTML', false, msg.message_id);

    // jika ketemu, ambil aja data pertama
    
    // penyederhanaan variable untuk geo data pertama
    var Lokasi = response.results[0];
    
    // untuk title, saya bingung dikasih apa
    // namanya di pantek Lokasi aja deh        
    var title = 'Lokasi';

    var address = Lokasi.formatted_address;
    var latitude = Lokasi.geometry.location.lat;
    var longitude = Lokasi.geometry.location.lng;

    // kirim Venue, ada di dokumentasi Lib V2
    // tg.sendVenue(chat_id, latitude, longitude, title, address, foursquare_id, foursquare_type, disable_notification, reply_to_message_id, reply_markup)

    return tg.sendVenue(msg.chat.id, latitude, longitude, title, address, false, false, false, msg.message_id)
        
    // --> akhir cek reverse GeoCode
}

Video I

Silakan disimak di video nya jika bingung atau ingin lebih jelas dalam prosesnya.

4. Mencari Rute

"Dora dan Teman"

Ayo bersama Dora, kita mulai mencari rute penjelajahan!

Kali ini kita enggak pakai fungsi scraping lagi. Yang akan kita manfaatkan adalah internal API dari Google sendiri, yakni ada pada Doc GAS Maps.

Ada banyak sekali method dan parameter disana, jadi silakan dibaca dan diteliti sendiri disesuaikan kebutuhan ya.

Saya berikan sample yang mudah dan sederhana, untuk diimplementasikan ke dalam bot telegram saja kali ini.

Gambaran

Kira-kira yang akan dibuat adalah seperti ini

user: !rute Kediri vs Nganjuk
bot : (kirim foto rute)

πŸ“ Jarak: 36,1 km
βŒ›οΈ Mobil: 1 jam 7 min

πŸ›« Dari:
 πŸ“Œ 112.0179516,-7.847838899999999
 Kediri, Jawa Timur, Indonesia

πŸ›¬ Tujuan:
 πŸ“Œ 111.9045581,-7.5943264
 Kabupaten Nganjuk, Jawa Timur, Indonesia

Di sini sebagai delimiter atau pemisah, saya menggunakan vs. Karena kalau pakai KE dikawatirkan ada padanan tempat yang pakai kata itu. Ingat, google map itu peta dunia ya.. jadi bisa jadi dibelahan negara lain ada lokasi atau tempat yang memakainya. Sedangkan vs kemungkinan bakal lebih jarang dipergunakan.

Saya tidak menggunakan delimiter koma (,) atau tanda baca lain. Karena bisa jadi juga dipakai. Contoh kasus:

user: !jarak Kediri, Jawa Timur vs Taman Mini Square, Bekasi

Koma, bisa dipakai sebagai penjelas lokasi kota, daerah, propinsi atau negara. Bisa juga sebagai penjelas lainnya.

Namun demikian, teman-teman bebas-bebas saja mengubah atau memodifikasi sesuai keinginan.

Code I

"Dora dan Teman"

Mari kita terapkan pada bot.. ini bagian yang agak serius, sedikit fokus dan lebih melotot.

Seperti biasa, bikin trigger nya:

// pencarian rute atau informasi jarak
pola = /^[\/!](jarak|rute|route) (.*) vs (.*)/i;
if (pola.exec(msg.text)) {
    var cocok = msg.text.match(pola);

    // tentukan variable sumber dan tujuan
    var dari = cocok[2];
    var tujuan = cocok[3];

    var response = Maps.newDirectionFinder()
    .setOrigin(dari)
    .setDestination(tujuan)

    // atur pakai mode kendaraan, bukan WALKING atau lainnya
    .setMode(Maps.DirectionFinder.Mode.DRIVING)

    // atur pakai bahasa indonesia
    .setLanguage('id')

    // dapatkan rutenya
    .getDirections();

    // periksa hasilnya, jika tidak ketemu keluarkan pesan error
    if (response.status !== 'OK') return tg.sendMsg(msg, "🚫 Rute tidak Ketemu.\nCoba dengan lebih spesifik menambahkan kota, wilayah, propinsi, atau negara.", 'HTML', false, msg.message_id);

    // jika ketemu, ambil aja data pertama
    var route = response.routes[0];

    
    // biar bagus dibuat marker / penanda
    // seting dulu penandanya
    var markerSize = Maps.StaticMap.MarkerSize.MID;
    var markerColor = Maps.StaticMap.Color.RED
    var markerLetterCode = 'A'.charCodeAt();

    // Menambahkan penanda ke peta
    var map = Maps.newStaticMap();
    for (var i = 0; i < route.legs.length; i++) {
        var leg = route.legs[i];
        if (i == 0) {
            // menambahkan penanda di lokasi mulai
            map.setMarkerStyle(markerSize, markerColor, String.fromCharCode(markerLetterCode));
            map.addMarker(leg.start_location.lat, leg.start_location.lng);
            markerLetterCode++;
        }
        map.setMarkerStyle(markerSize, markerColor, String.fromCharCode(markerLetterCode));
        map.addMarker(leg.end_location.lat, leg.end_location.lng);
        markerLetterCode++;
    }

    // Menambah jalur2nya
    map.addPath(route.overview_polyline.points);

    // mulaiC = koordinat posisi Start
    // akhirC = koordinat posisi End
  
    var mulai  = route.legs[0].start_address;
    var mulaiC = 'πŸ“Œ '+route.legs[0].start_location.lat+','+route.legs[0].start_location.lng;
  
    var akhir  = route.legs[0].end_address;
    var akhirC = 'πŸ“Œ '+route.legs[0].end_location.lat+','+route.legs[0].end_location.lng;
  
    var jarak  = route.legs[0].distance.text;
    var waktu  = route.legs[0].duration.text
  
    var caption = 'πŸ“ Jarak: '+jarak+'\nβŒ›οΈ Mobil: '+waktu+'\n\nπŸ›« Dari:\n <code>'+mulaiC+'</code>\n '+tg.util.clearHTML(mulai)+'\n\nπŸ›¬ Tujuan:\n <code>'+akhirC+'</code>\n '+tg.util.clearHTML(akhir);

    // peta kita buat dalam format blob
    var photo = map.getBlob();

    var data = { 
        chat_id : String(msg.chat.id),
        photo : photo,
        caption : caption,
        parse_mode: 'HTML'
    };
    
    // kita pake requestForm karena ada data blob nya
    return tg.requestForm('sendPhoto', data);

}

Kodenya agak rumit ya, silakan diperiksa sendiri dan dicocokkan dengan dokumentasi API nya Google Directions ya.

Silakan dicoba, semestinya berhasil..

Code II

"Dora dan Teman"

Biar lebih cantik, kita modif dan tambahkan dengan keyboard inline.

user: !rute Kediri vs Nganjuk
bot : (kirim foto rute)

πŸ“ Jarak: 36,1 km
βŒ›οΈ Mobil: 1 jam 7 min

[tombol 1: Kediri, Jawa Timur, Indonesia ]
[tombol 2: Kabupaten Nganjuk, Jawa Timur, Indonesia]

Jika tombol di pencet, akan mengirim lokasi nya.

Oke, mari memulai lagi…

Sesuaikan dari Code I, menjadi :

// pencarian rute atau informasi jarak
pola = /^[\/!](jarak|rute|route) (.*) vs (.*)/i;
if (pola.exec(msg.text)) {
    var cocok = msg.text.match(pola);

    // tentukan variable sumber dan tujuan
    var dari = cocok[2];
    var tujuan = cocok[3];

    var response = Maps.newDirectionFinder()
    .setOrigin(dari)
    .setDestination(tujuan)

    // atur pakai mode kendaraan, bukan WALKING atau lainnya
    .setMode(Maps.DirectionFinder.Mode.DRIVING)

    // atur pakai bahasa indonesia
    .setLanguage('id')

    // dapatkan rutenya
    .getDirections();

    // periksa hasilnya, jika tidak ketemu keluarkan pesan error
    if (response.status !== 'OK') return tg.sendMsg(msg, "🚫 Rute tidak Ketemu.\nCoba dengan lebih spesifik menambahkan kota, wilayah, propinsi, atau negara.", 'HTML', false, msg.message_id);

    // jika ketemu, ambil aja data pertama
    var route = response.routes[0];

    
    // biar bagus dibuat marker / penanda
    // seting dulu penandanya
    var markerSize = Maps.StaticMap.MarkerSize.MID;
    var markerColor = Maps.StaticMap.Color.RED
    var markerLetterCode = 'A'.charCodeAt();

    // Menambahkan penanda ke peta
    var map = Maps.newStaticMap();
    for (var i = 0; i < route.legs.length; i++) {
        var leg = route.legs[i];
        if (i == 0) {
            // menambahkan penanda di lokasi mulai
            map.setMarkerStyle(markerSize, markerColor, String.fromCharCode(markerLetterCode));
            map.addMarker(leg.start_location.lat, leg.start_location.lng);
            markerLetterCode++;
        }
        map.setMarkerStyle(markerSize, markerColor, String.fromCharCode(markerLetterCode));
        map.addMarker(leg.end_location.lat, leg.end_location.lng);
        markerLetterCode++;
    }

    // Menambah jalur2nya
    map.addPath(route.overview_polyline.points);

    // mulaiC = koordinat posisi Start
    // akhirC = koordinat posisi End
  
    var mulai = route.legs[0].start_address;
    var mulaiC = route.legs[0].start_location.lat + ',' + route.legs[0].start_location.lng;

    var akhir = route.legs[0].end_address;
    var akhirC = route.legs[0].end_location.lat + ',' + route.legs[0].end_location.lng;

    var jarak = route.legs[0].distance.text;
    var waktu = route.legs[0].duration.text
  
    var caption = 'πŸ“ Jarak: ' + jarak + '\nβŒ›οΈ Mobil: ' + waktu ;

    // peta kita buat dalam format blob
    var photo = map.getBlob();

    // buat keyboard
    var keyboard = [
        [tg.button.text('πŸ“ '+mulai, 'lokasi_' + mulaiC)],
        [tg.button.text('🏁 ' + akhir, 'lokasi_' + akhirC)]
    ]

    var reply_markup = {
        inline_keyboard: keyboard
    }

    var data = {
        chat_id: String(msg.chat.id),
        photo: photo,
        caption: caption,
        parse_mode: 'HTML',
        reply_markup: JSON.stringify(reply_markup)
    };

    // kita pake requestForm karena ada data blob nya
    return tg.requestForm('sendPhoto', data);
}

Kemudian, kita buat penangkapan event callback data query.

Letakkan sejajar dengan if (update.message) { atau dibawahnya tepat function prosesPesan(update) { :

// periksa apa ada data callback
 if (update.callback_query) {

    // penyederhaaan variable callback
    var cb = update.callback_query;

    // jika pola lokasi cocok, kirim sendLocation
    var pola = /^lokasi_(-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)$/i;
    if (cocok = pola.exec(cb.data)) 
        return tg.sendLocation(cb.message.chat.id, parseFloat(cocok[1]), parseFloat(cocok[2]));
}

Alright! Sampai di sini yaak.. sudah lumayan panjang.

"Dora dan Teman"

berhasil, berhasil, berhasil…

Semoga lancar belajarnya..

Video II

Silakan disimak di video nya jika bingung atau ingin lebih jelas dalam prosesnya.

Referensi

"Dora dan Teman"

Sebagai referensi dan tambahan bacaan dan materi, silakan diperiksa sebagai berikut:

Penutup

"Yuk Belajar"

Dora bahagia!

Jika ada pertanyaan, saran atau masukkan silakan didiskusikan. Jika ingin live dan biasanya tanggapan juga lebih cepat, sangat disarankan bergabung pada group Telegram @botIndonesia. Semoga bermanfaat.