From 6f53375b5e64bbf9c838e36f31da76c03a0a3334 Mon Sep 17 00:00:00 2001 From: Michael Schappacher Date: Thu, 22 Sep 2022 17:39:17 -0400 Subject: [PATCH 01/13] Begin adding ap mode, scan feature and multi wlan configuration --- firmware/lib/connection.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/firmware/lib/connection.py b/firmware/lib/connection.py index 6391a48..a7706e9 100644 --- a/firmware/lib/connection.py +++ b/firmware/lib/connection.py @@ -1,3 +1,4 @@ +from typing import List, Tuple import urequests as requests import ujson as json import utils @@ -25,6 +26,24 @@ def send_api_request(base_url, path, headers={}, data={}): requests.get(url=base_url + path + "/", headers=auth_variables).content ) +def scan_access_points(): + wlan = network.WLAN(network.STA_IF) + wlan.active(True) + nearby_wifi = wlan.scan() + wlan.active(False) + return nearby_wifi + +def wlan_nearby(nearby_ssids, wlan_variables): + matching_ssids = [] + ssid_list = [] + for ssid in nearby_ssids: + ssid_list.append(ssid[0]) + for ssid in wlan_variables["SSIDS_PASSWORD"].keys(): + if ssid in ssid_list: + matching_ssids.append(ssid) + if matching_ssids: + return matching_ssids[0] + return None def connect_to_wifi(wlan_variables): # Attempt to connect to WIFI @@ -40,6 +59,12 @@ def connect_to_wifi(wlan_variables): print("WLAN Connected") return wlan +def access_point_wifi_setup(): + ap = network.WLAN(network.AP_IF) + ap.config(essid="BabyScout", password="BabyBuddy") + ap.active(True) + return ap + def test_connection(url): try: From 65e7275a72ba9bbd6dc4f5e565b53b6490e4c19f Mon Sep 17 00:00:00 2001 From: Michael Schappacher Date: Thu, 22 Sep 2022 18:48:11 -0400 Subject: [PATCH 02/13] Begin work on website based configuration of BabyScout --- firmware/lib/connection.py | 23 ++++++++++++----------- firmware/main.py | 14 ++++++++++---- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/firmware/lib/connection.py b/firmware/lib/connection.py index a7706e9..3d97363 100644 --- a/firmware/lib/connection.py +++ b/firmware/lib/connection.py @@ -1,4 +1,3 @@ -from typing import List, Tuple import urequests as requests import ujson as json import utils @@ -27,30 +26,30 @@ def send_api_request(base_url, path, headers={}, data={}): ) def scan_access_points(): + nearby_access_point_list = [] wlan = network.WLAN(network.STA_IF) wlan.active(True) - nearby_wifi = wlan.scan() + nearby_access_points = wlan.scan() + for ssid in nearby_access_points: + nearby_access_point_list.append(ssid[0].decode('utf-8')) wlan.active(False) - return nearby_wifi + return nearby_access_point_list -def wlan_nearby(nearby_ssids, wlan_variables): +def access_point_nearby(nearby_ssids, wlan_variables): matching_ssids = [] - ssid_list = [] - for ssid in nearby_ssids: - ssid_list.append(ssid[0]) for ssid in wlan_variables["SSIDS_PASSWORD"].keys(): - if ssid in ssid_list: + if ssid in nearby_ssids: matching_ssids.append(ssid) if matching_ssids: return matching_ssids[0] return None -def connect_to_wifi(wlan_variables): +def connect_to_access_point(ssid, password): # Attempt to connect to WIFI wlan = network.WLAN(network.STA_IF) wlan.active(True) - wlan.connect(wlan_variables["SSID"], wlan_variables["PASSWORD"]) - print(f"Attempting to connect to {wlan_variables['SSID']}") + wlan.connect(ssid, password) + print(f"Attempting to connect to {ssid}") while not wlan.isconnected(): onboard_led() time.sleep(0.5) @@ -62,6 +61,7 @@ def connect_to_wifi(wlan_variables): def access_point_wifi_setup(): ap = network.WLAN(network.AP_IF) ap.config(essid="BabyScout", password="BabyBuddy") + ap.ifconfig(('192.168.0.2', '255.255.255.0', '192.168.0.1', '8.8.8.8')) ap.active(True) return ap @@ -74,3 +74,4 @@ def test_connection(url): return False except: return False + diff --git a/firmware/main.py b/firmware/main.py index 617da82..814237e 100644 --- a/firmware/main.py +++ b/firmware/main.py @@ -4,16 +4,21 @@ import uos as os import _thread from lib.utils import retrieve_auth_variables, join_path -from lib.connection import connect_to_wifi, test_connection +from lib.connection import connect_to_access_point, scan_access_points, access_point_nearby, access_point_wifi_setup from lib.scout import connect_to_baby_buddy # Retrieve WLAN Variables from secrets.json and establish connectivity to WLAN and BabyScout WLAN_VARIABLES = retrieve_auth_variables(join_path(os.getcwd(), "secrets.json")) BASE_URL = WLAN_VARIABLES["BASE_URL"] -WLAN = connect_to_wifi(wlan_variables=WLAN_VARIABLES) +nearby_matching_access_point = access_point_nearby(scan_access_points(), WLAN_VARIABLES) +if nearby_matching_access_point: + WLAN = connect_to_access_point(nearby_matching_access_point, WLAN_VARIABLES["SSIDS_PASSWORD"][nearby_matching_access_point]) +else: + print("No matching wifi, falling back to webpage based setup") + ap = access_point_wifi_setup() + BABY_SCOUT = connect_to_baby_buddy(base_url=BASE_URL) - # Set default to first child in BabyBuddy, add functionality to allow for toggling between multiple children. child = BABY_SCOUT.children[0] @@ -59,7 +64,7 @@ def ensure_connection(): print("Testing Connection") if not WLAN.isconnected(): print("Lost Connection") - WLAN = connect_to_wifi(wlan_variables=WLAN_VARIABLES) + WLAN = connect_to_access_point(wlan_variables=WLAN_VARIABLES) print("Reconnected") time.sleep(10) @@ -69,3 +74,4 @@ def ensure_connection(): # Begin button checking loop button_pressed() + From 1d9cd0b83fbd7341a4c53bd78b1cb32ac825aecf Mon Sep 17 00:00:00 2001 From: Michael Schappacher Date: Thu, 22 Sep 2022 18:49:36 -0400 Subject: [PATCH 03/13] Begin work on website based configuration of BabyScout --- firmware/lib/connection.py | 9 ++++++--- firmware/main.py | 15 +++++++++++---- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/firmware/lib/connection.py b/firmware/lib/connection.py index 3d97363..da220bf 100644 --- a/firmware/lib/connection.py +++ b/firmware/lib/connection.py @@ -25,16 +25,18 @@ def send_api_request(base_url, path, headers={}, data={}): requests.get(url=base_url + path + "/", headers=auth_variables).content ) + def scan_access_points(): nearby_access_point_list = [] wlan = network.WLAN(network.STA_IF) wlan.active(True) nearby_access_points = wlan.scan() for ssid in nearby_access_points: - nearby_access_point_list.append(ssid[0].decode('utf-8')) + nearby_access_point_list.append(ssid[0].decode("utf-8")) wlan.active(False) return nearby_access_point_list + def access_point_nearby(nearby_ssids, wlan_variables): matching_ssids = [] for ssid in wlan_variables["SSIDS_PASSWORD"].keys(): @@ -44,6 +46,7 @@ def access_point_nearby(nearby_ssids, wlan_variables): return matching_ssids[0] return None + def connect_to_access_point(ssid, password): # Attempt to connect to WIFI wlan = network.WLAN(network.STA_IF) @@ -58,10 +61,11 @@ def connect_to_access_point(ssid, password): print("WLAN Connected") return wlan + def access_point_wifi_setup(): ap = network.WLAN(network.AP_IF) ap.config(essid="BabyScout", password="BabyBuddy") - ap.ifconfig(('192.168.0.2', '255.255.255.0', '192.168.0.1', '8.8.8.8')) + ap.ifconfig(("192.168.0.2", "255.255.255.0", "192.168.0.1", "8.8.8.8")) ap.active(True) return ap @@ -74,4 +78,3 @@ def test_connection(url): return False except: return False - diff --git a/firmware/main.py b/firmware/main.py index 814237e..370f0de 100644 --- a/firmware/main.py +++ b/firmware/main.py @@ -4,7 +4,12 @@ import uos as os import _thread from lib.utils import retrieve_auth_variables, join_path -from lib.connection import connect_to_access_point, scan_access_points, access_point_nearby, access_point_wifi_setup +from lib.connection import ( + connect_to_access_point, + scan_access_points, + access_point_nearby, + access_point_wifi_setup, +) from lib.scout import connect_to_baby_buddy # Retrieve WLAN Variables from secrets.json and establish connectivity to WLAN and BabyScout @@ -13,11 +18,14 @@ BASE_URL = WLAN_VARIABLES["BASE_URL"] nearby_matching_access_point = access_point_nearby(scan_access_points(), WLAN_VARIABLES) if nearby_matching_access_point: - WLAN = connect_to_access_point(nearby_matching_access_point, WLAN_VARIABLES["SSIDS_PASSWORD"][nearby_matching_access_point]) + WLAN = connect_to_access_point( + nearby_matching_access_point, + WLAN_VARIABLES["SSIDS_PASSWORD"][nearby_matching_access_point], + ) else: print("No matching wifi, falling back to webpage based setup") ap = access_point_wifi_setup() - + BABY_SCOUT = connect_to_baby_buddy(base_url=BASE_URL) # Set default to first child in BabyBuddy, add functionality to allow for toggling between multiple children. child = BABY_SCOUT.children[0] @@ -74,4 +82,3 @@ def ensure_connection(): # Begin button checking loop button_pressed() - From 3a14d39c9f1b52393cf555d86ddd600064e0fb13 Mon Sep 17 00:00:00 2001 From: Michael Schappacher Date: Fri, 23 Sep 2022 14:59:49 -0400 Subject: [PATCH 04/13] Add in object to parse requests --- firmware/lib/connection.py | 22 +++++++++++++++++++++- firmware/lib/request.py | 25 +++++++++++++++++++++++++ firmware/lib/webpage.py | 13 +++++++++++++ firmware/main.py | 8 ++++++++ 4 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 firmware/lib/request.py create mode 100644 firmware/lib/webpage.py diff --git a/firmware/lib/connection.py b/firmware/lib/connection.py index da220bf..a593409 100644 --- a/firmware/lib/connection.py +++ b/firmware/lib/connection.py @@ -3,8 +3,10 @@ import utils import uos as os import network +import socket from pin import onboard_led import time +from request import Request def send_api_request(base_url, path, headers={}, data={}): @@ -65,10 +67,27 @@ def connect_to_access_point(ssid, password): def access_point_wifi_setup(): ap = network.WLAN(network.AP_IF) ap.config(essid="BabyScout", password="BabyBuddy") - ap.ifconfig(("192.168.0.2", "255.255.255.0", "192.168.0.1", "8.8.8.8")) ap.active(True) + print(ap) return ap +def open_socket(ip, port): + address = (ip, port) + new_socket = socket.socket() + new_socket.bind((ip, port)) + new_socket.listen(1) + return new_socket + +def serve(socket, webpage): + while True: + client = socket.accept()[0] + request = client.recv(1024) + print(request) + request = Request(request.decode('utf-8')) + print(request) + client.send(webpage) + client.close() + def test_connection(url): try: @@ -78,3 +97,4 @@ def test_connection(url): return False except: return False + diff --git a/firmware/lib/request.py b/firmware/lib/request.py new file mode 100644 index 0000000..b6277f9 --- /dev/null +++ b/firmware/lib/request.py @@ -0,0 +1,25 @@ +class Request: + def __init__(self, request): + self.raw = request + self.method = None + self.path = None + self.protocol = None + self.headers = None + self.body = None + self.parse_request() + + def parse_request(self): + request, self.body = self.raw.split("\r\n\r\n") + split_request = request.split("\r\n") + request_line = split_request.pop(0) + self.method, self.path, self.protocol = request_line.split(" ") + headers = {} + for header in split_request: + key, value = header.split(": ") + headers[key] = value + self.headers = headers + + + + + diff --git a/firmware/lib/webpage.py b/firmware/lib/webpage.py new file mode 100644 index 0000000..71d7ec8 --- /dev/null +++ b/firmware/lib/webpage.py @@ -0,0 +1,13 @@ +def webpage(): + webpage = """ + + + Example + + +

This is an example of a simple HTML page with one paragraph.

+ + + """ + + return webpage \ No newline at end of file diff --git a/firmware/main.py b/firmware/main.py index 370f0de..95bac67 100644 --- a/firmware/main.py +++ b/firmware/main.py @@ -9,7 +9,10 @@ scan_access_points, access_point_nearby, access_point_wifi_setup, + open_socket, + serve ) +from lib.webpage import webpage from lib.scout import connect_to_baby_buddy # Retrieve WLAN Variables from secrets.json and establish connectivity to WLAN and BabyScout @@ -25,6 +28,10 @@ else: print("No matching wifi, falling back to webpage based setup") ap = access_point_wifi_setup() + ip = ap.ifconfig()[0] + socket = open_socket(ip, 80) + serve(socket, webpage()) + BABY_SCOUT = connect_to_baby_buddy(base_url=BASE_URL) # Set default to first child in BabyBuddy, add functionality to allow for toggling between multiple children. @@ -82,3 +89,4 @@ def ensure_connection(): # Begin button checking loop button_pressed() + From 8e4638a0be0f576054a3e273999fb871a9099bfb Mon Sep 17 00:00:00 2001 From: Michael Schappacher Date: Fri, 23 Sep 2022 23:00:12 -0400 Subject: [PATCH 05/13] Create webserver object for allowing paths for web pages --- firmware/lib/connection.py | 18 +------------- firmware/lib/webpage.py | 15 +++--------- firmware/lib/webpages/config.html | 9 +++++++ firmware/lib/webpages/default.html | 15 ++++++++++++ firmware/lib/webrouter.py | 39 ++++++++++++++++++++++++++++++ firmware/main.py | 19 ++++++++++----- 6 files changed, 80 insertions(+), 35 deletions(-) create mode 100644 firmware/lib/webpages/config.html create mode 100644 firmware/lib/webpages/default.html create mode 100644 firmware/lib/webrouter.py diff --git a/firmware/lib/connection.py b/firmware/lib/connection.py index a593409..490c679 100644 --- a/firmware/lib/connection.py +++ b/firmware/lib/connection.py @@ -68,26 +68,10 @@ def access_point_wifi_setup(): ap = network.WLAN(network.AP_IF) ap.config(essid="BabyScout", password="BabyBuddy") ap.active(True) + print(ap.status()) print(ap) return ap -def open_socket(ip, port): - address = (ip, port) - new_socket = socket.socket() - new_socket.bind((ip, port)) - new_socket.listen(1) - return new_socket - -def serve(socket, webpage): - while True: - client = socket.accept()[0] - request = client.recv(1024) - print(request) - request = Request(request.decode('utf-8')) - print(request) - client.send(webpage) - client.close() - def test_connection(url): try: diff --git a/firmware/lib/webpage.py b/firmware/lib/webpage.py index 71d7ec8..ac19e96 100644 --- a/firmware/lib/webpage.py +++ b/firmware/lib/webpage.py @@ -1,13 +1,4 @@ -def webpage(): - webpage = """ - - - Example - - -

This is an example of a simple HTML page with one paragraph.

- - - """ - +def load_webpage(location): + with open(location, "r") as website: + webpage = website.read() return webpage \ No newline at end of file diff --git a/firmware/lib/webpages/config.html b/firmware/lib/webpages/config.html new file mode 100644 index 0000000..409e2d6 --- /dev/null +++ b/firmware/lib/webpages/config.html @@ -0,0 +1,9 @@ + + + + BabyScout + + +

This is annother example of a simple HTML page with one paragraph.

+ + \ No newline at end of file diff --git a/firmware/lib/webpages/default.html b/firmware/lib/webpages/default.html new file mode 100644 index 0000000..b87badb --- /dev/null +++ b/firmware/lib/webpages/default.html @@ -0,0 +1,15 @@ + + + + BabyScout + + +
+
+
+
+

+ +
+ + \ No newline at end of file diff --git a/firmware/lib/webrouter.py b/firmware/lib/webrouter.py new file mode 100644 index 0000000..895499e --- /dev/null +++ b/firmware/lib/webrouter.py @@ -0,0 +1,39 @@ +from request import Request +import socket + +class WebRouter: + def __init__(self, ip, port, default): + self.routes = { + "default": default + } + self.socket = self.open_socket(ip, port) + + def route(self, path): + def router(function): + def wrapper(*args, **kwargs): + self.routes[path] = function + return wrapper + return router + + + @staticmethod + def open_socket(ip, port): + address = (ip, port) + new_socket = socket.socket() + new_socket.bind((ip, port)) + new_socket.listen(1) + return new_socket + + def serve(self): + while True: + client = self.socket.accept()[0] + request = client.recv(1024) + request = Request(request.decode('utf-8')) + path = request.path + if path in self.routes.keys(): + webpage = self.routes[path](request=request) + else: + webpage = self.routes["default"](request=request) + client.send(webpage) + client.close() + diff --git a/firmware/main.py b/firmware/main.py index 95bac67..77313c7 100644 --- a/firmware/main.py +++ b/firmware/main.py @@ -8,15 +8,21 @@ connect_to_access_point, scan_access_points, access_point_nearby, - access_point_wifi_setup, - open_socket, - serve + access_point_wifi_setup ) -from lib.webpage import webpage +from lib.webpage import load_webpage from lib.scout import connect_to_baby_buddy +from lib.webrouter import WebRouter # Retrieve WLAN Variables from secrets.json and establish connectivity to WLAN and BabyScout +def default_route(*args, **kwargs): + return load_webpage("lib/webpages/default.html") + +def config_route(*args, **kwargs): + return load_webpage("lib/webpages/config.html") + + WLAN_VARIABLES = retrieve_auth_variables(join_path(os.getcwd(), "secrets.json")) BASE_URL = WLAN_VARIABLES["BASE_URL"] nearby_matching_access_point = access_point_nearby(scan_access_points(), WLAN_VARIABLES) @@ -29,8 +35,9 @@ print("No matching wifi, falling back to webpage based setup") ap = access_point_wifi_setup() ip = ap.ifconfig()[0] - socket = open_socket(ip, 80) - serve(socket, webpage()) + app = WebRouter(ip, 80, default_route) + app.route("/test")(config_route)() + app.serve() BABY_SCOUT = connect_to_baby_buddy(base_url=BASE_URL) From 7d174da563ec25108afb6c627fbb6a6cc6265c57 Mon Sep 17 00:00:00 2001 From: Michael Schappacher Date: Sat, 24 Sep 2022 00:04:14 -0400 Subject: [PATCH 06/13] Wifi based setup is now functional, need to add in extra options for baby buddy url, token and extra auth headers --- firmware/lib/request.py | 11 +++++++++++ firmware/lib/webpages/default.html | 10 +++++----- firmware/main.py | 16 +++++++++++++--- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/firmware/lib/request.py b/firmware/lib/request.py index b6277f9..ef53dd3 100644 --- a/firmware/lib/request.py +++ b/firmware/lib/request.py @@ -3,6 +3,7 @@ def __init__(self, request): self.raw = request self.method = None self.path = None + self.query_strings = None self.protocol = None self.headers = None self.body = None @@ -13,6 +14,16 @@ def parse_request(self): split_request = request.split("\r\n") request_line = split_request.pop(0) self.method, self.path, self.protocol = request_line.split(" ") + if "?" in self.path: + query_strings = {} + self.path, raw_query = self.path.split("?") + raw_query = raw_query.split("&") + for query in raw_query: + key, value = query.split("=") + query_strings[key] = value + self.query_strings = query_strings + + headers = {} for header in split_request: key, value = header.split(": ") diff --git a/firmware/lib/webpages/default.html b/firmware/lib/webpages/default.html index b87badb..a6c1d3c 100644 --- a/firmware/lib/webpages/default.html +++ b/firmware/lib/webpages/default.html @@ -4,11 +4,11 @@ BabyScout -
-
-
-
-

+ +
+
+
+

diff --git a/firmware/main.py b/firmware/main.py index 77313c7..9a0ff1d 100644 --- a/firmware/main.py +++ b/firmware/main.py @@ -1,7 +1,9 @@ from lib.pin import create_button, onboard_led import lib.scout as scout import time +import machine import uos as os +import ujson as json import _thread from lib.utils import retrieve_auth_variables, join_path from lib.connection import ( @@ -20,7 +22,15 @@ def default_route(*args, **kwargs): return load_webpage("lib/webpages/default.html") def config_route(*args, **kwargs): - return load_webpage("lib/webpages/config.html") + request = kwargs.get("request") + if request.query_strings: + if "secrets.json" in os.listdir(): + with open("secrets.json", "r+") as secret: + secret_json = json.loads(secret.read()) + with open("secrets.json", "w") as secret: + secret_json["SSIDS_PASSWORD"][request.query_strings["ssid"]] = request.query_strings["password"] + secret.write(json.dumps(secret_json)) + machine.soft_reset() WLAN_VARIABLES = retrieve_auth_variables(join_path(os.getcwd(), "secrets.json")) @@ -32,11 +42,11 @@ def config_route(*args, **kwargs): WLAN_VARIABLES["SSIDS_PASSWORD"][nearby_matching_access_point], ) else: - print("No matching wifi, falling back to webpage based setup") + print("No matching wifi, falling back to webpage based setup.") ap = access_point_wifi_setup() ip = ap.ifconfig()[0] app = WebRouter(ip, 80, default_route) - app.route("/test")(config_route)() + app.route("/config")(config_route)() app.serve() From 2ff35dda5013f4aa511e6384bf70392ece67a135 Mon Sep 17 00:00:00 2001 From: Michael Schappacher Date: Sat, 24 Sep 2022 00:36:23 -0400 Subject: [PATCH 07/13] Add in extra fields to point BabyScout to wifi and babybuddy --- firmware/lib/webpage.py | 25 ++++++++++++++++++++++++- firmware/lib/webpages/default.html | 8 ++++++-- firmware/main.py | 18 ++---------------- firmware/secrets.json.placeholder | 13 +++++++------ 4 files changed, 39 insertions(+), 25 deletions(-) diff --git a/firmware/lib/webpage.py b/firmware/lib/webpage.py index ac19e96..ccb7f07 100644 --- a/firmware/lib/webpage.py +++ b/firmware/lib/webpage.py @@ -1,4 +1,27 @@ +import uos as os +import ujson as json +import machine + def load_webpage(location): with open(location, "r") as website: webpage = website.read() - return webpage \ No newline at end of file + return webpage + +def default_route(*args, **kwargs): + return load_webpage("lib/webpages/default.html") + +def config_route(*args, **kwargs): + request = kwargs.get("request") + if request.query_strings: + if "secrets.json" in os.listdir(): + with open("secrets.json", "r+") as secret: + secret_json = json.loads(secret.read()) + with open("secrets.json", "w") as secret: + secret_json["SSIDS_PASSWORD"][request.query_strings["ssid"]] = request.query_strings["password"] + secret.write(json.dumps(secret_json)) + else: + with open("secrets.json", "w") as secret: + secret_json["SSIDS_PASSWORD"][request.query_strings["ssid"]] = request.query_strings["password"] + secret_json["AUTHORIZATION"]["Authorization"] = "Token " + request.query_strings["babyauth"] + secret.write(json.dumps(secret_json)) + machine.soft_reset() \ No newline at end of file diff --git a/firmware/lib/webpages/default.html b/firmware/lib/webpages/default.html index a6c1d3c..f06143e 100644 --- a/firmware/lib/webpages/default.html +++ b/firmware/lib/webpages/default.html @@ -6,9 +6,13 @@

-
+

-

+

+
+
+
+
diff --git a/firmware/main.py b/firmware/main.py index 9a0ff1d..8c1b22e 100644 --- a/firmware/main.py +++ b/firmware/main.py @@ -1,7 +1,6 @@ from lib.pin import create_button, onboard_led import lib.scout as scout import time -import machine import uos as os import ujson as json import _thread @@ -12,26 +11,13 @@ access_point_nearby, access_point_wifi_setup ) -from lib.webpage import load_webpage +from lib.webpage import config_route, default_route from lib.scout import connect_to_baby_buddy from lib.webrouter import WebRouter # Retrieve WLAN Variables from secrets.json and establish connectivity to WLAN and BabyScout -def default_route(*args, **kwargs): - return load_webpage("lib/webpages/default.html") - -def config_route(*args, **kwargs): - request = kwargs.get("request") - if request.query_strings: - if "secrets.json" in os.listdir(): - with open("secrets.json", "r+") as secret: - secret_json = json.loads(secret.read()) - with open("secrets.json", "w") as secret: - secret_json["SSIDS_PASSWORD"][request.query_strings["ssid"]] = request.query_strings["password"] - secret.write(json.dumps(secret_json)) - machine.soft_reset() - +# Case when secrets.json does not exist WLAN_VARIABLES = retrieve_auth_variables(join_path(os.getcwd(), "secrets.json")) BASE_URL = WLAN_VARIABLES["BASE_URL"] diff --git a/firmware/secrets.json.placeholder b/firmware/secrets.json.placeholder index fc0f5d8..6e339e3 100644 --- a/firmware/secrets.json.placeholder +++ b/firmware/secrets.json.placeholder @@ -1,10 +1,11 @@ { - "SSID": "", - "PASSWORD": "", - "BASE_URL": "http://192.168.0.232:30010/api/", + "SSIDS_PASSWORD": { + "MYSSID": "MYPASSWORD + }, + "BASE_URL": "http://baby.example.com/api/", "AUTHORIZATION": { - "Sample Cloudfront Access Header", - "Sample Cloudfront Access Header", - "Authorization": "TOKEN for access to BabyBuddy" + "CF-Access-Client-Id": "my cloudfront tunnel id", + "CF-Access-Client-Secret": "my cloudfront tunnel secret", + "Authorization": "Token my baby buddy token " } } \ No newline at end of file From b1b8fd0b29d32c9a48b8f6b3e5689865ba025463 Mon Sep 17 00:00:00 2001 From: Michael Schappacher Date: Sat, 24 Sep 2022 10:25:16 -0400 Subject: [PATCH 08/13] Remove empty ssids from scan_access_points --- firmware/lib/connection.py | 7 +++++-- firmware/main.py | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/firmware/lib/connection.py b/firmware/lib/connection.py index 490c679..1417e30 100644 --- a/firmware/lib/connection.py +++ b/firmware/lib/connection.py @@ -36,12 +36,15 @@ def scan_access_points(): for ssid in nearby_access_points: nearby_access_point_list.append(ssid[0].decode("utf-8")) wlan.active(False) + while '' in nearby_access_point_list: + nearby_access_point_list.remove('') + print(nearby_access_point_list) return nearby_access_point_list -def access_point_nearby(nearby_ssids, wlan_variables): +def access_point_nearby(nearby_ssids, configured_ssids): matching_ssids = [] - for ssid in wlan_variables["SSIDS_PASSWORD"].keys(): + for ssid in configured_ssids: if ssid in nearby_ssids: matching_ssids.append(ssid) if matching_ssids: diff --git a/firmware/main.py b/firmware/main.py index 8c1b22e..02fcef7 100644 --- a/firmware/main.py +++ b/firmware/main.py @@ -21,7 +21,8 @@ WLAN_VARIABLES = retrieve_auth_variables(join_path(os.getcwd(), "secrets.json")) BASE_URL = WLAN_VARIABLES["BASE_URL"] -nearby_matching_access_point = access_point_nearby(scan_access_points(), WLAN_VARIABLES) +local_access_points = scan_access_points() +nearby_matching_access_point = access_point_nearby(local_access_points, WLAN_VARIABLES["SSIDS_PASSWORD"].keys()) if nearby_matching_access_point: WLAN = connect_to_access_point( nearby_matching_access_point, From 30a5e3705040c948e4038afc869cff572c3a5dad Mon Sep 17 00:00:00 2001 From: Michael Schappacher Date: Sat, 24 Sep 2022 11:34:18 -0400 Subject: [PATCH 09/13] Cover all paths for ap mode --- firmware/lib/utils.py | 14 ++++- firmware/main.py | 138 +++++++++++++++++++++--------------------- 2 files changed, 82 insertions(+), 70 deletions(-) diff --git a/firmware/lib/utils.py b/firmware/lib/utils.py index 4690f1a..7802a94 100644 --- a/firmware/lib/utils.py +++ b/firmware/lib/utils.py @@ -2,9 +2,19 @@ def retrieve_auth_variables(auth_path): - with open(auth_path) as open_auth: - return json.load(open_auth) + try: + with open(auth_path) as open_auth: + return json.load(open_auth) + except: + return None +def auth_variables_valid(loaded_auth): + ssids = loaded_auth.get("SSIDS_PASSWORD") + base_url = loaded_auth.get("BASE_URL") + auth = loaded_auth.get("AUTHORIZATION") + if not ssids or not base_url or not auth: + return False + return True def get_base_path(path): split_path = path.split("/") diff --git a/firmware/main.py b/firmware/main.py index 02fcef7..b1f78e8 100644 --- a/firmware/main.py +++ b/firmware/main.py @@ -4,7 +4,7 @@ import uos as os import ujson as json import _thread -from lib.utils import retrieve_auth_variables, join_path +from lib.utils import retrieve_auth_variables, join_path, auth_variables_valid from lib.connection import ( connect_to_access_point, scan_access_points, @@ -18,79 +18,81 @@ # Retrieve WLAN Variables from secrets.json and establish connectivity to WLAN and BabyScout # Case when secrets.json does not exist +ap_mode = False WLAN_VARIABLES = retrieve_auth_variables(join_path(os.getcwd(), "secrets.json")) -BASE_URL = WLAN_VARIABLES["BASE_URL"] local_access_points = scan_access_points() -nearby_matching_access_point = access_point_nearby(local_access_points, WLAN_VARIABLES["SSIDS_PASSWORD"].keys()) -if nearby_matching_access_point: - WLAN = connect_to_access_point( - nearby_matching_access_point, - WLAN_VARIABLES["SSIDS_PASSWORD"][nearby_matching_access_point], - ) +if auth_variables_valid(WLAN_VARIABLES): + nearby_matching_access_point = access_point_nearby(local_access_points, WLAN_VARIABLES.get("SSIDS_PASSWORD").keys()) + if nearby_matching_access_point: + WLAN = connect_to_access_point( + nearby_matching_access_point, + WLAN_VARIABLES["SSIDS_PASSWORD"][nearby_matching_access_point], + ) + BABY_SCOUT = connect_to_baby_buddy(base_url=WLAN_VARIABLES["BASE_URL"]) + # Set default to first child in BabyBuddy, add functionality to allow for toggling between multiple children. + child = BABY_SCOUT.children[0] + + # Create button matrix, matching gpio pin to the specific action you want to capture + button_gpio_pins = [9, 8, 7, 6, 5, 4, 3, 2] + button_actions = [ + BABY_SCOUT.left_breast, + BABY_SCOUT.breast_feed, + BABY_SCOUT.right_breast, + BABY_SCOUT.bottle_feed, + BABY_SCOUT.wet_diaper, + BABY_SCOUT.solid_diaper, + BABY_SCOUT.wet_solid_diaper, + BABY_SCOUT.sleep, + ] + + # Initialize buttons + buttons = [] + for button in button_gpio_pins: + buttons.append(create_button(button)) + + + # Loop through and check if any button has been pressed. + + + def button_pressed(): + while True: + for index, button in enumerate(buttons): + if button.value(): + onboard_led(1) + time.sleep(0.5) + onboard_led(0) + button_actions[index](child) + + + # Continually check and assure connectivity to wireless and babyscout + + + def ensure_connection(): + global WLAN + global BABY_SCOUT + while True: + print("Testing Connection") + if not WLAN.isconnected(): + print("Lost Connection") + WLAN = connect_to_access_point(wlan_variables=WLAN_VARIABLES) + print("Reconnected") + time.sleep(10) + + + # Start thread to ensure internet connection + _thread.start_new_thread(ensure_connection, ()) + + # Begin button checking loop + button_pressed() + else: + ap_mode = True else: + ap_mode = True +if ap_mode: print("No matching wifi, falling back to webpage based setup.") ap = access_point_wifi_setup() ip = ap.ifconfig()[0] app = WebRouter(ip, 80, default_route) app.route("/config")(config_route)() - app.serve() - - -BABY_SCOUT = connect_to_baby_buddy(base_url=BASE_URL) -# Set default to first child in BabyBuddy, add functionality to allow for toggling between multiple children. -child = BABY_SCOUT.children[0] - -# Create button matrix, matching gpio pin to the specific action you want to capture -button_gpio_pins = [9, 8, 7, 6, 5, 4, 3, 2] -button_actions = [ - BABY_SCOUT.left_breast, - BABY_SCOUT.breast_feed, - BABY_SCOUT.right_breast, - BABY_SCOUT.bottle_feed, - BABY_SCOUT.wet_diaper, - BABY_SCOUT.solid_diaper, - BABY_SCOUT.wet_solid_diaper, - BABY_SCOUT.sleep, -] - -# Initialize buttons -buttons = [] -for button in button_gpio_pins: - buttons.append(create_button(button)) - - -# Loop through and check if any button has been pressed. - - -def button_pressed(): - while True: - for index, button in enumerate(buttons): - if button.value(): - onboard_led(1) - time.sleep(0.5) - onboard_led(0) - button_actions[index](child) - - -# Continually check and assure connectivity to wireless and babyscout - - -def ensure_connection(): - global WLAN - global BABY_SCOUT - while True: - print("Testing Connection") - if not WLAN.isconnected(): - print("Lost Connection") - WLAN = connect_to_access_point(wlan_variables=WLAN_VARIABLES) - print("Reconnected") - time.sleep(10) - - -# Start thread to ensure internet connection -_thread.start_new_thread(ensure_connection, ()) - -# Begin button checking loop -button_pressed() - + app.serve() \ No newline at end of file From b89d2d8892f913106689ddd127e0d8f61e593896 Mon Sep 17 00:00:00 2001 From: Michael Schappacher Date: Sun, 25 Sep 2022 09:44:56 -0400 Subject: [PATCH 10/13] Move all pi connection options to object for easier management, moved api_request logic to baby buddy, added reset logic for reconnecting to baby buddy if connection is lost. --- firmware/lib/connection.py | 117 ++++++++++++++++--------------------- firmware/lib/scout.py | 20 ++++++- firmware/lib/webpage.py | 2 +- firmware/main.py | 38 ++++++------ 4 files changed, 86 insertions(+), 91 deletions(-) diff --git a/firmware/lib/connection.py b/firmware/lib/connection.py index 1417e30..5d29882 100644 --- a/firmware/lib/connection.py +++ b/firmware/lib/connection.py @@ -9,79 +9,60 @@ from request import Request -def send_api_request(base_url, path, headers={}, data={}): - auth_variables = utils.retrieve_auth_variables( - utils.join_path(os.getcwd(), "secrets.json") - )["AUTHORIZATION"] - if headers: - auth_variables.update(headers) - if data: - data = json.dumps(data) - auth_variables["Content-Type"] = "application/json" - return json.loads( - requests.post( - url=base_url + path + "/", headers=auth_variables, data=data - ).content - ) - return json.loads( - requests.get(url=base_url + path + "/", headers=auth_variables).content - ) +class PicoConnection: + def __init__(self): + self.wlan = self.wireless_client_setup() + self.nearby_access_points = self.scan_access_points() + @staticmethod + def wireless_client_setup(): + wlan = network.WLAN(network.STA_IF) + wlan.active(True) + return wlan -def scan_access_points(): - nearby_access_point_list = [] - wlan = network.WLAN(network.STA_IF) - wlan.active(True) - nearby_access_points = wlan.scan() - for ssid in nearby_access_points: - nearby_access_point_list.append(ssid[0].decode("utf-8")) - wlan.active(False) - while '' in nearby_access_point_list: - nearby_access_point_list.remove('') - print(nearby_access_point_list) - return nearby_access_point_list + @staticmethod + def access_point_wifi_setup(): + ap = network.WLAN(network.AP_IF) + ap.config(essid="BabyScout", password="BabyBuddy") + ap.active(True) + print(ap.status()) + print(ap) + return ap - -def access_point_nearby(nearby_ssids, configured_ssids): - matching_ssids = [] - for ssid in configured_ssids: - if ssid in nearby_ssids: - matching_ssids.append(ssid) - if matching_ssids: - return matching_ssids[0] - return None - - -def connect_to_access_point(ssid, password): + def connect_to_access_point(self, ssid, password): # Attempt to connect to WIFI - wlan = network.WLAN(network.STA_IF) - wlan.active(True) - wlan.connect(ssid, password) - print(f"Attempting to connect to {ssid}") - while not wlan.isconnected(): - onboard_led() - time.sleep(0.5) - onboard_led() - time.sleep(0.5) - print("WLAN Connected") - return wlan - + if ssid not in self.nearby_access_points: + return False + self.wlan.active(True) + self.wlan.connect(ssid, password) + print(f"Attempting to connect to {ssid}") + while not self.wlan.isconnected(): + onboard_led() + time.sleep(0.5) + onboard_led() + time.sleep(0.5) + print("WLAN Connected") + return True + -def access_point_wifi_setup(): - ap = network.WLAN(network.AP_IF) - ap.config(essid="BabyScout", password="BabyBuddy") - ap.active(True) - print(ap.status()) - print(ap) - return ap + def scan_access_points(self): + nearby_access_point_list = [] + nearby_access_points = self.wlan.scan() + for ssid in nearby_access_points: + nearby_access_point_list.append(ssid[0].decode("utf-8")) + self.wlan.active(False) + while '' in nearby_access_point_list: + nearby_access_point_list.remove('') + print(nearby_access_point_list) + return nearby_access_point_list -def test_connection(url): - try: - status = requests.get(url=url).status_code - if status == 200: - return True - return False - except: - return False + def access_point_nearby(self, configured_ssids): + matching_ssids = [] + for ssid in configured_ssids: + if ssid in self.nearby_access_points: + matching_ssids.append(ssid) + if matching_ssids: + return matching_ssids[0] + return None diff --git a/firmware/lib/scout.py b/firmware/lib/scout.py index dbc5c8f..b9f74a6 100644 --- a/firmware/lib/scout.py +++ b/firmware/lib/scout.py @@ -1,9 +1,9 @@ +import utils import urequests as requests import ujson as json import uos as os import ussl as ssl from micropython import * -from connection import send_api_request from pin import onboard_led import time @@ -120,3 +120,21 @@ def connect_to_baby_buddy(base_url): onboard_led(0) print("Connected to BabyBuddy") return baby_buddy + +def send_api_request(base_url, path, headers={}, data={}): + auth_variables = utils.retrieve_auth_variables( + utils.join_path(os.getcwd(), "secrets.json") + )["AUTHORIZATION"] + if headers: + auth_variables.update(headers) + if data: + data = json.dumps(data) + auth_variables["Content-Type"] = "application/json" + return json.loads( + requests.post( + url=base_url + path + "/", headers=auth_variables, data=data + ).content + ) + return json.loads( + requests.get(url=base_url + path + "/", headers=auth_variables).content + ) diff --git a/firmware/lib/webpage.py b/firmware/lib/webpage.py index ccb7f07..3941d8f 100644 --- a/firmware/lib/webpage.py +++ b/firmware/lib/webpage.py @@ -24,4 +24,4 @@ def config_route(*args, **kwargs): secret_json["SSIDS_PASSWORD"][request.query_strings["ssid"]] = request.query_strings["password"] secret_json["AUTHORIZATION"]["Authorization"] = "Token " + request.query_strings["babyauth"] secret.write(json.dumps(secret_json)) - machine.soft_reset() \ No newline at end of file + machine.reset() diff --git a/firmware/main.py b/firmware/main.py index b1f78e8..fdadeee 100644 --- a/firmware/main.py +++ b/firmware/main.py @@ -1,3 +1,4 @@ +from cmath import pi from lib.pin import create_button, onboard_led import lib.scout as scout import time @@ -5,27 +6,24 @@ import ujson as json import _thread from lib.utils import retrieve_auth_variables, join_path, auth_variables_valid -from lib.connection import ( - connect_to_access_point, - scan_access_points, - access_point_nearby, - access_point_wifi_setup -) +from lib.connection import PicoConnection from lib.webpage import config_route, default_route from lib.scout import connect_to_baby_buddy from lib.webrouter import WebRouter +import machine # Retrieve WLAN Variables from secrets.json and establish connectivity to WLAN and BabyScout +WLAN_VARIABLES = retrieve_auth_variables(join_path(os.getcwd(), "secrets.json")) -# Case when secrets.json does not exist +# Setup object for managing AP connections +pico_connection = PicoConnection() ap_mode = False -WLAN_VARIABLES = retrieve_auth_variables(join_path(os.getcwd(), "secrets.json")) -local_access_points = scan_access_points() + if auth_variables_valid(WLAN_VARIABLES): - nearby_matching_access_point = access_point_nearby(local_access_points, WLAN_VARIABLES.get("SSIDS_PASSWORD").keys()) + nearby_matching_access_point = pico_connection.access_point_nearby(WLAN_VARIABLES.get("SSIDS_PASSWORD").keys()) if nearby_matching_access_point: - WLAN = connect_to_access_point( + pico_connection.connect_to_access_point( nearby_matching_access_point, WLAN_VARIABLES["SSIDS_PASSWORD"][nearby_matching_access_point], ) @@ -69,19 +67,16 @@ def button_pressed(): def ensure_connection(): - global WLAN - global BABY_SCOUT while True: print("Testing Connection") - if not WLAN.isconnected(): - print("Lost Connection") - WLAN = connect_to_access_point(wlan_variables=WLAN_VARIABLES) - print("Reconnected") + if not pico_connection.wlan.isconnected(): + print("Lost Connection, Rebooting") + machine.reset() time.sleep(10) - # Start thread to ensure internet connection - _thread.start_new_thread(ensure_connection, ()) + _thread.start_new_thread(ensure_connection, () + ) # Begin button checking loop button_pressed() @@ -91,8 +86,9 @@ def ensure_connection(): ap_mode = True if ap_mode: print("No matching wifi, falling back to webpage based setup.") - ap = access_point_wifi_setup() + ap = pico_connection.access_point_wifi_setup() ip = ap.ifconfig()[0] app = WebRouter(ip, 80, default_route) app.route("/config")(config_route)() - app.serve() \ No newline at end of file + app.serve() + From f89355f632aa06e2892fd4723dd5e25e8b68ed67 Mon Sep 17 00:00:00 2001 From: Michael Schappacher Date: Sun, 25 Sep 2022 09:58:01 -0400 Subject: [PATCH 11/13] Add vscode files, and reformat --- .picowgo | 1 + .vscode/Pico-W-Stub | 1 + .vscode/extensions.json | 7 +++++++ .vscode/settings.json | 13 +++++++++++++ firmware/lib/connection.py | 9 +++------ firmware/lib/request.py | 6 ------ firmware/lib/scout.py | 1 + firmware/lib/utils.py | 2 ++ firmware/lib/webpage.py | 15 ++++++++++++--- firmware/lib/webrouter.py | 13 ++++++------- firmware/main.py | 12 ++++-------- 11 files changed, 50 insertions(+), 30 deletions(-) create mode 100644 .picowgo create mode 120000 .vscode/Pico-W-Stub create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json diff --git a/.picowgo b/.picowgo new file mode 100644 index 0000000..2b7291a --- /dev/null +++ b/.picowgo @@ -0,0 +1 @@ +{'info': 'This file is just used to identify a project folder.'} \ No newline at end of file diff --git a/.vscode/Pico-W-Stub b/.vscode/Pico-W-Stub new file mode 120000 index 0000000..f3b2eb3 --- /dev/null +++ b/.vscode/Pico-W-Stub @@ -0,0 +1 @@ +/home/mschappacher/.config/Code/User/Pico-W-Stub \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..2d69e4c --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "ms-python.python", + "visualstudioexptteam.vscodeintellicode", + "ms-python.vscode-pylance" + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..d03f082 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,13 @@ +{ + "python.linting.enabled": true, + "python.analysis.typeshedPaths": [ + ".vscode/Pico-W-Stub" + ], + "python.languageServer": "Pylance", + "python.analysis.typeCheckingMode": "basic", + "python.analysis.extraPaths": [ + ".vscode/Pico-W-Stub/stubs" + ], + "picowgo.syncFolder": "", + "picowgo.openOnStart": true +} \ No newline at end of file diff --git a/firmware/lib/connection.py b/firmware/lib/connection.py index 5d29882..53984b3 100644 --- a/firmware/lib/connection.py +++ b/firmware/lib/connection.py @@ -30,7 +30,7 @@ def access_point_wifi_setup(): return ap def connect_to_access_point(self, ssid, password): - # Attempt to connect to WIFI + # Attempt to connect to WIFI if ssid not in self.nearby_access_points: return False self.wlan.active(True) @@ -43,7 +43,6 @@ def connect_to_access_point(self, ssid, password): time.sleep(0.5) print("WLAN Connected") return True - def scan_access_points(self): nearby_access_point_list = [] @@ -51,12 +50,11 @@ def scan_access_points(self): for ssid in nearby_access_points: nearby_access_point_list.append(ssid[0].decode("utf-8")) self.wlan.active(False) - while '' in nearby_access_point_list: - nearby_access_point_list.remove('') + while "" in nearby_access_point_list: + nearby_access_point_list.remove("") print(nearby_access_point_list) return nearby_access_point_list - def access_point_nearby(self, configured_ssids): matching_ssids = [] for ssid in configured_ssids: @@ -65,4 +63,3 @@ def access_point_nearby(self, configured_ssids): if matching_ssids: return matching_ssids[0] return None - diff --git a/firmware/lib/request.py b/firmware/lib/request.py index ef53dd3..0ea6d8e 100644 --- a/firmware/lib/request.py +++ b/firmware/lib/request.py @@ -22,15 +22,9 @@ def parse_request(self): key, value = query.split("=") query_strings[key] = value self.query_strings = query_strings - headers = {} for header in split_request: key, value = header.split(": ") headers[key] = value self.headers = headers - - - - - diff --git a/firmware/lib/scout.py b/firmware/lib/scout.py index b9f74a6..bee92c8 100644 --- a/firmware/lib/scout.py +++ b/firmware/lib/scout.py @@ -121,6 +121,7 @@ def connect_to_baby_buddy(base_url): print("Connected to BabyBuddy") return baby_buddy + def send_api_request(base_url, path, headers={}, data={}): auth_variables = utils.retrieve_auth_variables( utils.join_path(os.getcwd(), "secrets.json") diff --git a/firmware/lib/utils.py b/firmware/lib/utils.py index 7802a94..dfff412 100644 --- a/firmware/lib/utils.py +++ b/firmware/lib/utils.py @@ -8,6 +8,7 @@ def retrieve_auth_variables(auth_path): except: return None + def auth_variables_valid(loaded_auth): ssids = loaded_auth.get("SSIDS_PASSWORD") base_url = loaded_auth.get("BASE_URL") @@ -16,6 +17,7 @@ def auth_variables_valid(loaded_auth): return False return True + def get_base_path(path): split_path = path.split("/") return "/".join(split_path[0:-1]) diff --git a/firmware/lib/webpage.py b/firmware/lib/webpage.py index 3941d8f..78a63d8 100644 --- a/firmware/lib/webpage.py +++ b/firmware/lib/webpage.py @@ -2,14 +2,17 @@ import ujson as json import machine + def load_webpage(location): with open(location, "r") as website: webpage = website.read() return webpage + def default_route(*args, **kwargs): return load_webpage("lib/webpages/default.html") + def config_route(*args, **kwargs): request = kwargs.get("request") if request.query_strings: @@ -17,11 +20,17 @@ def config_route(*args, **kwargs): with open("secrets.json", "r+") as secret: secret_json = json.loads(secret.read()) with open("secrets.json", "w") as secret: - secret_json["SSIDS_PASSWORD"][request.query_strings["ssid"]] = request.query_strings["password"] + secret_json["SSIDS_PASSWORD"][ + request.query_strings["ssid"] + ] = request.query_strings["password"] secret.write(json.dumps(secret_json)) else: with open("secrets.json", "w") as secret: - secret_json["SSIDS_PASSWORD"][request.query_strings["ssid"]] = request.query_strings["password"] - secret_json["AUTHORIZATION"]["Authorization"] = "Token " + request.query_strings["babyauth"] + secret_json["SSIDS_PASSWORD"][ + request.query_strings["ssid"] + ] = request.query_strings["password"] + secret_json["AUTHORIZATION"]["Authorization"] = ( + "Token " + request.query_strings["babyauth"] + ) secret.write(json.dumps(secret_json)) machine.reset() diff --git a/firmware/lib/webrouter.py b/firmware/lib/webrouter.py index 895499e..b44ee08 100644 --- a/firmware/lib/webrouter.py +++ b/firmware/lib/webrouter.py @@ -1,20 +1,20 @@ from request import Request import socket + class WebRouter: def __init__(self, ip, port, default): - self.routes = { - "default": default - } + self.routes = {"default": default} self.socket = self.open_socket(ip, port) - + def route(self, path): def router(function): def wrapper(*args, **kwargs): self.routes[path] = function + return wrapper + return router - @staticmethod def open_socket(ip, port): @@ -28,7 +28,7 @@ def serve(self): while True: client = self.socket.accept()[0] request = client.recv(1024) - request = Request(request.decode('utf-8')) + request = Request(request.decode("utf-8")) path = request.path if path in self.routes.keys(): webpage = self.routes[path](request=request) @@ -36,4 +36,3 @@ def serve(self): webpage = self.routes["default"](request=request) client.send(webpage) client.close() - diff --git a/firmware/main.py b/firmware/main.py index fdadeee..87df45a 100644 --- a/firmware/main.py +++ b/firmware/main.py @@ -21,7 +21,9 @@ if auth_variables_valid(WLAN_VARIABLES): - nearby_matching_access_point = pico_connection.access_point_nearby(WLAN_VARIABLES.get("SSIDS_PASSWORD").keys()) + nearby_matching_access_point = pico_connection.access_point_nearby( + WLAN_VARIABLES.get("SSIDS_PASSWORD").keys() + ) if nearby_matching_access_point: pico_connection.connect_to_access_point( nearby_matching_access_point, @@ -49,10 +51,8 @@ for button in button_gpio_pins: buttons.append(create_button(button)) - # Loop through and check if any button has been pressed. - def button_pressed(): while True: for index, button in enumerate(buttons): @@ -62,10 +62,8 @@ def button_pressed(): onboard_led(0) button_actions[index](child) - # Continually check and assure connectivity to wireless and babyscout - def ensure_connection(): while True: print("Testing Connection") @@ -75,8 +73,7 @@ def ensure_connection(): time.sleep(10) # Start thread to ensure internet connection - _thread.start_new_thread(ensure_connection, () - ) + _thread.start_new_thread(ensure_connection, ()) # Begin button checking loop button_pressed() @@ -91,4 +88,3 @@ def ensure_connection(): app = WebRouter(ip, 80, default_route) app.route("/config")(config_route)() app.serve() - From d2ed3f16ca4e7a7f1c3a338611e74e3d7036e9d0 Mon Sep 17 00:00:00 2001 From: Michael Schappacher Date: Sun, 25 Sep 2022 11:59:48 -0400 Subject: [PATCH 12/13] Added in basic templating to html, allow for more dynamic webpages --- firmware/lib/request.py | 6 ++++- firmware/lib/scout.py | 2 +- firmware/lib/template.py | 5 ++++ firmware/lib/webpage.py | 38 ++++++++++++++++++------------ firmware/lib/webpages/default.html | 9 +------ 5 files changed, 35 insertions(+), 25 deletions(-) create mode 100644 firmware/lib/template.py diff --git a/firmware/lib/request.py b/firmware/lib/request.py index 0ea6d8e..631f898 100644 --- a/firmware/lib/request.py +++ b/firmware/lib/request.py @@ -10,7 +10,11 @@ def __init__(self, request): self.parse_request() def parse_request(self): - request, self.body = self.raw.split("\r\n\r\n") + print(self.raw) + try: + request, self.body = self.raw.split("\r\n\r\n") + except ValueError: + request = self.raw split_request = request.split("\r\n") request_line = split_request.pop(0) self.method, self.path, self.protocol = request_line.split(" ") diff --git a/firmware/lib/scout.py b/firmware/lib/scout.py index bee92c8..e11e0dc 100644 --- a/firmware/lib/scout.py +++ b/firmware/lib/scout.py @@ -124,7 +124,7 @@ def connect_to_baby_buddy(base_url): def send_api_request(base_url, path, headers={}, data={}): auth_variables = utils.retrieve_auth_variables( - utils.join_path(os.getcwd(), "secrets.json") + utils.join_path(os.getcwd(), "../secrets.json") )["AUTHORIZATION"] if headers: auth_variables.update(headers) diff --git a/firmware/lib/template.py b/firmware/lib/template.py new file mode 100644 index 0000000..853eca2 --- /dev/null +++ b/firmware/lib/template.py @@ -0,0 +1,5 @@ +def render_template(loaded_html, variables): + modified_html = loaded_html + for key, value in variables.items(): + modified_html = modified_html.replace("{{ " + key + " }}", value) + return modified_html diff --git a/firmware/lib/webpage.py b/firmware/lib/webpage.py index 78a63d8..4e55d41 100644 --- a/firmware/lib/webpage.py +++ b/firmware/lib/webpage.py @@ -1,6 +1,7 @@ import uos as os import ujson as json import machine +import template def load_webpage(location): @@ -10,27 +11,34 @@ def load_webpage(location): def default_route(*args, **kwargs): - return load_webpage("lib/webpages/default.html") + options = [ + {"ssid": "SSID:"}, + {"password": "Password:"}, + {"babybuddy": "BabyBuddy URL:"}, + {"babyauth": "BabyBuddy API Key"}] + render = "" + for option in options: + for key, value in option.items(): + render += f'''
+

''' + return template.render_template(load_webpage("lib/webpages/default.html"), {"render": render}) def config_route(*args, **kwargs): request = kwargs.get("request") + secret_json = {} if request.query_strings: if "secrets.json" in os.listdir(): with open("secrets.json", "r+") as secret: secret_json = json.loads(secret.read()) - with open("secrets.json", "w") as secret: - secret_json["SSIDS_PASSWORD"][ - request.query_strings["ssid"] - ] = request.query_strings["password"] - secret.write(json.dumps(secret_json)) - else: - with open("secrets.json", "w") as secret: - secret_json["SSIDS_PASSWORD"][ - request.query_strings["ssid"] - ] = request.query_strings["password"] - secret_json["AUTHORIZATION"]["Authorization"] = ( - "Token " + request.query_strings["babyauth"] - ) - secret.write(json.dumps(secret_json)) + with open("secrets.json", "w") as secret: + secret_json["SSIDS_PASSWORD"][ + request.query_strings.get("ssid", "") + ] = request.query_strings.get("password", "") + if request.query_strings.get("babybuddy"): + secret_json["BASE_URL"] = request.query_strings.get("babybuddy") + if request.query_strings.get("babyauth"): + secret_json["AUTHORIZATION"]["Authorization"] = request.query_strings.get("babyauth") + secret.write(json.dumps(secret_json)) machine.reset() + diff --git a/firmware/lib/webpages/default.html b/firmware/lib/webpages/default.html index f06143e..49eb146 100644 --- a/firmware/lib/webpages/default.html +++ b/firmware/lib/webpages/default.html @@ -5,14 +5,7 @@
-
-
-
-

-
-
-
-
+ {{ render }}
From 69265d206d668a47cd2000cabe3e5afed1554594 Mon Sep 17 00:00:00 2001 From: Michael Schappacher Date: Sun, 25 Sep 2022 21:25:53 -0400 Subject: [PATCH 13/13] Logic for static files, and finalized a basic setup page for BabyBuddy --- .vscode/settings.json | 2 +- firmware/lib/webpage.py | 5 ++--- firmware/lib/webrouter.py | 27 +++++++++++++++++++++++- firmware/main.py | 2 +- firmware/{lib => }/webpages/config.html | 0 firmware/{lib => }/webpages/default.html | 3 +++ firmware/webpages/static/babyscout.css | 22 +++++++++++++++++++ firmware/webpages/static/babyscout.js | 1 + 8 files changed, 56 insertions(+), 6 deletions(-) rename firmware/{lib => }/webpages/config.html (100%) rename firmware/{lib => }/webpages/default.html (68%) create mode 100644 firmware/webpages/static/babyscout.css create mode 100644 firmware/webpages/static/babyscout.js diff --git a/.vscode/settings.json b/.vscode/settings.json index d03f082..9fea9f5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,6 +8,6 @@ "python.analysis.extraPaths": [ ".vscode/Pico-W-Stub/stubs" ], - "picowgo.syncFolder": "", + "picowgo.syncFolder": "firmware", "picowgo.openOnStart": true } \ No newline at end of file diff --git a/firmware/lib/webpage.py b/firmware/lib/webpage.py index 4e55d41..f717874 100644 --- a/firmware/lib/webpage.py +++ b/firmware/lib/webpage.py @@ -19,9 +19,8 @@ def default_route(*args, **kwargs): render = "" for option in options: for key, value in option.items(): - render += f'''
-

''' - return template.render_template(load_webpage("lib/webpages/default.html"), {"render": render}) + render += f'''

''' + return template.render_template(load_webpage("webpages/default.html"), {"render": render}) def config_route(*args, **kwargs): diff --git a/firmware/lib/webrouter.py b/firmware/lib/webrouter.py index b44ee08..66d8bdd 100644 --- a/firmware/lib/webrouter.py +++ b/firmware/lib/webrouter.py @@ -1,11 +1,15 @@ from request import Request import socket +import uos as os class WebRouter: - def __init__(self, ip, port, default): + def __init__(self, ip, port, default, static_location="static"): self.routes = {"default": default} self.socket = self.open_socket(ip, port) + self.static_location = static_location + self.static_files = [] + self.add_static() def route(self, path): def router(function): @@ -16,6 +20,12 @@ def wrapper(*args, **kwargs): return router + def add_static(self): + static_files = os.listdir(self.static_location) + if static_files: + for file in static_files: + self.static_files.append(f"/{file}") + @staticmethod def open_socket(ip, port): address = (ip, port) @@ -24,15 +34,30 @@ def open_socket(ip, port): new_socket.listen(1) return new_socket + @staticmethod + def determine_mimetype(path): + mimetype = "text/html" + if path.endswith('.js'): + mimetype = "text/javascript" + if path.endswith('.css'): + mimetype = "text/css" + + def serve(self): while True: client = self.socket.accept()[0] request = client.recv(1024) request = Request(request.decode("utf-8")) path = request.path + header = 'HTTP/1.1 200 OK\n' + mimetype = self.determine_mimetype(path) if path in self.routes.keys(): webpage = self.routes[path](request=request) + elif path in self.static_files: + with open(f"{self.static_location}/{path}", "rb") as static: + webpage = static.read() else: webpage = self.routes["default"](request=request) + header += f"Content-Type: {mimetype}\n\n" client.send(webpage) client.close() diff --git a/firmware/main.py b/firmware/main.py index 87df45a..e5ef558 100644 --- a/firmware/main.py +++ b/firmware/main.py @@ -85,6 +85,6 @@ def ensure_connection(): print("No matching wifi, falling back to webpage based setup.") ap = pico_connection.access_point_wifi_setup() ip = ap.ifconfig()[0] - app = WebRouter(ip, 80, default_route) + app = WebRouter(ip, 80, default_route, "webpages/static") app.route("/config")(config_route)() app.serve() diff --git a/firmware/lib/webpages/config.html b/firmware/webpages/config.html similarity index 100% rename from firmware/lib/webpages/config.html rename to firmware/webpages/config.html diff --git a/firmware/lib/webpages/default.html b/firmware/webpages/default.html similarity index 68% rename from firmware/lib/webpages/default.html rename to firmware/webpages/default.html index 49eb146..9e333b1 100644 --- a/firmware/lib/webpages/default.html +++ b/firmware/webpages/default.html @@ -2,8 +2,11 @@ BabyScout + + +

BabyScout

{{ render }} diff --git a/firmware/webpages/static/babyscout.css b/firmware/webpages/static/babyscout.css new file mode 100644 index 0000000..e7ad9da --- /dev/null +++ b/firmware/webpages/static/babyscout.css @@ -0,0 +1,22 @@ +body { + font-family: system-ui; + background: #242A2C; + color: #0E7487; + text-align: center; + } + + form { + width: 300px; + background: #2C454A; + border: 15px solid #2C454A; + padding: 50px; + margin: auto; + border-radius: 12px; + } + + input { + padding:10px; + border:0; + box-shadow:0 0 15px 4px rgba(0,0,0,0.06); + border-radius: 8px; + } \ No newline at end of file diff --git a/firmware/webpages/static/babyscout.js b/firmware/webpages/static/babyscout.js new file mode 100644 index 0000000..d213c7b --- /dev/null +++ b/firmware/webpages/static/babyscout.js @@ -0,0 +1 @@ +document.getElementsByTagName("h1")[0].style.fontSize = "3vw"; \ No newline at end of file