Minggu, 14 Mei 2017

Absensi Berbasis RFID-RC522 dan NodeMCU

Tulisan ini adalah menbahas pemanfaatan RFID-RC522 dan NodeMCU untuk proses scan absensi berbasis RFID yang mana data akan dicatat di cloud dengan server berbasis PHP.

Gambar 1. Sensor RFID-RC522 dan RFID Card

Pin pada RFID-RC522


Pin pada NodeMCU


Sehingga interfacing antara sensor RFID-RCC522 dan NodeMCU dapat dilakukan sebagai berikut:

pin SDA ke D2
pin SCK ke D5
pin MOSI ke D7
pin MISO ke D6
pin IRQ diabaikan
pin GND ke GND
pin RST ke D4
pin VCC ke 3V3

Script Sketch:
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include "MFRC522.h"

const char* ssid     = "ssid wifi anda";
const char* password = "password wifi anda";
String url = "http://172.21.12.105/absensi.php?uid=";

#define RST_PIN D4
#define SS_PIN  D2
MFRC522 mfrc522(SS_PIN, RST_PIN);   // Create MFRC522 instance

boolean reconnect() {
  digitalWrite(D0, HIGH);
  WiFi.begin(ssid, password);

  int retry = 51;
  while (WiFi.status() != WL_CONNECTED) {
    if (retry > 50) {
      Serial.println("");
      Serial.printf("Trying connect to %s", ssid);
      retry = 0;
    }
    delay(500);
    Serial.print(".");
    retry++;
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  digitalWrite(D0, LOW);
}

String logToServer(unsigned long cardUID) {

  Serial.printf("Send Request to %s%u\n", url.c_str(), cardUID);
  HTTPClient http;

  http.begin(url + cardUID); //HTTP
  int httpCode = http.GET();
  if (httpCode > 0) {
    Serial.printf("[HTTP] GET... code: %d\n", httpCode);

    if (httpCode == HTTP_CODE_OK) {
      String payload = http.getString();

      Serial.println(payload);

      if (payload == "Ok!") {

        for (int i = 0; i < 3; i++) {
          digitalWrite(D0, HIGH);
          digitalWrite(D1, HIGH);
          delay(100);
          digitalWrite(D0, LOW);
          digitalWrite(D1, LOW);
          delay(100);
        }

      }
    }
  } else {
    Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
  }

  http.end();

}

void setup() {
  pinMode(D0, OUTPUT);
  pinMode(D1, OUTPUT);
  Serial.begin(9600);
  Serial.println("");
  delay(1000);

  reconnect();

  SPI.begin();        // Init SPI bus
  mfrc522.PCD_Init(); // Init MFRC522 card

  //If you set Antenna Gain to Max it will increase reading distance
  mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_max);
}

unsigned long getCardUID() {
  if ( !mfrc522.PICC_ReadCardSerial()) { //Since a PICC placed get Serial and continue
    return -1;
  }
  unsigned long hex_num;
  hex_num =  mfrc522.uid.uidByte[0] << 24;
  hex_num += mfrc522.uid.uidByte[1] << 16;
  hex_num += mfrc522.uid.uidByte[2] <<  8;
  hex_num += mfrc522.uid.uidByte[3];
  mfrc522.PICC_HaltA(); // Stop reading
  return hex_num;
}

int wait = 51;

void loop() {
  if (WiFi.status() != WL_CONNECTED)
    reconnect();

  if (wait > 50) {
    Serial.println("");
    Serial.print("Wait for new Card");
    wait = 0;
  }

  Serial.print(".");

  wait++;

  if (wait % 2 == 0)
    digitalWrite(D0, HIGH);
  else
    digitalWrite(D0, LOW);

  // Look for new cards
  if ( ! mfrc522.PICC_IsNewCardPresent()) {
    delay(100);
    return;
  }

  unsigned long cardUID = getCardUID();

  for (int i = 0; i < 3; i++) {
    digitalWrite(D0, HIGH);
    delay(100);
    digitalWrite(D0, LOW);
    delay(100);
  }

  if (cardUID == -1) {
    Serial.println("Failed to get UID");
    return;
  }

  Serial.printf("\nCard UID is %u\n", cardUID);

  for (int i = 0; i < 3; i++) {
    digitalWrite(D1, HIGH);
    delay(250);
    digitalWrite(D1, LOW);
    delay(250);
  }

  logToServer(cardUID);

  wait = 51;
}

Script PHP:

<?php
//Save string to log, use FILE_APPEND to append.
$info = date('Y-m-d H:i:s') . ';' . $_SERVER['REMOTE_ADDR'] . ';' . $_GET['uid'] . ';';
file_put_contents("./log/log_" . date('Ymd') . ".txt", $info . md5($info) . PHP_EOL, FILE_APPEND | LOCK_EX);

echo "Ok!";
?>

Rabu, 10 Mei 2017

Interfacing RFID-RC522 Sensor dengan Wemos D1 mini pro

FRID-RC522 Sensor adalah contacless reader/writer yang mendukung semua varian dari MIFARE Mini, baik protokol identifikasi MIFARE 1K maupun MIFARE 4K, MIFRARE Ultralight, MIFARE DESFire EV1 dan MIFARE Plus RF. Berikut ini adalah gambar sensor yang dimaksud.


Adapun Pin Dengan Pin sebagai berikut:


Adapun Pin pada Wemos D1 mini pro adalah sebagai berikut:


Sehingga Interfacing antara RFID-RC522 dengan Wemos D1 mini pro adalah:

pin SDA ke D2
pin SCK ke D5
pin MOSI ke D7
pin MISO ke D6
pin IRQ diabaikan
pin GND ke GND
pin RST ke D4
pin VCC ke 3V3

Setelah melakukan interfacing, maka kini saatnya untuk mempersiapkan lingkungan pengembangan dengan mendownload Arduino RFID Library for MFRC522 yang dapat didownload pada link, setelah download, maka pada sketch pilih menu :

Browse dan Add file rfid-master.zip

Copy dan Paste koding berikut ini yang saya peroleh dari internet, dan telah saya modifikasi (saya tandai warna merah)

#include "MFRC522.h"
#define RST_PIN D4  // RST-PIN ke D4
#define SS_PIN  D2  // SDA-PIN ke D2


MFRC522 mfrc522(SS_PIN, RST_PIN);   // Create MFRC522 instance
MFRC522::MIFARE_Key key;

void setup() {
  Serial.begin(9600); // Initialize serial communications
  while (!Serial);    // Do nothing until serial port is opened
  SPI.begin();        // Init SPI bus
  mfrc522.PCD_Init(); // Init MFRC522 card

  // Prepare the key (used both as key A and as key B)
  // using FFFFFFFFFFFFh which is the default at chip delivery from the factory
  for (byte i = 0; i < 6; i++) {
    key.keyByte[i] = 0xFF;
  }

  Serial.println(F("Scan a MIFARE Classic PICC to demonstrate read and write."));
  Serial.print(F("Using key (for A and B):"));
 
  dump_byte_array(key.keyByte, MFRC522::MF_KEY_SIZE);
 
  Serial.println();
  Serial.println(F("BEWARE: Data will be written to the PICC, in sector #1"));
}

/**
   Main loop.
*/
void loop() {
  // Look for new cards
  if ( ! mfrc522.PICC_IsNewCardPresent())
    return;

  // Select one of the cards
  if ( ! mfrc522.PICC_ReadCardSerial())
    return;

  // Show some details of the PICC (that is: the tag/card)
  Serial.print(F("Card UID:"));
  dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size);
  Serial.println();
  Serial.print(F("PICC type: "));
  MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
  Serial.println(mfrc522.PICC_GetTypeName(piccType));

  // Check for compatibility
  if (    piccType != MFRC522::PICC_TYPE_MIFARE_MINI
          &&  piccType != MFRC522::PICC_TYPE_MIFARE_1K
          &&  piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
    Serial.println(F("This sample only works with MIFARE Classic cards."));
    return;
  }

  // In this sample we use the second sector,
  // that is: sector #1, covering block #4 up to and including block #7
  byte sector         = 1;
  byte blockAddr      = 4;
  byte dataBlock[]    = {
    0x01, 0x02, 0x03, 0x04, //  1,  2,   3,  4,
    0x05, 0x06, 0x07, 0x08, //  5,  6,   7,  8,
    0x08, 0x09, 0xff, 0x0b, //  9, 10, 255, 12,
    0x0c, 0x0d, 0x0e, 0x0f  // 13, 14,  15, 16
  };
  byte trailerBlock   = 7;
  MFRC522::StatusCode status;
  byte buffer[18];
  byte size = sizeof(buffer);

  // Authenticate using key A
  Serial.println(F("Authenticating using key A..."));
  status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("PCD_Authenticate() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  // Show the whole sector as it currently is
  Serial.println(F("Current data in sector:"));
  mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector);
  Serial.println();

  // Read data from the block
  Serial.print(F("Reading data from block ")); Serial.print(blockAddr);
  Serial.println(F(" ..."));
  status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockAddr, buffer, &size);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("MIFARE_Read() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
  }
  Serial.print(F("Data in block ")); Serial.print(blockAddr); Serial.println(F(":"));
  dump_byte_array(buffer, 16); Serial.println();
  Serial.println();

  // Authenticate using key B
  Serial.println(F("Authenticating again using key B..."));
  status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, trailerBlock, &key, &(mfrc522.uid));
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("PCD_Authenticate() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  // Write data to the block
  Serial.print(F("Writing data into block ")); Serial.print(blockAddr);
  Serial.println(F(" ..."));
  dump_byte_array(dataBlock, 16); Serial.println();
  status = (MFRC522::StatusCode) mfrc522.MIFARE_Write(blockAddr, dataBlock, 16);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("MIFARE_Write() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
  }
  Serial.println();

  // Read data from the block (again, should now be what we have written)
  Serial.print(F("Reading data from block ")); Serial.print(blockAddr);
  Serial.println(F(" ..."));
  status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockAddr, buffer, &size);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("MIFARE_Read() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
  }
  Serial.print(F("Data in block ")); Serial.print(blockAddr); Serial.println(F(":"));
  dump_byte_array(buffer, 16); Serial.println();

  // Check that data in block is what we have written
  // by counting the number of bytes that are equal
  Serial.println(F("Checking result..."));
  byte count = 0;
  for (byte i = 0; i < 16; i++) {
    // Compare buffer (= what we've read) with dataBlock (= what we've written)
    if (buffer[i] == dataBlock[i])
      count++;
  }
  Serial.print(F("Number of bytes that match = ")); Serial.println(count);
  if (count == 16) {
    Serial.println(F("Success :-)"));
  } else {
    Serial.println(F("Failure, no match :-("));
    Serial.println(F("  perhaps the write didn't work properly..."));
  }
  Serial.println();

  // Dump the sector data
  Serial.println(F("Current data in sector:"));

  for (int sectorcount=0; sectorcount < 16; sectorcount++) {
    mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sectorcount);
    Serial.println();
  }


  // Halt PICC
  mfrc522.PICC_HaltA();
  // Stop encryption on PCD
  mfrc522.PCD_StopCrypto1();
}

/**
   Helper routine to dump a byte array as hex values to Serial.
*/
void dump_byte_array(byte *buffer, byte bufferSize) {
  for (byte i = 0; i < bufferSize; i++) {
    Serial.print(buffer[i] < 0x10 ? " 0" : " ");
    Serial.print(buffer[i], HEX);
  }
}

Hasil pengujian:

Aktifkan serial monitor:

 

Scan a MIFARE Classic PICC to demonstrate read and write.
Using key (for A and B): FF FF FF FF FF FF
BEWARE: Data will be written to the PICC, in sector #1
Card UID: 46 74 1E 2B
PICC type: MIFARE 1KB
Authenticating using key A...
Current data in sector:
   1      7   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ]
          6   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
          5   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
          4   01 02 03 04  05 06 07 08  08 09 FF 0B  0C 0D 0E 0F  [ 0 0 0 ]

Reading data from block 4 ...
Data in block 4:
 01 02 03 04 05 06 07 08 08 09 FF 0B 0C 0D 0E 0F

Authenticating again using key B...
Writing data into block 4 ...
 01 02 03 04 05 06 07 08 08 09 FF 0B 0C 0D 0E 0F

Reading data from block 4 ...
Data in block 4:
 01 02 03 04 05 06 07 08 08 09 FF 0B 0C 0D 0E 0F
Checking result...
Number of bytes that match = 16
Success :-)

Current data in sector:
   0      3   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ]
          2   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
          1   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
          0   46 74 1E 2B  07 08 04 00  62 63 64 65  66 67 68 69  [ 0 0 0 ]

   1      7   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ]
          6   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
          5   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
          4   01 02 03 04  05 06 07 08  08 09 FF 0B  0C 0D 0E 0F  [ 0 0 0 ]

   2     11   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ]
         10   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
          9   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
          8   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]

   3     15   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ]
         14   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         13   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         12   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]

   4     19   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ]
         18   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         17   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         16   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]

   5     23   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ]
         22   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         21   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         20   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]

   6     27   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ]
         26   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         25   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         24   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]

   7     31   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ]
         30   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         29   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         28   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]

   8     35   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ]
         34   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         33   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         32   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]

   9     39   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ]
         38   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         37   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         36   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]

  10     43   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ]
         42   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         41   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         40   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]

  11     47   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ]
         46   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         45   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         44   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]

  12     51   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ]
         50   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         49   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         48   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]

  13     55   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ]
         54   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         53   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         52   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]

  14     59   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ]
         58   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         57   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         56   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]

  15     63   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ]
         62   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         61   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
         60   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]

Trouble Shooting, jika anda mendapatkan pesan kesalahan seperti MIFARE_Read() failed: Timeout in communication atau PCD_Authenticate() failed: Timeout in communication.

Card UID: 46 74 1E 2B
PICC type: MIFARE 1KB
Authenticating using key A...
Current data in sector:
   1      7   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ]
          6   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
          5   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]
          4   01 02 03 04  05 06 07 08  08 09 FF 0B  0C 0D 0E 0F  [ 0 0 0 ]

Reading data from block 4 ...
MIFARE_Read() failed: Timeout in communication.
Data in block 4:
 30 04 26 EE 05 06 07 08 08 09 FF 0B 0C 0D 0E 0F

Authenticating again using key B...
PCD_Authenticate() failed: Timeout in communication.

Jangan kuatir, error tersebut diatas terjadi karena anda mengerakan kartu, atau tag RFID selama dibaca oleh sensor.

Selamat Memcoba.

Sabtu, 24 Desember 2016

Om Telolet Om: WeMos D1 OLED Shield (ESP-8266EX, NodeMCU, Lua)

Pada tulisan ini akan dibuat script untuk menampilkan pesan "Selamat Hari Natal" pada WeMos D1 OLED Shield.

Gambar 1. WeMos D1 mini OLED Shield

Untuk dapat menggunakan OLED Shield, anda perlu melakukan kustomisasi firmware NodeMCU dengan memasukan module i2c dan u8g, dan memilih ukuran OLED yang digunakan.

Gambar 8. Menentukan ukuran layar OLED

Sehingga ketika boot akan tampil module yang ditandai warna merah.
NodeMCU custom build by frightanic.com
    branch: master
    commit: 81ec3665cb5fe68eb8596612485cc206b65659c9
    SSL: true
    modules: bit,cjson,crypto,dht,file,gpio,http,i2c,net,node,rtctime,sntp,tmr,u8g,uart,websocket,wifi
 build     built on: 2016-12-23 16:47
 powered by Lua 5.1.4 on SDK 1.5.4.1(39cb9a32)
Adapun script yang digunakan untuk menampikan pesan adalah sebagai berikut:

sda = 2 -- SDA Pin
scl = 1 -- SCL Pin

function init_OLED(sda,scl) --Set up the u8glib lib
     sla = 0x3C
     i2c.setup(0, sda, scl, i2c.SLOW)
     disp = u8g.ssd1306_64x48_i2c(sla)
     disp:setFont(u8g.font_6x10)
     disp:setFontRefHeightExtendedText()
     disp:setDefaultForegroundColor()
     --disp:setRot90()           -- Rotate Display if needed
     --disp:setRot180()           -- Rotate Display if needed
     --disp:setRot270()           -- Rotate Display if needed
end

function print_OLED()
   disp:firstPage()
   --disp:setScale2x2()
   repeat
     --disp:drawFrame(0,0,64,47)
     disp:drawStr(0, 10, str1)
     disp:drawStr(0, 30, str2)
   until disp:nextPage() == false
   --disp:undoScale()
end

-- Main Program
str1="  Selamat   "
str2=" Hari Natal "
init_OLED(sda,scl)
print_OLED()

Jumat, 23 Desember 2016

Om Telolet Om: WeMos D1 mini pro as APSTATION (ESP-8266EX, NodeMCU, Lua)

Pada tulisan ini akan memberi contoh script untuk mengaktifkan WeMos D1 mini pro sebagai APSTATION yang terdiri dari tiga script utama yaitu init.lua yang bertujuan untuk menghindari terjebak reboot ulang tak terhingga akibat adanya kesalahan script pada init.lua, konfigurasi untuk APSTATION adalah disimpan pada apconfig.lua, dan konfigurasi untuk sebagai STATION adalah disimpan pada credentilas.lua. Script utama anda adalah disimpan pada file app.lua, yang secara otomatis akan diaktifkan dalam waktu tiga detik. Jika ada kesalahan pada script app.lua, maka anda dapat menjalankan perintah file.remove("app.lua") dalam waktu tiga detik sehingga terhindar dari jebakan reboot ulang tak terhingga.

Gambar 1. WeMos D1 mini pro

apconfig.lua
cfg={}
cfg.ssid="myssid"
cfg.pwd="password"
cfg.auth=wifi.WPA_WPA2_PSK

dhcp_config ={}
dhcp_config.start = "192.168.4.100"

credentials.lua
-- Credentials
SSID = "rapsberrypi"
PASSWORD = "password"

init.lua
-- aplikasi ini berfungsi menghindarkan module anda terjebak
-- pada kondisi restart tak terhingga jika terjadi bugs pada
-- init.lua.

-- aplikasi ini dapat mengaktifkan board anda sebagai access
-- point, jika anda menginginkan hal ini, maka anda perlu
-- menyediakan file apconfig.lua.

-- aplikasi dapat berjalan pada dua modus, yaitu standalone
-- atau terkoneksi ke wifi.

-- agar dapat terkoneksi ke wifi, maka username dan password
-- didefinisikan pada file credentials.lua

-- aplikasi akan menunggu selama 3 detik sebelum file app.lua
-- dieksekusi, jika terjadi bugs pada app.lua, maka anda
-- dapat menjalankan file.remove("app.lua") sehingga tidak
-- terjebak pada kondisi restart tak terhingga.

function startup()
    print("Running")
    -- aplikasi autoexec anda  sekarang adalah 'app.lua'
    if file.open("app.lua") == nil then
        print("app.lua tidak ditemukan, silakan buat app.lua sebagai auto executable.")
    else 
        file.close("app.lua")
        dofile("app.lua")
    end
end

if file.open("apconfig.lua") ~= nil then
    print("activate as access point")
    dofile("apconfig.lua")
    -- set mode as stationAP  
    wifi.setmode(wifi.STATIONAP)
    wifi.setphymode(wifi.PHYMODE_G)
    wifi.ap.config(cfg)
    print("AP IP Address:" .. wifi.ap.getip())   
    pool_ipstart, pool_ipend = wifi.ap.dhcp.config(dhcp_config)
    if wifi.ap.dhcp.start() then
        print("DHCP server started, pool addr from " .. pool_ipstart .. " to " .. pool_ipend .. "!")
    else
        print("DHCP server failed!")
    end
else
    -- default mode as station
    wifi.setmode(wifi.STATION)
    wifi.setphymode(wifi.PHYMODE_N)
end

-- periksa keberadaan file credentials.lua yang mendefinisikan
-- 'SSID' and 'PASSWORD' wifi
if file.open("credentials.lua") == nil then
    -- bagian module standalone
    print("Boot sebagai module standalone")
    print("You have 3 seconds to abort")
    print("Waiting...")
    -- jalankan fungsi startup setelah 3 detik      
    tmr.alarm(0, 3000, 0, startup)
else   
    -- bagian module koneksi wifi
    file.close("credentials.lua")
    -- muat variable SSID dan PASSWORD
    dofile("credentials.lua")
    print("Koneksi ke " .. SSID)
    station_cfg={}
    station_cfg.ssid=SSID
    station_cfg.pwd=PASSWORD
    wifi.sta.config(station_cfg, false)
   
    --wifi.sta.config(SSID, PASSWORD)
    -- wifi.sta.connect() not necessary because config() uses auto-connect=true by default

    -- mencoba koneksi setiap detik sampai tmr.stop(1)
    trycount = 1
    tmr.alarm(1, 1000, 1, function()
        if wifi.sta.getip() == nil then
            print("trying " .. trycount .. " second(s)")
            trycount = trycount + 1
        else
            -- berhasil koneksi dan mendapatkan IP Address
            tmr.stop(1)
            print("WiFi connected")
            print("Client IP Address:" .. wifi.sta.getip())
            print("You have 3 seconds to abort")
            print("Waiting...")
            -- issue file.remove("app.lua") here
            -- jalankan fungsi startup setelah 3 detik      
            tmr.alarm(0, 3000, 0, startup)
        end       
    end)
end

Om Telolet Om: WeMos DH11 Shield (ESP8266EX, NodeMCU, Lua)

Pada tulisan ini akan membahas pembuatan Lua script untuk mengukur temperatur dan humidity dengan menggunakan perangkat WeMos DH11, pemakai perangkat IoT dapat membantu para peneliti untuk merekam kondisi dilapangan dari waktu ke waktu sehingga cukup berkonsentrasi pada variabel lainnya, sedangkan variabel terkait dengan temperatur dan kelembaban dapat secara otomatis direkam oleh perangkat IoT.

Gambar 1. WeMos DHT11 Shield

Interface antara DH11 shield dengan WeMos board adalah melalui pin D1, keuntungan dari pemakaian shield adalah anda tidak membutuhkan bread-board maupun menggunakan jumper untuk menghubungkan antara WeMos board dengan sensor DH11, tetapi cukup shield DH11 ditumpukan diatas WeMos board.

pinDHT11 = 4 -- pin D4 pada board WeMos D1 mini

function readFromDHT11()
    status, temp, humi, temp_dec, humi_dec = dht.read11(pinDHT11)

    if status == dht.OK then
        wib = rtctime.epoch2cal(rtctime.get()+7*60*60) -- tambah 7 WEST INDONESIA TIME
        timeStr = string.format("%04d/%02d/%02d %02d:%02d:%02d", wib["year"], wib["mon"], wib["day"], wib["hour"], wib["min"], wib["sec"])
        print(timeStr ..";" .. temp .. ";" .. humi)
      
    elseif status == dht.ERROR_CHECKSUM then
        print( "DHT Checksum error." )
    elseif status == dht.ERROR_TIMEOUT then
        print( "DHT timed out." )
    end
end

sntp.sync("1.id.pool.ntp.org",
 function(sec,usec,server)
   print('setting time to:', sec, usec, "from: " .. server)
   rtctime.set(sec, usec)
 end,

 function()
   print('failed!')
 end
)

tmr.alarm(0,1000,1,readFromDHT11) -- setiap detik baca dari sensir DHT11

Pada script berikut ini adalah melakukan log ke file harian setiap 5 detik untuk keperluaan penelitian.

pinDHT11 = 4 -- pin D4 pada board WeMos D1 mini

function readFromDHT11()
    status, temp, humi, temp_dec, humi_dec = dht.read11(pinDHT11)

    if status == dht.OK then
        wib = rtctime.epoch2cal(rtctime.get()+7*60*60) -- tambah 7 WEST INDONESIA TIME
        timeStr = string.format("%04d/%02d/%02d %02d:%02d:%02d", wib["year"], wib["mon"], wib["day"], wib["hour"], wib["min"], wib["sec"])
        --print(timeStr ..";" .. temp .. ";" .. humi)
        payload = timeStr ..";" .. temp .. ";" .. humi
        return payload
      
    elseif status == dht.ERROR_CHECKSUM then
        print( "DHT Checksum error." )
    elseif status == dht.ERROR_TIMEOUT then
        print( "DHT timed out." )
    end
end

function logToFile()
    wib = rtctime.epoch2cal(rtctime.get()+7*60*60) -- tambah 7 WEST INDONESIA TIME
    fname = string.format("%04d%02d%02d", wib["year"], wib["mon"], wib["day"])
    -- open file in 'a+' mode   
    if file.open(fname, "a+") then
        -- write 'foo bar' to the end of the file
        file.writeline(readFromDHT11())
        print("log to " .. fname)
        file.close()
    end
end

sntp.sync("1.id.pool.ntp.org",
 function(sec,usec,server)
   print('setting time to:', sec, usec, "from: " .. server)
   rtctime.set(sec, usec)
 end,

 function()
   print('failed!')
 end
)

tmr.alarm(0,5000,1,logToFile) -- setiap detik baca dari sensir DHT11
 

Kamis, 22 Desember 2016

Om Telolet Om: Switch on/off WeMos Relay Shield (ESP8266EX, NodeMCU, Lua)

What is Om Telolet Om mean? Sir honk your horn sir.

Ketika tulisan ini dibuat, fenomena Om Telolet Om lagi menjadi fenomena trend di Indonesia, dan juga menjadi trending topic di Twitter. Hal ini menjadi penasaran bagi banyak orang apa sih artinya Om Telolet Om. Berdasarkan pembacaan di Internet dapat disimpulkan bahwa "Om Telolet Om" artinya meminta kepada pengemudi Bus angkutan untuk membunyikan klakson yang memiliki suara unik dalam melodi yang dapat dimainkan oleh supir. Awalnya Om Telolet Om menjadi hiburan bagi anak-anak dimana supir memainkan lagi anak-akan seperti unyil, happy birthday, dll.

 Gambar 1. WeMos Relay Shield

Pada tulisan ini penulis membahas tentang pengendalian switch pada WeMos Relay Shield dengan Lua. Pengendalian switch adalah mengatur GPIO pin 1 kepada kondisi HIGH (switch on), dan LOW (switch off).

relayPin = 1
interval = 2000 --pause for two seconds
mode = 0

gpio.mode(relayPin, gpio.OUTPUT);

function Switch()
  if mode==0 then 
    gpio.write(relayPin, gpio.HIGH)
  else
    gpio.write(relayPin, gpio.LOW)
  end
  mode = math.abs(mode)-1
end

tmr.alarm(0,interval,1,Switch)
Pada keadaan On, maka Led pada Shield akan hidup, dan sebaliknya adalah Off.

Senin, 19 Desember 2016

IOT Tutorial: Begining WeMos D1 Mini Pro (ESP-8266EX, NodeMCU, Lua)

Setelah menunggu hampir 21 hari, akhirnya IoT board WeMos D1 mini yang saya pesan dari Aliexpress sampai juga. Berdasarkan informasi dari wemos.cc, perbedaan utama antara WeMos D1 mini dengan WeMos D1 mini pro adalah pada ukuran flash dari 4MB menjadi 16MB. Perbedaan berikutnya adalah pada USB driver yang digunakan, jika yang biasa adalah menggunakan driver CH340G, maka yang pro adalah menggunakan CP2104.

 Gambar 0. WeMos D1 mini pro

Langkah-langkah flash firmware nodemcu:
1. Install driver CP2104.
2. Koneksikan board WeMos dengan komputer anda.
3. Catat nomor port hasil koneksi.
4. Download nodemcu-Flasher (baca)
5. Kustomisasi firmware nodemcu

Untuk melakukan kustomisasi, anda dapat menggunjungi https://nodemcu-build.com/
1. Isikan alamat email anda untuk mendapatkan konfirmasi proses builds dan hasil builds yang dapat didownload
2. Pilih module-module yang ingin anda ikut sertakan pada firmware, pilihlah module yang yang butuhkan saja, karena semakin banyak module yang dimasukan, maka binary firmware akan semakin besar. Beberapa module default yang dimasukan adalah file, GPIO, net, node, timer, UART, dan wifi, anda dapat menambahkan module seperti cjson, crypto, DHT, HTTP, I2C, RTC time, SNTP, dan websocket, masukan juga SSL support TLS. (untuk lingkungan produksi, anda dapat menkustomisasi firmware anda dengan modul-modul yang anda gunakan saja dalam implementasi, sehingga ukuran firmware menjadi compact). Kemudian klik pada Start your build.
Catatan: This project uses two main branches, master and dev. dev is actively worked on and it's also where PRs should be created against. master thus can be considered "stable" even though there are no automated regression tests.

Anda akan menerima email yang memberitahukan bahwa nodemcu custom build started, silakan menunggu untuk mendapatkan hasil build (berkisar 2 menit), anda akan menerima email nodemcu custom build finished disertai dengan link untuk mendownload hasil build.

http://nodemcu-build.com/builds/nodemcu-master-15-modules-2016-12-20-01-43-07-float.bin
http://nodemcu-build.com/builds/nodemcu-master-15-modules-2016-12-20-01-43-07-integer.bin

Catatan: There are two versions for each firmware version: the integer version which supports only integer operations and the float version which contains support for floating point calculations. From a performance point of view, the integer version should be better. It’s also smaller and most of the time, you will not need to work with floating point numbers.
Dalam hal ini ukuran binary saya yang float adalah 495412 bytes

6. Lakukan flash-firmware anda dengan menggunakan nodemcu-Flasher

6a. Aktifkan software nodemcu-Flasher

Gambar 1. NodeMCU Flasher
6b. Klik pada tab config, dan pilih firmware anda (hasil download langkah sebelumnya)
Gambar 2. Select Custom Firmware
Pilihlah file custom firmware yang didownload sebelumnya.

6c. Klik pada tab advanced, dan ubah parameter flash size menjadi 16M sesuai dengan ukuran flash D1 mini pro.

Gambar 3. Ubah Flash size 16MB (sesuai ukuran flash-size D1 mini pro)
6d. Kembali kehalaman operation, dan klik pada flash untuk memulai, jika berhasil akan mendapatkan tampilan sebagai berikut ini:

Gambar 4. Hasil Flash

7.Download software Esplor untuk sebagai lingkungan pengembangan nodemcu pada alamat https://esp8266.ru/esplorer/

8. Tutup Sofware nodemcu-flasher, dan lakukan koneksi dengan software esplor

8a. Dalam hal ini saya menggunakan port 8 dan kecepatan 115200 baud dengan hasil:
PORT OPEN 115200
Communication with MCU..
8b. Tekan tombol reset pada board
NodeMCU custom build by frightanic.com
    branch: master
    commit: 81ec3665cb5fe68eb8596612485cc206b65659c9
    SSL: true
    modules: cjson,crypto,dht,file,gpio,http,i2c,net,node,rtctime,sntp,tmr,uart,websocket,wifi
 build     built on: 2016-12-20 03:33
 powered by Lua 5.1.4 on SDK 1.5.4.1(39cb9a32)
lua: cannot open init.lua
Troubleshooting:
1. Blue led keep fast flashing and board trapped in forever loop reset condition

Connect to your board on 74880 baud , shown something like this
load 0x40100000, len 25952, room 16
tail 0
chksum 0xd7
load 0x3ffe8000, len 2260, room 8
tail 12
chksum 0xd9
ho 0 tail 12 room 4
load 0x3ffe88d4, len 8, room 12
tail 8
chksum 0xc5
csum 0xc5
rf_cal[0] !=0x05,is 0xFF

 ets Jan  8 2013,rst cause:2, boot mode:(3,7)
Solution 1: Must make sure that when flashing has set flash-size to 16MB

Gambar 5. Make sure to use 16MB

Solution 2: Check your firmware size firmware, noted that size cannot over 491 KB (the space before the system data)