Pada tutorial ini, Anda akan mempelajari cara memprogram board ESP32 dan ESP8266 menggunakan MicroPython untuk mengirimkan data hasil pembacaan sensor ke email. Sebagai contoh, tutorial ini menggunakan sensor BME280 untuk mengirimkan data suhu, kelembapan, dan tekanan udara. Namun, proyek ini dapat dengan mudah dimodifikasi untuk menggunakan jenis sensor lainnya sesuai kebutuhan.
Modul uMail
Untuk mempermudah pengiriman email menggunakan MicroPython, kita akan menggunakan modul bernama uMail. Modul ini tidak termasuk dalam kumpulan pustaka standar MicroPython, sehingga perlu diunggah secara terpisah ke board yang digunakan. Panduan lengkap untuk mengunggah modul tersebut akan dijelaskan pada bagian selanjutnya dalam tutorial ini.
Modul BME280
Untuk membaca data dari sensor BME280, kita akan menggunakan modul tambahan yang tidak termasuk dalam pustaka standar MicroPython secara default. Oleh karena itu, modul ini perlu diunggah terlebih dahulu ke board sebelum mulai menulis kode program. Modul BME280 dapat diunduh melalui tautan yang disediakan.
Sebagai panduan awal untuk mempelajari cara menghubungkan dan menggunakan sensor BME280 dengan ESP32/ESP8266 menggunakan MicroPython, Anda dapat merujuk ke tutorial berikut:
- MicroPython: BME280 dengan ESP32 dan ESP8266 (Tekanan, Suhu, dan Kelembaban)
Email Pengirim (Akun Baru)
Disarankan untuk membuat akun email baru yang khusus digunakan sebagai pengirim email ke alamat email pribadi utama Anda. Hindari menggunakan akun email utama untuk mengirim email melalui ESP32 atau ESP8266. Jika terjadi kesalahan pada kode program atau permintaan pengiriman email dilakukan terlalu sering, akun email Anda berisiko diblokir atau dinonaktifkan sementara. Pada tutorial ini, akun Gmail direkomendasikan, namun penyedia layanan email lain pada umumnya juga dapat digunakan.
Membuat App Password
Agar perangkat baru dapat mengirim email melalui akun Gmail, Anda perlu membuat App Password. App Password adalah kode sandi khusus berisi 16 digit yang memberikan izin akses kepada aplikasi atau perangkat dengan tingkat keamanan terbatas untuk menggunakan akun Google Anda. Informasi lebih lanjut mengenai login menggunakan App Password dapat dipelajari pada dokumentasi resmi Google.
Silakan ikuti panduan yang tersedia untuk mempelajari langkah-langkah pembuatan App Password.
Jika Anda menggunakan penyedia layanan email selain Gmail, periksa dokumentasi masing-masing penyedia mengenai cara membuat App Password. Biasanya, panduan tersebut dapat ditemukan dengan mudah melalui pencarian Google menggunakan kata kunci: “nama_penyedia_email + create app password”.
Pengkabelan BME280
Pada tutorial ini, kita akan membuat proyek contoh yang mengirimkan data hasil pembacaan sensor BME280 ke email. Oleh karena itu, sensor BME280 perlu dihubungkan terlebih dahulu ke board yang digunakan. Silakan ikuti salah satu diagram skematik pengkabelan berikut.
ESP32 dengan BME280
Komunikasi antara ESP32 dan modul sensor BME280 menggunakan protokol I2C. Hubungkan sensor BME280 ke pin I2C default pada ESP32, yaitu SCL (GPIO 22) dan SDA (GPIO 21), seperti yang ditunjukkan pada diagram skematik berikut.
ESP8266 dengan BME280
Komunikasi antara ESP8266 dan modul sensor BME280 menggunakan protokol I2C. Untuk itu, hubungkan sensor BME280 ke pin SDA (GPIO 4) dan SCL (GPIO 5) pada ESP8266, sesuai dengan diagram skematik berikut.
Mengunggah Modul uMail
Untuk mengirim email, kita akan menggunakan modul uMail. Anda dapat melihat repositori GitHub modul ini beserta beberapa contoh penggunaannya pada sumber yang tersedia. Perlu diperhatikan bahwa pustaka ini tidak termasuk dalam pustaka standar MicroPython secara default. Oleh karena itu, sebelum digunakan, Anda harus mengunggah file modul uMail ke board ESP32/ESP8266. Simpan file tersebut dengan nama `umail.py` agar dapat dipanggil dengan benar di dalam program.
import usocket
DEFAULT_TIMEOUT = 10 # sec
LOCAL_DOMAIN = '127.0.0.1'
CMD_EHLO = 'EHLO'
CMD_STARTTLS = 'STARTTLS'
CMD_AUTH = 'AUTH'
CMD_MAIL = 'MAIL'
AUTH_PLAIN = 'PLAIN'
AUTH_LOGIN = 'LOGIN'
class SMTP:
def cmd(self, cmd_str):
sock = self._sock;
sock.write('%s\r\n' % cmd_str)
resp = []
next = True
while next:
code = sock.read(3)
next = sock.read(1) == b'-'
resp.append(sock.readline().strip().decode())
return int(code), resp
def __init__(self, host, port, ssl=False, username=None, password=None):
import ssl
self.username = username
addr = usocket.getaddrinfo(host, port)[0][-1]
sock = usocket.socket(usocket.AF_INET, usocket.SOCK_STREAM)
sock.settimeout(DEFAULT_TIMEOUT)
sock.connect(addr)
if ssl:
sock = ssl.wrap_socket(sock)
code = int(sock.read(3))
sock.readline()
assert code==220, 'cant connect to server %d, %s' % (code, resp)
self._sock = sock
code, resp = self.cmd(CMD_EHLO + ' ' + LOCAL_DOMAIN)
assert code==250, '%d' % code
if not ssl and CMD_STARTTLS in resp:
code, resp = self.cmd(CMD_STARTTLS)
assert code==220, 'start tls failed %d, %s' % (code, resp)
self._sock = ssl.wrap_socket(sock)
if username and password:
self.login(username, password)
def login(self, username, password):
self.username = username
code, resp = self.cmd(CMD_EHLO + ' ' + LOCAL_DOMAIN)
assert code==250, '%d, %s' % (code, resp)
auths = None
for feature in resp:
if feature[:4].upper() == CMD_AUTH:
auths = feature[4:].strip('=').upper().split()
assert auths!=None, "no auth method"
from ubinascii import b2a_base64 as b64
if AUTH_PLAIN in auths:
cren = b64("\0%s\0%s" % (username, password))[:-1].decode()
code, resp = self.cmd('%s %s %s' % (CMD_AUTH, AUTH_PLAIN, cren))
elif AUTH_LOGIN in auths:
code, resp = self.cmd("%s %s %s" % (CMD_AUTH, AUTH_LOGIN, b64(username)[:-1].decode()))
assert code==334, 'wrong username %d, %s' % (code, resp)
code, resp = self.cmd(b64(password)[:-1].decode())
else:
raise Exception("auth(%s) not supported " % ', '.join(auths))
assert code==235 or code==503, 'auth error %d, %s' % (code, resp)
return code, resp
def to(self, addrs, mail_from=None):
mail_from = self.username if mail_from==None else mail_from
code, resp = self.cmd(CMD_EHLO + ' ' + LOCAL_DOMAIN)
assert code==250, '%d' % code
code, resp = self.cmd('MAIL FROM: <%s>' % mail_from)
assert code==250, 'sender refused %d, %s' % (code, resp)
if isinstance(addrs, str):
addrs = [addrs]
count = 0
for addr in addrs:
code, resp = self.cmd('RCPT TO: <%s>' % addr)
if code!=250 and code!=251:
print('%s refused, %s' % (addr, resp))
count += 1
assert count!=len(addrs), 'recipient refused, %d, %s' % (code, resp)
code, resp = self.cmd('DATA')
assert code==354, 'data refused, %d, %s' % (code, resp)
return code, resp
def write(self, content):
self._sock.write(content)
def send(self, content=''):
if content:
self.write(content)
self._sock.write('\r\n.\r\n') # the five letter sequence marked for ending
line = self._sock.readline()
return (int(line[:3]), line[4:].strip().decode())
def quit(self):
self.cmd("QUIT")
self._sock.close()
Terlepas dari IDE yang Anda gunakan, berikut adalah langkah-langkah umum untuk mengunggah pustaka uMail ke board:
1. Pastikan board sudah menggunakan firmware MicroPython. Silakan periksa bagian Prerequisites terlebih dahulu.
2. Buat file baru pada IDE Anda dengan nama `umail.py`, lalu salin kode modul uMail ke dalam file tersebut dan simpan.
3. Hubungkan board dengan komputer dan lakukan komunikasi serial melalui IDE yang digunakan.
4. Unggah file `umail.py` ke board ESP32/ESP8266.
5. Jika proses unggah berhasil, pustaka uMail sudah siap digunakan. Selanjutnya, Anda dapat memanfaatkan fungsi-fungsi yang tersedia dengan mengimpor pustaka tersebut ke dalam kode program menggunakan perintah: 'import umail'
Mengunggah Modul BME280
Untuk membaca data suhu, kelembapan, dan tekanan udara dari sensor BME280, kita akan menggunakan modul berikut. Sebelum diunggah ke board, pastikan file modul tersebut disimpan dengan nama `BME280.py` agar dapat digunakan dengan benar dalam program.
from machine import I2C
import time
# BME280 default address.
BME280_I2CADDR = 0x76
# Operating Modes
BME280_OSAMPLE_1 = 1
BME280_OSAMPLE_2 = 2
BME280_OSAMPLE_4 = 3
BME280_OSAMPLE_8 = 4
BME280_OSAMPLE_16 = 5
# BME280 Registers
BME280_REGISTER_DIG_T1 = 0x88 # Trimming parameter registers
BME280_REGISTER_DIG_T2 = 0x8A
BME280_REGISTER_DIG_T3 = 0x8C
BME280_REGISTER_DIG_P1 = 0x8E
BME280_REGISTER_DIG_P2 = 0x90
BME280_REGISTER_DIG_P3 = 0x92
BME280_REGISTER_DIG_P4 = 0x94
BME280_REGISTER_DIG_P5 = 0x96
BME280_REGISTER_DIG_P6 = 0x98
BME280_REGISTER_DIG_P7 = 0x9A
BME280_REGISTER_DIG_P8 = 0x9C
BME280_REGISTER_DIG_P9 = 0x9E
BME280_REGISTER_DIG_H1 = 0xA1
BME280_REGISTER_DIG_H2 = 0xE1
BME280_REGISTER_DIG_H3 = 0xE3
BME280_REGISTER_DIG_H4 = 0xE4
BME280_REGISTER_DIG_H5 = 0xE5
BME280_REGISTER_DIG_H6 = 0xE6
BME280_REGISTER_DIG_H7 = 0xE7
BME280_REGISTER_CHIPID = 0xD0
BME280_REGISTER_VERSION = 0xD1
BME280_REGISTER_SOFTRESET = 0xE0
BME280_REGISTER_CONTROL_HUM = 0xF2
BME280_REGISTER_CONTROL = 0xF4
BME280_REGISTER_CONFIG = 0xF5
BME280_REGISTER_PRESSURE_DATA = 0xF7
BME280_REGISTER_TEMP_DATA = 0xFA
BME280_REGISTER_HUMIDITY_DATA = 0xFD
class Device:
"""Class for communicating with an I2C device.
Allows reading and writing 8-bit, 16-bit, and byte array values to
registers on the device."""
def __init__(self, address, i2c):
"""Create an instance of the I2C device at the specified address using
the specified I2C interface object."""
self._address = address
self._i2c = i2c
def writeRaw8(self, value):
"""Write an 8-bit value on the bus (without register)."""
value = value & 0xFF
self._i2c.writeto(self._address, value)
def write8(self, register, value):
"""Write an 8-bit value to the specified register."""
b=bytearray(1)
b[0]=value & 0xFF
self._i2c.writeto_mem(self._address, register, b)
def write16(self, register, value):
"""Write a 16-bit value to the specified register."""
value = value & 0xFFFF
b=bytearray(2)
b[0]= value & 0xFF
b[1]= (value>>8) & 0xFF
self.i2c.writeto_mem(self._address, register, value)
def readRaw8(self):
"""Read an 8-bit value on the bus (without register)."""
return int.from_bytes(self._i2c.readfrom(self._address, 1),'little') & 0xFF
def readU8(self, register):
"""Read an unsigned byte from the specified register."""
return int.from_bytes(
self._i2c.readfrom_mem(self._address, register, 1),'little') & 0xFF
def readS8(self, register):
"""Read a signed byte from the specified register."""
result = self.readU8(register)
if result > 127:
result -= 256
return result
def readU16(self, register, little_endian=True):
"""Read an unsigned 16-bit value from the specified register, with the
specified endianness (default little endian, or least significant byte
first)."""
result = int.from_bytes(
self._i2c.readfrom_mem(self._address, register, 2),'little') & 0xFFFF
if not little_endian:
result = ((result << 8) & 0xFF00) + (result >> 8)
return result
def readS16(self, register, little_endian=True):
"""Read a signed 16-bit value from the specified register, with the
specified endianness (default little endian, or least significant byte
first)."""
result = self.readU16(register, little_endian)
if result > 32767:
result -= 65536
return result
def readU16LE(self, register):
"""Read an unsigned 16-bit value from the specified register, in little
endian byte order."""
return self.readU16(register, little_endian=True)
def readU16BE(self, register):
"""Read an unsigned 16-bit value from the specified register, in big
endian byte order."""
return self.readU16(register, little_endian=False)
def readS16LE(self, register):
"""Read a signed 16-bit value from the specified register, in little
endian byte order."""
return self.readS16(register, little_endian=True)
def readS16BE(self, register):
"""Read a signed 16-bit value from the specified register, in big
endian byte order."""
return self.readS16(register, little_endian=False)
class BME280:
def __init__(self, mode=BME280_OSAMPLE_1, address=BME280_I2CADDR, i2c=None,
**kwargs):
# Check that mode is valid.
if mode not in [BME280_OSAMPLE_1, BME280_OSAMPLE_2, BME280_OSAMPLE_4,
BME280_OSAMPLE_8, BME280_OSAMPLE_16]:
raise ValueError(
'Unexpected mode value {0}. Set mode to one of '
'BME280_ULTRALOWPOWER, BME280_STANDARD, BME280_HIGHRES, or '
'BME280_ULTRAHIGHRES'.format(mode))
self._mode = mode
# Create I2C device.
if i2c is None:
raise ValueError('An I2C object is required.')
self._device = Device(address, i2c)
# Load calibration values.
self._load_calibration()
self._device.write8(BME280_REGISTER_CONTROL, 0x3F)
self.t_fine = 0
def _load_calibration(self):
self.dig_T1 = self._device.readU16LE(BME280_REGISTER_DIG_T1)
self.dig_T2 = self._device.readS16LE(BME280_REGISTER_DIG_T2)
self.dig_T3 = self._device.readS16LE(BME280_REGISTER_DIG_T3)
self.dig_P1 = self._device.readU16LE(BME280_REGISTER_DIG_P1)
self.dig_P2 = self._device.readS16LE(BME280_REGISTER_DIG_P2)
self.dig_P3 = self._device.readS16LE(BME280_REGISTER_DIG_P3)
self.dig_P4 = self._device.readS16LE(BME280_REGISTER_DIG_P4)
self.dig_P5 = self._device.readS16LE(BME280_REGISTER_DIG_P5)
self.dig_P6 = self._device.readS16LE(BME280_REGISTER_DIG_P6)
self.dig_P7 = self._device.readS16LE(BME280_REGISTER_DIG_P7)
self.dig_P8 = self._device.readS16LE(BME280_REGISTER_DIG_P8)
self.dig_P9 = self._device.readS16LE(BME280_REGISTER_DIG_P9)
self.dig_H1 = self._device.readU8(BME280_REGISTER_DIG_H1)
self.dig_H2 = self._device.readS16LE(BME280_REGISTER_DIG_H2)
self.dig_H3 = self._device.readU8(BME280_REGISTER_DIG_H3)
self.dig_H6 = self._device.readS8(BME280_REGISTER_DIG_H7)
h4 = self._device.readS8(BME280_REGISTER_DIG_H4)
h4 = (h4 << 24) >> 20
self.dig_H4 = h4 | (self._device.readU8(BME280_REGISTER_DIG_H5) & 0x0F)
h5 = self._device.readS8(BME280_REGISTER_DIG_H6)
h5 = (h5 << 24) >> 20
self.dig_H5 = h5 | (
self._device.readU8(BME280_REGISTER_DIG_H5) >> 4 & 0x0F)
def read_raw_temp(self):
"""Reads the raw (uncompensated) temperature from the sensor."""
meas = self._mode
self._device.write8(BME280_REGISTER_CONTROL_HUM, meas)
meas = self._mode << 5 | self._mode << 2 | 1
self._device.write8(BME280_REGISTER_CONTROL, meas)
sleep_time = 1250 + 2300 * (1 << self._mode)
sleep_time = sleep_time + 2300 * (1 << self._mode) + 575
sleep_time = sleep_time + 2300 * (1 << self._mode) + 575
time.sleep_us(sleep_time) # Wait the required time
msb = self._device.readU8(BME280_REGISTER_TEMP_DATA)
lsb = self._device.readU8(BME280_REGISTER_TEMP_DATA + 1)
xlsb = self._device.readU8(BME280_REGISTER_TEMP_DATA + 2)
raw = ((msb << 16) | (lsb << 8) | xlsb) >> 4
return raw
def read_raw_pressure(self):
"""Reads the raw (uncompensated) pressure level from the sensor."""
"""Assumes that the temperature has already been read """
"""i.e. that enough delay has been provided"""
msb = self._device.readU8(BME280_REGISTER_PRESSURE_DATA)
lsb = self._device.readU8(BME280_REGISTER_PRESSURE_DATA + 1)
xlsb = self._device.readU8(BME280_REGISTER_PRESSURE_DATA + 2)
raw = ((msb << 16) | (lsb << 8) | xlsb) >> 4
return raw
def read_raw_humidity(self):
"""Assumes that the temperature has already been read """
"""i.e. that enough delay has been provided"""
msb = self._device.readU8(BME280_REGISTER_HUMIDITY_DATA)
lsb = self._device.readU8(BME280_REGISTER_HUMIDITY_DATA + 1)
raw = (msb << 8) | lsb
return raw
def read_temperature(self):
"""Get the compensated temperature in 0.01 of a degree celsius."""
adc = self.read_raw_temp()
var1 = ((adc >> 3) - (self.dig_T1 << 1)) * (self.dig_T2 >> 11)
var2 = ((
(((adc >> 4) - self.dig_T1) * ((adc >> 4) - self.dig_T1)) >> 12) *
self.dig_T3) >> 14
self.t_fine = var1 + var2
return (self.t_fine * 5 + 128) >> 8
def read_pressure(self):
"""Gets the compensated pressure in Pascals."""
adc = self.read_raw_pressure()
var1 = self.t_fine - 128000
var2 = var1 * var1 * self.dig_P6
var2 = var2 + ((var1 * self.dig_P5) << 17)
var2 = var2 + (self.dig_P4 << 35)
var1 = (((var1 * var1 * self.dig_P3) >> 8) +
((var1 * self.dig_P2) >> 12))
var1 = (((1 << 47) + var1) * self.dig_P1) >> 33
if var1 == 0:
return 0
p = 1048576 - adc
p = (((p << 31) - var2) * 3125) // var1
var1 = (self.dig_P9 * (p >> 13) * (p >> 13)) >> 25
var2 = (self.dig_P8 * p) >> 19
return ((p + var1 + var2) >> 8) + (self.dig_P7 << 4)
def read_humidity(self):
adc = self.read_raw_humidity()
# print 'Raw humidity = {0:d}'.format (adc)
h = self.t_fine - 76800
h = (((((adc << 14) - (self.dig_H4 << 20) - (self.dig_H5 * h)) +
16384) >> 15) * (((((((h * self.dig_H6) >> 10) * (((h *
self.dig_H3) >> 11) + 32768)) >> 10) + 2097152) *
self.dig_H2 + 8192) >> 14))
h = h - (((((h >> 15) * (h >> 15)) >> 7) * self.dig_H1) >> 4)
h = 0 if h < 0 else h
h = 419430400 if h > 419430400 else h
return h >> 12
@property
def temperature(self):
"Return the temperature in degrees."
t = self.read_temperature()
ti = t // 100
td = t - ti * 100
return "{}.{:02d}C".format(ti, td)
@property
def pressure(self):
"Return the temperature in hPa."
p = self.read_pressure() // 256
pi = p // 100
pd = p - pi * 100
return "{}.{:02d}hPa".format(pi, pd)
@property
def humidity(self):
"Return the humidity in percent."
h = self.read_humidity()
hi = h // 1024
hd = h * 100 // 1024 - hi * 100
return "{}.{:02d}%".format(hi, hd)
Terlepas dari IDE yang Anda gunakan, berikut adalah langkah-langkah umum untuk mengunggah pustaka BME280 ke board:
1. Pastikan board telah menggunakan firmware MicroPython. Silakan periksa bagian Prerequisites untuk memastikan hal tersebut.
2. Buat file baru pada IDE dengan nama `BME280.py`, lalu salin kode modul BME280 ke dalam file tersebut dan simpan.
3. Hubungkan board ke komputer dan lakukan komunikasi serial melalui IDE yang digunakan.
4. Unggah file `BME280.py` ke board ESP32/ESP8266.
Setelah proses unggah selesai, pustaka BME280 sudah siap digunakan. Selanjutnya, Anda dapat memanggil fungsi-fungsi yang tersedia dengan mengimpor pustaka tersebut ke dalam kode program menggunakan perintah: 'import BME280'
Mengirim Data Sensor melalui Email – MicroPython (Kode Program)
Pada tahap ini, Anda seharusnya sudah berhasil mengunggah file `umail.py` dan `BME280.py` ke board. Kedua pustaka tersebut diperlukan agar ESP32/ESP8266 dapat membaca data dari sensor BME280 sekaligus mengirimkannya melalui email.
Script berikut akan mengirimkan sebuah email berisi data pembacaan sensor terkini setiap kali board ESP32/ESP8266 dinyalakan atau dilakukan proses reset.
import umail
import network
import BME280
from machine import Pin, SoftI2C
# Your network credentials
ssid = 'REPLACE_WITH_YOUR_SSID'
password = 'REPLACE_WITH_YOUR_PASSWORD'
# Email details
sender_email = 'REPLACE_WITH_THE_SENDER_EMAIL'
sender_name = 'ESP32' #sender name
sender_app_password = 'REPLACE_WITH_THE_SENDER_EMAIL_APP_PASSWORD'
recipient_email ='REPLACE_WITH_THE_RECIPIENT_EMAIL'
email_subject ='BME280 Sensor Readings'
# BME280 pin assignment - ESP32
i2c = SoftI2C(scl=Pin(22), sda=Pin(21), freq=10000)
# BME280 pin assignment - ESP8266
#i2c = I2C(scl=Pin(5), sda=Pin(4), freq=10000)
bme = BME280.BME280(i2c=i2c)
def read_bme_sensor():
try:
temp = str(bme.temperature[:-1]) + " ºC"
#uncomment for temperature in Fahrenheit
#temp = str((bme.read_temperature()/100) * (9/5) + 32) + " 潞F"
hum = str(bme.humidity[:-1]) + " %"
pres = str(bme.pressure[:-3]) + " hPa"
return temp, hum, pres
#else:
# return('Invalid sensor readings.')
except OSError as e:
return('Failed to read sensor.')
def connect_wifi(ssid, password):
#Connect to your network
station = network.WLAN(network.STA_IF)
station.active(True)
station.connect(ssid, password)
while station.isconnected() == False:
pass
print('Connection successful')
print(station.ifconfig())
# Connect to your network
connect_wifi(ssid, password)
# Get sensor readings
temp, hum, pres = read_bme_sensor()
print(temp)
print(hum)
print(pres)
# Send the email
smtp = umail.SMTP('smtp.gmail.com', 465, ssl=True) # Gmail's SSL port
smtp.login(sender_email, sender_app_password)
smtp.to(recipient_email)
smtp.write("From:" + sender_name + "<"+ sender_email+">\n")
smtp.write("Subject:" + email_subject + "\n")
smtp.write("Temperature " + temp + "\n")
smtp.write("Humidity " + hum + "\n")
smtp.write("Pressure " + pres + "\n")
smtp.send()
smtp.quit()
Sebelum mengunggah kode ke board, Anda perlu menyesuaikan beberapa parameter sesuai dengan konfigurasi Anda, yaitu SSID dan password Wi-Fi, alamat email pengirim, nama pengirim, App Password yang sesuai, alamat email penerima, serta subjek email.
Setelah seluruh parameter diisi dengan benar, kode dapat diunggah ke board. Pastikan file program disimpan dengan nama `main.py`, karena file dengan nama inilah yang akan dieksekusi secara otomatis saat ESP32/ESP8266 dinyalakan. Jika menggunakan nama file lain, program tidak akan berjalan.
Cara Kerja Program
Silakan lanjutkan membaca untuk memahami penjelasan alur kerja kode, atau langsung menuju bagian Demonstrasi jika ingin melihat hasil akhirnya.
Menyertakan Library
Langkah pertama adalah menyertakan pustaka-pustaka yang diperlukan. Library uMail digunakan untuk mengirim email dan telah diunggah sebelumnya ke board. Library network digunakan untuk mengatur ESP32/ESP8266 sebagai Wi-Fi station agar dapat terhubung ke jaringan internet (jaringan lokal).
Selain itu, modul BME280 diimpor untuk membaca data dari sensor BME280, serta kelas pin dan I2C dari modul machine digunakan untuk membangun komunikasi I2C antara board dan sensor.
import umail # Micropython lib to send emails: https://github.com/shawwwn/uMail
import network
import BME280
from machine import Pin, SoftI2C
Kredensial Jaringan
Masukkan kredensial jaringan Anda, yaitu SSID dan password Wi-Fi, ke dalam variabel berikut agar board dapat terhubung ke jaringan internet.
ssid = 'REPLACE_WITH_YOUR_SSID'
password = 'REPLACE_WITH_YOUR_PASSWORD'
Detail Email
Masukkan informasi email yang diperlukan, yaitu alamat email pengirim, nama pengirim, serta App Password yang sesuai. Pastikan Anda telah membuat App Password, karena penggunaan password email biasa tidak akan berfungsi. Silakan merujuk ke panduan pembuatan App Password yang telah dijelaskan sebelumnya.
# Email details
sender_email = 'REPLACE_WITH_THE_SENDER_EMAIL'
sender_name = 'ESP32' #sender name
sender_app_password = 'REPLACE_WITH_THE_SENDER_EMAIL_APP_PASSWORD'
Masukkan alamat email penerima ke dalam variabel `recipient_email` berikut.
recipient_email ='REPLACE_WITH_THE_RECIPIENT_EMAIL'
BME280
Subjek email secara default diatur sebagai “BME280 Sensor Readings”, namun Anda dapat mengubahnya sesuai kebutuhan dengan menyesuaikan nilai pada variabel `email_subject`.
email_subject ='BME280 Sensor Readings'
Buat objek I2C menggunakan pin I2C pada board. Pada ESP32, komunikasi I2C menggunakan GPIO 22 sebagai SCL dan GPIO 21 sebagai SDA.
i2c = SoftI2C(scl=Pin(22), sda=Pin(21), freq=10000)
Jika Anda menggunakan board ESP8266, gunakan GPIO 4 sebagai SDA dan GPIO 5 sebagai **SCL** sebagai pengganti.
i2c = I2C(scl=Pin(5), sda=Pin(4), freq=10000)
Jika Anda menggunakan board dengan konfigurasi pin I2C yang berbeda, pastikan untuk menyesuaikan baris kode tersebut sesuai dengan pin yang digunakan.
Setelah objek I2C berhasil dibuat, selanjutnya kita dapat membuat objek BME280 (pada contoh ini diberi nama `bme`) yang akan berkomunikasi melalui pin-pin I2C tersebut.
bme = BME280.BME280(i2c=i2c)
Membaca BME280: Suhu, Kelembaban, dan Tekanan
Untuk membaca data dari sensor BME280, kita membuat sebuah fungsi bernama `read_bme_sensor()` yang mengembalikan nilai suhu, kelembapan, dan tekanan dalam bentuk string beserta satuan masing-masing. Format ini sangat ideal untuk langsung digunakan dalam isi email.
def read_bme_sensor():
try:
temp = str(bme.temperature[:-1]) + " ºC"
#uncomment for temperature in Fahrenheit
#temp = str((bme.read_temperature()/100) * (9/5) + 32) + " ºF"
hum = str(bme.humidity[:-1]) + " %"
pres = str(bme.pressure[:-3]) + " hPa"
return temp, hum, pres
#else:
# return('Invalid sensor readings.')
except OSError as e:
return('Failed to read sensor.')
Secara default, fungsi ini mengembalikan nilai suhu dalam satuan derajat Celcius. Jika Anda ingin mendapatkan suhu dalam satuan Fahrenheit, cukup hapus komentar pada baris kode berikut:
#temp = str((bme.read_temperature()/100) * (9/5) + 32) + " ºF"
Menghubungkan ke Wi-Fi
Untuk menghubungkan board ke jaringan Wi-Fi, kita membuat sebuah fungsi bernama `connect_wifi()` yang menerima SSID dan password dari jaringan yang ingin digunakan sebagai argumen. Fungsi ini harus dipanggil nantinya agar board ESP dapat benar-benar terhubung ke internet.
def connect_wifi(ssid, password):
#Connect to your network
station = network.WLAN(network.STA_IF)
station.active(True)
station.connect(ssid, password)
while station.isconnected() == False:
pass
print('Connection successful')
print(station.ifconfig())
Sebelum mengirim email, kita perlu menghubungkan ESP32/ESP8266 ke internet. Panggil fungsi `connect_wifi()` dan berikan SSID serta password sebagai argumennya.
# Connect to your network
connect_wifi(ssid, password)
Mendapatkan Data Terbaru
Untuk memperoleh data dari sensor dalam format yang diinginkan, cukup panggil fungsi `read_bme_sensor()` yang telah dibuat sebelumnya. Nilai suhu, kelembapan, dan tekanan disimpan pada variabel `temp`, `hum`, dan `pres`. Ketiga variabel ini berupa string yang sudah menyertakan satuan masing-masing (ºC, %, dan hPa). Baris-baris kode berikut akan mengambil pembacaan terbaru dan menampilkannya di shell.
# Get sensor readings
temp, hum, pres = read_bme_sensor()
print(temp)
print(hum)
print(pres)
Mengirim Email
Sekarang, kita dapat mulai menyiapkan dan mengirim email.
Mulailah dengan membuat SMTP client menggunakan pengaturan SMTP dari penyedia email Anda, dan simpan dengan nama `smtp`. Pada contoh ini, digunakan akun Gmail. Jika Anda menggunakan penyedia email lain, ubah pengaturan server, port, serta tentukan apakah SSL diperlukan atau tidak sesuai kebutuhan.
smtp = umail.SMTP('smtp.gmail.com', 465, ssl=True) # Gmail's SSL port
Selanjutnya, login ke akun email Anda menggunakan metode `login()` pada objek `smtp`, dengan memasukkan alamat email dan App Password yang sesuai sebagai argumen.
smtp.login(sender_email, sender_app_password)
Tentukan penerima email menggunakan metode `to()` dan berikan alamat email penerima sebagai argumennya:
smtp.to(recipient_email)
Selanjutnya, gunakan metode `write()` untuk menulis isi email. Metode ini juga dapat digunakan untuk menetapkan nama pengirim seperti contoh berikut.
smtp.write("From:" + sender_name + "<"+ sender_email+">\n")
Dan Anda dapat menggunakan baris kode berikut untuk menetapkan subjek email.
smtp.write("Subject:" + email_subject + "\n")
Terakhir, Anda dapat menulis isi email. Pada contoh ini, yang dikirim adalah nilai suhu, kelembaban, dan tekanan dalam badan email, namun Anda juga bisa menambahkan teks tambahan atau menggunakan HTML untuk memformat isi email. Metode `write()` akan mengirim email tersebut ke server SMTP.
smtp.write("Temperature " + temp + "\n")
smtp.write("Humidity " + hum + "\n")
smtp.write("Pressure " + pres + "\n")
Jika Anda perlu mengirim pesan email yang panjang, bagi isi email menjadi beberapa bagian kecil dan kirim setiap bagian menggunakan metode `write()`, lihat dokumentasi library uMail untuk referensi lebih lengkap.
Terakhir, gunakan metode `send()` agar server SMTP mengirimkan email tersebut ke penerima.
smtp.send()
Terakhir, tutup koneksi dengan server menggunakan metode `quit()`.
smtp.quit()
Demonstrasi
Setelah mengunggah modul uMail, BME280, dan skrip `main.py` ke board, jalankan kode atau lakukan reset/restart pada board. Anda seharusnya melihat pesan serupa di shell yang menandakan bahwa board berhasil terhubung ke internet dan menampilkan pembacaan sensor terkini.
Setelah beberapa saat, Anda akan menerima email baru di akun email penerima.
Buka email tersebut untuk memeriksa data pembacaan sensor terkini.
Siap Untuk Membuat Proyek Impianmu Menjadi Kenyataan?
Klik di sini untuk chat langsung via WhatsApp dan dapatkan dukungan langsung dari tim ahli kami!








0 on: "MicroPython - Mengirim Data Sensor melalui Email menggunakan ESP32/ESP8266 (BME280)"