Skip to content

Commit

Permalink
Refactor access-front-door
Browse files Browse the repository at this point in the history
  • Loading branch information
North101 committed Jun 29, 2024
1 parent 2403cee commit a3929dd
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 69 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.venv/
.vscode/

access-front-door/src/env.py
65 changes: 64 additions & 1 deletion access-front-door/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,66 @@
# Access Front Door

This is the code required for opening the front door latch.
This is the code required for opening the front door latch.


## Setting up environment variables

1. Copy or rename `access-front-door/src/env.example.py` to `access-front-door/src/env.py`
2. Set `WIFI_SSID` and `WIFI_PASSWORD` to your wifi ssid and password
3. Update any other variables


## Micropython type hints in VSCode

### Install these extensions:
* https://marketplace.visualstudio.com/items?itemName=ms-python.python
* https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance


### Setup virtualenv and install stubs
```bash
# setup virtualenv
python3 -m venv .venv

# activate virtualenv
source ./.venv/bin/activate

# install micropython stubs
pip3 install -U micropython-esp32-stubs

# install mpremote (optional, lets you connect via command line)
pip3 install -U mpremote
```

### Configure vscode
`.vscode/settings.json`
```json
{
"python.languageServer": "Pylance",
"python.analysis.typeCheckingMode": "basic",
"python.analysis.diagnosticSeverityOverrides": {
"reportMissingModuleSource": "none"
},
// Replace <python_version> with whatever the folder name is in .venv/lib/
"python.analysis.typeshedPaths": [
".venv/lib/<python_version>/site-packages",
],
// Fixes imports
"pylint.args": [
"--init-hook 'import sys; sys.path.append(\".\")'",
],
}
```


### Copy code to device via command line (requires mpremote)
```bash
# make sure you are in the access-front-door directory
cd access-front-door

# list connected devices
./run.sh

# copy code and run main.py on device
./run.sh [device_id]
```
68 changes: 0 additions & 68 deletions access-front-door/main.py

This file was deleted.

10 changes: 10 additions & 0 deletions access-front-door/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# bin/bash
if [[ -z "$1" ]]; then
echo "usage: $0 [device_id]"
mpremote devs
exit 1;
fi

mpremote connect id:$1 reset
mpremote connect id:$1 cp -r src/* :
mpremote connect id:$1 run ./src/main.py
5 changes: 5 additions & 0 deletions access-front-door/src/env.example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
WIFI_SSID = ""
WIFI_PASSWORD = ""
SHARED_PASSWORD = "access-front-door-psk"
HOSTNAME = "access-front-door"
DEFAULT_UNLOCK_DURATION = 10
100 changes: 100 additions & 0 deletions access-front-door/src/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import socket
import time

import network
from machine import PWM, Pin

from . import env


# Variables
RESPONSE = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\nConnection: close\r\n\r\n"


class Door():
def __init__(self):
self.pwm = PWM(Pin(23)) # Set up pin D23 to output
self.led = Pin(2, Pin.OUT) # Pin 2 is the built-in LED
self.setup_wifi()
self.setup_socket()

def setup_wifi(self):
self.wifi = network.WLAN(network.STA_IF)
self.wifi.active(True)
time.sleep_us(100)
self.wifi.config(dhcp_hostname=env.HOSTNAME)

def connect_wifi(self):
# Connect to WiFi
self.wifi.connect(env.WIFI_SSID, env.WIFI_PASSWORD)
while not self.wifi.isconnected():
pass

def setup_socket(self):
# Set up webserver
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.bind(('', 8080))
self.socket.listen(5)

def get_parameters_from(self, request: bytes):
parameters: dict[str, str] = {}
request_str = request.decode('utf-8')
params_index = request_str.find('Content-Length:')
ampersand_split = request_str[params_index:].split("&")
for element in ampersand_split:
equal_split = element.split("=")
parameters[equal_split[0]] = equal_split[1]

return parameters

def read_socket(self):
conn: socket.socket = self.socket.accept()[0]
request = conn.recv(1024)
parameters = self.get_parameters_from(request)
conn.send(RESPONSE)
conn.close()

return parameters

def lock(self):
self.led.off()
self.pwm.duty(0)

def unlock(self):
# Output signal on pin to unlock and light up the internal light
self.led.on()
self.pwm.duty(1023)

def run(self):
while True:
try:
self.update()
except Exception as e:
print(e)

def update(self):
self.lock()

if not self.wifi.isconnected():
self.connect_wifi()

parameters = self.read_socket()

# Bail if the request didn't come from a known source
if parameters.get('psk') != env.SHARED_PASSWORD:
return

duration = parameters.get("duration")
try:
duration = int(duration) if duration is not None else env.DEFAULT_UNLOCK_DURATION
except ValueError:
return
unlock_duration = max(min(duration, 30), 1)

self.unlock()
time.sleep(unlock_duration)


if __name__ == '__main__':
door = Door()
door.run()

0 comments on commit a3929dd

Please sign in to comment.