03 Jul 2018

Door Alarm Using ESP8266, MicroPython and a Reed Switch (Email Alerts)

Get email alerts when a door is opened or closed.

Requirements: ESP8266 compatible board, a Reed switch, a magnet, some wires and a USB cable (and a computer).

Schematic: One side of the reed switch connected to the ground and the other side to Pin D1 of the D1-Mini board (Pin 5 for ESP8266) and a 10k Ohm pull-up resistor. Schematic, D1-Mini/Reed Switch

Instructions:

  1. Install MicroPython on your ESP8266 board:

    • Connect board to your computer using a USB cable

    • Download MicroPython’s current firmware:

    • Install esptool:

        pip install --user esptool
      
    • Install ampy (Fedora):

        sudo dnf install ampy
      
    • Erase board’s flash:

        esptool.py --port /dev/ttyUSB0 erase_flash
      
    • Install new firmware:

        esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect 0 esp8266-20xxxxxx-vx.x.x.bin
      
  2. Setup webrpl

     picocom /dev/ttyUSB0 -b115200 -t "$(echo -ne '\r\nimport webrepl_setup\r\n')"
     press <e> and set your_password
     press <y> to reboot
    
  3. Install alarm code (the code can be found below):

    • Setup the board to act as a Wi-Fi client at boot time (change SSID and wifi_password before uploading):

        ampy --port /dev/ttyUSB0 put boot.py
      
    • Install alarm code (change email and email_password):

        ampy --port /dev/ttyUSB0 put main.py
      
    • Reboot board to make changes effective:

        picocom /dev/ttyUSB0 -b115200 -t "$(echo -ne '\r\nimport machine\r\nmachine.reset()\r\n')"
      

boot.py (setup webrepl and Wi-Fi):

import gc
import webrepl
import network

# change the value of the 2 variables below
ssid = "your_SSID"
pwd  = "wifi_password"

webrepl.start()
gc.collect()
sta_if = network.WLAN(network.STA_IF)
ap_if  = network.WLAN(network.AP_IF)
ap_if.active(False)
if not sta_if.isconnected():
  print('Connecting to WiFi...')
  sta_if.active(True)
  sta_if.connect(ssid, pwd)
  while not sta_if.isconnected():
    pass$
print('network config:', sta_if.ifconfig()

main.py (credit):

import machine
from time import sleep
# Micropython
try:
  import usocket as socket
  import ussl as ssl

# Python3
except:
  import socket
  import ssl

try:
    switch = machine.Pin(5, machine.Pin.IN) # D1/GPIO5
except:
    print("s:e")
    switch = 0 # open

prevValue      = 0
doorOpenTimer  = 0
email_user     = "user@gmail.com"
email_pwd      = "my_password"
email_user_b64 = "xxxxxxxxxxxxxxxxxxxxxx=" # base64 encoded email    (echo -n 'user@gmail.com' | base64)
email_pwd_b64  = "xxxxxxxxxxxxxxxxxxxxxx=" # base64 encoded password (echo -n 'my_password' | base64)

def send_email(username, subject, body):
    msg = """To: {0}\r\nSubject: {1}

    {2}
    """
    msg = msg.format(username,subject,body)

    endmsg = "\r\n.\r\n"

    mailserver = "smtp.gmail.com"
    port = 587

    # Create socket called clientSocket and establish a TCP connection with mailserver
    clientSocket = socket.socket()
    clientSocket.connect(socket.getaddrinfo(mailserver, port)[0][-1])
    recv = clientSocket.recv(1024)
    print(recv)
    print(recv[:3])
    if recv[:3] != b'220':
        print('220 reply not received from server.')

    # Send HELO command and print server response.
    heloCommand = 'EHLO Alice\r\n'
    clientSocket.send(heloCommand.encode())
    recv1 = clientSocket.recv(1024)
    recvCount=recv1.decode().count('\n')
    print(recv1)
    if recv1[:3] != b'250':
        print('250 reply not received from server.')

    # Request an encrypted connection
    startTlsCommand = 'STARTTLS\r\n'
    clientSocket.send(startTlsCommand.encode())
    tls_recv = clientSocket.recv(1024)
    print(tls_recv)
    if tls_recv[:3] != b'220':
        print('220 reply not received from server')

    # Encrypt the socket
    ssl_clientSocket = ssl.wrap_socket(clientSocket)
    print("Secure socket created")

    heloCommand = 'EHLO Alice\r\n'
    ssl_clientSocket.write(heloCommand.encode())
    recv1=''
    for index in range(0,recvCount):
      recv1 = recv1+ssl_clientSocket.readline().decode()
    print(recv1)

    # Send the AUTH LOGIN command and print server response.
    authCommand = 'AUTH LOGIN\r\n'
    ssl_clientSocket.write(authCommand.encode())
    auth_recv = ssl_clientSocket.readline()
    print(auth_recv)
    if auth_recv[:3] != b'334':
        print('334 reply not received from server')

    print("Sending username / password")
    # Send username and print server response.
    uname = email_user_b64 # base64 encoded email
    pword = email_pwd_b64  # base64 encoded password
    print(str(uname))
    ssl_clientSocket.write(uname)
    ssl_clientSocket.write('\r\n'.encode())
    uname_recv = ssl_clientSocket.readline()
    print(uname_recv)
    if uname_recv[:3] != b'334':
        print('334 reply not received from server')
    print(str(pword))
    ssl_clientSocket.write(pword)
    ssl_clientSocket.write('\r\n'.encode())
    pword_recv = ssl_clientSocket.readline()

    print(pword_recv)
    if pword_recv[:3] != b'235':
        print('235 reply not received from server')

    # Send MAIL FROM command and print server response.
    mailFromCommand = 'MAIL FROM: <' + username + '>\r\n'
    ssl_clientSocket.write(mailFromCommand.encode())
    recv2 = ssl_clientSocket.readline()
    print(recv2)
    if recv2[:3] != b'250':
        print('250 reply not received from server.')

    # Send RCPT TO command and print server response.
    rcptToCommand = 'RCPT TO: <' + username + '>\r\n'
    ssl_clientSocket.write(rcptToCommand.encode())
    recv3 = ssl_clientSocket.readline()
    print(recv3)
    if recv3[:3] != b'250':
        print('250 reply not received from server.')

    # Send DATA command and print server response.
    dataCommand = 'DATA\r\n'
    ssl_clientSocket.write(dataCommand.encode())
    recv4 = ssl_clientSocket.readline()
    print(recv4)
    if recv4[:3] != b'354':
        print('354 reply not received from server.')

    # Send message data.
    ssl_clientSocket.write(msg.encode())

    # Message ends with a single period.
    ssl_clientSocket.write(endmsg.encode())
    recv5 = ssl_clientSocket.readline()
    print(recv5)
    if recv5[:3] != b'250':
        print('250 reply not received from server.')

    # Send QUIT command and get server response.
    quitCommand = 'QUIT\r\n'
    ssl_clientSocket.write(quitCommand.encode())
    recv6 = ssl_clientSocket.readline()
    print(recv6)
    if recv6[:3] != b'221':
        print('221 reply not received from server.')

    clientSocket.close()

while True:
    sleep(1)
    print("s.v.: " + str( switch.value() ) )
    if prevValue != switch.value():
        if switch.value() == 0: # door opened
            send_email(email_user, "Door Opened", prevValue)
        if switch.value() == 1: # door closed
            send_email(email_user, "Door Closed", prevValue)
        try:
            prevValue = switch.value()
        except:
            prevValue = -1