Blog Archive

Arduino Indonesia. Gambar tema oleh Storman. Diberdayakan oleh Blogger.

Supported by Electronics 3 in 1

1. Jasa pencetakan PCB single layer dengan harga paling murah.

(Metode Pembuatan dengan Transfer Toner)
>PCB design sendiri (siap cetak) : Rp.150,-/Cm2
>PCB design dari kami : Rp.250,-/Cm2

(Metode Sablon Full Masking dan Silk Screen minimal pemesanan 100 Pcs)
>PCB design sendiri (siap cetak) : Rp.200,-/Cm2
>PCB design dari kami : Rp.250,-/Cm2

2. Jasa perancangan, perakitan, dan pembuatan trainer pembelajaran elektronika untuk SMK dan Mahasiswa.

3. Jasa perancangan, perakitan, dan pembuatan berbagai macam kontroller, sensor, aktuator, dan tranduser.
>Design Rangkaian / Sistem Elektronika
>Design Rangkaian / Sistem Instrumentasi
>Design Rangkaian / Sistem Kendali
>Kerjasama Riset (data atau peralatan)
>Kerjasama Produksi Produk-Produk KIT Elektronika
>Produksi Instrumentasi Elektronika

4. Jasa Pembuatan Proyek, Tugas Akhir, Tugas Laboratorium, PKM, Karya Ilmiah, SKRIPSI, dll

Like My Facebook

Popular Posts

Kamis, 25 Desember 2025

Tutorial MicroPython ESP32/ESP8266 - Publish Data Sensor BME280 via MQTT

Pelajari cara memprogram papan ESP32 atau ESP8266 dengan MicroPython untuk menerbitkan pembacaan sensor BME280 (suhu, kelembaban, dan tekanan) via MQTT ke platform apa pun yang mendukung MQTT atau ke klien MQTT mana pun. Sebagai contoh, kami akan menerbitkan data sensor ke Node-RED Dashboard.

Gambaran Proyek

Diagram berikut menunjukkan gambaran tingkat tinggi dari proyek yang akan kita bangun.


1. ESP membaca data suhu, kelembapan, dan tekanan dari sensor BME280.

2. Data suhu diterbitkan (published) ke topik esp/bme280/temperature.

3. Data kelembapan diterbitkan ke topik esp/bme280/humidity.

4. Data tekanan diterbitkan ke topik esp/bme280/pressure.

5. Node-RED berlangganan (subscribe) ke topik-topik tersebut.

6. Node-RED menerima data sensor dan menampilkannya pada dashboard.

7. Anda dapat menerima data di platform lain yang mendukung MQTT dan mengolahnya sesuai kebutuhan.

MQTT Broker

Untuk menggunakan MQTT, Anda memerlukan sebuah broker. Kami akan menggunakan broker Mosquitto yang diinstal pada Raspberry Pi.

Komponen yang Diperlukan

Untuk tutorial ini, Anda memerlukan komponen-komponen berikut:

- ESP32 atau ESP8266

- Sensor BME280

- Papan Raspberry Pi

- Kartu MicroSD – 16GB Class10

- Catu Daya Raspberry Pi (5V 2.5A)

- Kabel jumper

- Papan breadboard

Library umqttsimple

Untuk menggunakan MQTT dengan ESP32/ESP8266 dan MicroPython, kami akan menggunakan library `umqttsimple.py`. Ikuti set instruksi berikut sesuai dengan IDE yang Anda gunakan:

- Unggah Library `umqttsimple` dengan uPyCraft IDE

- Unggah Library `umqttsimple` dengan Thonny IDE

 

try:

    import usocket as socket

except:

    import socket

import ustruct as struct

from ubinascii import hexlify


class MQTTException(Exception):

    pass


class MQTTClient:


    def __init__(self, client_id, server, port=0, user=None, password=None, keepalive=0,

                 ssl=False, ssl_params={}):

        if port == 0:

            port = 8883 if ssl else 1883

        self.client_id = client_id

        self.sock = None

        self.server = server

        self.port = port

        self.ssl = ssl

        self.ssl_params = ssl_params

        self.pid = 0

        self.cb = None

        self.user = user

        self.pswd = password

        self.keepalive = keepalive

        self.lw_topic = None

        self.lw_msg = None

        self.lw_qos = 0

        self.lw_retain = False


    def _send_str(self, s):

        self.sock.write(struct.pack("!H", len(s)))

        self.sock.write(s)


    def _recv_len(self):

        n = 0

        sh = 0

        while 1:

            b = self.sock.read(1)[0]

            n |= (b & 0x7f) << sh

            if not b & 0x80:

                return n

            sh += 7


    def set_callback(self, f):

        self.cb = f


    def set_last_will(self, topic, msg, retain=False, qos=0):

        assert 0 <= qos <= 2

        assert topic

        self.lw_topic = topic

        self.lw_msg = msg

        self.lw_qos = qos

        self.lw_retain = retain


    def connect(self, clean_session=True):

        self.sock = socket.socket()

        addr = socket.getaddrinfo(self.server, self.port)[0][-1]

        self.sock.connect(addr)

        if self.ssl:

            import ussl

            self.sock = ussl.wrap_socket(self.sock, **self.ssl_params)

        premsg = bytearray(b"\x10\0\0\0\0\0")

        msg = bytearray(b"\x04MQTT\x04\x02\0\0")


        sz = 10 + 2 + len(self.client_id)

        msg[6] = clean_session << 1

        if self.user is not None:

            sz += 2 + len(self.user) + 2 + len(self.pswd)

            msg[6] |= 0xC0

        if self.keepalive:

            assert self.keepalive < 65536

            msg[7] |= self.keepalive >> 8

            msg[8] |= self.keepalive & 0x00FF

        if self.lw_topic:

            sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg)

            msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3

            msg[6] |= self.lw_retain << 5


        i = 1

        while sz > 0x7f:

            premsg[i] = (sz & 0x7f) | 0x80

            sz >>= 7

            i += 1

        premsg[i] = sz


        self.sock.write(premsg, i + 2)

        self.sock.write(msg)

        #print(hex(len(msg)), hexlify(msg, ":"))

        self._send_str(self.client_id)

        if self.lw_topic:

            self._send_str(self.lw_topic)

            self._send_str(self.lw_msg)

        if self.user is not None:

            self._send_str(self.user)

            self._send_str(self.pswd)

        resp = self.sock.read(4)

        assert resp[0] == 0x20 and resp[1] == 0x02

        if resp[3] != 0:

            raise MQTTException(resp[3])

        return resp[2] & 1


    def disconnect(self):

        self.sock.write(b"\xe0\0")

        self.sock.close()


    def ping(self):

        self.sock.write(b"\xc0\0")


    def publish(self, topic, msg, retain=False, qos=0):

        pkt = bytearray(b"\x30\0\0\0")

        pkt[0] |= qos << 1 | retain

        sz = 2 + len(topic) + len(msg)

        if qos > 0:

            sz += 2

        assert sz < 2097152

        i = 1

        while sz > 0x7f:

            pkt[i] = (sz & 0x7f) | 0x80

            sz >>= 7

            i += 1

        pkt[i] = sz

        #print(hex(len(pkt)), hexlify(pkt, ":"))

        self.sock.write(pkt, i + 1)

        self._send_str(topic)

        if qos > 0:

            self.pid += 1

            pid = self.pid

            struct.pack_into("!H", pkt, 0, pid)

            self.sock.write(pkt, 2)

        self.sock.write(msg)

        if qos == 1:

            while 1:

                op = self.wait_msg()

                if op == 0x40:

                    sz = self.sock.read(1)

                    assert sz == b"\x02"

                    rcv_pid = self.sock.read(2)

                    rcv_pid = rcv_pid[0] << 8 | rcv_pid[1]

                    if pid == rcv_pid:

                        return

        elif qos == 2:

            assert 0


    def subscribe(self, topic, qos=0):

        assert self.cb is not None, "Subscribe callback is not set"

        pkt = bytearray(b"\x82\0\0\0")

        self.pid += 1

        struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid)

        #print(hex(len(pkt)), hexlify(pkt, ":"))

        self.sock.write(pkt)

        self._send_str(topic)

        self.sock.write(qos.to_bytes(1, "little"))

        while 1:

            op = self.wait_msg()

            if op == 0x90:

                resp = self.sock.read(4)

                #print(resp)

                assert resp[1] == pkt[2] and resp[2] == pkt[3]

                if resp[3] == 0x80:

                    raise MQTTException(resp[3])

                return


    # Wait for a single incoming MQTT message and process it.

    # Subscribed messages are delivered to a callback previously

    # set by .set_callback() method. Other (internal) MQTT

    # messages processed internally.

    def wait_msg(self):

        res = self.sock.read(1)

        self.sock.setblocking(True)

        if res is None:

            return None

        if res == b"":

            raise OSError(-1)

        if res == b"\xd0":  # PINGRESP

            sz = self.sock.read(1)[0]

            assert sz == 0

            return None

        op = res[0]

        if op & 0xf0 != 0x30:

            return op

        sz = self._recv_len()

        topic_len = self.sock.read(2)

        topic_len = (topic_len[0] << 8) | topic_len[1]

        topic = self.sock.read(topic_len)

        sz -= topic_len + 2

        if op & 6:

            pid = self.sock.read(2)

            pid = pid[0] << 8 | pid[1]

            sz -= 2

        msg = self.sock.read(sz)

        self.cb(topic, msg)

        if op & 6 == 2:

            pkt = bytearray(b"\x40\x02\0\0")

            struct.pack_into("!H", pkt, 2, pid)

            self.sock.write(pkt)

        elif op & 6 == 4:

            assert 0


    # Checks whether a pending message from server is available.

    # If not, returns immediately with None. Otherwise, does

    # the same processing as wait_msg.

    def check_msg(self):

        self.sock.setblocking(False)

        return self.wait_msg()

 

Unggah Library umqttsimple dengan uPyCraft IDE

1. Buat file baru dengan menekan tombol New File.

2. Salin kode pustaka `umqttsimple` ke dalamnya.

3. Simpan file dengan menekan tombol Save.

4. Beri nama file baru ini `umqttsimple.py` dan tekan OK.

5.  Klik tombol Download and Run.

6.  File tersebut akan tersimpan di folder perangkat dengan nama `umqttsimple.py`, seperti yang ditunjukkan pada gambar di bawah.


Sekarang, Anda dapat menggunakan fungsi-fungsi pustaka dalam kode Anda dengan mengimpornya.

Unggah Pustaka umqttsimple dengan Thonny IDE

1.  Salin kode library ke dalam file baru.

2.  Buka menu File > Save as….



3.  Pilih opsi simpan ke "MicroPython device" (Simpan ke perangkat MicroPython).



4.  Beri nama file Anda `umqttsimple.py` dan tekan tombol OK.


Selesai. Pustaka telah berhasil diunggah ke papan Anda. Untuk memastikan pengunggahan berhasil, buka File > Save as… dan pilih MicroPython device. File Anda akan terdaftar di sana.

Setelah pustaka berhasil diunggah ke papan ESP, Anda dapat menggunakan fungsinya dalam kode dengan mengimpornya.

Library MicroPython untuk BME280

Pustaka untuk membaca data dari sensor BME280 tidak termasuk dalam library standar MicroPython secara default. Oleh karena itu, Anda perlu mengunggah pustaka berikut ke papan ESP32/ESP8266 Anda (simpan dengan nama `bme280.py`).

 

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)

 

Skematik: ESP32 dengan BME280

Hubungkan sensor BME280 ke papan pengembangan ESP32 seperti yang ditunjukkan pada diagram skematik berikut.



Skematik: ESP8266 NodeMCU dengan BME280

Jika Anda menggunakan ESP8266 NodeMCU, ikuti diagram berikut.

 

Kode

Setelah mengunggah pustaka-pustaka ke ESP32 atau ESP8266, salin kode berikut ke file `main.py`. Kode ini akan menerbitkan (publish) data suhu, kelembapan, dan tekanan ke topik esp/bme280/temperature, esp/bme280/humidity, dan esp/bme280/pressure setiap 5 detik.

 

import time

from umqttsimple import MQTTClient

import ubinascii

import machine

import micropython

import network

import esp

import BME280

from machine import Pin, I2C


esp.osdebug(None)

import gc

gc.collect()


ssid = 'REPLACE_WITH_YOUR_SSID'

password = 'REPLACE_WITH_YOUR_PASSWORD'

mqtt_server = '192.168.1.XXX'

#EXAMPLE IP ADDRESS

#mqtt_server = '192.168.1.106'


client_id = ubinascii.hexlify(machine.unique_id())


topic_pub_temp = b'esp/bme280/temperature'

topic_pub_hum = b'esp/bme280/humidity'

topic_pub_pres = b'esp/bme280/pressure'


last_message = 0

message_interval = 5


station = network.WLAN(network.STA_IF)


station.active(True)

station.connect(ssid, password)


while station.isconnected() == False:

  pass


print('Connection successful')


# ESP32 - Pin assignment

i2c = I2C(scl=Pin(22), sda=Pin(21), freq=10000)

# ESP8266 - Pin assignment

#i2c = I2C(scl=Pin(5), sda=Pin(4), freq=10000)

bme = BME280.BME280(i2c=i2c)


def connect_mqtt():

  global client_id, mqtt_server

  client = MQTTClient(client_id, mqtt_server)

  #client = MQTTClient(client_id, mqtt_server, user=your_username, password=your_password)

  client.connect()

  print('Connected to %s MQTT broker' % (mqtt_server))

  return client


def restart_and_reconnect():

  print('Failed to connect to MQTT broker. Reconnecting...')

  time.sleep(10)

  machine.reset()


def read_bme_sensor():

  try:

    temp = b'%s' % bme.temperature[:-1]

    #temp = (b'{0:3.1f},'.format((bme.read_temperature()/100) * (9/5) + 32))

    hum = b'%s' % bme.humidity[:-1]

    pres = b'%s'% bme.pressure[:-3]


    return temp, hum, pres

    #else:

    #  return('Invalid sensor readings.')

  except OSError as e:

    return('Failed to read sensor.')


try:

  client = connect_mqtt()

except OSError as e:

  restart_and_reconnect()


while True:

  try:

    if (time.time() - last_message) > message_interval:

      temp, hum, pres = read_bme_sensor()

      print(temp)

      print(hum)

      print(pres)

      client.publish(topic_pub_temp, temp)

      client.publish(topic_pub_hum, hum)      

      client.publish(topic_pub_pres, pres)


      last_message = time.time()

  except OSError as e:

    restart_and_reconnect()

 

Cara Kerja Kode

Impor library-library berikut:

 

import time

from umqttsimple import MQTTClient

import ubinascii

import machine

import micropython

import network

import esp

import BME280

from machine import Pin, I2C

 

Pada variabel berikut, Anda perlu memasukkan kredensial jaringan dan alamat IP broker MQTT Anda.

 

ssid = 'REPLACE_WITH_YOUR_SSID'

password = 'REPLACE_WITH_YOUR_PASSWORD'

mqtt_server = 'REPLACE_WITH_YOUR_MQTT_BROKER_IP'

 

Sebagai contoh, alamat IP broker kami adalah: 192.168.1.106.

 

mqtt_server = '192.168.1.106'

 

Untuk membuat klien MQTT, kita perlu mendapatkan ID unik ESP. Itulah yang kita lakukan pada baris berikut (ID disimpan dalam variabel `client_id`).

 

client_id = ubinascii.hexlify(machine.unique_id())

 

Selanjutnya, buat topik-topik di mana ESP Anda akan menerbitkan data. Dalam contoh kami, ESP akan menerbitkan:

- Suhu ke topik esp/bme280/temperature

- Kelembaban ke topik esp/bme280/humidity

- Tekanan ke topik esp/bme280/pressure

 

topic_pub_temp = b'esp/bme280/temperature'

topic_pub_hum = b'esp/bme280/humidity'

topic_pub_pres = b'esp/bme280/pressure'

 

Kemudian, buat variabel-variabel berikut:

 

last_message = 0

message_interval = 5

 

Variabel `last_message` akan menyimpan waktu terakhir sebuah pesan dikirim. `message_interval` adalah interval waktu antara setiap pesan yang dikirim. Di sini, kami mengaturnya menjadi 5 detik (artinya pesan baru akan dikirim setiap 5 detik). Anda dapat mengubahnya sesuai keinginan.

 

Setelah itu, hubungkan ESP ke jaringan lokal Anda.

 

station = network.WLAN(network.STA_IF)


station.active(True)

station.connect(ssid, password)


while station.isconnected() == False:

  pass


print('Connection successful')

 

Buat instance `i2c` pada pin I2C ESP32 untuk berkomunikasi dengan sensor BME280:

 

i2c = I2C(scl=Pin(22), sda=Pin(21), freq=10000)

 

Jika Anda menggunakan ESP8266, gunakan baris berikut sebagai gantinya (untuk menggunakan pin I2C default ESP8266).

 

#i2c = I2C(scl=Pin(5), sda=Pin(4), freq=10000)

 

Buat instance BME280 pada pin I2C ESP:

 

bme = BME280.BME280(i2c=i2c)

 

Terhubung ke Broker MQTT

Fungsi `connect_mqtt()` membuat Klien MQTT dan menghubungkannya ke broker Anda.

 

def connect_mqtt():

  global client_id, mqtt_server

  client = MQTTClient(client_id, mqtt_server)

  #client = MQTTClient(client_id, mqtt_server, user=your_username, password=your_password)

  client.connect()

  print('Connected to %s MQTT broker' % (mqtt_server))

  return client

 

Jika broker MQTT Anda memerlukan username dan password, Anda harus menggunakan baris berikut dan memberikan username serta password broker sebagai argumen.

 

client = MQTTClient(client_id, mqtt_server, user=your_username, password=your_password)

Restart dan Sambung Ulang

Fungsi `restart_and_reconnect()` me-reset papan ESP32/ESP8266. Fungsi ini akan dipanggil jika kita tidak dapat menerbitkan pembacaan via MQTT (misalnya karena broker terputus).

 

def restart_and_reconnect():

  print('Failed to connect to MQTT broker. Reconnecting...')

  time.sleep(10)

  machine.reset()

 

Membaca Sensor BME280

Kami membuat fungsi bernama `read_bme_sensor()` yang mengembalikan pembacaan suhu, kelembaban, dan tekanan terkini dari sensor BME280, serta menangani pengecualian jika gagal membaca sensor.

 

def read_bme_sensor():

  try:

    temp = b'%s' % bme.temperature[:-1]

    #temp = (b'{0:3.1f},'.format((bme.read_temperature()/100) * (9/5) + 32))

    hum = b'%s' % bme.humidity[:-1]

    pres = b'%s'% bme.pressure[:-3]


    return temp, hum, pres

    #else:

    #  return('Invalid sensor readings.')

  except OSError as e:

    return('Failed to read sensor.')

 

Menerbitkan Pesan MQTT

Di dalam perulangan `while`, kami menerbitkan pembacaan baru dari BME280 setiap 5 detik.

Pertama, kami memeriksa apakah sudah waktunya untuk mendapatkan pembacaan baru:

 

if (time.time() - last_message) > message_interval:

 

Jika ya, minta pembacaan baru dari sensor BME280 dengan memanggil fungsi `read_bme_sensor()`. Suhu disimpan dalam variabel `temp`, kelembaban dalam variabel `hum`, dan tekanan dalam variabel `pres`.

 

temp, hum, pres = read_bme_sensor()

 

Terakhir, terbitkan pembacaan tersebut dengan menggunakan metode `publish()` pada objek `client`. Metode `publish()` menerima argumen berupa topik dan pesan, seperti berikut:

 

client.publish(topic_pub_temp, temp)

client.publish(topic_pub_hum, hum)

client.publish(topic_pub_pres, pres)

 

Terakhir, perbarui waktu ketika pesan terakhir dikirim:

 

last_message = time.time()

 

Jika ESP32 atau ESP8266 terputus dari broker dan tidak dapat menerbitkan pembacaan, panggil fungsi `restart_and_reconnect()` untuk me-reset papan ESP dan mencoba menyambung kembali ke broker.

 

except OSError as e:

  restart_and_reconnect()

 

Setelah mengunggah kode, Anda akan mendapatkan pembacaan sensor baru di shell setiap 5 detik.

Sekarang, lanjutkan ke bagian berikutnya untuk menyiapkan Node-RED guna menerima data yang diterbitkan oleh ESP.

Mempersiapkan Dashboard Node-RED

ESP32 atau ESP8266 kini menerbitkan data sensor setiap 5 detik ke topik `esp/bme280/temperature`, `esp/bme280/humidity`, dan `esp/bme280/pressure`. Anda dapat menggunakan dashboard apa pun yang mendukung MQTT, atau perangkat lain yang mendukung MQTT, untuk berlangganan (subscribe) ke topik-topik tersebut dan menerima datanya.

 

Sebagai contoh, kami akan membuat alur (flow) sederhana menggunakan Node-RED untuk berlangganan ke topik-topik tersebut dan menampilkan datanya pada gauge.

Dengan Node-RED berjalan di Raspberry Pi Anda, buka alamat IP Raspberry Pi diikuti dengan `:1880`.

http://alamat-ip-raspberry-pi:1880

Antarmuka Node-RED akan terbuka. Seret tiga node "mqtt in" dan tiga node "gauge" ke dalam alur (flow).

Klik node MQTT dan edit propertinya.



Kolom Server merujuk ke broker MQTT. Dalam kasus kami, broker MQTT adalah Raspberry Pi itu sendiri, sehingga diatur ke `localhost:1883`. Jika Anda menggunakan broker MQTT cloud, Anda harus mengubah kolom tersebut.

 

Masukkan topik yang ingin Anda langgani dan QoS-nya. Node MQTT ini berlangganan ke topik `esp/bme280/temperature`.

 

Klik pada node mqtt in lainnya dan edit propertinya dengan server yang sama, namun untuk topik lain: `esp/bme280/humidity` dan `esp/bme280/pressure`.

 

Klik pada node gauge dan edit propertinya untuk setiap jenis pembacaan. Node berikut diatur untuk pembacaan suhu. Edit node gauge lainnya untuk pembacaan kelembapan dan tekanan.



Hubungkan node-node Anda seperti yang ditunjukkan di bawah:



Terakhir, deploy alur Anda (tekan tombol di sudut kanan atas).

Sebagai alternatif, Anda dapat membuka Menu > Import dan menyalin kode berikut ke Clipboard untuk membuat alur Node-RED Anda.

 

[{"id":"5a45b8da.52b0d8","type":"mqtt in","z":"b01416d3.f69f38","name":"","topic":"esp/bme280/temperature","qos":"1","datatype":"auto","broker":"8db3fac0.99dd48","x":310,"y":60,"wires":[["3042e15e.80a4ee"]]},{"id":"3042e15e.80a4ee","type":"ui_gauge","z":"b01416d3.f69f38","name":"","group":"37de8fe8.46846","order":2,"width":0,"height":0,"gtype":"gage","title":"Temperature","label":"ÂșC","format":"{{value}}","min":0,"max":"40","colors":["#00b500","#f7df09","#ca3838"],"seg1":"","seg2":"","x":590,"y":60,"wires":[]},{"id":"8ff168f0.0c74a8","type":"mqtt in","z":"b01416d3.f69f38","name":"","topic":"esp/bme280/humidity","qos":"1","datatype":"auto","broker":"8db3fac0.99dd48","x":300,"y":140,"wires":[["29251f29.6687c"]]},{"id":"29251f29.6687c","type":"ui_gauge","z":"b01416d3.f69f38","name":"","group":"37de8fe8.46846","order":2,"width":0,"height":0,"gtype":"gage","title":"Humidity","label":"%","format":"{{value}}","min":"30","max":"100","colors":["#53a4e6","#1d78a9","#4e38c9"],"seg1":"","seg2":"","x":580,"y":140,"wires":[]},{"id":"294f7eea.999d72","type":"mqtt in","z":"b01416d3.f69f38","name":"","topic":"esp/bme280/pressure","qos":"1","datatype":"auto","broker":"8db3fac0.99dd48","x":300,"y":220,"wires":[["58610d70.bb9764"]]},{"id":"58610d70.bb9764","type":"ui_gauge","z":"b01416d3.f69f38","name":"","group":"37de8fe8.46846","order":4,"width":0,"height":0,"gtype":"gage","title":"Pressure","label":"hPa","format":"{{value}}","min":0,"max":"1200","colors":["#b366ff","#8000ff","#440088"],"seg1":"","seg2":"","x":580,"y":220,"wires":[]},{"id":"8db3fac0.99dd48","type":"mqtt-broker","z":"","name":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":false,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"37de8fe8.46846","type":"ui_group","z":"","name":"BME280","tab":"53b8c8f9.cfbe48","order":1,"disp":true,"width":"6","collapse":false},{"id":"53b8c8f9.cfbe48","type":"ui_tab","z":"","name":"Home","icon":"dashboard","order":2,"disabled":false,"hidden":false}]

 

Demonstrasi

Buka alamat IP Raspberry Pi Anda diikuti dengan `:1880/ui`.

http://raspberry-pi-ip-address:1880/ui

Anda akan mendapatkan akses ke pembacaan suhu, kelembaban, dan tekanan BME280 terkini di Dashboard. Anda dapat menggunakan node tipe dashboard lainnya untuk menampilkan data dengan cara yang berbeda.



Selesai! Kini papan ESP32 atau ESP8266 Anda telah menerbitkan pembacaan suhu, kelembapan, dan tekanan dari BME280 ke Node-RED via MQTT menggunakan MicroPython.

 

 

 

 

 

 

 

 

 

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: "Tutorial MicroPython ESP32/ESP8266 - Publish Data Sensor BME280 via MQTT"