Mailbox IoT ESP 32 Project

Preamble

Out of curiosity I bought a ESP32 board to tinker with, but for almost half a year hadn’t got an idea what to do with it… But then!

Project Idea

The idea: Every time I get mail into my physical snail mail mailbox, the mailbox shall send a message via Telegram to my smartphone:

But with many ideas the execution can become time consuming. Well, let’s see 🙂

MicroPython

As a Python afficionado I was relieved as I found out, that you can use MicroPython on the ESP32 board. I wrote a separate article as a prerequisite:

Using MicroPython on FireBeetle ESP32

From now on I assume, that You have a MicroPython version running on the ESP32.

Buttons

When the lid of the mailbox is opened, a button shall trigger the action, so we need to configure a GPIO as an input.

This is done via the machine package.

When we don’t want to have external pullups we can enable the internal pullup resistor. Beware: the logic becomes inverted, because the pin is high in idle we pull it down with the button to 0 volts, hence button pressed equals value zero

import machine

button = machine.Pin(4, machine.Pin.IN, machine.Pin.PULL_UP)

while True:
    if not button.value():
        print('Button pressed!')

Deep Sleep

Due to the fact that the device will be battery powered and will just need to send a message once or twice a day, we will need the deepsleep capability.

The machine package gives you access to the deepsleep function as well.

A bit counterintuitive but you also need the esp32 package for defining a wake up cause. One caveat: not every GPIO is able to wake up the ESP32 from deepsleep but GPIO 4 will do it.

import machine 
import esp32 
from time import sleep 

wake1 = machine.Pin(4, machine.Pin.IN, machine.Pin.PULL_UP) 
esp32.wake_on_ext0(pin=wake1, level=esp32.WAKEUP_ALL_LOW) 
print('Im awake. Going to sleep in 10 seconds') 
sleep(10) 
print('Going to sleep now') 

machine.deepsleep()

Setting up Wifi in MicroPython

To be able to send messages we need a WiFi connection. In MicroPython this is handled by the network package.

import network

The ESP32 can either work as a station or as an access point. We need the first option so we use the STA_IF configuration.

sta_if = network.WLAN(network.STA_IF)

the interface has to be activated via

sta_if.active(True)

Now we can connect to our Wi-Fi

sta_if.connect(ssid,  password)

You can check the status of the connection via:

sta_if.isconnected():

Writing a Telegram Bot

Create TG bot

  1. Open Telegram app on your phone
  2. Search for @botfather
  3. Start chat
  4. Send /newbot
  5. Pick a name
  6. Pick a username (must be unique)
  7. Receive credentials

Chat with your bot

Now you can search for your bot’s name and send a message

Python test Program

Telegram has a nice python package which you can pip install

pip install python-telegram-bot --upgrade
import telegram

bot = telegram.Bot(token='<your_token>')

if __name__ == '__main__':
    print(bot.get_me())
    bot.send_message(chat_id="<your_chat_id>", text="Post ist da")

This program is just used to test the connectivity of your bot.

urequests

Because we don’t have access to the telegram package inside the ESP / MicroPython environment we use urequests.

urequests is similar to the requests package and lets you send http messages.

Sending messages looks like the following

import urequests
requests.get("https://api.telegram.org/bot<your_token>/sendMessage?text=hallo&chat_id=<your_chat_id>")

The complete Code

import network
import urequests
import machine
import esp32
from time import sleep

SSID = <your_ssid>
WIFI_PW = <your_wifi_pw>
TOKEN = <your_tg_token>
URL = "https://api.telegram.org/bot{}/".format(TOKEN)
CHAT_ID = <your_chat_id>


def connect_to_wifi(ssid, password):
    print("MBB: connect_to_wifi")
    sta_if = network.WLAN(network.STA_IF)

    if sta_if.isconnected():
        print("MBB: already connected")
        return

    if not sta_if.active():
        print("MBB: activate network adapter")
        sta_if.active(True)
        print("MBB: network adapter activated")

    if not sta_if.isconnected():
        print("MBB: trying to connect")
        sta_if.connect('%s' % ssid, '%s' % password)

        while not sta_if.isconnected():
            pass
        print("MBB: connected successfully")
    print(sta_if.ifconfig())


def get_url(url):
    response = urequests.get(url)
    content = response.text
    return content


def send_message(text, chat_id):
    url = URL + "sendMessage?text={}&chat_id={}".format(text, chat_id)
    get_url(url)


if __name__ == '__main__':
    print("MBB: start")
    #disable LED on firebeetle board
    p2 = machine.Pin(2, machine.Pin.OUT)
    p2.value(0)
    wake1 = machine.Pin(4, machine.Pin.IN, machine.Pin.PULL_UP) # pin 4 is able to wake
    esp32.wake_on_ext0(pin=wake1, level=esp32.WAKEUP_ALL_LOW)
    print('MBB: Im awake. Going to sleep in 10 seconds')
    connect_to_wifi(SSID, WIFI_PW)
    print("MBB: sending message")
    send_message("Post ist endlich da", CHAT_ID)
    print("MBB: finished")
    sleep(10)
    print('MBB: Going to sleep now')
    machine.deepsleep()


Testing

After charging the battery we can use the board independently from the computer

Sources

https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf