Telegram Bot Menemukan Lokasi Peta dan Rute dengan Google Map (GAS II-11)
Kita mulai materi lagi ya, bermain-main dengan koordinat menyenangkan bersama Dora. Ya, dimana kitaa? Kita perlu peta π
Mari berpetualang bersama Dora di Telegram!
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 ikutan belajar ya, teman-teman.
Fokus bahasan kali ini, relatif agak panjang juga. Ada 3 poin utama yang ingin disampaikan:
- Cara membaca koordinat yang dikirim posisi user
- Mencari lokasi yang diminta user
- 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 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
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.
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.
Code
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 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
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
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
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.
berhasil, berhasil, berhasilβ¦
Semoga lancar belajarnya..
Video II
Silakan disimak di video nya jika bingung atau ingin lebih jelas dalam prosesnya.
Referensi
Sebagai referensi dan tambahan bacaan dan materi, silakan diperiksa sebagai berikut:
- Welcome Bot Lib V2
- Library GAS Telegram Versi 2
- Bot API Telegram
- Materi Helo Bot
- Custom Command dan Regex
- Format Text / Parse Mode
- Doc GAS Maps
Penutup
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.