Sabtu, 07 Desember 2024
Grafik IOT Dynamic dengan Webhook - GoogleSheets - Google Apps Script
Senin, 30 September 2024
Membuat SMS Gateway Lucu Dengan SIM800L
#include <SoftwareSerial.h> #define TX_PIN 8 #define RX_PIN 7 SoftwareSerial serialSIM800(TX_PIN, RX_PIN); void setup() { Serial.begin(9600); //HW Serial Monitor while(!Serial); Serial.println("Inisialisasi modul SIM800L"); serialSIM800.begin(9600); delay(1000); Serial.println("Kirim SMS..."); //Set mode teks untuk pengiriman sms serialSIM800.write("AT+CMGF=1\r\n"); delay(1000); //Mulai mengirim Sms ganti nomer tujuan kamu serialSIM800.write("AT+CMGS=\"081234567890\"\r\n"); delay(1000); serialSIM800.write("System ready"); delay(1000); serialSIM800.write((char)26); //CTRL-Z delay(1000); Serial.println("SMS Terkirim!"); } void loop() { }
+CMT :"+628155555555","11/10/01,12 :30 :00+00", pesan sms disini
#include <SoftwareSerial.h>
#include <avr/pgmspace.h> // untuk menghemat RAM gunakan PROGMEM
SoftwareSerial gsm(2, 3); // RX, TX pins ke modem
String message = "";
String senderNumber = ""; // variabel nomer yang akan dibalas
bool newMessage = false; // Flag ada pesan baru
// jokes bapak bapak disimpan di PROGMEM
const char joke1[] PROGMEM = "Kenapa ayam nyebrang jalan? Karena mau ke seberang!";
const char joke2[] PROGMEM = "Kenapa gajah bawa koper? Karena mau pergi liburan!";
const char joke3[] PROGMEM = "Kenapa Indonesia panas banget ya? Padahal negara ASEAN.";
const char joke4[] PROGMEM = "Uang 100 ribu jika dilempar bakal jadi apa? Jadi rebutan.";
const char joke5[] PROGMEM = "Apa yang lebih besar dari dinosaurus? Hutan tempat mereka tinggal.";
const char joke6[] PROGMEM = "Huruf-huruf apa yang sering kedinginan? Huruf B karena ada di tengah-tengah AC.";
const char joke7[] PROGMEM = "Kentang apa yang bisa bikin bayi ketawa? Kentang-tingtung-tingtang-tingtungtang.";
const char joke8[] PROGMEM = "Kesenian apa yang sering dilakukan nasabah bank? Tari tunai.";
const char joke9[] PROGMEM = "Sapi apa yang larinya cepat? Sapida motor.";
const char joke10[] PROGMEM = "Monyet apa yang bikin sebel? Monyetel tivi nggak ada remote.";
const char joke11[] PROGMEM = "Sepeda apa yang tak bisa dicat? Sepeda hilang.";
const char* const jokes[] PROGMEM = {joke1, joke2, joke3, joke4, joke5, joke6, joke7, joke8, joke9, joke10, joke11}; // Array of joke pointers
void setup() {
gsm.begin(9600); // Start GSM communication
Serial.begin(9600); // For serial monitor
delay(1000);
Serial.println("Test GSM Modem Server for UNESA");
// Initialize GSM modem
gsm.println("ATE1");
delay(1000);
gsm.println("AT+CMGF=1"); // Set text mode
delay(1000);
gsm.println("AT+CNMI=2,2"); // Sms langsung baca
delay(1000);
gsm.println("AT+CMGD=31,4"); // Hapus sms
delay(1000);
}
void loop() {
if (gsm.available()) {
char c = gsm.read();
message += c;
if (c == '\n') { // End of a line
Serial.print("Received: ");
Serial.println(message);
// Check for SMS header (+CMT) to know it's an incoming message
if (message.indexOf("+CMT") != -1) {
senderNumber = extractPhoneNumber(message); // Extract sender's number
newMessage = true; // Set flag indicating the next line will be the message body
}
else if (newMessage && message.length() > 1) { // Process the next line after +CMT as the message body
String studentName = message;
studentName.trim(); // Remove any trailing spaces or newlines
// Send greeting with a random joke
String reply = createReply(studentName);
sendSMS(senderNumber, reply); // Use senderNumber extracted earlier
newMessage = false; // Reset flag after sending the SMS
}
message = ""; // Clear the message for the next line
}
}
}
// Extract phone number from the +CMT line
String extractPhoneNumber(String msg) {
int startIndex = msg.indexOf("\"") + 1;
int endIndex = msg.indexOf("\"", startIndex);
return msg.substring(startIndex, endIndex);
}
// Create the reply message with a greeting and a random joke
String createReply(String name) {
String greeting = "Halo " + name + ", ";
// Generate a random index and fetch the joke from PROGMEM
int randomIndex = random(0, 11);
char joke[100]; // Create a buffer to store the joke
strcpy_P(joke, (char*)pgm_read_word(&(jokes[randomIndex]))); // Read the joke from PROGMEM
return greeting + String(joke); // Combine greeting with joke
}
// Function to send an SMS
void sendSMS(String phoneNumber, String message) {
gsm.println("AT+CMGS=\"" + phoneNumber + "\"\r"); // Send the AT command for the recipient's number
delay(100);
gsm.print(message); // Send the SMS body
delay(100);
gsm.write(26); // Send Ctrl+Z to end the SMS
delay(500);
}
if (gsm.available()) {
char c = gsm.read();
message += c;
if (c == '\n') { // End of a line
Serial.print("Received: ");
Serial.println(message);
// Check for SMS header (+CMT) to know it's an incoming message
if (message.indexOf("+CMT") != -1) {
senderNumber = extractPhoneNumber(message); // Extract sender's number
newMessage = true; // Set flag indicating the next line will be the message body
}
else if (newMessage && message.length() > 1) { // Process the next line after +CMT as the message body
String studentName = message;
studentName.trim(); // Remove any trailing spaces or newlines
// Send greeting with a random joke
String reply = createReply(studentName);
sendSMS(senderNumber, reply); // Use senderNumber extracted earlier
newMessage = false; // Reset flag after sending the SMS
}
message = ""; // Clear the message for the next line
}
}
// Extract phone number from the +CMT line
String extractPhoneNumber(String msg) {
int startIndex = msg.indexOf("\"") + 1;
int endIndex = msg.indexOf("\"", startIndex);
return msg.substring(startIndex, endIndex);
}
// Create the reply message with a greeting and a random joke
String createReply(String name) {
String greeting = "Halo " + name + ", ";
// Generate a random index and fetch the joke from PROGMEM
int randomIndex = random(0, 11);
char joke[100]; // Create a buffer to store the joke
strcpy_P(joke, (char*)pgm_read_word(&(jokes[randomIndex]))); // Read the joke from PROGMEM
return greeting + String(joke); // Combine greeting with joke
}
// Function to send an SMS
void sendSMS(String phoneNumber, String message) {
gsm.println("AT+CMGS=\"" + phoneNumber + "\"\r"); // Send the AT command for the recipient's number
delay(100);
gsm.print(message); // Send the SMS body
delay(100);
gsm.write(26); // Send Ctrl+Z to end the SMS
delay(500);
}
Selasa, 26 Maret 2024
[Modbus] Menampilkan Sensor Suhu Infra Red ke Matrix P10
Sambungan dari praktek membaca sensor suhu infra red RS-WD-HW-N01 yang saya bahas sebelumnya disini , saya akan ajarkan bagaimana menampilkan suhunya di dot matrix display P10. Display dot matrix ini paling umum digunakan di layar sekolah, toko, masjid dll, ini sangat banyak yang membahas di blog maupun youtube, dengan harga yang sangat murah (menyebabkan 10 tahun lalu saya berhenti jadi pengrajin display led matrix), namun kali ini kebetulan ada proyek dan akan saya bagi ilmunya secara perlahan.
PINOUT
Pinoutnya berupa header 2x8 dan beberapa seller online shop diluar sana menjual header converter ke arduino uno seperti gambar diatas. Jika ingin buat sendiri tentunya tidak akan menjadi kesulitan. Untuk tegangan 5 volt sebaiknya diberikan terpisah dari arduino dengan adaptor 5v yang mempunyai ampere lebih tinggi.
LIBRARY
Library asli dibuat oleh produsen aslinya yaitu FREETRONICS dan dapat di unduh disini. Pemilihan portnya berbasiskan port SPI dimana akan memanfaatkan 2 pin MOSI (13) dan SCK (11). Sedangkan pemilihan pin OE (output enable) harus berhubungan dengan timer1 sehingga kakinya jangan dirubah dari nomer 9.
Untuk menambahkan font yang lebih keren, beberapa pengembang elektronika mikrokontroller di Indonesia berkreasi dengan library DMD3 yang bisa di googling sendiri.
SCRIPT
Saya bagi aja langsung dan semoga bermanfaat untuk belajar kalian maupun tugas di sekolah/kampus.
/* Sensor Suhu Infra merah Tampilan ke Led Matrix P10 type : RS-WD-HW-N01 RS485 www.aisi555.com ahocool@gmail.com */ #include "BIG7SEGMENT.h" #include "DMD3.h" #include "DejaVuSans9.h" #include "bmz9.h" #include "bmz6x7.h" #include <SoftwareSerial.h> SoftwareSerial mod(12, 10); // RX (A) , TX (B) ke rs485 sensor DMD3 display (1,1); byte baca[] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x84, 0x0A};//perintah baca suhu byte bufferDataModbus[18]; byte *ptr; int incomingByte ; int suhune, puluhan, satuan; bool terima = false; unsigned long previousMillis = 0; char dmdBuff1[10]; //Suhu Digit Depan koma char dmdBuff2[10]; //belakang koma void scan() { display.refresh(); } void setup() { Serial.begin(9600); Serial.println(F("Sensor infra red ke p10")); Serial.println(F("http://www.aisi555.com")); Serial.println(); mod.begin(4800); ptr = bufferDataModbus; Timer1.initialize(1350); Timer1.attachInterrupt(scan); Timer1.pwm(9,255); } void loop() { unsigned long currentMillis = millis(); if(currentMillis - previousMillis >= 5000) { // timer baca sensor tiap 5 detik previousMillis = currentMillis; //kirim perintah ke modbus baca suhu mod.write(baca, sizeof(baca)); } //check modbus timeout long millisResponModbus = millis() + 1000; while (!mod.available()) { if (millisResponModbus < millis()) { break;//timeout } } // baca data serial yang masuk dari modbus lalu simpan pada pointer while (mod.available()) { byte b = mod.read(); *ptr++ = b; Serial.print("0x"); Serial.print(String(b, HEX)); Serial.print(" "); delay(2); terima = true; } if (terima){ ptr = bufferDataModbus; suhune = (ptr[3] *256) + ptr[4]; puluhan = suhune / 10; satuan = suhune % 10; Serial.print("Suhu = "); Serial.print(puluhan); Serial.print(","); Serial.print(satuan); Serial.println(" Celcius"); memset(bufferDataModbus, 0x00, sizeof(bufferDataModbus)); terima =false; display.clear(); //tulis suhu ke p10 display.setFont(BIG7SEGMENT); sprintf(dmdBuff1, "%.2d", puluhan); sprintf(dmdBuff2, "%.1d", satuan); display.drawText(0, 0, dmdBuff1); display.setFont(bmz9); display.drawText(26, -1, "C"); display.drawRect(22,1,24,3,1); display.setFont(bmz6x7); display.drawRect(22,13,23,14,1); display.drawText(25, 8 , dmdBuff2); } }
Minggu, 17 Maret 2024
[Modbus] Membaca Sensor Suhu RS-WD-HW-N01 RS485 - Arduino
Sebagai pembuka saya ingin berbagi bahwa sensor suhu inframerah memiliki beberapa kekurangan yang perlu dipertimbangkan:
1. **Akurasi terbatas**: Akurasi sensor suhu inframerah dapat dipengaruhi oleh berbagai faktor seperti emisivitas objek yang diukur, suhu lingkungan, kelembaban, dan jarak sensor dari objek. Hal ini dapat mengakibatkan pembacaan yang kurang tepat dibandingkan dengan sensor suhu kontak.
2. **Efek permukaan**: Sensor suhu inframerah mengukur suhu permukaan objek. Hal ini dapat menjadi kelemahan ketika berurusan dengan material dengan konduktivitas termal rendah atau permukaan yang tidak merata dalam suhu. Misalnya, permukaan yang mengkilap atau reflektif dapat memantulkan radiasi inframerah lingkungan, menyebabkan pembacaan yang tidak akurat.
3. **Rentang terbatas**: Beberapa sensor suhu inframerah memiliki rentang pengukuran yang terbatas, yang mungkin tidak sesuai untuk semua aplikasi. Sebagai contoh, beberapa sensor mungkin tidak dapat mengukur suhu yang sangat tinggi atau rendah dengan akurat.
4. **Waktu respons**: Sensor suhu inframerah mungkin memiliki waktu respons yang lebih lambat dibandingkan dengan sensor suhu kontak, terutama ketika mengukur suhu yang berubah dengan cepat atau objek yang bergerak.
5. **Interferensi lingkungan**: Faktor lingkungan seperti asap, debu, atau partikel lainnya di udara dapat mengganggu pengukuran suhu inframerah, menyebabkan ketidakakuratan.
6. **Biaya**: Sensor suhu inframerah dapat lebih mahal dibandingkan dengan sensor suhu kontak, terutama untuk model presisi tinggi atau yang memiliki fitur canggih.
7. **Kalibrasi**: Kalibrasi berkala diperlukan untuk menjaga akurasi sensor suhu inframerah. Hal ini membutuhkan peralatan dan keahlian khusus, menambah biaya dan kompleksitas penggunaan sensor tersebut.
8. **Kedalaman penetrasi terbatas**: Radiasi inframerah hanya dapat menembus permukaan objek yang diukur sampai kedalaman tertentu. Hal ini dapat menjadi keterbatasan ketika mengukur suhu material tebal atau tidak tembus pandang.
Meskipun memiliki kelemahan-kelemahan ini, sensor suhu inframerah tetap banyak digunakan dalam berbagai industri karena sifat non-kontaknya, kemudahan penggunaan, dan kecocokannya untuk beberapa aplikasi tertentu.
void loop() { unsigned long currentMillis = millis(); if(currentMillis - previousMillis >= 5000) { // timer baca dht11 tiap 5 detik previousMillis = currentMillis; //kirim perintah ke modbus baca dht 11 mod.write(humitemp, sizeof(humitemp)); } //check modbus timeout long millisResponModbus = millis() + 1000; while (!mod.available()) { if (millisResponModbus < millis()) { break;//timeout } } // baca data serial yang masuk dari modbus lalu simpan pada pointer while (mod.available()) { byte b = mod.read(); *ptr++ = b; Serial.print("0x"); Serial.print(String(b, HEX)); Serial.print(" "); delay(2); } //proses komparasi data yg masuk (DHT11) dengan array jawaban lalu parsing if (memcmp(bufferDataModbus, dhtOK, sizeof(dhtOK)) == 0) { ptr = bufferDataModbus; Serial.println(""); Serial.print(F("SUHU :")); Serial.print(ptr[4]); //alamat byte ke 4 Serial.print(F(",")); Serial.print(ptr[6]); //alamat byte ke 6 Serial.print(F(" C HUMI :")); Serial.print(ptr[8]); //alamat byte ke 8 Serial.println(" %"); memset(bufferDataModbus, 0x00, sizeof(bufferDataModbus)); } }
Jadi script diatas dulu itu akan menunggu membaca data OK berdasarkan Check Sum / CRC modbus 16bit. Namun sepertinya itu bisa diabaikan karena hampir error jarang sekali terjadi. Jadi untuk membaca sensor suhu RS-WD-HW-N01 RS485, kira kira scriptnya seperti berikut :
/* Cara baca Sensor Suhu Infra merah type : RS-WD-HW-N01 RS485 www.aisi555.com ahocool@gmail.com */ #include <SoftwareSerial.h> SoftwareSerial mod(12, 10); // RX, TX ke rs485 //perintah baca suhu, baca penjelasan di blog byte baca[] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x84, 0x0A}; byte bufferDataModbus[10]; byte *ptr; int incomingByte ; int suhune, puluhan, satuan; bool terima = false; unsigned long previousMillis = 0; void setup() { Serial.begin(9600); Serial.println(F("Testing Sensor Infra Ke Serial")); Serial.println(F("http://www.aisi555.com")); Serial.println(); //baud rate default 4800 mod.begin(4800); ptr = bufferDataModbus; } void loop() { unsigned long currentMillis = millis(); if(currentMillis - previousMillis >= 5000) { // timer baca sensor tiap 5 detik previousMillis = currentMillis; //kirim perintah ke modbus baca sensor mod.write(baca, sizeof(baca)); } //check modbus timeout long millisResponModbus = millis() + 1000; while (!mod.available()) { if (millisResponModbus < millis()) { break;//timeout } } // baca data serial yang masuk dari modbus lalu simpan pada pointer while (mod.available()) { byte b = mod.read(); *ptr++ = b; Serial.print("0x"); Serial.print(String(b, HEX)); Serial.print(" "); delay(1); terima = true; } //parsing data suhu dan tampilkan di serial debug if (terima){ ptr = bufferDataModbus; suhune = (ptr[3] *256) + ptr[4]; puluhan = suhune / 10; satuan = suhune % 10; Serial.print("Suhu = "); Serial.print(puluhan); Serial.print(","); Serial.print(satuan); Serial.println(" Celcius"); memset(bufferDataModbus, 0x00, sizeof(bufferDataModbus)); terima =false; } }
Hasil dari tangkapan layar debug seperti ini :
Data suhu yang akan dibaca adalah data ke-4 (0x1) dan data ke-5 (0x3E). Data lainnya bisa diabaikan, sehingga rumus parsing saya dilakukan dengan script berikut:
if (terima){ ptr = bufferDataModbus; // pindahkan data //ini rumus sederhana untuk merubah 2byte modbus jadi desimal suhune = (ptr[3] *256) + ptr[4]; //pointer memori mulai dari nol puluhan = suhune / 10; satuan = suhune % 10; Serial.print("Suhu = "); Serial.print(puluhan); Serial.print(","); Serial.print(satuan); Serial.println(" Celcius"); //bersihkan memori memset(bufferDataModbus, 0x00, sizeof(bufferDataModbus)); terima =false; }
Sehingga secara gampangannya , 0x01 merupakan High Byte sehingga dapat dikalikan 256 (desimal) untuk mendapatkan nilai desimal High Byte, sedangkan 0x3E (Low Byte) bernilai desimal 62, dan selanjutnya tinggal ditambahkan saja yaitu 256 + 62 = 318. Ini cocok hasilnya dengan hexa 0x13E. Sebenernya ada cara lebih "elegan" yaitu dengan geser byte ke kiri, namun saya yakin pembaca akan tambah bingung.
Jumat, 22 September 2023
[Tutorial] Sensor Suhu Ds18b20 dan output ke display oled
#include <OneWire.h>
#include <DallasTemperature.h>
// Sensor data ke digital pin 4, sesuaikan yg dipakai
#define ONE_WIRE_BUS 4
// inisialisasi nama library one wire
OneWire oneWire(ONE_WIRE_BUS);
// menghubungkan library onewire vs Dallas Temperature
DallasTemperature sensors(&oneWire);
void setup(void)
{
// Start serial baud 9600
Serial.begin(9600);
// memulai ibrary library
sensors.begin();
}
void loop(void){
// Panggil pembacaan sensor pada bus one wire
sensors.requestTemperatures();
//tulis ke serial monitor
Serial.print("Celsius temperature: ");
// kasi index 0 karena cuman 1 sensor, bisa untuk banyak sensor
Serial.print(sensors.getTempCByIndex(0));
Serial.print(" - Fahrenheit temperature: ");
Serial.println(sensors.getTempFByIndex(0));
delay(1000);
}
// Sensor data ke digital pin D4, sesuaikan yg dipakai
#define ONE_WIRE_BUS D4
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define SCREEN_WIDTH 128 // display display width, in pixels
#define SCREEN_HEIGHT 64 // display display height, in pixels
#define SENSOR_PIN D4 // pin sensor DS18B20
#define BUZZER_PIN D5 // pin buzzer
#define display_RESET -1 // Reset pin
#define SCREEN_ADDRESS 0x3C ///address i2c oled
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, display_RESET);
OneWire oneWire(SENSOR_PIN); // setup a oneWire
DallasTemperature tempSensor(&oneWire); // pass oneWire
unsigned long previousMillis = 0;
String tempString,tempString1;
float batas = 35; // batas suhu biar alarm
float tempCelsius;
void setup() {
Serial.begin(9600);
pinMode(BUZZER_PIN,OUTPUT);
digitalWrite(BUZZER_PIN,LOW);
// initialize display display with address 0x3C for 128x64
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
while (true);
}
delay(2000); // wait for initializing
display.clearDisplay(); // clear display
display.setTextSize(1); // text size
display.setTextColor(WHITE); // text color
displayDisplayCenter("Teknik Listrik", 4);
displayDisplayCenter("Vokasi Unesa 2023",56);
display.setTextSize(2);
display.setCursor(0, 32); // position to display
tempSensor.begin(); // initialize the sensor
tempString.reserve(10); // to avoid fragmenting memory when using String
}
void loop() {
tempSensor.requestTemperatures(); // send the command to get temperatures
tempCelsius = tempSensor.getTempCByIndex(0); // read temperature in Celsius
tempString = String(tempCelsius, 2); // two decimal places
tempString += (char)247;
tempString += "C";
//biar ketumpuk hitam dulu jika suhu nya berubah
if(tempString != tempString1)
{
display.setTextColor(BLACK);
displayDisplayCenter(tempString1,28);
}
tempString1= tempString;
Serial.println(tempString); // print the temperature in Celsius to Serial Monitor
//lanjut tulis warna putih
display.setTextColor(WHITE);
displayDisplayCenter(tempString,28);
if( tempCelsius >= batas) //cek alarm vs buzzer
{
digitalWrite(BUZZER_PIN,HIGH);
delay(200);
digitalWrite(BUZZER_PIN,LOW);
delay(50);
}
else digitalWrite(BUZZER_PIN,LOW);
}
//function agar tulisan rata tengah (center)
void displayDisplayCenter(String text, int posisi) {
int16_t x1;
int16_t y1;
uint16_t width;
uint16_t height;
display.getTextBounds(text, 0, 0, &x1, &y1, &width, &height);
display.setCursor((SCREEN_WIDTH - width) / 2, posisi);
display.println(text); // text to display
display.display();
}
Rabu, 20 September 2023
[Tutorial] Dasar Input - Output Pada Mikrokontroler
Pada umumnya terdapat 2 jenis input output yang terlihat paling "sederhana" dan paling sering dibahas pada sebuah sistem mikrokontroler AVR, arduino maupun ESP 8266. Dari list dibawah ini, nomer 1 dan 2 akan kita praktekkan pada tulisan blog kali ini, bersama dengan adik - adik mahasiswa di jurusan teknik listrik vokasi unesa Surabaya.
Jenis Input Output :
- Digital Pin
- Analog Pin
- PWM
- Serial
- I2C
- SPI
Rabu, 25 Mei 2022
LoRaWan - Antares id "Hello World" dengan SX1276 / RFM95 di Frekuensi AS923-2
Lora bukanlah barang yang asing bagi saya karena telah cukup lama mengenal modul modem RF nya kira-kira 7 tahun yang lalu, dan berhasil mengirimkan data text / terminal serial antar 2 modul lora (point to point) yang saya letakkan dari ujung ke ujung jembatan Suramadu. Kala itu modul yang digunakan masih menggunakan frekuensi 433 Mhz yang cukup terjangkau harganya, namun setelah praktek sederhana ini saya merasa tak ada yg spesial dari sekedar kirim-kiriman data jarak jauh. Kemudian ketika konsep IOT saya sudah lumayan mendapatkan pencerahan dan lebih memilih wifi sebagai koneksi paling murah meriah, maka modul ini jadi terlupakan dan entah terselip dimana. Apalagi kemudian pemerintah baru men-standarkan dan meregulasi frekuensi lora sesuai dengan pembagian regional ITU - Lora aliance yaitu di 923Mhz pada tahun 2019.
Breaking news: Telkom akan melakukan migrasi LoRaWan ke Telkomiot.id, Silahkan baca disini
Ketiadaan gateway lora pada tahun dimana saya mencoba lora juga menjadi kendala untuk oprek-oprek, dan saat itu pernah membantu seorang mahasiswa menyeting GW Lora dragino yang ternyata harganya sangat memberatkan kantong mahasiswa. Baik TTN ( the things network) maupun Lora alliance tidak muncul juga gatewaynya saat saya getol2nya mengoprek modul lora 433Mhz. Sampai suatu ketika saya mendapatkan request pembaca untuk menengok perkembangan gateway LoraWan yang dipasang telkom bersama mitratel. Lalu meluncurlah saya ke websitenya Telkom iot dan mendapatkan Lorawan nya ternyata telah di deploy dan memancar dilokasi yang tak jauh dari kediaman saya.
Peta diatas terasa sangat familiar bagi saya, perasaan de-ja-vu pun muncul...yahh karena telkom surabaya adalah mantan terindah buat saya. Cieee...cieee....ya iyalah hampir 9 tahun saya berkutat dengan map dan coverage persis dengan gambar diatas. Dan benar saja lingkaran merah yang menyatakan sinyal Lorawan nya besar, itu berada pada titik lokasi STO Telkom yang memiliki tower BTS / Radio. Yahhh..kenangan mantan memang menyakitkan, namun saya harus MOVE ON dan segera mencari modul Lora dengan frekuensi sesuai standar di Indonesia.
Banyak modul Lora yang beredar di pasaran online, dan saya sangat berhati-hati agar tidak salah membeli karena dana sedang tipis-tipisnya. Apalagi ada yg memberitahu saya kalau modul lora berbasis esp32 TTG / LilyGo sedang kosong dipasaran. Pilihan datang ke breakout board Lora berbasis SX1276 atau RFM95 yang lumayan terjangkau, namun belum siap pakai karena harus melakukan penyesuaian ke microcontroller yang digunakan. Namun setelah diyakinkan oleh seller online nya dan seharian membaca di internet, saya memutuskan untuk membelinya dan menyandingkannya dengan Arduino nano yang teronggok tak terpakai di gudang. Rangkaian / skematik yg saya gunakan kira-kira tak jauh dari yang bisa didapatkan di internet.
Library yang pertama saya gunakan adalah library LoraId milik antares yang tersedia di sketch arduino, maupun library lainnya yang terdapat pada modul training di website antares. Sesuai pengalaman sebelumnya saat saya membahas library Antares, muncul keraguan kalau library ini tidak bisa langsung pakai dan harus saya oprek terlebih dahulu. Dan benar saja modul lora yang sukses saya koneksikan ke arduino, ternyata tidak mengirimkan data ke console web antares.
Bahkan saya harus berkeliling kota, nostalgia pekerjaan 10 tahun yang lalu yaitu mencari sinyal sesuai peta coverage yang diberikan Telkom. Namun tetap saja hasilnya zonk ! Saya menggunakan script example yang ada pada librarynya Lora-antares, namun kenapa gagal ya ?
Pulang dengan tangan hampa dan wajah terbakar panasnya matahari Surabaya, saya teringat bagaimana proses yg saya lakukan ketika dulu, saya pernah menemukan bug pada library antares yang pernah saya bahas disini. Saya menggunakan mode koneksi ke gateway secara ABP (Activation by Personalization) sehingga id dan key saya tetap gak berubah, dibanding saya harus menggunakan Autentifikasi lewat OTAA. Jadi kira-kira analisa saya, kenapa tidak bisa terhubung ke gateway antares, seperti ini:
- NwkSkey, ApkSkey dan DevAdress kemungkinan salah format
- Frekuensi yang digunakan tidak tepat
- Library nya kacau ayuk diubah aja
Berdasarkan tutorial dari librarynya antares, key dan id dari device lora di console antares, mirip dengan yang diajarkan sebelumnya untuk library lainnya, yaitu seperti script ini :
// Put Antares Key and DevAddress here
lora.setAccessKey("your Access Key");
lora.setDeviceId("your Device Id");
Lalu menurut contoh pada modul tutorial, setAccessKey didapatkan dengan melihat pair key dari id userkey di console antares yang berformat : 1111111111111111:2222222222222222 . Jadi 16karakter:16karakter. Namun saat di jalankan maka dilihat pada debug terminal, format dari NwkSkey dan ApkSkey sesuai dengan literatur yang saya baca yaitu 128bit atau 32 karakter. Sedangkan format device ID nya benar.
Kecurigaan muncul dari saat proses ADD DEVICE lalu SETLORA. Ternyata sudah disediakan NwkSkey dan ApkSkey namun tidak ditampilkan pada console. Dilalahnya pair userkey bukanlah seperti key 128 bit yang ditampilkan pada layar.
#include <SPI.h>
#include <LoRa.h>
#include <LoRaWanPacket.h>
// sesuaikan pin yang dipakai
const int csPin = 10;
const int resetPin = 9;
const int irqPin = 2; // DIO0
//sesuaikan key dan address device lora antares
const char *devAddr = "xxxxxxxx";
const char *nwkSKey = "11111111111111110000000000000000";
const char *appSKey = "00000000000000002222222222222222";
unsigned int counter = 1;
struct LoRa_config
{
long Frequency;
int SpreadingFactor;
long SignalBandwidth;
int CodingRate4;
bool enableCrc;
bool invertIQ;
int SyncWord;
int PreambleLength;
};
//frekuensi SF BW dan sebagainya
static LoRa_config txLoRa = {922000000, 10, 125000, 5, true, false, 0x34, 8};
void LoRa_setConfig(struct LoRa_config config)
{
LoRa.setFrequency(config.Frequency);
LoRa.setSpreadingFactor(config.SpreadingFactor);
LoRa.setSignalBandwidth(config.SignalBandwidth);
LoRa.setCodingRate4(config.CodingRate4);
if (config.enableCrc)
LoRa.enableCrc();
else
LoRa.disableCrc();
if (config.invertIQ)
LoRa.enableInvertIQ();
else
LoRa.disableInvertIQ();
LoRa.setSyncWord(config.SyncWord);
LoRa.setPreambleLength(config.PreambleLength);
}
void LoRa_TxMode()
{
LoRa_setConfig(txLoRa);
LoRa.idle();
}
void setup()
{
Serial.begin(115200);
while (!Serial);
LoRaWanPacket.personalize(devAddr, nwkSKey, appSKey);
LoRa.setPins(csPin, resetPin, irqPin);
if (!LoRa.begin(txLoRa.Frequency)) {
Serial.println("LoRa init failed. Check your connections.");
while (true);
}
Serial.println("LoRa init succeeded.");
Serial.println();
LoRa_sendMessage();
}
void loop() {
if (runEvery(10000)) {
LoRa_sendMessage();
counter++;
Serial.println("Send Message!");
}
}
void LoRa_sendMessage()
{
LoRa_TxMode();
LoRaWanPacket.clear();
LoRaWanPacket.print("Hello World");
LoRaWanPacket.print(" data ke-");
LoRaWanPacket.print(String(counter));
if (LoRaWanPacket.encode())
{
LoRa.beginPacket();
LoRa.write(LoRaWanPacket.buffer(), LoRaWanPacket.length());
LoRa.endPacket();
}
}
boolean runEvery(unsigned long interval)
{
static unsigned long previousMillis = 0;
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval)
{
previousMillis = currentMillis;
return true;
}
return false;
}