Produk SONOFF Untuk Pengukuran Energi

Produk SONOFF yang dapat dipakai untuk Untuk Pengukuran Energi adalah sebagai berikut

Produk-produk tersebut tidak memiliki fitur DIY (Do It Yourself) seperti MINIR2. Jadi jika ingin dipakai sebagai perangkat IoT (Internet of Things) sendiri, kita mesti mengganti firmware di dalamnya (flashing)

Berikut ini daftar teknik flashing untuk produk tersebut

SONOFF SPM
SONOFF SPM

 

SONOFF POWR3
SONOFF POWR3
SONOFF DUALR3
SONOFF DUALR3

Berikut ini foto SONOFF MINIR2, POWR2 dan POWR3

SONOFF MINI-R2 POWR2 POWR3

Daftar pencarian produk di toko online:

  • SPM-Main https://www.tokopedia.com/search?st=product&q=SPM-Main%20sonoff
  • POWR3 https://www.tokopedia.com/search?st=product&q=sonoff%20powr3
  • DUALR3: https://www.tokopedia.com/search?st=product&q=dualr3%20sonoff
  • POWR2: https://www.tokopedia.com/search?st=product&q=sonoff%20powr2

Referensi

 

Buffer pada Komunikasi Serial Arduino Nano ATmega328

Arduino Nano dapat melakukan komunikasi serial baik transmit (mengirim) maupun receive (menerima). Pada library Arduino, sudah disiapkan buffer FIFO (First In First Out) pada data yang dikirimkan maupun data yang diterima. Pada tulisan ini dilakukan pengecekan berapa ukuran buffer tersebut. Pengujian ini dilakukan pada Arduino Nano dengan prosesor ATmega328. Untuk prosesor lain, ada kemungkinan ukuran buffernya berbeda.

Library Arduino untuk komunikasi serial memiliki buffer FIFO untuk outgoing maupun incoming.

Hardware yang diperlukan:

  • Komputer Desktop PC / Laptop
  • Arduino Nano Atmega328
  • Kabel USB

Buffer Pengiriman

Ukuran buffer pengiriman yang tersisa dapat dicek dengan fungsi Serial.availableForWrite() . Pada kondisi awal seharusnya buffer yang tersisa adalah maksimal, karena belum ada karakter yang dikirim.

Contoh program:

void setup() {
  Serial.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);
}

// the loop routine runs over and over again forever:
void loop() {
  int incomingByte ;
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);
  incomingByte = Serial.availableForWrite();
  Serial.print("jumlah available: ");
  Serial.println(incomingByte, DEC);
}

Output seperti sebagai berikut

14:42:26.343 -> jumlah available: 63

Artinya ukuran bufffer outgoing adalah 63 karakter

Buffer Penerimaan

Ukuran buffer data masuk (receive) dapat dicek dengan fungsi Serial.available

Contoh program

void setup() {
  Serial.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  int incomingByte ;
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);
  incomingByte = Serial.availableForWrite();
  Serial.print("jumlah available: ");
  Serial.println(incomingByte, DEC);
}

Setelah itu kirimkan beberapa karakter dari PC ke Arduino. Angka yang ditampilkan akan naik, namun akan berhenti di suatu batas tertentu. Angka inilah yang menunjukkan ukuran buffer FIFO incoming.

Dari hasil percobaan didapatkan rekaman komunikas serial sebagai berikut

14:37:37.062 -> jumlah available: 0
14:37:39.051 -> jumlah available: 0
14:37:41.043 -> jumlah available: 30
14:37:43.038 -> jumlah available: 43
14:37:45.064 -> jumlah available: 54
14:37:47.057 -> jumlah available: 63
14:37:49.050 -> jumlah available: 63
14:37:51.042 -> jumlah available: 63
14:37:53.067 -> jumlah available: 63
14:37:55.058 -> jumlah available: 63
14:37:57.050 -> jumlah available: 63

Artinya jumlah data yang menunggu untuk dibaca oleh software adalah maksimum 63 karakter.

Referensi

Membuat Filter Digital dari Fungsi Transfer Dengan Transformasi Bilinear

Pada tulisan ini akan diuraikan bagaimana membuat filter digital dalam bahasa C dari persamaan filter dalam transformasi Laplace. Contoh ini diadaptasi dari Example 8.4 di buku  “Lizhe Tan, Digital Signal Processing, Fundamentals and Applications” halaman 324.

Misal diketahui suatu filter dalam domain s (Laplace) dengan persamaan sebagai berikut:

\(H(s)=\frac{10}{s+10} \)

Untuk mengubah ke bentuk digital, kita perlu tentukan perioda sampling. Misal dipilih perioda sampling T=0.01 detik

Persamaan transformasi s ke z sebagai berikut

\( s=\frac{2(z -1) }{Tz + 1} \)

H(s) diubah ke H(z) dengan cara  substitusi s pada H(s). T=0.01 dimasukkan ke persamaan transformasi. Maka didapat persamaan berikut:

\( H(z)=\frac{10}{\frac{200(z-1)}{z+1}+10 } \)
\( H(z)=\frac{0.05}{\frac{z-1}{z+1}+0.05 } \)
\( H(z)=\frac{0.05(z+1)}{z-1+0.05(z+1) } \)
\( H(z)=\frac{0.05z+0.05}{1.05z – 0.95 } \)
\( H(z)=\frac{(0.05z+0.05)/1.05z}{(1.05z – 0.95)/1.05z } \)

Didapatkan H(z) dengan bentuk standar.

\( H(z)=\frac{0.0476+0.0476z^{-1}}{1 – 0.9048 z^{-1} } \)

Selanjutnya terapkan teknik di Bab 6 (Example 6.5) untuk mengubah persamaan dalam domain (z) ke domain waktu (n).

Akan didapat persamaan difference dalam n sebagai berikut:

y(n)=0.0476 x(n) + 0.0476 x(n-1) + 0.9048 y(n-1)

 

Simulasi

Tahap selanjutnya adalah simulasi persamaan difference tersebut dengan input fungsi step.

Tahap simulasi ini penting untuk mengecek apakah filter digital yang dihasilkan memiliki perilaku yang sama dengan filter analog di awal. Jika hasilnya berbeda, ada kemungkinan salah perhitungan atau salah koding.

Simulasi dapat dilakukan dengan bahasa pemrograman apa saja, misal C, C++, Matlab, Python, dan sebagainya.

Simulasi di bawah ini dibuat dengan bahasa Python. GUI yang dipakai adalah Jupyter Notebook

import matplotlib
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import AutoMinorLocator
from matplotlib import gridspec
import matplotlib.ticker as ticker

%matplotlib inline
t=-1 # start time at -1
xn=0
xn1=0
yn1=0
period=0.01

times=np.linspace(-1, 10, 111).reshape(111, 1)
xs=[]
ys=[]
ts=[]
for counter in range(0,200):
    if t<0:
        xn=0        
    else:
        xn=1    
    t=t+period
    xs.append(xn)                    
    y=0.04676 * xn + 0.0476 * xn1 + 0.9048 * yn1
    ys.append(y)
    ts.append(t)
    yn1=y
    xn1=xn
fig = plt.figure(figsize=(8,4))
gs = gridspec.GridSpec(1,1)
ax1 = fig.add_subplot(gs[0])
ax1.plot(ts,xs,"g-",label="input x")
ax1.plot(ts,ys,"r-",label="output y")
ax1.plot(1/10,.632,"bo",label="output y")
ax1.set_xlabel("waktu",family="serif",  fontsize=12)
ax1.set_ylabel("value",family="serif",  fontsize=12)
ax1.legend(loc='best')
fig.tight_layout()
plt.grid(True)
fig.savefig("blt-step.jpg", format="jpg",dpi=65)

Berikut ini output sistem (merah) terhadap input step (warna hijau).

time constant = 1/10

Titik biru adalah t = time constant, dengan value = 63.2%. Posisi titik biru ini pada grafik merah, sehingga dapat disimpulkan respon sistem ini cocok dengan yang diharapkan.

Selanjutnya adalah memberi sinyal sinusoidal dengan frekuensi = frekuensi cut-off ke filter tersebut . Menurut teori, amplitudo pada steady state adalah 0.707 x amplitudo maksimum.

Berikut ini kode untuk memberikan sinyal sinusoida.

t=-1 # start time at -1
xn=0
xn1=0
yn1=0
period=0.01

times=np.linspace(-1, 10, 111).reshape(111, 1)
xs=[]
ys=[]
ts=[]
w=10
for counter in range(0,200):    
    t=t+period
    xn=math.sin(w*t)
    xs.append(xn)                    
    y=0.04676 * xn + 0.0476 * xn1 + 0.9048 * yn1
    ys.append(y)
    ts.append(t)
    yn1=y
    xn1=xn

Berikut ini kode untuk menampilkan grafik sinyal

fig = plt.figure(figsize=(8,4))
gs = gridspec.GridSpec(1,1)
ax1 = fig.add_subplot(gs[0])
ax1.plot(ts,xs,"g-",label="input x")
ax1.plot(ts,ys,"r-",label="output y")
ax1.set_xlabel("waktu",family="serif",  fontsize=12)
ax1.set_ylabel("value",family="serif",  fontsize=12)
ax1.legend(loc='best')
fig.tight_layout()
plt.grid(True)
fig.savefig("blt-sinusoidal.jpg", format="jpg",dpi=65)

Grafik tersebut menunjukkan amplitudo output (merah) ada di sekitar 0.7 dari amplitudo sinyal input (hijau). Terjadi pergeseran fasa sekitar 45 derajat.

Implementasi Bahasa C di Windows

Tahap selanjutnya adalah membuat implementasi filter dengan bahasa C.

Compiler yang digunakan adalah CodeBlocks

Berikut ini kode filter digital dalam bahasa C.

Output program ini adalah file win10-filter.csv

#include <stdio.h>
#include <stdlib.h>

// inisialisasi filter digital

void filter_init(float *xn1,float *yn1)
{
    *yn1=0;
    *xn1=0;
}

// hitung output filter digital filter digital
// delayed variabel diberikan sebagai parameter
float filter_run(float *xn,float *xn1,float *yn1)
{
    float y;
    y=0.04676 * *xn + 0.0476 * *xn1 + 0.9048 * *yn1;
    *yn1=y;
    *xn1=*xn;
    return y;
}

int main()
{
    FILE * fp;
    float y,xn,xn1,yn1;
    int i;
    float t;
    float period;
    t=-1;
    period=0.01;

    fp = fopen ("win10-filter.csv", "w+");
    filter_init(&xn1,&yn1);

    for (i=0; i<200; i++)
    {
        t=t+period;
        if(t<0)
        {
            xn=0;
        }
        else
        {
            xn=1;
        }
        y=filter_run(&xn,&xn1,&yn1);
        fprintf(fp,"%f,%f,%f\n",t,xn,y);
    }
    fclose(fp);
    return 0;
}

Berikut ini grafik dari file csv dengan Excel

Bentuk grafik sesuai dengan grafik di Python. Nilai output csv dapat dibandingkan dengan simulasi di Python. Hasilnya sesuai.

Implementasi Bahasa C di ATmega328

Implementasi filter di ATmega328 diperlukan jika kita membuat filter digital atau membuat simulator plant untuk Hardware In the Loop (HIL)

under construction

Implementasi Bahasa C di ESP32

Implementasi filter di ESP32diperlukan jika kita membuat filter digital atau membuat simulator plant untuk Hardware In the Loop (HIL)

under construction

Catatan

Referensi

  • Lizhe Tan, Digital Signal Processing, Fundamentals and Applications 3rd edition, Academic Press 2019
  • Matlab FIR Filter https://os.mbed.com/handbook/Matlab-FIR-Filter

Sonoff Mini R2

 

Berikut ini foto Sonoff Mini R2 bagian luar dan dalamnya. Benda ini kecil sekali, 1 kotak di foto adalah 1 cm.

Tampak atas
Tampak atas

 

 

Tampak bawah
Tampak bawah

 

 

bagian dalam tampak atas
bagian dalam tampak atas

 

 

bagian dalam tampak bawah
bagian dalam tampak bawah

 

Referensi

 

Kendali Lampu di ThingsBoard Dengan Remote Procedure Call

Pada tulisan ini diuraikan cara mengendalikan lampu secara wireless dengan ThingsBoard. Mikroprosesor yang dipakai adalah ESP32. Metode yang dipakai adalah RPC (Remote Procedure Call)

 

ESP32 di breadboard dengan 3 buah LED biruBerikut ini kode firmware untuk ESP32. Inspirasi kode dari “ESP32 Pico Kit GPIO Control and DHT22 sensor monitor using ThingBoard Arduino SDK

Parameter yang perlu disesuaikan:

  • WIFI_AP_NAME adalah nama access point
  • WIFI_PASSWORD adalah password WiFi yang dipakai
  • TOKEN adalah kode token dari perangkat. Diambil dari ThingsBoard
#include <WiFi.h>           // WiFi control for ESP32
#include <ThingsBoard.h>    // ThingsBoard SDK

// Helper macro to calculate array size
#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))

// WiFi access point
#define WIFI_AP_NAME        "WIFI_AP_NAME        "
// WiFi password
#define WIFI_PASSWORD       "WIFI_PASSWORD       "

// See https://thingsboard.io/docs/getting-started-guides/helloworld/
// to understand how to obtain an access token
#define TOKEN               "yd8R3K3GE61Drm7TtvgF"
// ThingsBoard server instance.
#define THINGSBOARD_SERVER  "192.168.0.90"

#define ONBOARD_LED 22
// Baud rate for debug serial
#define SERIAL_DEBUG_BAUD    115200

// Initialize ThingsBoard client
WiFiClient espClient;
// Initialize ThingsBoard instance
ThingsBoard tb(espClient);
// the Wifi radio's status
int status = WL_IDLE_STATUS;

// Array with LEDs that should be controlled from ThingsBoard, one by one
uint8_t leds_control[] = { 12, 13, 27 };

// Main application loop delay
int quant = 20;

// Initial period of LED cycling.
int led_delay = 1000;
// Period of sending a temperature/humidity data.
int send_delay = 2000;

// Time passed after LED was turned ON, milliseconds.
int led_passed = 0;
// Time passed after temperature/humidity data was sent, milliseconds.
int send_passed = 0;

// Set to true if application is subscribed for the RPC messages.
bool subscribed = false;
// LED number that is currenlty ON.
//int current_led = 0;

// Processes function for RPC call "setGpioStatus"
// RPC_Data is a JSON variant, that can be queried using operator[]
// See https://arduinojson.org/v5/api/jsonvariant/subscript/ for more details
RPC_Response processSetGpioState(const RPC_Data &data)
{
  Serial.println("Received the set GPIO RPC method");
  int pin = data["pin"];
  bool enabled = data["enabled"];
  if (pin < COUNT_OF(leds_control)) {
    Serial.print("Setting LED ");
    Serial.print(pin);
    Serial.print(" to state ");
    Serial.println(enabled);
    digitalWrite(leds_control[pin], enabled);
  }
  return RPC_Response(data["pin"], (bool)data["enabled"]);
}

// RPC handlers
RPC_Callback callbacks[] = {
  { "setGpioStatus",    processSetGpioState },
};

// Setup an application
void setup() {
  // Initialize serial for debugging
  Serial.begin(SERIAL_DEBUG_BAUD);
  WiFi.begin(WIFI_AP_NAME, WIFI_PASSWORD);
  InitWiFi();

  for (size_t i = 0; i < COUNT_OF(leds_control); ++i) {
    pinMode(leds_control[i], OUTPUT);
  }
  pinMode(ONBOARD_LED, OUTPUT); \

// LED check
  digitalWrite(leds_control[0], HIGH);
  delay(500);
  digitalWrite(leds_control[1], HIGH);
  delay(500);
  digitalWrite(leds_control[2], HIGH);
  delay(500);
  digitalWrite(leds_control[0], LOW);
  delay(500);
  digitalWrite(leds_control[1], LOW);
  delay(500);
  digitalWrite(leds_control[2], LOW);
  delay(500);
}

// Main application loop
void loop() {
  delay(quant);
  led_passed += quant;
  send_passed += quant;
  // Reconnect to WiFi, if needed
  if (WiFi.status() != WL_CONNECTED) {
    reconnect();
    return;
  }
  // Reconnect to ThingsBoard, if needed
  if (!tb.connected()) {
    subscribed = false;
    // Connect to the ThingsBoard
    Serial.print("Connecting to: ");
    Serial.print(THINGSBOARD_SERVER);
    Serial.print(" with token ");
    Serial.println(TOKEN);
    if (!tb.connect(THINGSBOARD_SERVER, TOKEN)) {
      Serial.println("Failed to connect");
      return;
    }
  }
  // Subscribe for RPC, if needed
  if (!subscribed) {
    Serial.println("Subscribing for RPC...");
    // Perform a subscription. All consequent data processing will happen in
    // callbacks as denoted by callbacks[] array.
    if (!tb.RPC_Subscribe(callbacks, COUNT_OF(callbacks))) {
      Serial.println("Failed to subscribe for RPC");
      return;
    }
    Serial.println("Subscribe done");
    subscribed = true;
  }

  if (send_passed > send_delay) {
    send_passed = 0;
  }
  // Process messages
  tb.loop();


  static int blink_counter = 0;
  if (blink_counter < 50) {
    digitalWrite(ONBOARD_LED, LOW);
  } else {
    digitalWrite(ONBOARD_LED, HIGH);
  }
  blink_counter++;
  if (blink_counter >= 100) {
    blink_counter = 0;
  }
}

void InitWiFi()
{
  Serial.println("Connecting to AP ...");
  // attempt to connect to WiFi network
  WiFi.begin(WIFI_AP_NAME, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("Connected to AP");
}

void reconnect() {
  // Loop until we're reconnected
  status = WiFi.status();
  if ( status != WL_CONNECTED) {
    WiFi.begin(WIFI_AP_NAME, WIFI_PASSWORD);
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
    }
    Serial.println("Connected to AP");
  }
}

Berikut ini software PHP untuk mengendalikan LED dari Windows/Ubuntu

 

<?php

// kendali LED dengan REST API
// Create a new cURL resource
// Setup request to send json via POST
// login untuk mendapatkan JWT

$url = 'http://192.168.0.90:8080/api/auth/login';
$body_array = array();
$body_array["username"] = "[email protected]";
$body_array["password"] = "tenant";
$body = json_encode($body_array);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json', 'Accept: application/json'));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
print_r($result);

$result_array = json_decode($result, true);
print_r($result_array);
$token = $result_array["token"];
printf("token %s\n", $result_array["token"]);

// sekarang kirim command pakai token

function SetGpio($led_index, $value, $token) {
    $url = 'http://192.168.0.90:8080/api/rpc/twoway/e048cf90-cacc-11ec-84b1-a3192844351e';
    $params = array();
    $params["pin"] = $led_index;
    $params["enabled"] = $value;
    $body_array = array();
    $body_array["method"] = "setGpioStatus";
    $body_array["params"] = $params;
    $body_array["persistent"] = false;
    $body_array["timeout"] = 5000;
    $body = json_encode($body_array);
    $header = array();
    $header[] = 'Content-Type:application/json';
    $header[] = 'Accept: application/json';
    $header[] = 'X-Authorization: Bearer ' . $token;

    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $result = curl_exec($ch);
    curl_close($ch);
    print_r($result);
}

while (1) {
    SetGpio(0, 1, $token);
    usleep(50000);
    SetGpio(0, 0, $token);
    usleep(50000);
    SetGpio(1, 1, $token);
    usleep(50000);
    SetGpio(1, 0, $token);
    usleep(50000);
    SetGpio(2, 1, $token);
    usleep(50000);
    SetGpio(2, 0, $token);
    usleep(50000);
}

ESP8266 NodeMCU

NodeMCU pinout

LED di port D2

NodeMCU Versi 0.9

Berikut ini foto development kit NodeMCU versi original [sumber]

NodeMCU Devkit v0.9 ESP8266
NodeMCU Devkit v0.9
Definisi Pin NodeMCU V0.9 ESP8266
Definisi Pin NodeMCU V0.9

Berikut ini skematik rangkaian NodeMCU versi 0.9 [sumber]

Skematik NodeMCU 0.9 ESP8266
Skematik NodeMCU 0.9

NodeMCU Versi 1.0

Berikut ini foto development kit NodeMCU V1.0 versi original [sumber]

NodeMCU Devkit v1.0 ESP8266
NodeMCU Devkit v1.0
NodeMCU ESP8266
NodeMCU ESP8266

Definisi pin NodeMCU menurut situs NodeMCU DEVKIT V1.0

Definisi Pin NodeMCU Devkit V1.0
Definisi Pin NodeMCU Devkit V1.0

Skema Rangkaian

Sumber: https://github.com/nodemcu/nodemcu-devkit-v1.0/blob/master/NODEMCU_DEVKIT_V1.0.PDF

Skema rangkaian NodeMCU Devkit V1.0 Konektor
Skema rangkaian NodeMCU Devkit V1.0 Konektor
Skema rangkaian NodeMCU Devkit V1.0 Catu Daya
Skema rangkaian NodeMCU Devkit V1.0 Catu Daya
Skema rangkaian NodeMCU Devkit V1.0 Serial
Skema rangkaian NodeMCU Devkit V1.0 Serial
Skema rangkaian NodeMCU Devkit V1.0 Inti
Skema rangkaian NodeMCU Devkit V1.0 Inti

 

Referensi

Instalasi ThingsBoard IoT Gateway di Ubuntu 20.04

Ada beberapa cara instalasi ThingsBoard IoT Gateway:

Instalasi ThingsBoard

Pada tulisan ini akan diuraikan proses instalasi menggunakan PIP (Python) di Ubuntu 20.04.4

Pertama-tama update dan upgrade Ubuntu ke versi terbaru

sudo apt update && apt upgrade

Selanjutnya lakukan instalasi library di Ubuntu

sudo apt install python3-dev python3-pip libglib2.0-dev 

Selanjutnya instal ThingsBoard Gateway dengan pip:

sudo pip3 install thingsboard-gateway

Download contoh file konfigurasi dan buat folder log

wget https://github.com/thingsboard/thingsboard-gateway/releases/download/2.0/configs.tar.gz

Buat direktori untuk file-file konfigurasi

sudo mkdir /etc/thingsboard-gateway

Buat direktori untuk file log

sudo mkdir /var/log/thingsboard-gateway

Buka file-file konfigurasi

sudo tar -xvzf configs.tar.gz -C /etc/thingsboard-gateway

Jalankan thingsboard gateway dengan perintah berikut

thingsboard-gateway

Akan timbul pesan kesalahan seperti di bawah ini, karena belum dikonfigurasi

[STREAM ONLY] 2022-05-12 00:54:46,314 - ERROR - [mqtt_connector.py] - mqtt_connector - 142 - 'attributeRequests' section missing from configuration
[STREAM ONLY] 2022-05-12 00:54:46,315 - ERROR - [mqtt_connector.py] - mqtt_connector - 207 - [Errno 111] Connection refused
[STREAM ONLY] 2022-05-12 00:54:46,938 - ERROR - [tb_device_mqtt.py] - tb_device_mqtt - 146 - connection FAIL with error 3 server unavailable
[STREAM ONLY] 2022-05-12 00:54:46,939 - DEBUG - [tb_device_mqtt.py] - tb_device_mqtt - 123 - Disconnected client: <paho.mqtt.client.Client object at 0x7fb426ddc490>, user data: None, result code: 0
 nano /etc/thingsboard-gateway/config/tb_gateway.yaml

Konfigurasi Dasar

Buat device Iot Gateway di ThingsBoard. Caranya:

  • Masuk ke ThingsBoard web interface (misal alamatnya http://192.168.0.90:8080)

  • Klik di “Devices”
  • Klik di tanda “+”, kemudian “Add new device” untuk membuat device baru
  • Masukkan nama device. Misal “iot-gateway-93”
  • Klik di checkbutton “is gateway” untuk menandakan bahwa device yang dibuat adalah IoT gateway
  • Klik “Add”. Maka pembuatan Device IoT Gateway selesai.

Selanjutnya adalah mengambil Access Token.

  • Klik di menu “Devices”. Akan muncul daftar devices yang ada
  • Klik di device IoT gateway yang baru dibuat
  • Klik di “Copy access token”, maka access token akan tersimpan di clipboard Windows.
  • selanjutnya masuk ke console Ubuntu untuk mengedit file konfigurasi ThingsBoard Gateway.
  • edit file /etc/thingsboard-gateway/config/tb_gateway.yaml dengan teks editor editor, misalnya dengan ‘nano’.
  • Ganti “host” dengan alamat dari server ThingsBoard. Defaultnya adalah demo.thingsboard.io. Misal pada contoh ini alamat server ThingsBoard adalah 192.168.0.90, sehingga alamat host diganti menjadi 192.168.0.90
  • port tetap di 1883 (MQTT) . Umumnya tidak ada perubahan.
  • Ganti string PUT_YOUR_GW_ACCESS_TOKEN_HERE dengan access token yang dicopy di atas. Misal access token adalah KbllULqUCAj1PWt1pvCQ

thingsboard:
  host: demo.thingsboard.io
  port: 1883
  security:
    accessToken: PUT_YOUR_GW_ACCESS_TOKEN_HERE

Maka file akan berubah seperti berikut ini:

thingsboard:
  host: 192.168.0.90
  port: 1883
  security:
    accessToken: KbllULqUCAj1PWt1pvCQ

Untuk sementara bagian lain dari file konfigurasi belum perlu diubah.

Hentikan thingsboard gateway dengan menekan CTRL-C di console Ubuntu.

Selanjutnya jalankan lagi thingsboard gateway dari console Ubuntu untuk melihat apakah ada perubahan

 thingsboard-gateway 

Akan muncul pesan seperti berikut ini:

[STREAM ONLY] 2022-05-12 01:19:55,467 - ERROR - [mqtt_connector.py] - mqtt_connector - 142 - 'attributeRequests' section missing from configuration
[STREAM ONLY] 2022-05-12 01:19:55,468 - ERROR - [mqtt_connector.py] - mqtt_connector - 207 - [Errno 111] Connection refused

Pesan itu normal, karena memang MQTT belum dikonfigurasi.

Selanjutnya lihat di web interface ThingsBoard untuk melihat apakah sudah ada koneksi dari thingsboard gateway.

Caranya:

  • Masuk ke daftar devices dengan cara klik “Devices” di menu web ThingsBoard
  • Klik di IoT gateway yang baru dibuat, misal tadi namanya adalah “iot-gateway-93”
  • Klik di “Latest telemetry”. Seharusnya akan muncul beberapa key berikut ini, dengan “last update time” sesuai dengan waktu start thingsboard gateway di console Ubuntu
    • eventsProduced
    • eventsSent
    • LOGS
    • mqttbrokerconnectorEventsProduced
    • mqttbrokerconnectorEventsSent

Thingsboard IoT gateway Telemetry

Jika muncul data telemetry seperti di atas, maka artinya ThingsBoard gateway sudah berhasil berkomunikasi dengan ThingsBoard Server.

Tahap selanjutnya adalah melakukan konfigurasi connector di ThingsBoard Gateway supaya dapat menerima / mengirim data ke devices yang ada. Contohnya untuk REST API dapat dilihat di artikel “Koneksi REST API ke ThingsBoard IoT Gateway

Pada contoh ikni script thingsboard-gateway perlu dijalankan secara manual. Jika ingin dijalankan secara otomatis, dapat dibuat menjadi service atau ditambahkan ke crontab ataupun  etc/rc.local

Konfigurasi File Log

Pada contoh file konfigurasi yang diberikan, file log disimpan di “./log”, jadi relatif terhadap dari mana kita menjalankan thingsboard-gateway. Supaya rapi, file log disimpan di /var/log/thingsboard-gateway. Untuk itu edit file /etc/thingsboard-gateway/config/logs.conf untuk mengubah lokasi file log sesuai keinginan.

Berikut ini bagian dari file logs.conf yang mengatur lokasi file log

[handler_connectorHandler]
level=DEBUG
class=logging.handlers.TimedRotatingFileHandler
formatter=LogFormatter
args=(“/var/log/thingsboard-gateway/connector.log”, ‘d’, 1, 7,)

[handler_storageHandler]
level=DEBUG
class=logging.handlers.TimedRotatingFileHandler
formatter=LogFormatter
args=(“/var/log/thingsboard-gateway/storage.log”, ‘d’, 1, 7,)

[handler_serviceHandler]
level=DEBUG
class=logging.handlers.TimedRotatingFileHandler
formatter=LogFormatter
args=(“/var/log/thingsboard-gateway/service.log”, ‘d’, 1, 7,)

[handler_converterHandler]
level=DEBUG
class=logging.handlers.TimedRotatingFileHandler
formatter=LogFormatter
args=(“/var/log/thingsboard-gateway/converter.log”, ‘d’, 1, 3,)

[handler_extensionHandler]
level=DEBUG
class=logging.handlers.TimedRotatingFileHandler
formatter=LogFormatter
args=(“/var/log/thingsboard-gateway/extension.log”, ‘d’, 1, 3,)

[handler_tb_connectionHandler]
level=DEBUG
class=logging.handlers.TimedRotatingFileHandler
formatter=LogFormatter
args=(“/var/log/thingsboard-gateway/tb_connection.log”, ‘d’, 1, 3,)

 

Daftar Artikel Tentang ThingsBoard IoT Gateway

Referensi

Koneksi REST API ke ThingsBoard IoT Gateway

ThingsBoard gateway dapat menerima data dari client dengan protokol REST connector.

Arsitektur Thingsboard IoT Gateway
Arsitektur Thingsboard IoT Gateway

 

 

Setting Server

Untuk mengaktifkan REST API, pastikan ada baris berikut ini pada file /etc/thingsboard-gateway/config/tb_gateway.yaml

Penjelasan detail di artikel “IoT Gateway Configuration

  -
    name: REST Connector
    type: rest
    configuration: rest.json

Berikut ini contoh konfigurasi connector untuk REST API.

Lokasi file adalah di /etc/thingsboard-gateway/config/rest.json

Penjelasan detail format file ini ada di artikel “REST Connector Configuration

 

{
  "host": "0.0.0.0",
  "port": "5000",
  "SSL": false,
  "security": {
    "cert": "~/ssl/cert.pem",
    "key": "~/ssl/key.pem"
  },
  "mapping": [
    {
      "endpoint": "/device1",
      "HTTPMethods": [
        "POST"
      ],
      "security": {
        "type": "anonymous"
      },
      "converter": {
        "type": "json",
        "deviceNameExpression": "Device ${name}",
        "deviceTypeExpression": "default",
        "attributes": [
          {
            "type": "string",
            "key": "model",
            "value": "${sensorModel}"
          }
        ],
        "timeseries": [
          {
            "type": "double",
            "key": "temperature",
            "value": "${temp}"
          },
          {
            "type": "double",
            "key": "humidity",
            "value": "${hum}"
          }
        ]
      }
    }
  ],
  "attributeUpdates": [
    {
      "HTTPMethod": "POST",
      "SSLVerify": false,
      "httpHeaders": {
        "CONTENT-TYPE": "application/json"
      },
      "security": {
        "type": "basic",
        "username": "user",
        "password": "passwd"
      },
      "timeout": 0.5,
      "tries": 3,
      "allowRedirects": true,
      "deviceNameFilter": ".*REST$",
      "attributeFilter": "data",
      "requestUrlExpression": "sensor/${deviceName}/${attributeKey}",
      "valueExpression": "{\"${attributeKey}\":\"${attributeValue}\"}"
    }
  ],
  "serverSideRpc": [
    {
      "deviceNameFilter": ".*",
      "methodFilter": "echo",
      "requestUrlExpression": "http://127.0.0.1:5001/${deviceName}",
      "responseTimeout": 1,
      "HTTPMethod": "GET",
      "valueExpression": "${params}",
      "timeout": 10.0,
      "tries": 3,
      "httpHeaders": {
        "Content-Type": "application/json"
      },
      "security": {
        "type": "anonymous"
      }
    },
    {
      "deviceNameFilter": ".*",
      "methodFilter": "no-reply",
      "requestUrlExpression": "sensor/${deviceName}/request/${methodName}/${requestId}",
      "HTTPMethod": "POST",
      "valueExpression": "${params}",
      "httpHeaders": {
        "Content-Type": "application/json"
      },
      "security": {
        "type": "anonymous"
      }
    }
  ]
}

Penjelasan

“host”

  "host": "0.0.0.0",

Setting host di contoh aslinya menggunakan 127.0.0.1, namun kalau pakai IP ini tidak dapat dikontak dari komputer lain. Supaya dapat dikontak dari IP lain, maka menggunakan 0.0.0.0 , atau bisa juga menggunakan IP address dari IoT Gateway tersebut

“port”

Port yang dipakai bebas. Pada contoh ini menggunakan port 5000 seperti sesuai contoh file aslinya.

“SSL”

konfigurasi ini tidak menggunakan security

“mapping”

Bagian ini berisi konfigurasi penerimaan data dari client dan juga pemetaan data untuk dikirim ke ThingsBoard Core.

“endpoint”: untuk mendefinisikan URL dari REST API

IoT Gateway ini misalnya menggunakan IP address 192.168.0.92. Jadi alamat dari REST API adalah http://192.168.0.92:5000/device1

“HTTPMethods”: konfigurasi ini menggunakan HTTP POST. Sesuai contoh dari Thingsboard

“security”: anonymous, tidak menggunakan password samsekali

“converter”: berisi pemetaan data yang diterima, ke parameter yang akan dikirim ke ThingsBoard Core

“deviceNameExpression”: “Device ${name}”, : baris ini artinya mengharapkan adanya parameter “name” dari data yang masuk. Data ini kemudian akan dikirim sebagai string “Device $name” ke ThingsBoard Core.

“attributes”: berisi atribut dari device di client

“timeseries”: berisi entry data yang akan dimasukkan sebagai data telemetri di Device di ThingsBoard Core.

Pada contoh ini ada 2 entry data, yaitu temperatur dan humidity. Parameter yang diharapkan diterima adalah “temp” dan “hum”. Parameter “temp” akan dipetakan ke parameter “temperature”, dan parameter “hum” akan dipetakan ke parameter “humidity”.

Client Dengan PHP CURL

Berikut ini contoh client menggunakan PHP Curl

<?php 
// API URL
$url = 'http://192.168.0.92:5000/device1';
// Create a new cURL resource
$ch = curl_init($url);
// Setup request to send json via POST

$body_array = array();
$body_array["name"] = "123123";
$body_array["sensorModel"] = "CX811";
$body_array["hum"] = 78;
$body_array["temp"] = 65;
$body = json_encode($body_array);
// Attach encoded JSON string to the POST fields
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
// Set the content type to application/json
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
// curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// Execute the POST request
$result = curl_exec($ch);
// Close cURL resource
curl_close($ch);
print_r($payload);
print_r($result);

Berikut ini data yang masuk ke ThingsBoard sebagai latest telemetry

 

Jika koneksi berhasil, pada console thingsboard dan file log “connector.log” akan muncul pesan seperti berikut ini:


”2022-05-12 01:40:58′ – INFO – rest_connector – 319 – CONVERTER CONFIG: {‘type’: ‘json’, ‘deviceNameExpression’: ‘Device ${name}’, ‘deviceTypeExpression’: ‘default’, ‘attributes’: [{‘type’: ‘string’, ‘key’: ‘model’, ‘value’: ‘${sensorModel}’}], ‘timeseries’: [{‘type’: ‘double’, ‘key’: ‘temperature’, ‘value’: ‘${temp}’}, {‘type’: ‘double’, ‘key’: ‘humidity’, ‘value’: ‘${hum}’}]}’
”2022-05-12 01:40:58′ – INFO – rest_connector – 324 – CONVERTED_DATA: {‘deviceName’: ‘Device 58749’, ‘deviceType’: ‘default’, ‘attributes’: [{‘model’: ‘BMP280’}], ‘telemetry’: [{‘temperature’: ’80’}, {‘humidity’: ’67’}]}’

Dari pesan itu dapat diperiksa apakah konfigurasi “mapping” di rest.json sudah sesuai.

Client Dengan POSTMAN

Jika menggunakan software POSTMAN atau semacamnya, yg perlu diset adalah sebagai berikut:

  • URL: http://192.168.0.92:5000/device1
  • Payload dalam format JSON: {“name”:”58749″,”sensorModel”:”BMP280″,”hum”:67,”temp”:80}

Literatur

 

 

 

 

Sensor HTU21D Temperatur & Kelembaban

Referensi:

Contoh Program untuk ESP32

 

// library: https://github.com/adafruit/Adafruit_HTU21DF_Library
#define I2C_SDA 15
#define I2C_SCL 13

#include <Wire.h>
#include "Adafruit_HTU21DF.h"

// Connect Vin to 3-5VDC
// Connect GND to ground
// Connect SCL to I2C clock pin (13)
// Connect SDA to I2C data pin (15)

Adafruit_HTU21DF htu = Adafruit_HTU21DF();

void setup() {
  Serial.begin(115200);
  Serial.println("HTU21D-F test");
  Wire.begin(I2C_SDA, I2C_SCL);
  if (!htu.begin()) {
    Serial.println("Couldn't find sensor!");
    while (1);
  }
}

void loop() {
  float temp = htu.readTemperature();
  float rel_hum = htu.readHumidity();
  Serial.print("Temp: "); Serial.print(temp); Serial.print(" C");
  Serial.print("\t\t");
  Serial.print("Humidity: "); Serial.print(rel_hum); Serial.println(" \%");
  delay(500);
}

Sensor Temperatur MCP9808

Contoh kode ESP32 untuk menghubungkan MCP9808 ke ThingsBoard. Kode ini menggunakan library MCP9808 dari Adafruit

// CJMCU-9808
// Adafruit MCP9808 Library https://github.com/adafruit/Adafruit_MCP9808_Library

#include <WiFi.h>           // WiFi control for ESP32
#include <ThingsBoard.h>    // ThingsBoard SDK
#include <Wire.h>
#include "Adafruit_MCP9808.h"
#include <Arduino.h>
#include <Wire.h>

Adafruit_MCP9808 tempsensor = Adafruit_MCP9808();

// WiFi access point
#define WIFI_AP_NAME        "WIFI_AP_NAME"
// WiFi password
#define WIFI_PASSWORD       "WIFI_PASSWORD"
#define TOKEN               "THINGSBOARD_TOKEN"

#define BUILTIN_LED 22
// ThingsBoard server instance.
#define THINGSBOARD_SERVER  "192.168.0.90"

#define I2C_SDA 15
#define I2C_SCL 13

// Initialize ThingsBoard client
WiFiClient espClient;
// Initialize ThingsBoard instance
ThingsBoard tb(espClient);
// the Wifi radio's status
int status = WL_IDLE_STATUS;

// main application loop delay (ms)
int quant = 20;

// Period of sending a temperature/humidity data.
int send_delay = 2000;

// Time passed after telemetry data was sent, milliseconds.
int send_passed = 0;

char mac_str[20]; // storing MAC address string
byte mac_byte[6]; // storing MAC address bytes

int led_counter = 0; //blinking built int led

void setup() {
  pinMode(BUILTIN_LED, OUTPUT);
  // put your setup code here, to run once:
  Serial.begin(115200);
  delay(1000);

  //wait for serial connection to open (only necessary on some boards)
  while (!Serial);

  Wire.begin(I2C_SDA, I2C_SCL);

  I2C_Scan() ; // just for verifying

  if (!tempsensor.begin(0x18)) {
    Serial.println("Couldn't find MCP9808! Check your connections and verify the address is correct.");
    while (1);
  }
  tempsensor.setResolution(3);

  WiFi.begin(WIFI_AP_NAME, WIFI_PASSWORD);
  InitWiFi();
  WiFi.macAddress(mac_byte);
  sprintf(mac_str, "%02x%02x%02x%02x%02x%02x", mac_byte[0], mac_byte[1], mac_byte[2], mac_byte[3], mac_byte[4], mac_byte[5]);
  Serial.print("ESP board MAC address:  ");
  Serial.println(WiFi.macAddress());
  Serial.print("ESP board  IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  float temperature = 25;
  float pressure = 0;
  float humidity = 60; // default humidity
  float co2 = 0;
  float tvoc = 0;

  delay(quant);
  send_passed += quant;

  // Reconnect to WiFi, if needed
  if (WiFi.status() != WL_CONNECTED) {
    reconnect();
    return;
  }

  // Reconnect to ThingsBoard, if needed
  if (!tb.connected()) {
    // Connect to the ThingsBoard
    Serial.print("Connecting to: ");
    Serial.print(THINGSBOARD_SERVER);
    Serial.print(" with token ");
    Serial.println(TOKEN);
    if (!tb.connect(THINGSBOARD_SERVER, TOKEN)) {
      Serial.println("Failed to connect");
      return;
    }
  }

  // Check if it is a time to send sensor data
  if (send_passed > send_delay) {
//    Serial.println("wake up MCP9808.... "); // wake up MCP9808 - power consumption ~200 mikro Ampere
    tempsensor.wake();   // wake up, ready to read!

    // Read and print out the temperature, also shows the resolution mode used for reading.
    //    Serial.print("Resolution in mode: ");
    //    Serial.println (tempsensor.getResolution());
    float c = tempsensor.readTempC();
    //    Serial.print("Temp: ");
    //    Serial.print(c, 4);
    //    Serial.print("*C\t and ");
    //    Serial.println("Shutdown MCP9808.... ");
    tempsensor.shutdown_wake(1); // shutdown MSP9808 - power consumption ~0.1 mikro Ampere, stops temperature sampling
//    Serial.println("");

    Serial.print("Sending telemetry data...");
    Serial.print("Temp ");
    Serial.print(c);
    Serial.println(" ");
    tb.sendTelemetryFloat("temperature", c);
    send_passed = 0;
  }

  // Process messages
  tb.loop();

  led_counter++; // LED blink at 1 Hz
  if (led_counter > 50) {
    led_counter = 0;
  }
  if (led_counter > 25) {
    digitalWrite(BUILTIN_LED , LOW);
  } else {
    digitalWrite(BUILTIN_LED , HIGH);
  }
}

void I2C_Scan() {
  byte error, address;

  int nDevices;
  Serial.println("I2C Scanning...");
  nDevices = 0;
  for (address = 1; address < 127; address++ ) {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
    if (error == 0) {
      Serial.print("I2C device found at address 0x");
      if (address < 16) {
        Serial.print("0");
      }
      Serial.println(address, HEX);
      nDevices++;
    }
    else if (error == 4) {
      Serial.print("Unknow error at address 0x");
      if (address < 16) {
        Serial.print("0");
      }
      Serial.println(address, HEX);
    }
  }
  if (nDevices == 0) {
    Serial.println("No I2C devices found\n");
  }
  else {
    Serial.println("done\n");
  }
}

void InitWiFi()
{
  Serial.println("Connecting to AP ...");
  // attempt to connect to WiFi network

  WiFi.begin(WIFI_AP_NAME, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("Connected to AP");
}

void reconnect() {
  // Loop until we're reconnected
  status = WiFi.status();
  if ( status != WL_CONNECTED) {
    WiFi.begin(WIFI_AP_NAME, WIFI_PASSWORD);
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
    }
    Serial.println("Connected to AP");
  }
}

update: ditambah dengan watch dog timer

// CJMCU-9808
// Adafruit MCP9808 Library https://github.com/adafruit/Adafruit_MCP9808_Library

#include <WiFi.h>           // WiFi control for ESP32
#include <ThingsBoard.h>    // ThingsBoard SDK
#include <Wire.h>
#include "Adafruit_MCP9808.h"
#include <Arduino.h>
#include <Wire.h>
#include <esp_task_wdt.h>

Adafruit_MCP9808 tempsensor = Adafruit_MCP9808();

#define WDT_TIMEOUT 60
#define WIFI_AP_NAME        "abc" // WiFi access point
#define WIFI_PASSWORD       "123"
#define TOKEN               "jiowre43278feowjk4"

#define BUILTIN_LED 22
// ThingsBoard server instance.
#define THINGSBOARD_SERVER  "192.168.0.114"

#define I2C_SDA 15
#define I2C_SCL 13

// Initialize ThingsBoard client
WiFiClient espClient;
// Initialize ThingsBoard instance
ThingsBoard tb(espClient);
// the Wifi radio's status
int status = WL_IDLE_STATUS;

// main application loop delay (ms)
int quant = 20;

// Period of sending a temperature/humidity data.
int send_delay = 2000;

// Time passed after telemetry data was sent, milliseconds.
int send_passed = 0;

char mac_str[20]; // storing MAC address string
byte mac_byte[6]; // storing MAC address bytes

int led_counter = 0; //blinking built int led

void setup() {
  pinMode(BUILTIN_LED, OUTPUT);
  // put your setup code here, to run once:
  Serial.begin(115200);
  delay(1000);
  Serial.print(__FILE__);
  //wait for serial connection to open (only necessary on some boards)
  while (!Serial);

  Wire.begin(I2C_SDA, I2C_SCL);

  I2C_Scan() ; // just for verifying

  if (!tempsensor.begin(0x18)) {
    Serial.println("Couldn't find MCP9808! Check your connections and verify the address is correct.");
    while (1);
  }
  tempsensor.setResolution(3);

  WiFi.begin(WIFI_AP_NAME, WIFI_PASSWORD);
  InitWiFi();
  WiFi.macAddress(mac_byte);
  sprintf(mac_str, "%02x%02x%02x%02x%02x%02x", mac_byte[0], mac_byte[1], mac_byte[2], mac_byte[3], mac_byte[4], mac_byte[5]);
  Serial.print("ESP board MAC address:  ");
  Serial.println(WiFi.macAddress());
  Serial.print("ESP board  IP address: ");
  Serial.println(WiFi.localIP());

  // setup WDT
  esp_task_wdt_init(WDT_TIMEOUT, true); //enable panic so ESP32 restarts
  esp_task_wdt_add(NULL); //add current thread to WDT watch

}

void loop() {
  float temperature = 25;
  float pressure = 0;
  float humidity = 60; // default humidity
  float co2 = 0;
  float tvoc = 0;

  delay(quant);
  send_passed += quant;

  // Reconnect to WiFi, if needed
  if (WiFi.status() != WL_CONNECTED) {
    reconnect();
    sleep(5); // wait to reconnect
  }

  // Reconnect to ThingsBoard, if needed
  if (!tb.connected()) {
    // Connect to the ThingsBoard
    Serial.print("Connecting to: ");
    Serial.print(THINGSBOARD_SERVER);
    Serial.print(" with token ");
    Serial.println(TOKEN);
    if (!tb.connect(THINGSBOARD_SERVER, TOKEN)) {
      Serial.println("Failed to connect");
      return;
    }
  }

  // Check if it is a time to send sensor data
  if (send_passed > send_delay) {
    //    Serial.println("wake up MCP9808.... "); // wake up MCP9808 - power consumption ~200 mikro Ampere
    tempsensor.wake();   // wake up, ready to read!

    // Read and print out the temperature, also shows the resolution mode used for reading.
    //    Serial.print("Resolution in mode: ");
    //    Serial.println (tempsensor.getResolution());
    float c = tempsensor.readTempC();
    //    Serial.print("Temp: ");
    //    Serial.print(c, 4);
    //    Serial.print("*C\t and ");
    //    Serial.println("Shutdown MCP9808.... ");
    tempsensor.shutdown_wake(1); // shutdown MSP9808 - power consumption ~0.1 mikro Ampere, stops temperature sampling
    //    Serial.println("");

    Serial.print("Sending telemetry data...");
    Serial.print("Temp ");
    Serial.print(c);
    Serial.println(" ");
    tb.sendTelemetryFloat("temperature", c);
    send_passed = 0;
    esp_task_wdt_reset(); // WDT reset setelah berhasil mengirim data
  }

  // Process messages
  tb.loop();

  led_counter++; // LED blink at 1 Hz
  if (led_counter > 50) {
    led_counter = 0;
  }
  if (led_counter > 25) {
    digitalWrite(BUILTIN_LED , LOW);
  } else {
    digitalWrite(BUILTIN_LED , HIGH);
  }
}

void I2C_Scan() {
  byte error, address;

  int nDevices;
  Serial.println("I2C Scanning...");
  nDevices = 0;
  for (address = 1; address < 127; address++ ) {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
    if (error == 0) {
      Serial.print("I2C device found at address 0x");
      if (address < 16) {
        Serial.print("0");
      }
      Serial.println(address, HEX);
      nDevices++;
    }
    else if (error == 4) {
      Serial.print("Unknow error at address 0x");
      if (address < 16) {
        Serial.print("0");
      }
      Serial.println(address, HEX);
    }
  }
  if (nDevices == 0) {
    Serial.println("No I2C devices found\n");
  }
  else {
    Serial.println("done\n");
  }
}

void InitWiFi()
{
  Serial.println("Connecting to AP ...");
  // attempt to connect to WiFi network

  WiFi.begin(WIFI_AP_NAME, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("Connected to AP");
}

void reconnect() {
  // Loop until we're reconnected
  status = WiFi.status();
  if ( status != WL_CONNECTED) {
    WiFi.begin(WIFI_AP_NAME, WIFI_PASSWORD);
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
    }
    Serial.println("Connected to AP");
  }
}

Referensi:

ESP32 Dengan BMP280

Berikut ini antar muka minimalis antara ESP32 dengan sensor lingkungan BMP280

Pin yang dipakai:

  • VCC di ESP32 dihubungkan ke VCC di BMP280
  • GND di ESP32 dihubungkan ke GND di BMP280
  • SCL di ESP32 dihubungkan ke SCL di BMP280
  • SDA di ESP32 dihubungkan ke SDA di BMP280

Software juga dibuat minimalis

// https://bitbucket.org/christandlg/bmx280mi/src/master/examples/BMx280_I2C/BMx280_I2C.ino
// BMx280_I2C.ino
//
// shows how to use the BMP280 / BMx280 library with the sensor connected using I2C.
//
// Copyright (c) 2018 Gregor Christandl
//
// connect the AS3935 to the Arduino like this:
//
// Arduino - BMP280 / BME280
// 3.3V ---- VCC
// GND ----- GND
// SDA ----- SDA
// SCL ----- SCL
// some BMP280/BME280 modules break out the CSB and SDO pins as well:
// 5V ------ CSB (enables the I2C interface)
// GND ----- SDO (I2C Address 0x76)
// 5V ------ SDO (I2C Address 0x77)
// other pins can be left unconnected.

#include <Arduino.h>
#include <Wire.h>

#define I2C_SDA 15
#define I2C_SCL 13

#include <BMx280I2C.h>

#define I2C_ADDRESS 0x76

//create a BMx280I2C object using the I2C interface with I2C Address 0x76
BMx280I2C bmx280(I2C_ADDRESS);

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  delay(1000);

  //wait for serial connection to open (only necessary on some boards)
  while (!Serial);

  //  Wire.begin();
  Wire.begin(I2C_SDA, I2C_SCL);

  I2C_Scan() ; // just for verifying
  
  //begin() checks the Interface, reads the sensor ID (to differentiate between BMP280 and BME280)
  //and reads compensation parameters.
  if (!bmx280.begin())
  {
    Serial.println("begin() failed. check your BMx280 Interface and I2C Address.");
    while (1);
  }

  if (bmx280.isBME280())
    Serial.println("sensor is a BME280");
  else
    Serial.println("sensor is a BMP280");

  //reset sensor to default parameters.
  bmx280.resetToDefaults();

  //by default sensing is disabled and must be enabled by setting a non-zero
  //oversampling setting.
  //set an oversampling setting for pressure and temperature measurements.
  bmx280.writeOversamplingPressure(BMx280MI::OSRS_P_x16);
  bmx280.writeOversamplingTemperature(BMx280MI::OSRS_T_x16);

  //if sensor is a BME280, set an oversampling setting for humidity measurements.
  if (bmx280.isBME280())
    bmx280.writeOversamplingHumidity(BMx280MI::OSRS_H_x16);
}

void loop() {
  float temperature = 0;
  float pressure = 0;
  float humidity = 60; // default humidity
  float co2 = 0;
  float tvoc = 0;

  delay(1000);

  //start a measurement
  if (!bmx280.measure())
  {
    Serial.println("could not start measurement, is a measurement already running?");
    return;
  }

  //wait for the measurement to finish
  do
  {
    delay(100);
  } while (!bmx280.hasValue());

  //  Serial.print("Pressure: "); Serial.println(bmx280.getPressure());
  //  Serial.print("Pressure (64 bit): "); Serial.println(bmx280.getPressure64());
  //  Serial.print("Temperature: "); Serial.println(bmx280.getTemperature());

  pressure = bmx280.getPressure();
  temperature = bmx280.getTemperature();

  //important: measurement data is read from the sensor in function hasValue() only.
  //make sure to call get*() functions only after hasValue() has returned true.
  if (bmx280.isBME280())
  {
    //    Serial.print("Humidity: ");
    //    Serial.println(bmx280.getHumidity());
    humidity = bmx280.getHumidity();
  }

  Serial.print("Temp\t");
  Serial.print(temperature);
  Serial.print("\t");
  Serial.print("Humidity\t");
  Serial.print(humidity);
  Serial.print("\t");
  Serial.print("Pressure\t");
  Serial.print(pressure);
  Serial.print("\t");
  Serial.println("");
}

void I2C_Scan() {
  byte error, address;

  int nDevices;
  Serial.println("I2C Scanning...");
  nDevices = 0;
  for (address = 1; address < 127; address++ ) {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
    if (error == 0) {
      Serial.print("I2C device found at address 0x");
      if (address < 16) {
        Serial.print("0");
      }
      Serial.println(address, HEX);
      nDevices++;
    }
    else if (error == 4) {
      Serial.print("Unknow error at address 0x");
      if (address < 16) {
        Serial.print("0");
      }
      Serial.println(address, HEX);
    }
  }
  if (nDevices == 0) {
    Serial.println("No I2C devices found\n");
  }
  else {
    Serial.println("done\n");
  }
}

Telemetri Data Sakelar Dengan Thingsboard

Pada percobaan ini dilakukan pengiriman data telemetri dari ESP32 ke Thingsboard. Sensor yang dipakai adalah sakelar on-off. Percobaan ini adalah bagian dari pembuatan sistem IoT (Internet of Things) yang terdiri dari beberapa ESP32 dan software ThingsBoard.

Arsitektur ThingsBoard adalah sebagai berikut:

Arsitektur ThingsBoard
Arsitektur ThingsBoard

Pada percobaan ini , tidak semua komponen ThingsBoard dipakai. Yang dipakai adalah sebagai berikut

  • Devices: menggunakan ESP32 dan sakelar sebagas sensor 
  • Protokol HTTP sebagai ThingsBoard Transports
  • ThingsBoard Core
  • SQL Database
  • External Systems

Aliran data pada sistem yang dibuat adalah sebagai berikut:

Aliran data pada sistem. Sensor berupa sakelar. Kondisi sakelar dibaca oleh ESP32, kemudian dikirim secara teratur ke ThingsBoard.

Sakelar bertindak sebagai sensor. Besaran yang dihasilkan oleh sakelar adalah 0 dan 1. ESP32 membaca status sensor setiap interval tertentu, dan kemudian mengirimkannya ke ThingsBoard menggunakan protokol HTTP. Data ini kemudian disimpan di Database.

Data dari database ini dapat ditampilkan menggunakan Dashboard pada Thingsboard, dan juga dapat diambil oleh aplikasi eksternal menggunakan REST API (REpresentational State Transfer Application Program Interface)

Hardware yang dipakai adalah sebagai berikut:

  • ESP32 Lolin Wemos
  • 2 buah sakelar. Pada percobaan ini digunakan sakelar geser SPDT dan push button.
ESP32 Lolin Wemos
ESP32 Lolin Wemos

Daftar pin ESP32 yang dipakai adalah sebagai berikut

  • pin 13 sebagai input digital, diberi nama SW0. Input active low.
  • pin 15 sebagai input digital, diberi nama SW1. Input active low.

Berikut ini foto rangkaian setelah dirakit

Perangkat lunak yang dipakai

  • Arduino versi 1.8.19 (Windows)
  • ThingsBoard versi 3.3.4.1
  • Ubuntu Linux 20.04.04 LTS
  • Wireshark versi 3.02

Setting ThingsBoard

[under construction]

Perangkat Lunak ESP32

Perangkat lunak ESP32 dibuat dengan Arduino

Library yang dipakai di Arduino adalah sebagai berikut

Prosedur instalasi dapat dilihat di artikel “ESP32 Pico Kit GPIO Control and DHT22 sensor monitor using ThingBoard Arduino SDK

// demo switch telemetry to Thingsboard
// adapted from https://thingsboard.io/docs/samples/esp32/gpio-control-pico-kit-dht22-sensor/

#include <WiFi.h>           // WiFi control for ESP32
#include <ThingsBoard.h>    // ThingsBoard SDK

// onboard LED
#define BUILTIN_LED 22
// switch pin definition
#define SW0 13
#define SW1 15

// Helper macro to calculate array size
// #define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))

// WiFi access point
#define WIFI_AP_NAME        "ACCESS_POINT_NAME"
// WiFi password
#define WIFI_PASSWORD       "ACCESS_POINT_PASSWORD"

// See https://thingsboard.io/docs/getting-started-guides/helloworld/
// to understand how to obtain an access token
#define TOKEN               "QdqSrxBAjBvxAoJyeoXN"
// ThingsBoard server instance.
#define THINGSBOARD_SERVER  "192.168.0.90"

// Baud rate for debug serial
#define SERIAL_DEBUG_BAUD    115200

// Initialize ThingsBoard client
WiFiClient espClient;
// Initialize ThingsBoard instance
ThingsBoard tb(espClient);
// the Wifi radio's status
int status = WL_IDLE_STATUS;

// main application loop delay (ms)
int quant = 20;

// Period of sending a temperature/humidity data.
int send_delay = 2000;

// Time passed after telemetry data was sent, milliseconds.
int send_passed = 0;

char mac_str[20]; // storing MAC address string
byte mac_byte[6]; // storing MAC address bytes

int led_counter = 0; //blinking built int led

// Setup an application
void setup() {
  pinMode(SW0, INPUT_PULLUP); // input switch
  pinMode(SW1, INPUT_PULLUP);

  pinMode(BUILTIN_LED , OUTPUT);


  // Initialize serial for debugging
  Serial.begin(SERIAL_DEBUG_BAUD);
  WiFi.begin(WIFI_AP_NAME, WIFI_PASSWORD);
  InitWiFi();

  WiFi.macAddress(mac_byte);
  sprintf(mac_str, "%02x%02x%02x%02x%02x%02x", mac_byte[0], mac_byte[1], mac_byte[2], mac_byte[3], mac_byte[4], mac_byte[5]);
  Serial.print("ESP board MAC address:  ");
  Serial.println(WiFi.macAddress());
  Serial.print("ESP board  IP address: ");
  Serial.println(WiFi.localIP());
}

// Main application loop
void loop() {
  delay(quant);
  send_passed += quant;

  // Reconnect to WiFi, if needed
  if (WiFi.status() != WL_CONNECTED) {
    reconnect();
    return;
  }

  // Reconnect to ThingsBoard, if needed
  if (!tb.connected()) {
    // Connect to the ThingsBoard
    Serial.print("Connecting to: ");
    Serial.print(THINGSBOARD_SERVER);
    Serial.print(" with token ");
    Serial.println(TOKEN);
    if (!tb.connect(THINGSBOARD_SERVER, TOKEN)) {
      Serial.println("Failed to connect");
      return;
    }
  }

  // Check if it is a time to send switch data
  if (send_passed > send_delay) {
    int switch0, switch1;
    switch0 = digitalRead(SW0);
    switch1 = digitalRead(SW1);
    Serial.print("Sending telemetry data...");
    Serial.print(" SW0:");
    Serial.print(switch0);
    Serial.print(" SW1:");
    Serial.println(switch1);
    tb.sendTelemetryInt("switch00", switch0);
    tb.sendTelemetryInt("switch01", switch1);
    send_passed = 0;
  }

  // Process messages
  tb.loop();

  led_counter++; // LED blink at 1 Hz
  if (led_counter > 50) {
    led_counter = 0;
  }
  if (led_counter > 25) {
    digitalWrite(BUILTIN_LED , LOW);
  } else {
    digitalWrite(BUILTIN_LED , HIGH);
  }
}

void InitWiFi()
{
  Serial.println("Connecting to AP ...");
  // attempt to connect to WiFi network

  WiFi.begin(WIFI_AP_NAME, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("Connected to AP");
}

void reconnect() {
  // Loop until we're reconnected
  status = WiFi.status();
  if ( status != WL_CONNECTED) {
    WiFi.begin(WIFI_AP_NAME, WIFI_PASSWORD);
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
    }
    Serial.println("Connected to AP");
  }
}

Pengecekan Telemetri

Setelah sistem dirakit dan ESP32 diprogram, perlu dilakukan pengecekan apakah sistem berfungsi dengan baik. Pengecekan pengiriman data telemetri dilakukan dengan cara:

  • Memantau output dari port serial ESP32
  • Mengecek data telemetri di server Thingsboard

Berikut ini output dari serial monitor ESP32.

19:45:30.745 -> Connecting to AP ...
19:45:31.225 -> ......Connected to AP
19:45:33.738 -> ESP board MAC address:  3C:71:BF:03:41:4C
19:45:33.738 -> ESP board  IP address: 192.168.0.124
19:45:33.773 -> Connecting to: 192.168.0.90 with token QdqSrxBAjBvxAoJyeoXN
19:45:35.798 -> Sending telemetry data... SW0:1 SW1:1
19:45:37.819 -> Sending telemetry data... SW0:1 SW1:1
19:45:39.850 -> Sending telemetry data... SW0:1 SW1:1

Dari output tersebut dapat disimpulkan:

  • ESP32 berhasil terhubung ke access point
  • ESP32 berhasil mendapatkan IP address
  • ESP32 berhasil mengirim data ke ThingsBoard

Untuk mengecek data yang masuk ke server, prosedurnya sebagai berikut:

  • Login ke ThingsBoard sebagai tenant. username: [email protected], password: tenant (jika belum diganti)
  • Klik di “Devices”
  • Klik di “ESP32 Dual Switch”
  • Klik di “Latest telemetry”

Jika pengiriman data normal, maka status sakelar terakhir akan muncul di Device details, seperti gambar berikut ini.

Angka di kolom “Value” akan sesuai dengan status sakelar. Pada percobaan ini pengiriman data dilakukan dengan interval 2 detik, jadi selambatnya dalam 2 detik status sakelar terakhir akan masuk.

Dashboard di ThingsBoard

Setelah data dicek masuk, kita dapat membuat dashboard di Thingsboard untuk menampilkan data dari sensor. Berikut ini contoh tampilan dashboard.

dashboard ThingsBoard untuk dual switch

Pengambilan Data Telemetri Dengan REST API

Data telemetri di server ThingsBoard dapat diambil menggunakan REST API dari aplikasi lain.

Pada percobaan ini data diambil dengan menggunakan software ‘curl’ di Ubuntu Linux.

Pertama-tama membuat dulu JWT (JSON Web Token).

curl -X POST –header ‘Content-Type: application/json’ –header ‘Accept: application/json’ -d ‘{“username”:”[email protected]”, “password”:”tenant”}’ ‘http://192.168.0.90:8080/api/auth/login’

Hasilnya dalam bentuk JSON sebagai berikut

{“token”:”eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZW5hbnRAdGhpbmdzYm9hcmQub3JnIiwic2NvcGVzIjpbIlRFTkFOVF9BRE1JTiJdLCJ1c2VySWQiOiI2ZjEyZDE5MC1jOTAwLTExZWMtOWRlYS1kN2UzNGUyNDNiZWIiLCJlbmFibGVkIjp0cnVlLCJpc1B1YmxpYyI6ZmFsc2UsInRlbmFudElkIjoiNmU3OTI5YTAtYzkwMC0xMWVjLTlkZWEtZDdlMzRlMjQzYmViIiwiY3VzdG9tZXJJZCI6IjEzODE0MDAwLTFkZDItMTFiMi04MDgwLTgwODA4MDgwODA4MCIsImlzcyI6InRoaW5nc2JvYXJkLmlvIiwiaWF0IjoxNjUxNTgzNjI5LCJleHAiOjE2NTE1OTI2Mjl9.Ci_MA7PgSQk6xeMOgjJ_NRr3ipuRwLc2t3Yow2Nc5WWDCTPNNfbYPl4-bTikYH7DYFB5-ZqBuhnVVMY4kdJpaQ”,”refreshToken”:”eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZW5hbnRAdGhpbmdzYm9hcmQub3JnIiwic2NvcGVzIjpbIlJFRlJFU0hfVE9LRU4iXSwidXNlcklkIjoiNmYxMmQxOTAtYzkwMC0xMWVjLTlkZWEtZDdlMzRlMjQzYmViIiwiaXNQdWJsaWMiOmZhbHNlLCJpc3MiOiJ0aGluZ3Nib2FyZC5pbyIsImp0aSI6ImUwNGE0MDUyLTA3ZmYtNDRmNS04NmQ3LTRhYTIwYjEzNjFiOSIsImlhdCI6MTY1MTU4MzYyOSwiZXhwIjoxNjUyMTg4NDI5fQ.ZpLUtoqoY2BZBooRPu3vqF8DEbXOJuM33YsaRaR6IorBenRyRmnNAb_rTbpRfHWzh8-zBGDc0Ah0w6qqYK3ksA”}

Parameter yang diperlukan adalah hanya “token”, tidak termasuk”refresh token”.

Berikutnya membuat query REST API

curl -v -X GET http://192.168.0.90:8080/api/plugins/telemetry/DEVICE/e19fb430-caa4-11ec-84b1-a3192844351e/values/timeseries?keys=switch00,switch01 \
> –header “Content-Type:application/json” \
> –header “X-Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZW5hbnRAdGhpbmdzYm9hcmQub3JnIiwic2NvcGVzIjpbIlRFTkFOVF9BRE1JTiJdLCJ1c2VySWQiOiI2ZjEyZDE5MC1jOTAwLTExZWMtOWRlYS1kN2UzNGUyNDNiZWIiLCJlbmFibGVkIjp0cnVlLCJpc1B1YmxpYyI6ZmFsc2UsInRlbmFudElkIjoiNmU3OTI5YTAtYzkwMC0xMWVjLTlkZWEtZDdlMzRlMjQzYmViIiwiY3VzdG9tZXJJZCI6IjEzODE0MDAwLTFkZDItMTFiMi04MDgwLTgwODA4MDgwODA4MCIsImlzcyI6InRoaW5nc2JvYXJkLmlvIiwiaWF0IjoxNjUxNTgzNjI5LCJleHAiOjE2NTE1OTI2Mjl9.Ci_MA7PgSQk6xeMOgjJ_NRr3ipuRwLc2t3Yow2Nc5WWDCTPNNfbYPl4-bTikYH7DYFB5-ZqBuhnVVMY4kdJpaQ”
Note: Unnecessary use of -X or –request, GET is already inferred.
* Trying 192.168.0.90:8080…
* TCP_NODELAY set
* Connected to 192.168.0.90 (192.168.0.90) port 8080 (#0)
> GET /api/plugins/telemetry/DEVICE/e19fb430-caa4-11ec-84b1-a3192844351e/values/timeseries?keys=switch00,switch01 HTTP/1.1
> Host: 192.168.0.90:8080
> User-Agent: curl/7.68.0
> Accept: */*
> Content-Type:application/json
> X-Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZW5hbnRAdGhpbmdzYm9hcmQub3JnIiwic2NvcGVzIjpbIlRFTkFOVF9BRE1JTiJdLCJ1c2VySWQiOiI2ZjEyZDE5MC1jOTAwLTExZWMtOWRlYS1kN2UzNGUyNDNiZWIiLCJlbmFibGVkIjp0cnVlLCJpc1B1YmxpYyI6ZmFsc2UsInRlbmFudElkIjoiNmU3OTI5YTAtYzkwMC0xMWVjLTlkZWEtZDdlMzRlMjQzYmViIiwiY3VzdG9tZXJJZCI6IjEzODE0MDAwLTFkZDItMTFiMi04MDgwLTgwODA4MDgwODA4MCIsImlzcyI6InRoaW5nc2JvYXJkLmlvIiwiaWF0IjoxNjUxNTgzNjI5LCJleHAiOjE2NTE1OTI2Mjl9.Ci_MA7PgSQk6xeMOgjJ_NRr3ipuRwLc2t3Yow2Nc5WWDCTPNNfbYPl4-bTikYH7DYFB5-ZqBuhnVVMY4kdJpaQ
>

Berikut ini output dari curl:

* Mark bundle as not supporting multiuse
< HTTP/1.1 200
< Vary: Origin
< Vary: Access-Control-Request-Method
< Vary: Access-Control-Request-Headers
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< Content-Type: application/json
< Transfer-Encoding: chunked
< Date: Tue, 03 May 2022 13:16:56 GMT
<
* Connection #0 to host 192.168.0.90 left intact
{“switch00”:[{“ts”:1651583815502,”value”:”0″}],”switch01″:[{“ts”:1651583815505,”value”:”1″}]}

Output dalam format JSON

Referensi

Kegagalan Fatal Perangkat Lunak pada Sistem Berbasis Mikroprosesor

Berikut ini beberapa kecelakaan yang terjadi karena kegagalan pada sistem mikroprosesor, terutama yang disebabkan kesalahan di perangkat lunak (software).

Toyota Unintended Acceleration

Mobil Toyota melakukan akselerasi sendiri tanpa diperintah oleh pengemudi. Korban total 89 orang. Penyebab: kesalahan pada software ETCS (Electronic Throttle Control) pada mobil Camry,Lexus ES, Tacoma buatan Toyota.

Roket Ariane 5 flight V88(1996)

Roket Ariane 5 gagal meluncur karena bugs pada software. Masalah di konversi floating 64 bit ke signed integer 16 bit.

Mesin Terapi Radiasi Therac 25 (1985 ~ 1987)

Therac-25 adalah mesin untuk melakukan terapi radiasi pada pasien. Bugs pada software menyebabkan dosis radiasi melebihi batas. Korban 6 orang: 3 pasien meninggal, 3 pasien luka.

Mesin Terapi Radiasi Cobalt-60

Bugs pada software menyebabkan dosis radiasi melebihi batas. Korban meninggal: 5 orang, 15 orang lainnya terkena over-radiation.

Airbus A400M Crash

Pesawat A400M jatuh karena 3 dari 4 mesin mati.
“The key scenario being examined by investigators is that the torque calibration parameter data was accidentally wiped on three engines as the engine software was being installed at Airbus facilities, which would prevent the FADECs from operating”

Boeing 737 MAX MCAS

Puing-puing Ethiopian Airlines Flight ET302
Puing-puing Ethiopian Airlines Flight ET302

Software MCAS (Maneuvering Characteristics Augmentation System) menyebabkan 2 buah pesawat Boeing 737 MAX jatuh. Softwarenya sendiri tidak bermasalah, namun proses engineering pada pembuatannya yang bermasalah.

Mars Climate Orbiter

Mars Climate Orbiter
Mars Climate Orbiter

Kesalahan satuan pada software menyebabkan wahana Mars Climate Orbiter gagal mengorbit Mars.

Soviet Early Warning System Faulty Reports (1983)

Pada era perang dingin, USSR memiliki sistem pendeteksi (early warning) peluncuran rudal antar benua (ICBM) dari Amerika. Sistem ini gagal bekerja karena terjadi false positive.
“the false alarm was eventually traced to the satellite, which picked up the sun’s reflection off the tops of clouds and mistook it for a missile launch. The computer program that was supposed to filter out such information was rewritten.”

Patriot Missile Failure (1991)

Patriot Missile adalah Surface to Air Missile (SAM). Pada perang teluk (Gulf War), Rudal Patriot ini gagal menembak misil Scud yang ditembakkan dari Iraq. Akibatnya 28 orang tentara meninggal dan 100 orang luka.

Self Driving Car (2018)

Mobil otonom (self driving car) menabrak pejalan kaki

The sinking of the Sleipner A offshore platform (1991)

Anjungan lepas pantai, teggelam karena kesalahan di program finite element yang dipakai untuk desain.

Referensi

Analisis Rangkaian LED

Berikut ini ada 2 skema rangkaian untuk menyalakan LED dengan baterai 10 volt.

Permasalahan: mana yang menyala lebih terang.

Jawaban:

Kecerahan LED tergantung pada arus yang mengalir pada LED tersebut. Makin besar arusnya, makan makin terang LED tersebut.

Rangkaian kita tandai dulu dengan arus dan tegangan yang akan dihitung.

Analisis Rangkaian 1

Pertama kita cek dulu apakah LED menyala atau tidak.

Kita asumsikan LED merah dengan tegangan maju 2 volt, sehingga LED tersebut perlu tegangan sekurang-kurangnya 2 volt untuk dapat menyala.

Jika LED kita anggap tidak ada, maka R1 dan R2 menjadi pembagi tegangan, dengan

Vd= 6/(4+6) x 10 volt = 6 volt.

Tegangan Vd lebih dari 6 volt, sehingga tegangan di Vd cukup untuk menyalakan LED.

Karena LED menyala, maka tegangan pada titik Vd adalah sama dengan tegangan maju LED, yaitu 2 volt

Selanjutnya dihitung arus i1 yang mengalir pada R1. Untuk ini perlu menggunakan KVL (Kirchoff Voltage Law)

VB1 = VR1 + VD1

10 volt = i1 x 400 + 2 volt

i1 = (10 – 2)/400= 0,02 ampere

i3 dihitung dengan hukum ohm:

V = I x R

i3 = Vd / R2 = 2 / 600 = 0,00333 ampere

i2 dihitung dengan KCL (Kirchoff Current Law)

i1 = i2 + i3

i2 = i1 – i3 = 0,02 – 0,00333 = 0,01677 ampere

Analisis Rangkaian 2

Vd = tegangan maju LED = 2 volt

Dari KVL:

– VB1 + VR3 + VR4 + VD2 = 0

– 10 + i4 x R3 + i4 x R4 + 2 =0

i4 (R3+R4)= 10 -2

i4=8 / (400+600) = 0,008 ampere

i2 lebih besar dari i4, jadi kesimpulannya LED di rangkaian 1 menyala lebih terang.

Sumber diskusi: https://www.facebook.com/groups/928410417191779