BB Korry
Published © CC BY

Open Sesame Equation

It's a safe for math lovers.

IntermediateShowcase (no instructions)Over 1 day156
Open Sesame Equation

Things used in this project

Hardware components

SG90 Micro-servo motor
SG90 Micro-servo motor
×1
M5Stack Dial v1.1 - ESP32-S3 Smart Rotary Knob with 1.28" Round Touch Screen
M5Stack Dial v1.1 - ESP32-S3 Smart Rotary Knob with 1.28" Round Touch Screen
×1

Software apps and online services

MicroPython
MicroPython

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Code

main.py

MicroPython
Mathematical safe main control
import M5
from M5 import * 
import _thread 
from hardware import Rotary
from machine import PWM,Pin,I2C
from utime import sleep
from random import choice

# A constant that specifies the duty of the SG90 (lock, unlock).
deg = [2676, 5788]

# A constant that specifies the lock level.
LPRM = [range(0,10), range(-9,10), range(0,30), range(-15,16)]

# A constant that specifies the segment pattern
DI = {'0':0,'1':1,'2':2,'3':3,'4':4,
      '5':5,'6':6,'7':7,'8':8,'9':9,
      'a':10,'b':11,'c':12,'d':13,'e':14,'f':15,
       '-':16,' ':17}

# Defining Global Variables
bsw = 0 # Previous sw status
bro = 0 # Previous rotary status
d = [17 for i in range(16)] # LED display characters
b = [1 for i in range(16)] # LED blinking setting

# Initialization
M5.begin()
sw = Pin(1, Pin.IN, Pin.PULL_UP)
ro = Rotary()
Widgets.setBrightness(0)
sleep(0.1)
sv = PWM(Pin(2), freq=50, duty_u16=deg[0])
sleep(0.3)
Widgets.setBrightness(150)
Speaker.setVolume(200)

# LED display processing (multi-threaded)
def led_change():
    i2c = I2C(0, scl=Pin(15), sda=Pin(13), freq=400000)
    addr = i2c.scan()
    i2c.writeto(addr[0], bytes([0x21])) # SYSTEM on
    i2c.writeto(addr[0], bytes([0x81])) # LED power on
    i2c.writeto(addr[0], bytes([0xE8])) # LED brightness setting
    for i in range(16): i2c.writeto_mem(addr[0], i, bytes([0x00])) #LED initialization 
    p = [0xee, 0x48, 0xba, 0xda, 0x5c, 0xd6, 0xf6, 0x4e, 0xfe, 0xde, # LED lighting bit data
         0x7e, 0xf4, 0xa6, 0xf8, 0xb6, 0x36, 0x10, 0x00]
    bf = 0 # Blinking Flag
    while True:
        for i in range(8):
            i2c.writeto_mem(addr[0], i*2, bytes([p[d[i]] * (b[i]|bf)]))
            i2c.writeto_mem(addr[0], i*2+1, bytes([p[d[i+8]] * (b[i+8]|bf)]))
        bf = (bf+1)%2
        sleep(0.1)

# LCD display processing
def disp_change(n, val):
    if n==0 or n==1:
        Widgets.fillScreen(0xffffff)
    else:
        Widgets.fillScreen(0x000000)
    if n==0:
        l0 = Widgets.Label(" LOCK ",50,105,1.0,0x000000,0xffffff,Widgets.FONTS.DejaVu40)
    if n==1:
        l0 = Widgets.Label("UNLOCK",30,105,1.0,0x000000,0xffffff,Widgets.FONTS.DejaVu40)
    if n>=2:
        c0 = Widgets.Circle(120, 120, 100, 0xffffff, 0xffffff)
        c1 = Widgets.Circle(120, 120, 90, 0x000000, 0x000000)
        r0 = Widgets.Rectangle(110, 12, 20, 20, 0x000000, 0x000000)
        r1 = Widgets.Rectangle(0, 120, 240, 120, 0x000000, 0x000000)
        t0 = Widgets.Triangle(10, 114, 40, 114, 25, 130, 0xffffff, 0xffffff)
        t1 = Widgets.Triangle(200, 115, 230, 115, 215, 130, 0xffffff, 0xffffff)
    if n==2:
        r0 = Widgets.Rectangle(0, 0,120,240, 0x000000, 0x000000)
        lr = Widgets.Label("LOCK", 130, 71, 1.0, 0xffff00, 0x000000, Widgets.FONTS.DejaVu18)
    if n==3:
        lr = Widgets.Label("-  SELECT  +", 60, 90, 1.0, 0xffffff, 0x000000, Widgets.FONTS.DejaVu18)
    if n==2 or n==3:
        l1 = Widgets.Label("LOCK LEVEL", 60, 148, 1.0, 0x000000, 0xffffff, Widgets.FONTS.DejaVu18)
        l2 = Widgets.Label(str(val+1),110, 180, 1.0, 0xffffff, 0x000000, Widgets.FONTS.DejaVu40)
    if n==4:
        r2 = Widgets.Rectangle(0, 140, 240, 100, 0xffffff, 0xffffff)
        l1 = Widgets.Label("UNLOCK PASS", 50, 148, 1.0, 0xffffff, 0x000000, Widgets.FONTS.DejaVu18)
        l2 = Widgets.Label("yQ = yA", 64, 175, 1.0, 0x000000, 0xffffff, Widgets.FONTS.DejaVu24)
        l3 = Widgets.Label("(x=1~5)", 75, 208, 1.0, 0x000000, 0xffffff, Widgets.FONTS.DejaVu18)
    if n==4 and val==0:
        lr = Widgets.Label("X + ", 140, 90, 1.0, 0xffff00, 0x000000, Widgets.FONTS.DejaVu18)
        ll = Widgets.Label("NEXT",  50, 90, 1.0, 0xffffff, 0x000000, Widgets.FONTS.DejaVu18)
    if n==4 and val==1:
        lr = Widgets.Label("NEXT", 140, 90, 1.0, 0xffffff, 0x000000, Widgets.FONTS.DejaVu18)
        ll = Widgets.Label("a - ",  50, 90, 1.0, 0xffff00, 00000000, Widgets.FONTS.DejaVu18)
    if n==4 and val==2:
        lr = Widgets.Label("b + ", 140, 90, 1.0, 0xffff00, 0x000000, Widgets.FONTS.DejaVu18)
        ll = Widgets.Label("NEXT",  50, 90, 1.0, 0xffffff, 0x000000, Widgets.FONTS.DejaVu18)
    if n==4 and val==3:
        lr = Widgets.Label("NEXT", 140, 90, 1.0, 0xffffff, 0x000000, Widgets.FONTS.DejaVu18)
        ll = Widgets.Label("c - ",  50, 90, 1.0, 0xffff00, 0x000000, Widgets.FONTS.DejaVu18)
    M5.update() 

# Key Scan Processing
def key_serch():
    global bsw, bro
    nsw = sw.value()
    nro = ro.get_rotary_value()
    k = 0
    if bsw != nsw and nsw == 0: k=2 # key2:sw on
    if bsw != nsw and nsw == 1: k=3 # key3:sw off
    if bro != nro and nro - bro > 0: k=1 # key1:rotary+
    if bro != nro and nro - bro < 0: k=-1 # key-1:rotary-
    bsw = nsw
    bro = nro
    return k

# Multi-threading Start
_thread.start_new_thread(led_change, ())

# Main loop start
while True:

    # Initialization before unlocking
    dp = 3
    lv = 0
    d = [17 for i in range(16)] 
    disp_change(3, lv) 
    Speaker.tone(2400, 200)
    sleep(0.5)
  
    #Processing during unlock
    while dp != 0:
        key = 0
        while key == 0: key = key_serch()
        if sw.value() == 1 and key == 1: lv = (lv+1)%len(LPRM) # Lv select +
        if sw.value() == 1 and key == -1: lv = (lv-1)%len(LPRM) # Lv select -
        if key == 2: dp = 2 # Screen switching(Lock display)
        if key == 3: dp = 3 # Screen switching(Unlock display)
        if sw.value() == 0 and key== 1: dp=0 # Door locking conditions
        disp_change(dp, lv)
        if abs(key) == 1: Speaker.tone(1600, 50)
        else: Speaker.tone(1200, 300)

    #Unlocking Process
    Widgets.setBrightness(0)
    sleep(0.1)
    sv.duty_u16(deg[1])    
    sleep(0.3)
    Widgets.setBrightness(150)
    d = [17,17,17,17,17,17,17,17,0,0,0,0,0,0,0,0]
    b = [ 1, 1, 1, 1, 1, 1, 1, 1,0,0,0,0,0,0,0,0]
    disp_change(0, 0)
    Speaker.tone(3000, 1000)
    sleep(3)
    sel = 0
    x = 0
    ka = [0, 0, 0]
    kq = [0, 0, 0]
    while 0 in kq: kq = [choice(LPRM[lv]) for i in range(3)]
    dp = 4
    disp_change(dp, sel)
  
    # Processing during lock
    while True:
        asum = 0
        for i in range(5):
            q = kq[0]*(i+1)*(i+1) + kq[1]*(i+1) + kq[2]
            a = ka[0]*(i+1)*(i+1) + ka[1]*(i+1) + ka[2]
            if x==i:
                nyq = q
                nya = a
            if q==a: asum += 1
        sx = str(x+1)
        if lv != 3: # Display numbers as decimal numbers
            syq = f'{nyq:04}'
            sya = f'{nya:04}'
            sk0 = f'{ka[0]:02}'
            sk1 = f'{ka[1]:02}'
            sk2 = f'{ka[2]:02}'
        if lv == 3: # Display numbers in hexadecimal
            syq = f'{nyq:04x}'
            sya = f'{nya:04x}'
            sk0 = f'{ka[0]:02x}'
            sk1 = f'{ka[1]:02x}'
            sk2 = f'{ka[2]:02x}'          
        d = [DI[' ']   ,DI[ sx[0]],DI[sk0[1]],DI[sk0[0]],
             DI[sk1[1]],DI[sk1[0]],DI[sk2[1]],DI[sk2[0]],
             DI[syq[3]],DI[syq[2]],DI[syq[1]],DI[syq[0]],
             DI[sya[3]],DI[sya[2]],DI[sya[1]],DI[sya[0]]]
        if asum==5: break # Unlocked when all conditions are met
        b = [1 for i in range(16)] # Initialize the blinking state
        b[sel*2] = 0
        b[sel*2+1] = 0 
        nsel = sel
        key = 0 
        while key==0: key = key_serch()
        if   key == 1 and sel == 0:
            x = (x+1)%5 # x +
        elif key == -1 and sel == 1:
            ka[0] = ka[0]-1 if ka[0]>min(LPRM[lv]) else max(LPRM[lv]) # ka -
        elif key == 1 and sel == 2:
            ka[1] = ka[1]+1 if ka[1]<max(LPRM[lv]) else min(LPRM[lv]) # kb +
        elif key == -1 and sel == 3:
            ka[2] = ka[2]-1 if ka[2]>min(LPRM[lv]) else max(LPRM[lv]) # kc -
        elif key != 2 and key != 3:
            sel = (sel+1)%4 # Change your selection
            disp_change(dp, sel)
        if abs(key) == 1 and sel == nsel:Speaker.tone(1600, 50)
        if abs(key) == 1 and sel != nsel:Speaker.tone(2400, 200)

    # Unlocking Process
    Widgets.setBrightness(0)
    sleep(0.1)
    sv.duty_u16(deg[0])
    sleep(0.3)
    Widgets.setBrightness(150)
    b=[0 for i in range(16)]
    disp_change(1, 0)
    Speaker.tone(3000, 1000)
    sleep(2)
    key = 0
    while key != 3: key = key_serch()

Credits

BB Korry
2 projects • 0 followers

Comments