Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ print(connection.get_status())
-------------------------------------------------------------------


## Limitations & Considerations

- This library disables concurrent write protection-
If your code stores something to a file, be careful when writing to it while the board is plugged in to avoid corruption!

### Testing Status:
| MCU | Description |
| ----------- | ----------- |
Expand Down
10 changes: 10 additions & 0 deletions boot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# OFFICIAL CubeServer Helper Code - DO NOT REMOVE!
""" This file is run on hard resets and during code updates.
Copyright (c) 2023 Joseph R. Freeston
"""

import storage

print("Mounting storage with concurrent write protection off.")
storage.remount("/", False, disable_concurrent_write_protection=True)

14 changes: 13 additions & 1 deletion code.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,23 @@

from servercom import Connection, Text

# Connect to server:
print("Connecting to the server...")
connection = Connection()
print("Connected!")

connection.post(Text("Test from CircuitPython!"))
# Turn off WiFi to save power:
connection.close_wifi()

# Reconnect WiFi when ready:
connection.connect_wifi()

# Check for code updates from the server:
connection.code_update()

# If none, post Hello World:
connection.post(Text("Hello World!"))

# Get status:
print("Getting status:")
print(connection.get_status())
Binary file added cubeserver-api-python.zip
Binary file not shown.
2 changes: 1 addition & 1 deletion package.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env bash

./update_version.sh
zip -r cubeserver-api-python.zip . -x .gitignore -x ./.git 2>&1 > /dev/null
zip -r cubeserver-api-python.zip . -x .gitignore -x ./.git -x package.sh -x update_version.sh -x version.txt 2>&1 > /dev/null
echo cubeserver-api-python.zip
2 changes: 1 addition & 1 deletion LICENSE → servercom/LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2022 Joseph R. Freeston (snorklerjoe)
Copyright (c) 2022-2023 Joseph R. Freeston (snorklerjoe)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
75 changes: 71 additions & 4 deletions servercom/implementations/circuitpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,23 @@

import ssl
import wifi
import time
import socketpool
from gc import collect
from errno import EAGAIN
from binascii import b2a_base64
from binascii import b2a_base64, a2b_base64
from json import loads
from microcontroller import reset

# Helpers:
def _replace_code(new_code: bytes, do_reset=True):
"""Replaces the contents of code.py with a new bytes
"""
with open("/code.py", "wb") as fp:
fp.write(new_code)
if do_reset:
reset()

def enum(**enums):
"""Fake enum-maker"""
return type('Enum', (), enums)
Expand Down Expand Up @@ -157,12 +167,21 @@ def __init__(
self.context.load_verify_locations(cadata=server_cert)
self.connect_wifi()

def connect_wifi(self) -> None:
def connect_wifi(self, attempts=10) -> None:
"""Creates the wifi connection to the access point"""
wifi.radio.enabled = True
if self.v:
print("Connecting to the access point...")
wifi.radio.connect(self.conf.AP_SSID)
connected = False
while not connected and attempts > 0:
try:
wifi.radio.connect(self.conf.AP_SSID)
continue
except ConnectionError as e:
if self.v:
print(e.with_traceback)
attempts -= 1
time.sleep(1)
if self.v:
print("Initializing socket pool...")
self.pool = socketpool.SocketPool(wifi.radio)
Expand Down Expand Up @@ -356,11 +375,19 @@ def request(
raise last_error

def get_status(self) -> GameStatus:
resp = self.request('GET', '/status')
if self.v:
print("Getting status...")
resp = self.request('GET', '/status',
headers=['User-Agent: CircuitPython, dude!']
)
resp_json = loads(resp[1])
if self.v:
print(f"It is {resp_json['unix_time']} seconds since the epoch.")
return GameStatus(resp_json['unix_time'], resp_json['status']['score'], resp_json['status']['strikes'])

def post(self, point: DataPoint) -> bool:
if self.v:
print("Posting datapoint!")
return self.request(
'POST',
'/data',
Expand All @@ -370,6 +397,8 @@ def post(self, point: DataPoint) -> bool:
).code == 201

def email(self, msg: Email) -> bool:
if self.v:
print(f"Sending email {msg.subject}...")
return self.request(
'POST',
'/email',
Expand All @@ -378,6 +407,44 @@ def email(self, msg: Email) -> bool:
headers=['User-Agent: CircuitPython, dude!']
).code == 201

def code_update(self, reset=True) -> bool:
"""Checks for code updates from the server (uploaded by team)
call like code_update(reset=False) to download the update but not reset
(Must reset to run the new code)
Otherwise, run like code_update()
Returns True if reset is False and the update is successful.
Reset the microcontroller in this case.
Otherwise, returning False, the update is stale or invalid.
"""
if self.v:
print("Checking for updates...")
response = self.request(
'GET',
'/update',
headers=['User-Agent: CircuitPython, dude!']
)
if response.code != 200:
if self.v:
print(f"Bad response code {response.code}")
return False
print(f"Response: {response[1]}")
resp_json = loads(response[1])
if resp_json['new']:
if self.v:
print("New Update!")
_replace_code(
a2b_base64(
resp_json['code']
),
reset=reset
)
if self.v:
print("code.py replaced!")
return True
if self.v:
print("Stale update.")
return False

def __exit__(self):
if self.v:
print("Closing the server connection-")
Expand Down
2 changes: 2 additions & 0 deletions servercom/implementations/cpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,8 @@ def email(self, msg: Email) -> bool:
content_type = 'application/json',
headers=['User-Agent: CPython, dude!']
).code == 201
def code_update(reset=True):
pass
def __exit__(self):
if self.v:
print("Closing the server connection-")
Expand Down