From 84ac35fce34dfa45ba08d728599c24c8159dc9c4 Mon Sep 17 00:00:00 2001 From: Nick Art <100365428+NicK4rT@users.noreply.github.com> Date: Sat, 23 Nov 2024 14:49:26 -0500 Subject: [PATCH 01/10] Delete .github/workflows directory --- .github/workflows/render-README.yml | 50 ----------------------------- 1 file changed, 50 deletions(-) delete mode 100644 .github/workflows/render-README.yml diff --git a/.github/workflows/render-README.yml b/.github/workflows/render-README.yml deleted file mode 100644 index 50c5c92..0000000 --- a/.github/workflows/render-README.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Render README.qmd to Markdown - -on: - push: - branches: - - stage - -jobs: - render: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - persist-credentials: false # Prevents GitHub token reuse - - - name: Set up R - uses: r-lib/actions/setup-r@v2 - - - name: Install Required R Packages - run: | - Rscript -e 'if (!requireNamespace("rmarkdown", quietly = TRUE)) install.packages("rmarkdown", repos = "https://cloud.r-project.org/")' - Rscript -e 'if (!requireNamespace("knitr", quietly = TRUE)) install.packages("knitr", repos = "https://cloud.r-project.org/")' - - - name: Set up Quarto - uses: quarto-dev/quarto-actions/setup@v2 - - - name: Find and Render README.qmd Files - run: | - find . -name "README.qmd" | while read qmd_file; do - quarto render "$qmd_file" --to markdown - done - - - name: Commit and Push Rendered Files - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - git config --local user.name "$GITHUB_ACTOR" - git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" - git add . - git commit -m "Render README.qmd files to Markdown [skip ci]" || echo "No changes to commit" - - git fetch origin - git checkout stage || git checkout -b stage - - git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git - - git push origin stage - From df132ac5f6e7c85692b7e9be4e0b05310ca97a03 Mon Sep 17 00:00:00 2001 From: Nick Art Date: Mon, 25 Nov 2024 13:31:27 -0500 Subject: [PATCH 02/10] Added Code to recv commands --- .DS_Store | Bin 12292 -> 12292 bytes .gitignore | 2 + docs/.DS_Store | Bin 8196 -> 8196 bytes software/.DS_Store | Bin 8196 -> 8196 bytes software/applications/.DS_Store | Bin 10244 -> 10244 bytes software/networking/.DS_Store | Bin 6148 -> 6148 bytes software/networking/config.py | 3 +- software/networking/networking.py | 850 ++++++++++++++++-------------- 8 files changed, 446 insertions(+), 409 deletions(-) diff --git a/.DS_Store b/.DS_Store index 9720e53693e55910db9e6ab8b2da07d7d25842ad..64e8d3072c081024d824da2c00f4472d4a5531c2 100644 GIT binary patch delta 346 zcmZokXi1ph&uFqSU^hRb+GGJnkP(z04A~5+43!MUle@&47>y@eE4tM~MRL*& zgOl@f3m6apt~xj0#U&{xKM5$sA!gk8;&tUQM<5$XJ_WCQK?a7|>P(yag*8~2Sth-nyi1~xiOpfNuH-$o%?eB& zjFY()q~b)kZ)ad&U}4Z>NN31oD9O!taY@R_PXdZ@SpAVWIj`uLBdUA~UipFy!{Frn z+ybB;1_nKY$;}FT7|kX-D26dDY1=$QaWgC1uBBo?Qzr+i=S{vZAwF47k{9Tx$-0sX Nn^`s7*l|kB0|3tMK)C<_ diff --git a/.gitignore b/.gitignore index 5b6a065..08d1dcf 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ .Rhistory .RData .Ruserdata +keys/ACTIONS_RENDER.pub +keys/ACTIONS_RENDER diff --git a/docs/.DS_Store b/docs/.DS_Store index 78ce0ae9d3d3df1e129229fc3c5522e5b5c09c8c..e96c85dc11a0de087c6a8b03c46334c597fed8da 100644 GIT binary patch delta 161 zcmZp1XmOa}&nUVvU^hRb=wu!N877gg%~}F4S%f(mf*4#G92r~~e1WtcLoP$gQfSI7CIBYAA&vk5 delta 47 ycmZp1XmOa}&nUbxU^hRb@MInV879%&o3#X9vTUvt?PHqQkhYm!f`=8#Nd^FE#t&iu diff --git a/software/.DS_Store b/software/.DS_Store index 6d29c9c21830e9f91bfe2917bf9d630beefe5fc1..c72074347e0f50c95fd382ce557113964bc3e6c6 100644 GIT binary patch delta 153 zcmZp1XmQx!BgnLE!DK%{4c1#3@p20%R|{%GS*rzg851_&6kNc}%oxEuxkgllgH3{S qcW1>hM<7Q^D8(fyCqIdSfdN@qV)7eNUM41o&A&zK*vZq!$pirL`!Cf1 delta 153 zcmZp1XmQx!Bgi!6Gj&V)k|KelWX79diWQ&&=S+`7MV@&r~T1XFDCIaWT#gw1zZS21p8=lIJH0Kg?TJ^%m! delta 88 zcmZoMXfc@JFUrNhz`)4BAi%(o$&k*V$56mf>6x=xkYhPBBiH60mKa7R{_M%GSQXgr k%y95noI6>7O$osio9xHN$EdJ5mTeW|#D<2=>>Pjj0kRPoHvj+t diff --git a/software/networking/config.py b/software/networking/config.py index 26b6133..ab422a5 100644 --- a/software/networking/config.py +++ b/software/networking/config.py @@ -1,5 +1,6 @@ mysecrets = {"SSID": "Tufts_Robot", "key" : ""} -codes = {"0": b'PairingCodePhrase', "1": b'PairingResponsePhrase', "2": b'PairingConfirmationPhrase'} +msg_codes = {"cmd": b'\x01', "inf": b'\x01', "ack": b'\x01'} +msg_subcodes = {"cmd": {"Reboot": b'\x00', "Firmware-Update": b'\x01', "File-Update": b'\x02', "File-Download": b'\x03', "File-Run": b'\x05', "Set-Admin": b'\x06', "Whitelist-Add": b'\x07', "Config-Change": b'\x08', "Ping": b'\x10', "Pair": b'\x11', "Set-Pair": b'\x12', "RSSI/Status/Config-Boop": b'\x13', "Directory-Get": b'\x14', "Echo": b'\x15', "Resend": b'\x16', "WiFi-Connect": b'\x21', "WiFi-Disconnect": b'\x22', "AP-Enable": b'\x23', "AP-Disable": b'\x24', "Pause": b'\x25', "Continue": b'\x26'}, "inf": {"RSSI": b'\x20', "Sensor": b'\x21', "Message": b'\x22', "Directory": b'\x23'}, "ack": {"Pong": b'\x10', "Success": b'\x11', "Fail": b'\x12', "Confirm": b'\x13', "Echo": b'\x15'}} configname = "Nickname" config = "AdminModuleConfig" whitelist = [b'd\xe83\x84\xd8\x18',b'd\xe83\x84\xd8\x19',b'd\xe83\x85\xd3\xbc', b'd\xe83\x85\xd3\xbd', b'd\xe83\x84\xd8\x18', b'd\xe83\x84\xd8\x19'] #each ESP32 has two MAC addresses diff --git a/software/networking/networking.py b/software/networking/networking.py index 3d7e15e..d1ce2a7 100644 --- a/software/networking/networking.py +++ b/software/networking/networking.py @@ -1,6 +1,6 @@ import network import machine -from config import mysecrets, configname, config, whitelist, i2c_dict, version +from config import mysecrets, configname, config, whitelist, i2c_dict, version, msg_codes, msg_subcodes import time import ubinascii import urequests @@ -21,7 +21,7 @@ def __init__(self, infmsg=False, dbgmsg=False, admin=False): self.master = self self.infmsg = infmsg self.dbgmsg = dbgmsg - self._admin = admin + self.admin = admin self._staif = network.WLAN(network.STA_IF) self._apif = network.WLAN(network.AP_IF) @@ -32,7 +32,7 @@ def __init__(self, infmsg=False, dbgmsg=False, admin=False): self.id = ubinascii.hexlify(machine.unique_id()).decode() self.name = configname - if self.name == "" or self.name == None: + if not self.name: self.name = str(self.id) self.config = config self.version = version @@ -40,14 +40,13 @@ def __init__(self, infmsg=False, dbgmsg=False, admin=False): if infmsg: print(f"{(time.ticks_ms() - inittime) / 1000:.3f} seconds: Networking initialised and ready") - def _cleanup(self): - self._dprint("._cleanup") - self.aen.irq(None) - self.aen._aen.active(False) + def cleanup(self): + self.dprint(".cleanup") + self.aen.cleanup() self._staif.active(False) self._apif.active(False) - def _iprint(self, message): + def iprint(self, message): if self.infmsg: try: print(f"{(time.ticks_ms() - inittime) / 1000:.3f} Networking Info: {message}") @@ -55,7 +54,7 @@ def _iprint(self, message): print(f"Error printing networking Info: {e}") return - def _dprint(self, message): + def dprint(self, message): if self.dbgmsg: try: print(f"{(time.ticks_ms() - inittime) / 1000:.3f} Networking Debug: {message}") @@ -66,60 +65,61 @@ def _dprint(self, message): class Sta: + def __init__(self, master, _staif): self.master = master self._sta = _staif self._sta.active(True) - self.master._iprint("STA initialised and ready") + self.master.iprint("STA initialised and ready") def scan(self): - self.master._dprint("sta.scan") + self.master.dprint("sta.scan") scan_result = self._sta.scan() if self.infmsg: for ap in scan_result: - self.master._iprint(f"SSID:%s BSSID:%s Channel:%d Strength:%d RSSI:%d Auth:%d " % (ap)) + self.master.iprint(f"SSID:%s BSSID:%s Channel:%d Strength:%d RSSI:%d Auth:%d " % ap) return scan_result def connect(self, ssid, key="", timeout=10): - self.master._dprint("sta.connect") + self.master.dprint("sta.connect") self._sta.connect(ssid, key) stime = time.time() while time.time() - stime < timeout: if self._sta.ifconfig()[0] != '0.0.0.0': - self.master._iprint("Connected to WiFi") + self.master.iprint("Connected to WiFi") return time.sleep(0.1) - self.master._iprint(f"Failed to connect to WiFi: {self._sta.status()}") + self.master.iprint(f"Failed to connect to WiFi: {self._sta.status()}") def disconnect(self): - self.master._dprint("sta.disconnect") + self.master.dprint("sta.disconnect") self._sta.disconnect() def ip(self): - self.master._dprint("sta.ip") + self.master.dprint("sta.ip") return self._sta.ifconfig() def mac(self): - self.master._dprint("sta.mac") + self.master.dprint("sta.mac") return bytes(self._sta.config('mac')) def mac_decoded(self):#Necessary? - self.master._dprint("sta.mac_decoded") + self.master.dprint("sta.mac_decoded") return ubinascii.hexlify(self._sta.config('mac'), ':').decode() def channel(self): - self.master._dprint("sta.channel") + self.master.dprint("sta.channel") return self._sta.config('channel') def set_channel(self, number): - self.master._dprint("sta.set_channel") + self.master.dprint("sta.set_channel") if number > 14 or number < 0: number = 0 self._sta.config(channel=number) self.vprint(f"STA channel set to {number}") def get_joke(self): - self.master._dprint("sta.get_joke") + self.master.dprint("sta.get_joke") try: reply = urequests.get('https://v2.jokeapi.dev/joke/Programming') if reply.status_code == 200: @@ -136,10 +136,10 @@ def __init__(self, master, _apif): self.master = master self._ap = _apif self._ap.active(True) - self.master._iprint("AP initialised and ready") + self.master.iprint("AP initialised and ready") def set_ap(self, name="", password="", max_clients=10): - self.master._dprint("ap.setap") + self.master.dprint("ap.set_ap") if name == "": name = self.name self._ap.active(True) @@ -147,31 +147,31 @@ def set_ap(self, name="", password="", max_clients=10): if password: self._ap.config(authmode=network.AUTH_WPA_WPA2_PSK, password=password) self._ap.config(max_clients=max_clients) - self.master._iprint(f"Access Point {name} set with max clients {max_clients}") + self.master.iprint(f"Access Point {name} set with max clients {max_clients}") def deactivate(self): - self.master._dprint("ap.deactivate") + self.master.dprint("ap.deactivate") self._ap.active(False) - self.master._iprint("Access Point deactivated") + self.master.iprint("Access Point deactivated") def ip(self): - self.master._dprint("ap.ip") + self.master.dprint("ap.ip") return self._ap.ifconfig() def mac(self): - self.master._dprint("ap.mac") + self.master.dprint("ap.mac") return bytes(self._ap.config('mac')) def mac_decoded(self): - self.master._dprint("ap.mac_decoded") + self.master.dprint("ap.mac_decoded") return ubinascii.hexlify(self._ap.config('mac'), ':').decode() def channel(self): - self.master._dprint("ap.channel") + self.master.dprint("ap.channel") return self._ap.config('channel') def set_channel(self, number): - self.master._dprint("ap.set_channel") + self.master.dprint("ap.set_channel") if number > 14 or number < 0: number = 0 self._ap.config(channel=number) @@ -207,119 +207,163 @@ def __init__(self, master): self._aen.irq(self._irq) - self.master._iprint("ESP-NOW initialised and ready") - + self.master.iprint("ESP-NOW initialised and ready") + + def cleanup(self): + self.master.iprint("aen.cleanup") + self.irq(None) + self._aen.active(False) + #add delete buffers and stuff + def update_peer(self, peer_mac, name=None, channel=None, ifidx=None): - self.master._dprint("aen.update_peer") + self.master.dprint("aen.update_peer") if peer_mac in self._peers: try: - if name != None: + if name is not None: self._peers[peer_mac]['name'] = name - if channel != None: + if channel is not None: self._peers[peer_mac]['channel'] = channel - if ifidx != None: + if ifidx is not None: self._peers[peer_mac]['ifidx'] = ifidx - self.master._dprint(f"Peer {peer_mac} updated to channel {channel}, ifidx {ifidx} and name {name}") + self.master.dprint(f"Peer {peer_mac} updated to channel {channel}, ifidx {ifidx} and name {name}") except OSError as e: print(f"Error updating peer {peer_mac}: {e}") return - self.master._iprint(f"Peer {peer_mac} not found") + self.master.iprint(f"Peer {peer_mac} not found") def add_peer(self, peer_mac, name=None, channel=None, ifidx=None): - self.master._dprint("aen.add_peer") + self.master.dprint("aen.add_peer") if peer_mac not in self._peers: try: self._peers[peer_mac] = {'channel': channel, 'ifidx': ifidx, 'name': name} - self.master._dprint(f"Peer {peer_mac} added with channel {channel}, ifidx {ifidx} and name {name}") + self.master.dprint(f"Peer {peer_mac} added with channel {channel}, ifidx {ifidx} and name {name}") except OSError as e: print(f"Error adding peer {peer_mac}: {e}") else: - self.master._dprint(f"Peer {peer_mac} already exists, updating") + self.master.dprint(f"Peer {peer_mac} already exists, updating") self.update_peer(peer_mac, name, channel, ifidx) def remove_peer(self, peer_mac): - self.master._dprint("aen.remove_peers") + self.master.dprint("aen.remove_peers") if peer_mac in self._peers: try: del self._peers[peer_mac] - self.master._iprint(f"Peer {peer_mac} removed") + self.master.iprint(f"Peer {peer_mac} removed") except OSError as e: print(f"Error removing peer {peer_mac}: {e}") def peers(self): - self.master._dprint("aen.peers") + self.master.dprint("aen.peers") return self._peers def peer_name(self, key): - self.master._dprint("aen.name") + self.master.dprint("aen.name") if key in self._peers: return self._peers[key]['name'] else: return None def rssi(self): - self.master._dprint("aen.rssi") + self.master.dprint("aen.rssi") return self._aen.peers_table - + + #Send cmds def ping(self, mac, channel=None, ifidx=None): - self.master._dprint("aen.ping") + self.master.dprint("aen.ping") if bool(self.ifidx): - schannel = self.master.ap.channel() + send_channel = self.master.ap.channel() else: - schannel = self.master.sta.channel() - self._compose(mac, [schannel,self.ifidx,self.master.name], 0x01, 0x10, channel, ifidx) #sends channel, ifidx and name - self.master._iprint(f"Sent ping to {mac} ({self.peer_name(mac)})") + send_channel = self.master.sta.channel() + self._compose(mac, [send_channel,self.ifidx,self.master.name], 0x01, 0x10, channel, ifidx) #sends channel, ifidx and name + self.master.iprint(f"Sent ping to {mac} ({self.peer_name(mac)})") gc.collect() def echo(self, mac, message, channel=None, ifidx=None): - self.master._dprint("aen.echo") + self.master.dprint("aen.echo") try: - self.master._iprint(f"Sending echo ({message}) to {mac} ({self.peer_name(mac)})") + self.master.iprint(f"Sending echo ({message}) to {mac} ({self.peer_name(mac)})") except Exception as e: - self.master._iprint(f"Sending echo to {mac} ({self.peer_name(mac)}), but error printing message content: {e}") + self.master.iprint(f"Sending echo to {mac} ({self.peer_name(mac)}), but error printing message content: {e}") self._compose(mac, message, 0x01, 0x15, channel, ifidx) gc.collect() def send(self, mac, message, channel=None, ifidx=None): - self.master._dprint("aen.message") + self.master.dprint("aen.message") if len(str(message)) > 241: try: - self.master._iprint(f"Sending message ({str(message)[:50] + '... (truncated)'}) to {mac} ({self.peer_name(mac)})") + self.master.iprint(f"Sending message ({str(message)[:50] + '... (truncated)'}) to {mac} ({self.peer_name(mac)})") except Exception as e: - self.master._iprint(f"Sending message to {mac} ({self.peer_name(mac)}), but error printing message content: {e}") + self.master.iprint(f"Sending message to {mac} ({self.peer_name(mac)}), but error printing message content: {e}") gc.collect() else: - self.master._iprint(f"Sending message ({message}) to {mac} ({self.peer_name(mac)})") + self.master.iprint(f"Sending message ({message}) to {mac} ({self.peer_name(mac)})") self._compose(mac, message, 0x02, 0x22, channel, ifidx) gc.collect() - self.master._dprint(f"Free memory: {gc.mem_free()}") + self.master.dprint(f"Free memory: {gc.mem_free()}") def broadcast(self, message, channel=None, ifidx=None): - self.master._dprint("aen.broadcast") + self.master.dprint("aen.broadcast") mac = b'\xff\xff\xff\xff\xff\xff' self.send(mac, message, channel, ifidx) - def send_sensor(self, mac, message, channel=None, ifidx=None):#message is a dict, key is the sensor type and the value is the sensor value - self.master._dprint("aen.message") + def send_data_sensor(self, mac, message, channel=None, ifidx=None):#message is a dict, key is the sensor type and the value is the sensor value + self.master.dprint("aen.message") try: - self.master._iprint(f"Sending sensor data ({message}) to {mac} ({self.peer_name(mac)})") + self.master.iprint(f"Sending sensor data ({message}) to {mac} ({self.peer_name(mac)})") except Exception as e: - self.master._iprint(f"Sending sensor data to {mac} ({self.peer_name(mac)}), but error printing message content: {e}") + self.master.iprint(f"Sending sensor data to {mac} ({self.peer_name(mac)}), but error printing message content: {e}") self._compose(mac, message, 0x02, 0x21, channel, ifidx) + #Boop RSSI/Config + + #set pair + + #pairing + + #Firmware Update Mode + + #File Update + + #enable WebREPL + + #Run File + + #Reboot + + #WiFi enable + + #WiFi disable + + #AP enable + + #AP disable + + #admin bool + + #ad admin mac to whitelist + + #continue + + #pause + + #download gitHub files + + #file directory cmd + + def check_messages(self): - self.master._dprint("aen.check_message") + self.master.dprint("aen.check_message") return len(self._received_messages) > 0 def return_message(self): - self.master._dprint("aen.return_message") + self.master.dprint("aen.return_message") if self.check_messages(): self._received_messages_size.pop() return self._received_messages.pop() - return (None, None, None) + return None, None, None def return_messages(self): - self.master._dprint("aen.return_messages") + self.master.dprint("aen.return_messages") if self.check_messages(): messages = self._received_messages[:] self._received_messages.clear() @@ -328,9 +372,9 @@ def return_messages(self): return messages return [(None, None, None)] - def _irq(self, espnow): - self.master._dprint("aen._irq") - if self.master._admin: + def _irq(self): + self.master.dprint("aen._irq") + if self.master.admin: try: self._receive() if self._irq_function and self.check_messages() and self._running: @@ -339,18 +383,19 @@ def _irq(self, espnow): return except KeyboardInterrupt: #machine.disable_irq() #throws errors - self.master._iprint("aen._irq except KeyboardInterrupt") + self.master.iprint("aen._irq except KeyboardInterrupt") #self._aen.irq(None) #does not work self._aen.active(False) - #self.master._cleanup() + #self.master.cleanup() #network cleanup + #self.cleanup() #aen cleanup raise SystemExit("Stopping networking execution. ctrl-c or ctrl-d again to stop main code") #in thonny stops library code but main code keeps running, same in terminal #self._running = False #raise KeyboardInterrupt #error in thonny but then stops running, just keeps running in terminal - #sys.exit(0) #breaks thonny, keeps running and recv (although ctl-d-able and keps running main loop in terminal + #sys.exit(0) #breaks thonny, keeps running and recv (although ctl-d-able and keeps running main loop in terminal #machine.reset() #nogo keeps raising errors and running in terminal - #uos.sysexit() #raises an error in thonny but keeps running in terminal (althouzgh ctrl-d able) + #uos.sysexit() #raises an error in thonny but keeps running in terminal (although ctrl-d able) #raise SystemExit #stops current library script, but main script keeps running, but now it just keeps the main code running in terminal... - #os.execv(sys.argv[0], sys.argv) #error in thonny, keeps running recv in terminal + #os.exec(sys.argv[0], sys.argv) #error in thonny, keeps running recv in terminal #raise Exception("An error occurred!") #error in thonny, and then stops running due to keyboard interrupt, keeps running recv and irq in terminal #raise KeyboardInterrupt("User interrupt simulated.") #interrupts library code, but main code keeps running, recv just keeps running in terminal else: @@ -361,46 +406,36 @@ def _irq(self, espnow): return def irq(self, func): - self.master._dprint("aen.irq") + self.master.dprint("aen.irq") self._irq_function = func def _send(self, peers_mac, messages, channel, ifidx): - self.master._dprint("aen._send") - - def __aen_add_peer(peers_mac, channel, ifidx): #Rethink the logic here! - if isinstance(peers_mac, bytes): - peers_mac = [peers_mac] - for peer_mac in peers_mac: - try: - if channel != None and ifidx != None: - self._aen.add_peer(peer_mac, channel=channel, ifidx=ifidx) - elif channel != None: - if peer_mac in self._peers: - self._aen.add_peer(peer_mac, channel=channel, ifidx=self._peers[peer_mac]['ifidx']) - else: - self._aen.add_peer(peer_mac, channel=channel, ifidx=self.ifidx) - elif ifidx != None: - if peer_mac in self._peers: - self._aen.add_peer(peer_mac, channel=self._peers[peer_mac]['channel'], ifidx=ifidx) - else: - self._aen.add_peer(peer_mac, channel=0, ifidx=ifidx) - elif peer_mac in self._peers: - self._aen.add_peer(peer_mac, channel=self._peers[peer_mac]['channel'], ifidx=self._peers[peer_mac]['ifidx']) + self.master.dprint("aen._send") + + if isinstance(peers_mac, bytes): + peers_mac = [peers_mac] + for peer_mac in peers_mac: + try: + if channel is not None and ifidx is not None: + self._aen.add_peer(peer_mac, channel=channel, ifidx=ifidx) + elif channel is not None: + if peer_mac in self._peers: + self._aen.add_peer(peer_mac, channel=channel, ifidx=self._peers[peer_mac]['ifidx']) else: - self._aen.add_peer(peer_mac, channel=0, ifidx=self.ifidx) - except Exception as e: - print(f"Error adding {peer_mac} to buffer: {e}") + self._aen.add_peer(peer_mac, channel=channel, ifidx=self.ifidx) + elif ifidx is not None: + if peer_mac in self._peers: + self._aen.add_peer(peer_mac, channel=self._peers[peer_mac]['channel'], ifidx=ifidx) + else: + self._aen.add_peer(peer_mac, channel=0, ifidx=ifidx) + elif peer_mac in self._peers: + self._aen.add_peer(peer_mac, channel=self._peers[peer_mac]['channel'], + ifidx=self._peers[peer_mac]['ifidx']) + else: + self._aen.add_peer(peer_mac, channel=0, ifidx=self.ifidx) + except Exception as e: + print(f"Error adding {peer_mac} to buffer: {e}") - def __aen_del_peer(peers_mac): - if isinstance(peers_mac, bytes): - peers_mac = [peers_mac] - for peer_mac in peers_mac: - try: - self._aen.del_peer(peer_mac) - except Exception as e: - print(f"Error removing {peer_mac} from buffer: {e}") - - __aen_add_peer(peers_mac, channel, ifidx) for m in range(len(messages)): if isinstance(peers_mac, list): mac = None @@ -413,13 +448,19 @@ def __aen_del_peer(peers_mac): break except Exception as e: print(f"Error sending to {mac}: {e}") - self.master._dprint(f"Sent {messages[m]} to {mac} ({self.peer_name(mac)})") + self.master.dprint(f"Sent {messages[m]} to {mac} ({self.peer_name(mac)})") gc.collect() - __aen_del_peer(peers_mac) - - + + if isinstance(peers_mac, bytes): + peers_mac = [peers_mac] + for peer_mac in peers_mac: + try: + self._aen.del_peer(peer_mac) + except Exception as e: + print(f"Error removing {peer_mac} from buffer: {e}") + def _compose(self, peer_mac, payload=None, msg_type=0x02, subtype=0x22, channel=None, ifidx=None): - self.master._dprint("aen._compose") + self.master.dprint("aen._compose") if isinstance(peer_mac, list): for peer_macs in peer_mac: @@ -428,29 +469,29 @@ def _compose(self, peer_mac, payload=None, msg_type=0x02, subtype=0x22, channel= elif peer_mac not in self._peers: self.add_peer(peer_mac, None, channel, ifidx) - def __encode_payload(payload): - self.master._dprint("aen.__encode_payload") + def __encode_payload(): + self.master.dprint("aen.__encode_payload") if payload is None: #No payload type return b'\x00', b'' elif isinstance(payload, bytearray): #bytearray - return (b'\x01', bytes(payload)) + return b'\x01', bytes(payload) elif isinstance(payload, bytes): #bytes - return (b'\x01', payload) + return b'\x01', payload elif isinstance(payload, bool): #bool - return (b'\x02', (b'\x01' if payload else b'\x00')) + return b'\x02', (b'\x01' if payload else b'\x00') elif isinstance(payload, int): #int - return (b'\x03', struct.pack('>i', payload)) + return b'\x03', struct.pack('>i', payload) elif isinstance(payload, float): #float - return (b'\x04', struct.pack('>f', payload)) + return b'\x04', struct.pack('>f', payload) elif isinstance(payload, str): #string - return (b'\x05', payload.encode('utf-8')) + return b'\x05', payload.encode('utf-8') elif isinstance(payload, dict) or isinstance(payload, list): #json dict or list json_payload = json.dumps(payload) - return (b'\x06', json_payload.encode('utf-8')) + return b'\x06', json_payload.encode('utf-8') else: raise ValueError("Unsupported payload type") - payload_type, payload_bytes = __encode_payload(payload) + payload_type, payload_bytes = __encode_payload() messages = [] identifier = 0x2a timestamp = time.ticks_ms() @@ -466,11 +507,11 @@ def __encode_payload(payload): message[:8] = header message[8:-1] = payload_bytes message[-1:] = (sum(message) % 256).to_bytes(1, 'big') #Checksum - self.master._dprint(f"Message {1}/{1}; Length: {len(message)}; Free memory: {gc.mem_free()}") + self.master.dprint(f"Message {1}/{1}; Length: {len(message)}; Free memory: {gc.mem_free()}") messages.append(message) else: - self.master._dprint("Long message: Splitting!") + self.master.dprint("Long message: Splitting!") max_size = 238 #241-3 total_chunk_number = (-(-len(payload_bytes)//max_size)) #Round up division lba = b'\x07' @@ -484,25 +525,24 @@ def __encode_payload(payload): message[10] = payload_type[0] message[11:-1] = payload_bytes[chunk_index * max_size: (chunk_index + 1) * max_size] message[-1:] = (sum(message) % 256).to_bytes(1, 'big') #Checksum - self.master._dprint(message) + self.master.dprint(message) messages.append(bytes(message)) - self.master._dprint(f"Message {chunk_index+1}/{total_chunk_number}; length: {len(message)}; Free memory: {gc.mem_free()}") + self.master.dprint(f"Message {chunk_index+1}/{total_chunk_number}; length: {len(message)}; Free memory: {gc.mem_free()}") gc.collect() # key = bytearray() # key.extend(header[1:8]) # key.extend(total_chunk_number.to_bytes(1, 'big')) # self._long_sent_buffer[bytes(key)] = (messages, (channel,ifidx)) - - message = bytearray() + gc.collect() self._send(peer_mac, messages, channel, ifidx) def _receive(self): #Processes all the messages in the buffer - self.master._dprint("aen._receive") + self.master.dprint("aen._receive") def __decode_payload(payload_type, payload_bytes): - self.master._dprint("aen.__decode_payload") + self.master.dprint("aen.__decode_payload") if payload_type == b'\x00': #None return None elif payload_type == b'\x01': #bytearray or bytes @@ -522,33 +562,33 @@ def __decode_payload(payload_type, payload_bytes): else: raise ValueError(f"Unsupported payload type: {payload_type} Message: {payload_bytes}") - def __process_message(sender_mac, message, rtimestamp): - self.master._dprint("aen.__process_message") - if message[0] != 0x2a: # Uniqe Message Identifier Check - self.master._dprint("Invalid message: Message ID Fail") + def __process_message(sender_mac, message, receive_timestamp): + self.master.dprint("aen.__process_message") + if message[0] != 0x2a: # Unique Message Identifier Check + self.master.dprint("Invalid message: Message ID Fail") return None if len(message) < 9: # Min size - self.master._dprint("Invalid message: too short") + self.master.dprint("Invalid message: too short") return None msg_type = bytes(message[1:2]) subtype = bytes(message[2:3]) - stimestamp = int.from_bytes(message[3:7], 'big') + send_timestamp = int.from_bytes(message[3:7], 'big') payload_type = bytes(message[7:8]) payload = message[8:-1] checksum = message[-1] - self.master._dprint(f"{type(msg_type)}: {msg_type}, {type(subtype)}: {subtype}, {type(stimestamp)}: {stimestamp}, {type(payload_type)}: {payload_type}, {type(payload)}: {payload}, {type(checksum)}: {checksum}") + self.master.dprint(f"{type(msg_type)}: {msg_type}, {type(subtype)}: {subtype}, {type(send_timestamp)}: {send_timestamp}, {type(payload_type)}: {payload_type}, {type(payload)}: {payload}, {type(checksum)}: {checksum}") #Checksum if checksum != sum(message[:-1]) % 256: - self.master._dprint("Invalid message: checksum mismatch") + self.master.dprint("Invalid message: checksum mismatch") return None if sender_mac not in self._peers: self.add_peer(sender_mac) if payload_type == b'\x07': - self.master._dprint("Long message received, processing...") + self.master.dprint("Long message received, processing...") part_n = int.from_bytes(payload[0:1], 'big') total_n = int.from_bytes(payload[1:2], 'big') payload_type = bytes(payload[2:3]) @@ -562,7 +602,7 @@ def __process_message(sender_mac, message, rtimestamp): key.extend(payload_type) key.append(total_n) key = bytes(key) - self.master._dprint(f"Key: {key}") + self.master.dprint(f"Key: {key}") # Check if the key already exists in the long buffer if key in self._long_buffer: @@ -570,7 +610,7 @@ def __process_message(sender_mac, message, rtimestamp): if self._long_buffer[key][part_n] is None: self._long_buffer[key][part_n] = payload self._long_buffer_size[key] = self._long_buffer_size[key] + len(payload) - self.master._dprint(f"Long message: Key found, message added to entry in long_message_buffer, {sum(1 for item in self._long_buffer[key] if item is not None)} out of {total_n} packages received") + self.master.dprint(f"Long message: Key found, message added to entry in long_message_buffer, {sum(1 for item in self._long_buffer[key] if item is not None)} out of {total_n} packages received") # If there are still missing parts, return if any(value is None for value in self._long_buffer[key]): gc.collect() @@ -581,26 +621,13 @@ def __process_message(sender_mac, message, rtimestamp): payloads[part_n] = payload self._long_buffer[key] = payloads self._long_buffer_size[key] = len(payload) - self.master._dprint(f"Long message: Key not found and new entry created in long_message_buffer, {sum(1 for item in self._long_buffer[key] if item is not None)} out of {total_n} packages received") + self.master.dprint(f"Long message: Key not found and new entry created in long_message_buffer, {sum(1 for item in self._long_buffer[key] if item is not None)} out of {total_n} packages received") while len(self._long_buffer) > 8 or sum(self._long_buffer_size.values()) > 75000: - self.master._dprint(f"Maximum buffer size reached: {len(self._long_buffer)}, {sum(self._long_buffer_size.values())} bytes; Reducing!") + self.master.dprint(f"Maximum buffer size reached: {len(self._long_buffer)}, {sum(self._long_buffer_size.values())} bytes; Reducing!") self._long_buffer.popitem(last=False) self._long_buffer_size.popitem(last=False) gc.collect() -# # If there are missing parts, request missing messages, due to buffer constraints this is disabled -# if any(value is None for value in self._long_buffer[key]): -# none_indexes = [index for index, value in enumerate(self._long_buffer[key]) if value is None] -# response = bytearray() -# response.extend(msg_type) -# response.extend(subtype) -# response.extend(message[3:7])#stimestamp.to_bytes(4, 'big') -# response.extend(payload_type) -# response.extend(payload[1:2])#total_n.to_bytes(1, 'big') -# for none_index in none_indexes: -# response.extend(none_index.to_bytes(1, 'big')) -# #asyncio.create_task(__request_missing_messages(sender_mac, response, key, total_n)) -# gc.collect() return # If all parts have been received, reconstruct the message @@ -610,121 +637,191 @@ def __process_message(sender_mac, message, rtimestamp): payload.extend(self._long_buffer[key][i]) del self._long_buffer[key] del self._long_buffer_size[key] - self.master._dprint("Long message: All packages received!") + self.master.dprint("Long message: All packages received!") else: - self.master._dprint("Long Message: Safeguard triggered, code should not have gotten here") + self.master.dprint("Long Message: Safeguard triggered, code should not have gotten here") gc.collect() return #Handle the message based on type - if msg_type == b'\x01': # Command Message - __handle_cmd(sender_mac, subtype, stimestamp, rtimestamp, payload_type, payload if payload else None) - elif msg_type == b'\x02': # Informational Message - __handle_inf(sender_mac, subtype, stimestamp, rtimestamp, payload_type, payload if payload else None) - elif msg_type == b'\x03': # Acknowledgement Message - __handle_ack(sender_mac, subtype, stimestamp, rtimestamp, payload_type, payload if payload else None) + if msg_type == (msg_key := msg_codes["cmd"]): # Command Message + __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload_type, payload if payload else None, msg_key) + elif msg_type == (msg_key := cmsg_codes["inf"]): # Informational Message + __handle_inf(sender_mac, subtype, send_timestamp, receive_timestamp, payload_type, payload if payload else None, msg_key) + elif msg_type == (msg_key := msg_codes["ack"]): # Acknowledgement Message + __handle_ack(sender_mac, subtype, send_timestamp, receive_timestamp, payload_type, payload if payload else None, msg_key) else: - self.master._iprint(f"Unknown message type from {sender_mac} ({self.peer_name(sender_mac)}): {message}") + self.master.iprint(f"Unknown message type from {sender_mac} ({self.peer_name(sender_mac)}): {message}") - async def __request_missing_messages(sender_mac, payload, key, total_n=0, retries=3, waittime=2): - self.master._dprint("aen.__request_missing_messages") - for i in range(retries): - i += i - asyncio.sleep(waittime + total_n*0.1) - if key in self._long_buffer: - self._compose(sender_mac, payload, 0x01, 0x17) + def __check_authorisation(sender_mac, payload): + return sender_mac in self._whitelist or payload == "sudo" or payload[-1] == "sudo" + + def __send_confirmation(type, recipient_mac, msg_subkey_type, payload=None, error=None): + if type == "Success": + self._compose(recipient_mac, [msg_subkey_type, payload], 0x03, 0x11) + elif type == "Fail": + self._compose(recipient_mac, [msg_subkey_type, error, payload], 0x03, 0x12) + else: + self._compose(recipient_mac, [msg_subkey_type, payload], 0x03, 0x13) + + def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload_type, payload, msg_key): + self.master.dprint(f"aen.__handle_cmd") + payload = __decode_payload(payload_type, payload) + if subtype == msg_subcodes[msg_key][msg_subkey := "Reboot"]: # Reboot + self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + if self.__check_authorisation(sender_mac, payload): + __send_confirmation("Confirm", sender_mac, f"{msg_subkey} ({subtype})", payload) + machine.reset() else: - return - - def __handle_cmd(sender_mac, subtype, stimestamp, rtimestamp, payload_type, payload): - self.master._dprint("aen.__handle_cmd") - if subtype == b'\x10': #Ping - self.master._iprint(f"Ping command received from {sender_mac} ({self.peer_name(sender_mac)})") - info = __decode_payload(payload_type, payload) - self.add_peer(sender_mac, info[2], info[0], info[1]) + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") + elif subtype == msg_subcodes[msg_key][msg_subkey := "Firmware-Update"]: # Firmware-Update + self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + if self.__check_authorisation(sender_mac, payload): + try: + # Insert update logic here + self.master.iprint("no update logic written just yet") + __send_confirmation("Success", sender_mac, f"{msg_subkey} ({subtype})", payload) + except Exception as e: + self.master.iprint(f"Error: {e} with payload: {payload}") + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) + else: + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") + elif subtype == msg_subcodes[msg_key][msg_subkey := "File-Update"]: # File-Update + self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + if self.__check_authorisation(sender_mac, payload): + try: + # Insert update logic here + self.master.iprint("No update logic written just yet") + __send_confirmation("Success", sender_mac, f"{msg_subkey} ({subtype})", payload) + except Exception as e: + self.master.iprint(f"Error: {e} with payload: {payload}") + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) + else: + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") + elif subtype == msg_subcodes[msg_key][msg_subkey := "File-Download"]: #File-Download + self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + payload = __decode_payload(payload_type, payload) #should return a list with a link and the list of files to download + if self.__check_authorisation(sender_mac, payload): + try: + import mip + base = payload[0] + files_to_copy = payload[1] + for f in files_to_copy: + print("Installing: ", f) + mip.install(base + f) + __send_confirmation("Success", sender_mac, f"{msg_subkey} ({subtype})", payload) + except Exception as e: + self.master.iprint(f"Error: {e} with payload: {payload}") + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) + else: + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") + # enable WebREPL + elif subtype == msg_subcodes[msg_key][msg_subkey := "File-Run"]: #File-Run + self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + if self.__check_authorisation(sender_mac, payload): + try: + self.master.iprint("Execute logic not implemented") + #insert run logic here + except Exception as e: + self.master.iprint(f"Error: {e} with payload: {payload}") + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) + else: + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") + elif subtype == msg_subcodes[msg_key][msg_subkey := "Set-Admin"]: #Set Admin Bool + self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + if self.__check_authorisation(sender_mac, payload): + self.master.iprint(f"Received Set-Admin command: self.admin set to {payload[0]}") + try: + self.master.admin = payload[0] + __send_confirmation("Success", sender_mac, f"{msg_subkey} ({subtype})", payload) + except Exception as e: + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) + else: + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") + elif subtype == msg_subcodes[msg_key][msg_subkey := "Whitelist-Add"]: # Whitelist-Add - Add Admin macs to _whitelist + self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + if __check_authorisation(sender_mac, payload): + self.master.iprint(f"Received add admin macs to _whitelist command, added {payload[0]} and {payload[1]}") + try: + self._whitelist.append(payload[0]) + self._whitelist.append(payload[1]) + __send_confirmation("Success", sender_mac, f"{msg_subkey} ({subtype})", payload) + except Exception as e: + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) + else: + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") + elif subtype == msg_subcodes[msg_key][msg_subkey := "Config-Change"]: # change config + self.master.iprint( + f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + if __check_authorisation(sender_mac, payload): + try: + self.master.iprint(f"Not yet implemented") + __send_confirmation("Success", sender_mac, f"{msg_subkey} ({subtype})", payload) + except Exception as e: + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) + else: + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") + elif subtype == msg_subcodes[msg_key][msg_subkey := "Ping"]: #Ping + self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + self.add_peer(sender_mac, payload[2], payload[0], payload[1]) if bool(self.ifidx): channel = self.master.ap.channel() else: channel = self.master.sta.channel() - response = [channel, self.ifidx, self.master.name, stimestamp] + response = [channel, self.ifidx, self.master.name, send_timestamp] self._compose(sender_mac, response, 0x03, 0x10) - elif subtype == b'\x11': #Pair - self.master._iprint(f"Pairing command received from {sender_mac} ({self.peer_name(sender_mac)})") - payload = __decode_payload(payload_type, payload) - if self._pairing == True: + elif subtype == msg_subcodes[msg_key][msg_subkey := "Pair"]: #Pair + self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + if self._pairing: try: # Insert pairing logic here - self.master._iprint("no pairing logic written just yet") - self._compose(sender_mac, ["Pair (\x11)", payload], 0x03, 0x11) + self.master.iprint("no pairing logic written just yet") + __send_confirmation("Success", sender_mac, f"{msg_subkey} ({subtype})", payload) except Exception as e: - self.master._iprint(f"Error: {e} with payload: {payload}") - self._compose(sender_mac, ["Pair (\x11)", e, payload], 0x03, 0x12) + self.master.iprint(f"Error: {e} with payload: {payload}") + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: - self._compose(sender_mac, ["Pair (\x11)", "Pairing disabled", payload], 0x03, 0x12) - elif subtype == b'\x26': #Set Pair - self.master._iprint(f"Pairing command received from {sender_mac} ({self.peer_name(sender_mac)})") - payload = __decode_payload(payload_type, payload) #should be a list with a bool - if sender_mac in self._whitelist or payload == "sudo" or payload[-1] == "sudo": + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", "Pairing disabled", payload) + elif subtype == msg_subcodes[msg_key][msg_subkey := "Set-Pair"]: #Enable pairing mode + self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + if self.__check_authorisation(sender_mac, payload): try: self._pairing = payload[0] - self._compose(sender_mac, ["Set Pair (\x11)", payload], 0x03, 0x11) - except Exception as e: - self.master._iprint(f"Error: {e} with payload: {payload}") - self._compose(sender_mac, ["Set Pair (\x11)", e, payload], 0x03, 0x12) - else: - elf._compose(sender_mac, ["Set Pair (\x11)", "Not authorised", payload], 0x03, 0x12) - elif subtype == b'\x12': #Change Mode to Firmware Update - self.master._iprint(f"Update command received from {sender_mac} ({self.peer_name(sender_mac)})") - payload = __decode_payload(payload_type, payload) - if sender_mac in self._whitelist or payload == "sudo" or payload[-1] == "sudo": - try: - # Insert update logic here - self.master._iprint("no update logic written just yet") - self._compose(sender_mac, ["Update (\x12)", payload], 0x03, 0x11) + __send_confirmation("Success", sender_mac, f"{msg_subkey} ({subtype})", payload) except Exception as e: - self.master._iprint(f"Error: {e} with payload: {payload}") - self._compose(sender_mac, ["Update (\x12)", e, payload], 0x03, 0x12) + self.master.iprint(f"Error: {e} with payload: {payload}") + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: - self._compose(sender_mac, ["Update (\x12)", "Not authorised", payload], 0x03, 0x12) - elif subtype == b'\x13': #RSSI/Status/Config Boop + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") + elif subtype == msg_subcodes[msg_key][msg_subkey := "RSSI/Status/Config-Boop"]: # RSSI/Status/Config Boop self.boops = self.boops + 1 - self.master._iprint(f"Boop command received from {sender_mac} ({self.peer_name(sender_mac)}), Received total of {self.boops} boops!") + self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)}), Received total of {self.boops} boops!") try: self._compose(sender_mac, [self.master.id, self.master.name, self.master.config, self.master.version_n, self.master.version, self.master.sta.mac, self.master.ap.mac, self.rssi()], 0x02, 0x20) #[ID, Name, Config, Version, sta mac, ap mac, rssi] except Exception as e: - self._compose(sender_mac, ["RSSI Boop (\x13)", e, payload], 0x03, 0x12) - elif subtype == b'\x14': #Reboot - self.master._iprint(f"Reboot command received from {sender_mac} ({self.peer_name(sender_mac)})") - payload = __decode_payload(payload_type, payload) - if sender_mac in self._whitelist or payload == "sudo" or payload[-1] == "sudo": - self._compose(sender_mac, ["Reboot (\x14)", payload], 0x03, 0x13) - machine.reset() - else: - self._compose(sender_mac, ["Reboot (\x14)", "Not authorised", payload], 0x03, 0x12) - elif subtype == b'\x15': #Echo - self.master._iprint(f"Echo command received from {sender_mac} ({self.peer_name(sender_mac)}): {__decode_payload(payload_type, payload)}")#Check i or d + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) + elif subtype == msg_subcodes[msg_key][msg_subkey := "Directory-Get"]: #Get List of Files + self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + try: + result = [] + entries = os.listdir() + for entry in entries: + full_path = f"{path}/{entry}" + if os.stat(full_path)[0] & 0x4000: + result.extend(list_all_paths(full_path)) + else: + result.append(full_path) + self._compose(sender_mac, result, 0x02, 0x20) + except Exception as e: + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) + elif subtype == msg_subcodes[msg_key][msg_subkey := "Echo"]: #Echo + self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)}): {__decode_payload(payload_type, payload)}") #Check i or d self._compose(sender_mac, payload, 0x03, 0x15) - elif subtype == b'\x16': #Run file - filename = __decode_payload(payload_type, payload) - self.master._iprint(f"Run command received from {sender_mac} ({self.peer_name(sender_mac)}): {filename}") - #try: - # task = asyncio.create_task(run_script(filename)) - #Needs - #async def execute_script(script_path): - # Load and execute the script - #with open(script_path) as f: - # script_code = f.read() - # - #exec(script_code) # This executes the script in the current namespace - # - # Alternatively, if you want to run this in a separate function scope - #exec(script_code, {'__name__': '__main__'}) - # except Exception as e: - # print(f"Error running {filename}: {e}") - elif subtype == b'\x17': #Resend lost long messages - self.master._iprint("Received resend long message command, long_sent_buffer disabled due to memory constraints") + elif subtype == msg_subcodes[msg_key][msg_subkey := "Resend"]: #Resend lost long messages + self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + self.master.iprint("Long_sent_buffer disabled due to memory constraints") # payload = __decode_payload(payload_type, payload) -# self.master._iprint("Received resend long message command, checking buffer for lost message") +# self.master.iprint("Received resend long message command, checking buffer for lost message") # key = payload[0:8] # indexes_b = payload[8:] # indexes = [] @@ -737,213 +834,150 @@ def __handle_cmd(sender_mac, subtype, stimestamp, rtimestamp, payload_type, payl # message.append(self._long_sent_buffer[key][0][index]) # self._send(sender_mac, messages, channel, ifidx) # #resend the message from the message buffer -# self.master._iprint("Resent all requested messages") +# self.master.iprint("Resent all requested messages") # else: -# self.master._iprint("Message not found in the buffer") - elif subtype == b'\x18': #Connect to WiFi - payload = __decode_payload(payload_type, payload) #should return a list of ssid and password - self.master._iprint("Received connect to wifi command") - if sender_mac in self._whitelist or payload == "sudo" or payload[-1] == "sudo": +# self.master.iprint("Message not found in the buffer") + elif subtype == msg_subcodes[msg_key][msg_subkey := "WiFi-Connect"]: #Connect to Wi-Fi + self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + if self.__check_authorisation(sender_mac, payload): try: self.connect(payload[0], payload[1]) - self._compose(sender_mac, ["WiFi connect (\x18)", payload], 0x03, 0x11) + __send_confirmation("Success", sender_mac, f"{msg_subkey} ({subtype})", payload) except Exception as e: - self.master._iprint(f"Error: {e} with payload: {payload}") - self._compose(sender_mac, ["WiFi connect (\x18)", e, payload], 0x03, 0x12) + self.master.iprint(f"Error: {e} with payload: {payload}") + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: - self._compose(sender_mac, ["WiFi connect (\x18)", "Not authorised", payload], 0x03, 0x12) - elif subtype == b'\x19': #Disconnect from WiFi - self.master._iprint("Received disconnect from wifi command") - payload = __decode_payload(payload_type, payload) - if sender_mac in self._whitelist or payload == "sudo" or payload[-1] == "sudo": + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") + elif subtype == msg_subcodes[msg_key][msg_subkey := "WiFi-Disconnect"]: #Disconnect from Wi-Fi + self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + if self.__check_authorisation(sender_mac, payload): try: self.disconnect() - self._compose(sender_mac, ["WiFi disconnect (\x19)", payload], 0x03, 0x11) + __send_confirmation("Success", sender_mac, f"{msg_subkey} ({subtype})", payload) except Exception as e: - self.master._iprint(f"Error: {e}") - self._compose(sender_mac, ["WiFi disconnect (\x19)", e, payload], 0x03, 0x12) + self.master.iprint(f"Error: {e}") + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: - self._compose(sender_mac, ["WiFi disconnect (\x19)", "Not authorised", payload], 0x03, 0x12) - elif subtype == b'\x20': #Enable AP - payload = __decode_payload(payload_type, payload) #should return a list of desired name, password an max clients - self.master._iprint("Received setup AP command") - if sender_mac in self._whitelist or payload == "sudo" or payload[-1] == "sudo": + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") + elif subtype == msg_subcodes[msg_key][msg_subkey := "AP-Enable"]: #Enable AP + self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + if self.__check_authorisation(sender_mac, payload): try: ssid = payload[0] if ssid == "": ssid = self.master.name password = payload[1] self.setap(ssid, password) - self._compose(sender_mac, ["Setup AP (\x20)", payload], 0x03, 0x11) + __send_confirmation("Success", sender_mac, f"{msg_subkey} ({subtype})", payload) except Exception as e: - self.master._iprint(f"Error: {e} with payload: {payload}") - self._compose(sender_mac, ["Setup AP (\x20)", e, payload], 0x03, 0x12) + self.master.iprint(f"Error: {e} with payload: {payload}") + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: - self._compose(sender_mac, ["Setup AP (\x20)", "Not authorised", payload], 0x03, 0x12) - elif subtype == b'\x21': #Disable AP - self.master._iprint("Received disable AP command") - payload = __decode_payload(payload_type, payload) #should return a list of desired name, password an max clients - if sender_mac in self._whitelist or payload == "sudo" or payload[-1] == "sudo": + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") + elif subtype == msg_subcodes[msg_key][msg_subkey := "AP-Disable"]: #Disable AP + self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + payload = __decode_payload(payload_type, payload) #should return a list of desired name, password and max clients + if self.__check_authorisation(sender_mac, payload): try: self.master.ap.deactivate() - self._compose(sender_mac, ["Disable AP (\x21)", payload], 0x03, 0x11) - except Exception as e: - self.master._iprint(f"Error: {e}") - self._compose(sender_mac, ["Disable AP (\x21)", e, payload], 0x03, 0x12) - else: - self._compose(sender_mac, ["Disable AP (\x21)", "Not authorised", payload], 0x03, 0x12) - elif subtype == b'\x22': #Set Admin Bool - payload = __decode_payload(payload_type, payload) #should return a bool in a list - if sender_mac in self._whitelist or payload == "sudo" or payload[-1] == "sudo": - self.master._iprint(f"Received set admin command: self.admin set to {payload[0]}") - try: - self.master._admin = payload[0] - self._compose(sender_mac, ["Set Admin Bool (\x21)", "Success", payload], 0x03, 0x11) - except Exception as e: - self._compose(sender_mac, ["Set Admin Bool (\x21)", e, payload], 0x03, 0x12) - else: - self._compose(sender_mac, ["Set Admin Bool (\x21)", "Not authorised", payload], 0x03, 0x12) - elif subtype == b'\x27': #Add Admin macs to _whitelist - payload = __decode_payload(payload_type, payload) #should return a bool in a list - if sender_mac in self._whitelist or payload == "sudo" or payload[-1] == "sudo": - self.master._iprint(f"Received add admin macs to _whitelist command, added {payload[0]} and {payload[1]}") - try: - self._whitelist.append(payload[0]) - self._whitelist.append(payload[1]) - self._compose(sender_mac, ["Add admin macs to _whitelist (\x27)", "Success", payload], 0x03, 0x11) + __send_confirmation("Success", sender_mac, f"{msg_subkey} ({subtype})", payload) except Exception as e: - self._compose(sender_mac, ["Add admin macs to _whitelist (\x27)", e, payload], 0x03, 0x12) + self.master.iprint(f"Error: {e}") + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: - self._compose(sender_mac, ["Add admin macs to _whitelist (\x27)", "Not authorised", payload], 0x03, 0x12) - elif subtype == b'\x23': #Set Pause - payload = __decode_payload(payload_type, payload) #should return a bool - if sender_mac in self._whitelist or payload == "sudo" or payload[-1] == "sudo": + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") + elif subtype == msg_subcodes[msg_key][msg_subkey := "Pause"]: #Set Pause + self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + if self.__check_authorisation(sender_mac, payload): try: - self.master._iprint(f"Received pause command: {payload[0]}") + self.master.iprint(f"Received pause command: {payload[0]}") self._running = False - self._compose(sender_mac, ["Set Pause (\x23)", "Success", payload], 0x03, 0x11) + __send_confirmation("Success", sender_mac, f"{msg_subkey} ({subtype})", payload) if self._pause_function: self._pause_function() #calls the custom set pause function to display a screen while not self._running: sleep(0.5) except Exception as e: - self._compose(sender_mac, ["Set Pause (\x23)", e, payload], 0x03, 0x12) + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: - self._compose(sender_mac, ["Set Pause (\x23)", "Not authorised", payload], 0x03, 0x12) - elif subtype == b'\x24': #Set Continue - payload = __decode_payload(payload_type, payload) #should return a bool - if sender_mac in self._whitelist or payload == "sudo" or payload[-1] == "sudo": + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") + elif subtype == msg_subcodes[msg_key][msg_subkey := "Continue"]: #Set Continue + self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + if self.__check_authorisation(sender_mac, payload): try: - self.master._iprint(f"Received continue command: {payload}") + self.master.iprint(f"Received continue command: {payload}") self.master._running = True - self._compose(sender_mac, ["Set Continue (\x23)", "Success", payload], 0x03, 0x11) + __send_confirmation("Success", sender_mac, f"{msg_subkey} ({subtype})", payload) except Exception as e: - self._compose(sender_mac, ["Set Continue (\x23)", e, payload], 0x03, 0x12) + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: - self._compose(sender_mac, ["Set Continue (\x23)", "Not authorised", payload], 0x03, 0x12) - elif subtype == b'\x25': #Download github files - self.master._iprint(f"Received download files command") - payload = __decode_payload(payload_type, payload) #should return a list with a link and the list of files to download - if sender_mac in self._whitelist or payload[-1] == "sudo": - try: - import mip - base = payload[0] - files_to_copy = payload[1] - for f in files_to_copy: - print("Installing: ", f) - mip.install(base + f) - self._compose(sender_mac, ["Github Download (\x25)", payload], 0x03, 0x11) - except Exception as e: - self.master._iprint(f"Error: {e} with payload: {payload}") - self._compose(sender_mac, ["Github Download (\x25)", e, payload], 0x03, 0x12) - else: - self._compose(sender_mac, ["Github Download (\x25)", "Not authorised", payload], 0x03, 0x12) - elif subtype == b'\x28': #Get List of Files - self.master._iprint(f"Received list files command") - try: - result = [] - entries = os.listdir() - for entry in entries: - full_path = f"{path}/{entry}" - if os.stat(full_path)[0] & 0x4000: - result.extend(list_all_paths(full_path)) - else: - result.append(full_path) - self._compose(sender_mac, result, 0x02, 0x20) - except Exception as e: - self._compose(sender_mac, ["List files (\x28)", e, payload], 0x03, 0x12) + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") else: - self.master._iprint(f"Unknown command subtype from {sender_mac} ({self.peer_name(sender_mac)}): {subtype}") - - def __handle_inf(sender_mac, subtype, stimestamp, rtimestamp, payload_type, payload): - self.master._dprint("aen.__inf") - if subtype == b'\x20': #RSSI - payload = __decode_payload(payload_type, payload) - #payload["time_sent"] = stimestamp - #payload["time_recv"] = rtimestamp - self.master._iprint(f"RSSI data received from {sender_mac} ({self.peer_name(sender_mac)}): {payload}") + self.master.iprint(f"Unknown command subtype from {sender_mac} ({self.peer_name(sender_mac)}): {subtype}") + + def __handle_inf(sender_mac, subtype, send_timestamp, receive_timestamp, payload_type, payload, msg_key): + self.master.dprint("aen.__handle_inf") + payload = __decode_payload(payload_type, payload) + if subtype == msg_subcodes[msg_key][msg_subkey := "RSSI"]: #RSSI + #payload["time_sent"] = send_timestamp + #payload["time_recv"] = receive_timestamp + self.master.iprint(f"{msg_subkey} ({subtype}) data received from {sender_mac} ({self.peer_name(sender_mac)}): {payload}") self.received_rssi_data[sender_mac] = payload - #self._compose(sender_mac, ["RSSI (\x20)", payload], 0x03, 0x13) #confirm message recv - elif subtype == b'\x21': #Sensor Data - payload = __decode_payload(payload_type, payload) - payload["time_sent"] = stimestamp - payload["time_recv"] = rtimestamp - self.master._iprint(f"Sensor data received from {sender_mac} ({self.peer_name(sender_mac)}): {payload}") + #__send_confirmation("Confirm", sender_mac, f"{msg_subkey} ({subtype})", payload) #confirm message recv + elif subtype == msg_subcodes[msg_key][msg_subkey := "Sensor"]: #Sensor Data + payload["time_sent"] = send_timestamp + payload["time_recv"] = receive_timestamp + self.master.iprint(f"{msg_subkey} ({subtype}) data received from {sender_mac} ({self.peer_name(sender_mac)}): {payload}") self.received_sensor_data[sender_mac] = payload - #self._compose(sender_mac, ["Sensor Data (\x21)", payload], 0x03, 0x13) #confirm message recv - elif subtype == b'\x22': #Message / Other - payloadlength = len(payload) - payload = __decode_payload(payload_type, payload) - self.master._iprint(f"Message received from {sender_mac} ({self.peer_name(sender_mac)}): {payload}") - self._received_messages.append((sender_mac, payload, rtimestamp)) - self._received_messages_size.append(payloadlength) + #__send_confirmation("Confirm", sender_mac, f"{msg_subkey} ({subtype})", payload) #confirm message recv + elif subtype == msg_subcodes[msg_key][msg_subkey := "Message"]: #Message / Other + self.master.iprint(f"{msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}): {payload}") + self._received_messages.append((sender_mac, payload, receive_timestamp)) + self._received_messages_size.append(len(payload)) while len(self._received_messages) > 2048 or sum(self._received_messages_size) > 20000: - self.master._dprint(f"Maximum buffer size reached: {len(self._received_messages)}, {sum(self._received_messages_size)} bytes; Reducing!") + self.master.dprint(f"Maximum buffer size reached: {len(self._received_messages)}, {sum(self._received_messages_size)} bytes; Reducing!") self._received_messages.pop(0) self._received_messages_size.pop(0) - #self._compose(sender_mac, ["Other (\x22)", payload], 0x03, 0x13) #confirm message recv - elif subtype == b'\x23': #File Directory - payload = __decode_payload(payload_type, payload) - self.master._iprint(f"Directory received from {sender_mac} ({self.peer_name(sender_mac)}): {payload}") - #self._compose(sender_mac, ["Other (\x23)", payload], 0x03, 0x13) #confirm message recv + #__send_confirmation("Confirm", sender_mac, f"{msg_subkey} ({subtype})", payload) #confirm message recv + elif subtype == msg_subcodes[msg_key][msg_subkey := "Directory"]: #File Directory + self.master.iprint(f"{msg_subkey} ({subtype}) data received from {sender_mac} ({self.peer_name(sender_mac)}): {payload}") + #__send_confirmation("Confirm", sender_mac, f"{msg_subkey} ({subtype})", payload) #confirm message recv else: - payload = __decode_payload(payload_type, payload) - self.master._iprint(f"Unknown info subtype from {sender_mac} ({self.peer_name(sender_mac)}): {subtype}") + self.master.iprint(f"Unknown info subtype from {sender_mac} ({self.peer_name(sender_mac)}): {subtype}") - def __handle_ack(sender_mac, subtype, stimestamp, rtimestamp, payload_type, payload): - self.master._dprint("aen.__handle_ack") - if subtype == b'\x10': #Pong - info = __decode_payload(payload_type, payload) - self.add_peer(sender_mac, info[2], info[0], info[1]) - self.master._iprint(f"Pong received from {sender_mac} ({self.peer_name(sender_mac)}), {rtimestamp-info[3]}") - elif subtype == b'\x15': #Echo - self.master._iprint(f"Echo received from {sender_mac} ({self.peer_name(sender_mac)}), {__decode_payload(payload_type, payload)}") - elif subtype == b'\x11': #Success - payload = __decode_payload(payload_type, payload) # should return a list with a cmd type and payload - self.master._iprint(f"Success received from {sender_mac} ({self.peer_name(sender_mac)}) for type {payload[0]} with payload {payload[1]}") + def __handle_ack(sender_mac, subtype, send_timestamp, receive_timestamp, payload_type, payload, msg_key): + self.master.dprint("aen.__handle_ack") + payload = __decode_payload(payload_type, payload) + if subtype == msg_subcodes[msg_key][msg_subkey := "Pong"]: #Pong + self.add_peer(sender_mac, payload[2], payload[0], payload[1]) + self.master.iprint(f"{msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}), {receive_timestamp-info[3]}") + elif subtype == msg_subcodes[msg_key][msg_subkey := "Echo"]: #Echo + self.master.iprint(f"{msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}), {__decode_payload(payload_type, payload)}") + elif subtype == msg_subcodes[msg_key][msg_subkey := "Success"]: #Success + # payload should return a list with a cmd type and payload + self.master.iprint(f"Cmd {msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}) for type {payload[0]} with payload {payload[1]}") #add to ack buffer - elif subtype == b'\x12': #Fail - payload = __decode_payload(payload_type, payload) # should return a list with a cmd type, error and payload - self.master._iprint(f"Command fail received from {sender_mac} ({self.peer_name(sender_mac)}) for type {payload[0]} with error {payload[1]} and payload {payload[2]}") + elif subtype == msg_subcodes[msg_key][msg_subkey := "Fail"]: #Fail + # payload should return a list with a cmd type, error and payload + self.master.iprint(f"Cmd {msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}) for type {payload[0]} with error {payload[1]} and payload {payload[2]}") #add to ack buffer - elif subtype == b'\x13': #Confirmation - payload = __decode_payload(payload_type,payload) # should return a list with message type and payload - self.master._iprint(f"Receive confirmation received from {sender_mac} ({self.peer_name(sender_mac)}) for type {payload[0]} with payload {payload[1]}") + elif subtype == msg_subcodes[msg_key][msg_subkey := "Confirm"]: #Confirmation + # payload should return a list with message type and payload + self.master.iprint(f"{msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}) for type {payload[0]} with payload {payload[1]}") #add to ack buffer else: - self.master._iprint(f"Unknown ack subtype from {sender_mac} ({self.peer_name(sender_mac)}): {subtype}, Payload: {payload}") + self.master.iprint(f"Unknown ack subtype from {sender_mac} ({self.peer_name(sender_mac)}): {subtype}, Payload: {payload}") # Insert more acknowledgement logic here and/or add message to acknowledgement buffer if self._aen.any(): - for sender_mac, data in self._aen: - self.master._dprint(f"Received {sender_mac, data}") - if sender_mac is None: # mac, msg will equal (None, None) on timeout + for mac, data in self._aen: + self.master.dprint(f"Received {mac, data}") + if mac is None: # mac, msg will equal (None, None) on timeout break if data: - rtimestamp = time.ticks_ms() - if sender_mac != None and data != None: - #self._received_messages.append((sender_mac, data, rtimestamp))#Messages will be saved here, this is only for debugging purposes - __process_message(sender_mac, data, rtimestamp) + if mac and data is not None: + #self._received_messages.append((sender_mac, data, receive_timestamp))#Messages will be saved here, this is only for debugging purposes + __process_message(mac, data, time.ticks_ms()) if not self._aen.any():#this is necessary as the for loop gets stuck and does not exit properly. break From 003bd8d80a7f1e977cef60943f336d1f78682fca Mon Sep 17 00:00:00 2001 From: Nick Art Date: Mon, 25 Nov 2024 18:54:49 -0500 Subject: [PATCH 03/10] added commands to networking And somehow in the process I broke it. --- .DS_Store | Bin 12292 -> 12292 bytes software/.DS_Store | Bin 8196 -> 8196 bytes software/networking/config.py | 3 +- software/networking/networking.py | 306 ++++++++++++++++++------------ 4 files changed, 183 insertions(+), 126 deletions(-) diff --git a/.DS_Store b/.DS_Store index 64e8d3072c081024d824da2c00f4472d4a5531c2..8e1d6f29e68dab471ff8f6a184b260484a772ade 100644 GIT binary patch delta 88 zcmZokXi3;`SDbOzWCO-RO{wZ?Ljy}w9R(vx(^?&cYC|Ja104kmQ-j)CP7YCJee0n3 k?3~=Z{GQ48#N-)!H&2r&X5Y-MaETqPUu`ps#!V;_0K(oIAOHXW delta 42 ucmZokXi3;`SA4QQWA$V^MaRj;l7gGpNW`;m=2W=C4ir`2%%X7<%m4sP1r7B8 diff --git a/software/.DS_Store b/software/.DS_Store index c72074347e0f50c95fd382ce557113964bc3e6c6..aaa302a02e05ef5ccf713d79ba52bc108f7a0d79 100644 GIT binary patch delta 208 zcmZp1XmOa}&nUGqU^hRb)MP(Fnavsk#Vm}wCg%tgdP-GS8yZ-e>L?gln%3$lR2v$Z z8t5okm>Sg9a&m|&>strKXXoVR<@Ydv0V5-XX5fX=FsgTQji|)t98p=ujb$~Ao7pAU KSZQK*B_jaXmMO9T delta 358 zcmZp1XmOa}&nUk!U^hRb{A52tnavsk#VnIw3so~&noQ0Rwx8T6D!MsORF;vGm7#Lz8yEwC+9#G=-OMh*#yUAxm~*hZ^b!EKhF1ar diff --git a/software/networking/config.py b/software/networking/config.py index ab422a5..e86c6b5 100644 --- a/software/networking/config.py +++ b/software/networking/config.py @@ -1,6 +1,7 @@ mysecrets = {"SSID": "Tufts_Robot", "key" : ""} msg_codes = {"cmd": b'\x01', "inf": b'\x01', "ack": b'\x01'} -msg_subcodes = {"cmd": {"Reboot": b'\x00', "Firmware-Update": b'\x01', "File-Update": b'\x02', "File-Download": b'\x03', "File-Run": b'\x05', "Set-Admin": b'\x06', "Whitelist-Add": b'\x07', "Config-Change": b'\x08', "Ping": b'\x10', "Pair": b'\x11', "Set-Pair": b'\x12', "RSSI/Status/Config-Boop": b'\x13', "Directory-Get": b'\x14', "Echo": b'\x15', "Resend": b'\x16', "WiFi-Connect": b'\x21', "WiFi-Disconnect": b'\x22', "AP-Enable": b'\x23', "AP-Disable": b'\x24', "Pause": b'\x25', "Continue": b'\x26'}, "inf": {"RSSI": b'\x20', "Sensor": b'\x21', "Message": b'\x22', "Directory": b'\x23'}, "ack": {"Pong": b'\x10', "Success": b'\x11', "Fail": b'\x12', "Confirm": b'\x13', "Echo": b'\x15'}} +msg_subcodes = {"cmd": {"Reboot": b'\x00', "Firmware-Update": b'\x01', "File-Update": b'\x02', "File-Download": b'\x03', "File-Run": b'\x05', "Set-Admin": b'\x06', "Whitelist-Add": b'\x07', "Config-Change": b'\x08', "Ping": b'\x10', "Pair": b'\x11', "Set-Pair": b'\x12', "RSSI/Status/Config-Boop": b'\x13', "Directory-Get": b'\x14', "Echo": b'\x15', "Resend": b'\x16', "WiFi-Connect": b'\x21', "WiFi-Disconnect": b'\x22', "AP-Enable": b'\x23', "AP-Disable": b'\x24', "Pause": b'\x25', "Resume": b'\x26'}, "inf": {"RSSI": b'\x20', "Sensor": b'\x21', "Message": b'\x22', "Directory": b'\x23'}, "ack": {"Pong": b'\x10', "Success": b'\x11', "Fail": b'\x12', "Confirm": b'\x13', "Echo": b'\x15'}} +networking_keys = {"default_handshake_key": "handshake", "handshake_key1": "handshake1", "handshake_key2": "handshake2", "handshake_key3": "handshake3", "handshake_key4": "handshake4", "default_ap_key": "password", "default_wifi_key": "password"} configname = "Nickname" config = "AdminModuleConfig" whitelist = [b'd\xe83\x84\xd8\x18',b'd\xe83\x84\xd8\x19',b'd\xe83\x85\xd3\xbc', b'd\xe83\x85\xd3\xbd', b'd\xe83\x84\xd8\x18', b'd\xe83\x84\xd8\x19'] #each ESP32 has two MAC addresses diff --git a/software/networking/networking.py b/software/networking/networking.py index d1ce2a7..529ee8d 100644 --- a/software/networking/networking.py +++ b/software/networking/networking.py @@ -1,6 +1,6 @@ import network import machine -from config import mysecrets, configname, config, whitelist, i2c_dict, version, msg_codes, msg_subcodes +from config import mysecrets, configname, config, whitelist, i2c_dict, version, msg_codes, msg_subcodes, networking_keys import time import ubinascii import urequests @@ -11,13 +11,12 @@ import json import os -inittime = time.ticks_ms() class Networking: - def __init__(self, infmsg=False, dbgmsg=False, admin=False): + def __init__(self, infmsg=False, dbgmsg=False, admin=False, inittime=time.ticks_ms()): self.inittime = inittime if infmsg: - print(f"{(time.ticks_ms() - inittime) / 1000:.3f} Initialising Networking") + print(f"{(time.ticks_ms() - self.inittime) / 1000:.3f} Initialising Networking") self.master = self self.infmsg = infmsg self.dbgmsg = dbgmsg @@ -38,7 +37,7 @@ def __init__(self, infmsg=False, dbgmsg=False, admin=False): self.version = version self.version_n = ''.join(str(value) for value in self.version.values()) if infmsg: - print(f"{(time.ticks_ms() - inittime) / 1000:.3f} seconds: Networking initialised and ready") + print(f"{(time.ticks_ms() - self.inittime) / 1000:.3f} seconds: Networking initialised and ready") def cleanup(self): self.dprint(".cleanup") @@ -49,7 +48,7 @@ def cleanup(self): def iprint(self, message): if self.infmsg: try: - print(f"{(time.ticks_ms() - inittime) / 1000:.3f} Networking Info: {message}") + print(f"{(time.ticks_ms() - self.inittime) / 1000:.3f} Networking Info: {message}") except Exception as e: print(f"Error printing networking Info: {e}") return @@ -57,7 +56,7 @@ def iprint(self, message): def dprint(self, message): if self.dbgmsg: try: - print(f"{(time.ticks_ms() - inittime) / 1000:.3f} Networking Debug: {message}") + print(f"{(time.ticks_ms() - self.inittime) / 1000:.3f} Networking Debug: {message}") except Exception as e: print(f"Error printing networking Debug: {e}") return @@ -192,17 +191,19 @@ def __init__(self, master): self._long_buffer_size = {} self.received_sensor_data = {} self.received_rssi_data = {} - #self._long_sent_buffer = {} self._irq_function = None self._pause_function = None self.boops = 0 self.ifidx = 0 #0 sends via sta, 1 via ap - #self._channel = 0 + #self.channel = 0 self._whitelist = whitelist #Flags - self._pairing = True + self._pairing_enabled = True + self._pairing = False + self._paired = False + self._paired_macs = [] self._running = True self._aen.irq(self._irq) @@ -268,16 +269,82 @@ def rssi(self): return self._aen.peers_table #Send cmds - def ping(self, mac, channel=None, ifidx=None): - self.master.dprint("aen.ping") - if bool(self.ifidx): - send_channel = self.master.ap.channel() + def send_command(self, msg_subkey, mac, payload=None, channel=None, ifidx=None, sudo=False): + self.master.dprint("aen.send_command") + if sudo and isinstance(payload, list): + payload.append("sudo") + elif sudo and payload is None: + payload = ["sudo"] else: - send_channel = self.master.sta.channel() - self._compose(mac, [send_channel,self.ifidx,self.master.name], 0x01, 0x10, channel, ifidx) #sends channel, ifidx and name - self.master.iprint(f"Sent ping to {mac} ({self.peer_name(mac)})") + payload = [payload, "sudo"] + if (msg_key := msg_codes["cmd"]) and msg_subkey in msg_subcodes[msg_key]: + self._compose(mac, payload, msg_key, msg_subcodes[msg_key][msg_subkey], channel, ifidx) + self.master.iprint( + f"Sent {msg_subkey} ({msg_subcodes[msg_key][msg_subkey]}) command to {mac} ({self.peer_name(mac)})") + else: + self.master.iprint(f"Command {msg_subkey} not found") gc.collect() - + + def reboot(self, mac, channel=None, ifidx=None, sudo=False): + self.master.dprint("aen.reboot") + send_command("Reboot", mac, None, channel, ifidx, sudo) + + def firmware_update(self, mac, channel=None, ifidx=None, sudo=False): + self.master.dprint("aen.firmware_update") + send_command("Firmware-Update", mac, None, channel, ifidx, sudo) + + def file_update(self, mac, channel=None, ifidx=None, sudo=False): + self.master.dprint("aen.file_update") + send_command("File-Update", mac, None, channel, ifidx, sudo) + + def file_download(self, mac, link, list=None, channel=None, ifidx=None, sudo=False): + self.master.dprint("aen.file_download") + send_command("File-Download", mac, [link, list], None, channel, ifidx, sudo) + + def web_repl(self, mac, channel=None, ifidx=None, sudo=False): + self.master.dprint("aen.web_repl") + self.master.ap.set_ap(ap_name := self.master.name, password := networking_keys["default_ap_key"]) + send_command("Web-Repl", mac, [ap_name, password], channel, ifidx, sudo) + #await success message and if success False disable AP or try again + + def file_run(self, mac, filename, channel=None, ifidx=None, sudo=False): + self.master.dprint("aen.file_run") + send_command("File-Run", mac, filename, None, channel, ifidx, sudo) + + def admin_set(self, mac, new_bool, channel=None, ifidx=None, sudo=False): + self.master.dprint("aen.admin_set") + send_command("Admin-Set", mac, new_bool, None, channel, ifidx, sudo) + + def whitelist_add(self, mac, list=None, channel=None, ifidx=None, sudo=False): + self.master.dprint("aen.whitelist_add") + if list is not None: + list = [self.master.sta.mac,self.master.ap.mac] + send_command("Whitelist-Add", mac, list, None, channel, ifidx, sudo) + + def config_change(self, mac, new_config, channel=None, ifidx=None, sudo=False): + self.master.dprint("aen.config_chain") + send_command("Config-Chain", mac, new_config, channel, ifidx, sudo) + + def ping(self, mac, channel=None, ifidx=None): + self.master.dprint("aen.ping") + send_command("Ping", mac, [send_channel,self.ifidx,self.master.name], channel, ifidx) #sends channel, ifidx and name + + def pair(self, mac, key=networking_keys["handshake_key1"], channel=None, ifidx=None): + self.master.dprint("aen.pair") + send_command("Pair", mac, key, channel, ifidx) + + def pair_enable(self, mac, bool, channel=None, ifidx=None, sudo=False): + self.master.dprint("aen.pair") + send_command("Set-Pair", mac, bool, channel, ifidx, sudo) + + def boop(self, mac, channel=None, ifidx=None, sudo=False): + self.master.dprint("aen.boop") + send_command("RSSI/Status/Config-Boop", mac, None, channel, ifidx, sudo) + + def directory_get(self, mac, channel=None, ifidx=None, sudo=False): + self.master.dprint("aen.directory_get") + send_command("Directory-Get", mac, None, channel, ifidx, sudo) + def echo(self, mac, message, channel=None, ifidx=None): self.master.dprint("aen.echo") try: @@ -286,7 +353,33 @@ def echo(self, mac, message, channel=None, ifidx=None): self.master.iprint(f"Sending echo to {mac} ({self.peer_name(mac)}), but error printing message content: {e}") self._compose(mac, message, 0x01, 0x15, channel, ifidx) gc.collect() - + + #resend cmd + + def wifi_connect(self, mac, name, password, channel=None, ifidx=None, sudo=False): + self.master.dprint("aen.wifi_connect") + send_command("Wifi-Connect", mac, [name, password], channel, ifidx, sudo) + + def wifi_disconnect(self, mac, channel=None, ifidx=None, sudo=False): + self.master.dprint("aen.wifi_disconnect") + send_command("Wifi-Disconnect", mac, None, channel, ifidx, sudo) + + def ap_enable(self, mac, name, password, channel=None, ifidx=None, sudo=False): + self.master.dprint("aen.ap_enable") + send_command("AP-Enable", mac, name, password, channel, ifidx, sudo) + + def ap_disable(self, mac, channel=None, ifidx=None, sudo=False): + self.master.dprint("aen.ap_disable") + send_command("AP-Disable", mac, None, channel, ifidx, sudo) + + def pause(self, mac, channel=None, ifidx=None, sudo=False): + self.master.dprint("aen.pause") + send_command("Pause", mac, None, channel, ifidx, sudo) + + def resume(self, mac, channel=None, ifidx=None, sudo=False): + self.master.dprint("aen.resume") + send_command("Resume", mac, None, channel, ifidx, sudo) + def send(self, mac, message, channel=None, ifidx=None): self.master.dprint("aen.message") if len(str(message)) > 241: @@ -306,7 +399,7 @@ def broadcast(self, message, channel=None, ifidx=None): mac = b'\xff\xff\xff\xff\xff\xff' self.send(mac, message, channel, ifidx) - def send_data_sensor(self, mac, message, channel=None, ifidx=None):#message is a dict, key is the sensor type and the value is the sensor value + def send_sensor(self, mac, message, channel=None, ifidx=None):#message is a dict, key is the sensor type and the value is the sensor value self.master.dprint("aen.message") try: self.master.iprint(f"Sending sensor data ({message}) to {mac} ({self.peer_name(mac)})") @@ -314,43 +407,6 @@ def send_data_sensor(self, mac, message, channel=None, ifidx=None):#message is a self.master.iprint(f"Sending sensor data to {mac} ({self.peer_name(mac)}), but error printing message content: {e}") self._compose(mac, message, 0x02, 0x21, channel, ifidx) - #Boop RSSI/Config - - #set pair - - #pairing - - #Firmware Update Mode - - #File Update - - #enable WebREPL - - #Run File - - #Reboot - - #WiFi enable - - #WiFi disable - - #AP enable - - #AP disable - - #admin bool - - #ad admin mac to whitelist - - #continue - - #pause - - #download gitHub files - - #file directory cmd - - def check_messages(self): self.master.dprint("aen.check_message") return len(self._received_messages) > 0 @@ -389,15 +445,6 @@ def _irq(self): #self.master.cleanup() #network cleanup #self.cleanup() #aen cleanup raise SystemExit("Stopping networking execution. ctrl-c or ctrl-d again to stop main code") #in thonny stops library code but main code keeps running, same in terminal - #self._running = False - #raise KeyboardInterrupt #error in thonny but then stops running, just keeps running in terminal - #sys.exit(0) #breaks thonny, keeps running and recv (although ctl-d-able and keeps running main loop in terminal - #machine.reset() #nogo keeps raising errors and running in terminal - #uos.sysexit() #raises an error in thonny but keeps running in terminal (although ctrl-d able) - #raise SystemExit #stops current library script, but main script keeps running, but now it just keeps the main code running in terminal... - #os.exec(sys.argv[0], sys.argv) #error in thonny, keeps running recv in terminal - #raise Exception("An error occurred!") #error in thonny, and then stops running due to keyboard interrupt, keeps running recv and irq in terminal - #raise KeyboardInterrupt("User interrupt simulated.") #interrupts library code, but main code keeps running, recv just keeps running in terminal else: self._receive() if self._irq_function and self.check_messages() and self._running: @@ -529,10 +576,6 @@ def __encode_payload(): messages.append(bytes(message)) self.master.dprint(f"Message {chunk_index+1}/{total_chunk_number}; length: {len(message)}; Free memory: {gc.mem_free()}") gc.collect() -# key = bytearray() -# key.extend(header[1:8]) -# key.extend(total_chunk_number.to_bytes(1, 'big')) -# self._long_sent_buffer[bytes(key)] = (messages, (channel,ifidx)) gc.collect() self._send(peer_mac, messages, channel, ifidx) @@ -667,14 +710,14 @@ def __send_confirmation(type, recipient_mac, msg_subkey_type, payload=None, erro def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload_type, payload, msg_key): self.master.dprint(f"aen.__handle_cmd") payload = __decode_payload(payload_type, payload) - if subtype == msg_subcodes[msg_key][msg_subkey := "Reboot"]: # Reboot + if (msg_subkey := "Reboot") and subtype == msg_subcodes[msg_key][msg_subkey]: # Reboot self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") if self.__check_authorisation(sender_mac, payload): __send_confirmation("Confirm", sender_mac, f"{msg_subkey} ({subtype})", payload) machine.reset() else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif subtype == msg_subcodes[msg_key][msg_subkey := "Firmware-Update"]: # Firmware-Update + elif (msg_subkey := "Firmware-Update") and subtype == msg_subcodes[msg_key][msg_subkey]: # Firmware-Update self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") if self.__check_authorisation(sender_mac, payload): try: @@ -686,7 +729,7 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif subtype == msg_subcodes[msg_key][msg_subkey := "File-Update"]: # File-Update + elif (msg_subkey := "File-Update") and subtype == msg_subcodes[msg_key][msg_subkey]: # File-Update self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") if self.__check_authorisation(sender_mac, payload): try: @@ -698,25 +741,40 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif subtype == msg_subcodes[msg_key][msg_subkey := "File-Download"]: #File-Download + elif (msg_subkey := "File-Download") and subtype == msg_subcodes[msg_key][msg_subkey]: #File-Download self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") - payload = __decode_payload(payload_type, payload) #should return a list with a link and the list of files to download + #should return a list with a link and the list of files to download if self.__check_authorisation(sender_mac, payload): try: import mip base = payload[0] files_to_copy = payload[1] - for f in files_to_copy: - print("Installing: ", f) - mip.install(base + f) + if files_to_copy is None: + mip.install(base) + else: + for f in files_to_copy: + mip.install(base + f) __send_confirmation("Success", sender_mac, f"{msg_subkey} ({subtype})", payload) except Exception as e: self.master.iprint(f"Error: {e} with payload: {payload}") __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - # enable WebREPL - elif subtype == msg_subcodes[msg_key][msg_subkey := "File-Run"]: #File-Run + elif (msg_subkey := "Web-Repl") and subtype == msg_subcodes[msg_key][msg_subkey]: #Web-Repl + self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + #should be a list with name and password + if self.__check_authorisation(sender_mac, payload): + try: + # add logic to connect to Wi-Fi and set up webrepl + self.master.sta.connect(payload[0], payload[1]) + link = "webrepl link" + __send_confirmation("Success", sender_mac, f"{msg_subkey} ({subtype})", link) + except Exception as e: + self.master.iprint(f"Error: {e} with payload: {payload}") + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) + else: + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") + elif (msg_subkey := "File-Run") and subtype == msg_subcodes[msg_key][msg_subkey]: #File-Run self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") if self.__check_authorisation(sender_mac, payload): try: @@ -727,7 +785,7 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif subtype == msg_subcodes[msg_key][msg_subkey := "Set-Admin"]: #Set Admin Bool + elif (msg_subkey := "Set-Admin") and subtype == msg_subcodes[msg_key][msg_subkey]: #Set Admin Bool self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") if self.__check_authorisation(sender_mac, payload): self.master.iprint(f"Received Set-Admin command: self.admin set to {payload[0]}") @@ -738,7 +796,7 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif subtype == msg_subcodes[msg_key][msg_subkey := "Whitelist-Add"]: # Whitelist-Add - Add Admin macs to _whitelist + elif (msg_subkey := "Whitelist-Add") and subtype == msg_subcodes[msg_key][msg_subkey]: # Whitelist-Add - Add Admin macs to _whitelist self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") if __check_authorisation(sender_mac, payload): self.master.iprint(f"Received add admin macs to _whitelist command, added {payload[0]} and {payload[1]}") @@ -750,7 +808,7 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif subtype == msg_subcodes[msg_key][msg_subkey := "Config-Change"]: # change config + elif (msg_subkey := "Config-Change") and subtype == msg_subcodes[msg_key][msg_subkey]: # change config self.master.iprint( f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") if __check_authorisation(sender_mac, payload): @@ -761,7 +819,7 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif subtype == msg_subcodes[msg_key][msg_subkey := "Ping"]: #Ping + elif (msg_subkey := "Ping") and subtype == msg_subcodes[msg_key][msg_subkey]: #Ping self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") self.add_peer(sender_mac, payload[2], payload[0], payload[1]) if bool(self.ifidx): @@ -770,37 +828,52 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload channel = self.master.sta.channel() response = [channel, self.ifidx, self.master.name, send_timestamp] self._compose(sender_mac, response, 0x03, 0x10) - elif subtype == msg_subcodes[msg_key][msg_subkey := "Pair"]: #Pair + elif (msg_subkey := "Pair") and subtype == msg_subcodes[msg_key][msg_subkey]: #Pair #add something that checks that the messages are from the same mac self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") - if self._pairing: + if self._pairing_enabled and networking_keys["handshake_key_1"] == payload: + self._pairing = True + self.pair(sender_mac, networking_keys["handshake_key_2"]) + #some timer for if key 3 is not received to reset states + elif self._pairing_enabled and self._pairing and networking_keys["handshake_key_2"] == payload: + self._paired = True + self._paired_macs.append(sender_mac) + self.pair(sender_mac, networking_keys["handshake_key_3"]) + #some timer that sets to false if key 4 is not received + elif self._pairing_enabled and self._pairing and networking_keys["handshake_key_3"] == payload: try: - # Insert pairing logic here + # Insert pairing logic here do a reverse handshake + self._paired = True + self._paired_macs.append(sender_mac) + self.pair(sender_mac, networking_keys["handshake_key_4"]) self.master.iprint("no pairing logic written just yet") __send_confirmation("Success", sender_mac, f"{msg_subkey} ({subtype})", payload) except Exception as e: self.master.iprint(f"Error: {e} with payload: {payload}") __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) + elif self._pairing_enabled and self._pairing and networking_keys["handshake_key_3"] == payload: + self._paired = True + #remove timer from before else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", "Pairing disabled", payload) - elif subtype == msg_subcodes[msg_key][msg_subkey := "Set-Pair"]: #Enable pairing mode + elif (msg_subkey := "Set-Pair") and subtype == msg_subcodes[msg_key][msg_subkey]: #Enable pairing mode self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") if self.__check_authorisation(sender_mac, payload): try: - self._pairing = payload[0] + self._pairing_enabled = payload[0] __send_confirmation("Success", sender_mac, f"{msg_subkey} ({subtype})", payload) except Exception as e: self.master.iprint(f"Error: {e} with payload: {payload}") __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif subtype == msg_subcodes[msg_key][msg_subkey := "RSSI/Status/Config-Boop"]: # RSSI/Status/Config Boop + elif (msg_subkey := "RSSI/Status/Config-Boop") and subtype == msg_subcodes[msg_key][msg_subkey]: # RSSI/Status/Config Boop self.boops = self.boops + 1 self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)}), Received total of {self.boops} boops!") try: self._compose(sender_mac, [self.master.id, self.master.name, self.master.config, self.master.version_n, self.master.version, self.master.sta.mac, self.master.ap.mac, self.rssi()], 0x02, 0x20) #[ID, Name, Config, Version, sta mac, ap mac, rssi] except Exception as e: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) - elif subtype == msg_subcodes[msg_key][msg_subkey := "Directory-Get"]: #Get List of Files + elif (msg_subkey := "Directory-Get") and subtype == msg_subcodes[msg_key][msg_subkey]: #Get List of Files self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") try: result = [] @@ -814,30 +887,13 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload self._compose(sender_mac, result, 0x02, 0x20) except Exception as e: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) - elif subtype == msg_subcodes[msg_key][msg_subkey := "Echo"]: #Echo + elif (msg_subkey := "Echo") and subtype == msg_subcodes[msg_key][msg_subkey]: #Echo self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)}): {__decode_payload(payload_type, payload)}") #Check i or d self._compose(sender_mac, payload, 0x03, 0x15) - elif subtype == msg_subcodes[msg_key][msg_subkey := "Resend"]: #Resend lost long messages + elif (msg_subkey := "Resend") and subtype == msg_subcodes[msg_key][msg_subkey]: #Resend lost long messages self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") self.master.iprint("Long_sent_buffer disabled due to memory constraints") -# payload = __decode_payload(payload_type, payload) -# self.master.iprint("Received resend long message command, checking buffer for lost message") -# key = payload[0:8] -# indexes_b = payload[8:] -# indexes = [] -# for i in range(0, len(indexes_b)): -# indexes.append(int.from_bytes(indexes_b[i], 'big')) -# if key in self._long_sent_buffer: -# channel = self._long_sent_buffer[key][1][0] -# ifidx = self._long_sent_buffer[key][1][1] -# for index in indexes: -# message.append(self._long_sent_buffer[key][0][index]) -# self._send(sender_mac, messages, channel, ifidx) -# #resend the message from the message buffer -# self.master.iprint("Resent all requested messages") -# else: -# self.master.iprint("Message not found in the buffer") - elif subtype == msg_subcodes[msg_key][msg_subkey := "WiFi-Connect"]: #Connect to Wi-Fi + elif (msg_subkey := "WiFi-Connect") and subtype == msg_subcodes[msg_key][msg_subkey]: #Connect to Wi-Fi self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") if self.__check_authorisation(sender_mac, payload): try: @@ -848,7 +904,7 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif subtype == msg_subcodes[msg_key][msg_subkey := "WiFi-Disconnect"]: #Disconnect from Wi-Fi + elif (msg_subkey := "WiFi-Disconnect") and subtype == msg_subcodes[msg_key][msg_subkey]: #Disconnect from Wi-Fi self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") if self.__check_authorisation(sender_mac, payload): try: @@ -859,7 +915,7 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif subtype == msg_subcodes[msg_key][msg_subkey := "AP-Enable"]: #Enable AP + elif (msg_subkey := "AP-Enable") and subtype == msg_subcodes[msg_key][msg_subkey]: #Enable AP self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") if self.__check_authorisation(sender_mac, payload): try: @@ -874,7 +930,7 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif subtype == msg_subcodes[msg_key][msg_subkey := "AP-Disable"]: #Disable AP + elif (msg_subkey := "AP-Disable") and subtype == msg_subcodes[msg_key][msg_subkey]: #Disable AP self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") payload = __decode_payload(payload_type, payload) #should return a list of desired name, password and max clients if self.__check_authorisation(sender_mac, payload): @@ -886,7 +942,7 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif subtype == msg_subcodes[msg_key][msg_subkey := "Pause"]: #Set Pause + elif (msg_subkey := "Pause") and subtype == msg_subcodes[msg_key][msg_subkey]: #Set Pause self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") if self.__check_authorisation(sender_mac, payload): try: @@ -901,7 +957,7 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif subtype == msg_subcodes[msg_key][msg_subkey := "Continue"]: #Set Continue + elif (msg_subkey := "Resume") and subtype == msg_subcodes[msg_key][msg_subkey]: #Set Continue self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") if self.__check_authorisation(sender_mac, payload): try: @@ -918,19 +974,19 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload def __handle_inf(sender_mac, subtype, send_timestamp, receive_timestamp, payload_type, payload, msg_key): self.master.dprint("aen.__handle_inf") payload = __decode_payload(payload_type, payload) - if subtype == msg_subcodes[msg_key][msg_subkey := "RSSI"]: #RSSI + if (msg_subkey := "RSSI") and subtype == msg_subcodes[msg_key][msg_subkey]: #RSSI #payload["time_sent"] = send_timestamp #payload["time_recv"] = receive_timestamp self.master.iprint(f"{msg_subkey} ({subtype}) data received from {sender_mac} ({self.peer_name(sender_mac)}): {payload}") self.received_rssi_data[sender_mac] = payload #__send_confirmation("Confirm", sender_mac, f"{msg_subkey} ({subtype})", payload) #confirm message recv - elif subtype == msg_subcodes[msg_key][msg_subkey := "Sensor"]: #Sensor Data + elif (msg_subkey := "Sensor") and subtype == msg_subcodes[msg_key][msg_subkey]: #Sensor Data payload["time_sent"] = send_timestamp payload["time_recv"] = receive_timestamp self.master.iprint(f"{msg_subkey} ({subtype}) data received from {sender_mac} ({self.peer_name(sender_mac)}): {payload}") self.received_sensor_data[sender_mac] = payload #__send_confirmation("Confirm", sender_mac, f"{msg_subkey} ({subtype})", payload) #confirm message recv - elif subtype == msg_subcodes[msg_key][msg_subkey := "Message"]: #Message / Other + elif (msg_subkey := "Message") and subtype == msg_subcodes[msg_key][msg_subkey]: #Message / Other self.master.iprint(f"{msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}): {payload}") self._received_messages.append((sender_mac, payload, receive_timestamp)) self._received_messages_size.append(len(payload)) @@ -939,7 +995,7 @@ def __handle_inf(sender_mac, subtype, send_timestamp, receive_timestamp, payload self._received_messages.pop(0) self._received_messages_size.pop(0) #__send_confirmation("Confirm", sender_mac, f"{msg_subkey} ({subtype})", payload) #confirm message recv - elif subtype == msg_subcodes[msg_key][msg_subkey := "Directory"]: #File Directory + elif (msg_subkey := "Directory") and subtype == msg_subcodes[msg_key][msg_subkey]: #File Directory self.master.iprint(f"{msg_subkey} ({subtype}) data received from {sender_mac} ({self.peer_name(sender_mac)}): {payload}") #__send_confirmation("Confirm", sender_mac, f"{msg_subkey} ({subtype})", payload) #confirm message recv else: @@ -948,20 +1004,20 @@ def __handle_inf(sender_mac, subtype, send_timestamp, receive_timestamp, payload def __handle_ack(sender_mac, subtype, send_timestamp, receive_timestamp, payload_type, payload, msg_key): self.master.dprint("aen.__handle_ack") payload = __decode_payload(payload_type, payload) - if subtype == msg_subcodes[msg_key][msg_subkey := "Pong"]: #Pong + if (msg_subkey := "Pong") and subtype == msg_subcodes[msg_key][msg_subkey]: #Pong self.add_peer(sender_mac, payload[2], payload[0], payload[1]) self.master.iprint(f"{msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}), {receive_timestamp-info[3]}") - elif subtype == msg_subcodes[msg_key][msg_subkey := "Echo"]: #Echo + elif (msg_subkey := "Echo") and subtype == msg_subcodes[msg_key][msg_subkey]: #Echo self.master.iprint(f"{msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}), {__decode_payload(payload_type, payload)}") - elif subtype == msg_subcodes[msg_key][msg_subkey := "Success"]: #Success + elif (msg_subkey := "Success") and subtype == msg_subcodes[msg_key][msg_subkey]: #Success # payload should return a list with a cmd type and payload self.master.iprint(f"Cmd {msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}) for type {payload[0]} with payload {payload[1]}") #add to ack buffer - elif subtype == msg_subcodes[msg_key][msg_subkey := "Fail"]: #Fail + elif (msg_subkey := "Fail") and subtype == msg_subcodes[msg_key][msg_subkey]: #Fail # payload should return a list with a cmd type, error and payload self.master.iprint(f"Cmd {msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}) for type {payload[0]} with error {payload[1]} and payload {payload[2]}") #add to ack buffer - elif subtype == msg_subcodes[msg_key][msg_subkey := "Confirm"]: #Confirmation + elif (msg_subkey := "Confirm") and subtype == msg_subcodes[msg_key][msg_subkey]: #Confirmation # payload should return a list with message type and payload self.master.iprint(f"{msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}) for type {payload[0]} with payload {payload[1]}") #add to ack buffer From 743fd1f3295e3152aa86ffc0bdd67a9ea12807a2 Mon Sep 17 00:00:00 2001 From: Nick Art Date: Mon, 25 Nov 2024 20:01:20 -0500 Subject: [PATCH 04/10] small bug fixes small bug fixes (still does not work) --- .../inspectionProfiles/profiles_settings.xml | 6 +++ software/networking/.idea/misc.xml | 7 +++ software/networking/networking.py | 51 ++++++++++--------- 3 files changed, 41 insertions(+), 23 deletions(-) create mode 100644 software/networking/.idea/inspectionProfiles/profiles_settings.xml create mode 100644 software/networking/.idea/misc.xml diff --git a/software/networking/.idea/inspectionProfiles/profiles_settings.xml b/software/networking/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/software/networking/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/software/networking/.idea/misc.xml b/software/networking/.idea/misc.xml new file mode 100644 index 0000000..f4e3a38 --- /dev/null +++ b/software/networking/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/software/networking/networking.py b/software/networking/networking.py index 529ee8d..c5d7a8b 100644 --- a/software/networking/networking.py +++ b/software/networking/networking.py @@ -14,6 +14,7 @@ class Networking: def __init__(self, infmsg=False, dbgmsg=False, admin=False, inittime=time.ticks_ms()): + gc.collect() self.inittime = inittime if infmsg: print(f"{(time.ticks_ms() - self.inittime) / 1000:.3f} Initialising Networking") @@ -287,63 +288,67 @@ def send_command(self, msg_subkey, mac, payload=None, channel=None, ifidx=None, def reboot(self, mac, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.reboot") - send_command("Reboot", mac, None, channel, ifidx, sudo) + self.send_command("Reboot", mac, None, channel, ifidx, sudo) def firmware_update(self, mac, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.firmware_update") - send_command("Firmware-Update", mac, None, channel, ifidx, sudo) + self.send_command("Firmware-Update", mac, None, channel, ifidx, sudo) def file_update(self, mac, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.file_update") - send_command("File-Update", mac, None, channel, ifidx, sudo) + self.send_command("File-Update", mac, None, channel, ifidx, sudo) def file_download(self, mac, link, list=None, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.file_download") - send_command("File-Download", mac, [link, list], None, channel, ifidx, sudo) + self.send_command("File-Download", mac, [link, list], None, channel, ifidx, sudo) def web_repl(self, mac, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.web_repl") self.master.ap.set_ap(ap_name := self.master.name, password := networking_keys["default_ap_key"]) - send_command("Web-Repl", mac, [ap_name, password], channel, ifidx, sudo) + self.send_command("Web-Repl", mac, [ap_name, password], channel, ifidx, sudo) #await success message and if success False disable AP or try again def file_run(self, mac, filename, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.file_run") - send_command("File-Run", mac, filename, None, channel, ifidx, sudo) + self.send_command("File-Run", mac, filename, None, channel, ifidx, sudo) def admin_set(self, mac, new_bool, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.admin_set") - send_command("Admin-Set", mac, new_bool, None, channel, ifidx, sudo) + self.send_command("Admin-Set", mac, new_bool, None, channel, ifidx, sudo) def whitelist_add(self, mac, list=None, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.whitelist_add") if list is not None: list = [self.master.sta.mac,self.master.ap.mac] - send_command("Whitelist-Add", mac, list, None, channel, ifidx, sudo) + self.send_command("Whitelist-Add", mac, list, None, channel, ifidx, sudo) def config_change(self, mac, new_config, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.config_chain") - send_command("Config-Chain", mac, new_config, channel, ifidx, sudo) + self.send_command("Config-Chain", mac, new_config, channel, ifidx, sudo) def ping(self, mac, channel=None, ifidx=None): self.master.dprint("aen.ping") - send_command("Ping", mac, [send_channel,self.ifidx,self.master.name], channel, ifidx) #sends channel, ifidx and name + if bool(self.ifidx): + send_channel = self.master.ap.channel() + else: + send_channel = self.master.sta.channel() + self.send_command("Ping", mac, [send_channel,self.ifidx,self.master.name], channel, ifidx) # sends channel, ifidx and name def pair(self, mac, key=networking_keys["handshake_key1"], channel=None, ifidx=None): self.master.dprint("aen.pair") - send_command("Pair", mac, key, channel, ifidx) + self.send_command("Pair", mac, key, channel, ifidx) def pair_enable(self, mac, bool, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.pair") - send_command("Set-Pair", mac, bool, channel, ifidx, sudo) + self.send_command("Set-Pair", mac, bool, channel, ifidx, sudo) def boop(self, mac, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.boop") - send_command("RSSI/Status/Config-Boop", mac, None, channel, ifidx, sudo) + self.send_command("RSSI/Status/Config-Boop", mac, None, channel, ifidx, sudo) def directory_get(self, mac, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.directory_get") - send_command("Directory-Get", mac, None, channel, ifidx, sudo) + self.send_command("Directory-Get", mac, None, channel, ifidx, sudo) def echo(self, mac, message, channel=None, ifidx=None): self.master.dprint("aen.echo") @@ -358,27 +363,27 @@ def echo(self, mac, message, channel=None, ifidx=None): def wifi_connect(self, mac, name, password, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.wifi_connect") - send_command("Wifi-Connect", mac, [name, password], channel, ifidx, sudo) + self.send_command("Wifi-Connect", mac, [name, password], channel, ifidx, sudo) def wifi_disconnect(self, mac, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.wifi_disconnect") - send_command("Wifi-Disconnect", mac, None, channel, ifidx, sudo) + self.send_command("Wifi-Disconnect", mac, None, channel, ifidx, sudo) def ap_enable(self, mac, name, password, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.ap_enable") - send_command("AP-Enable", mac, name, password, channel, ifidx, sudo) + self.send_command("AP-Enable", mac, name, password, channel, ifidx, sudo) def ap_disable(self, mac, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.ap_disable") - send_command("AP-Disable", mac, None, channel, ifidx, sudo) + self.send_command("AP-Disable", mac, None, channel, ifidx, sudo) def pause(self, mac, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.pause") - send_command("Pause", mac, None, channel, ifidx, sudo) + self.send_command("Pause", mac, None, channel, ifidx, sudo) def resume(self, mac, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.resume") - send_command("Resume", mac, None, channel, ifidx, sudo) + self.send_command("Resume", mac, None, channel, ifidx, sudo) def send(self, mac, message, channel=None, ifidx=None): self.master.dprint("aen.message") @@ -689,7 +694,7 @@ def __process_message(sender_mac, message, receive_timestamp): #Handle the message based on type if msg_type == (msg_key := msg_codes["cmd"]): # Command Message __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload_type, payload if payload else None, msg_key) - elif msg_type == (msg_key := cmsg_codes["inf"]): # Informational Message + elif msg_type == (msg_key := msg_codes["inf"]): # Informational Message __handle_inf(sender_mac, subtype, send_timestamp, receive_timestamp, payload_type, payload if payload else None, msg_key) elif msg_type == (msg_key := msg_codes["ack"]): # Acknowledgement Message __handle_ack(sender_mac, subtype, send_timestamp, receive_timestamp, payload_type, payload if payload else None, msg_key) @@ -952,7 +957,7 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload if self._pause_function: self._pause_function() #calls the custom set pause function to display a screen while not self._running: - sleep(0.5) + time.sleep(0.5) except Exception as e: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: @@ -1006,7 +1011,7 @@ def __handle_ack(sender_mac, subtype, send_timestamp, receive_timestamp, payload payload = __decode_payload(payload_type, payload) if (msg_subkey := "Pong") and subtype == msg_subcodes[msg_key][msg_subkey]: #Pong self.add_peer(sender_mac, payload[2], payload[0], payload[1]) - self.master.iprint(f"{msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}), {receive_timestamp-info[3]}") + self.master.iprint(f"{msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}), {receive_timestamp-payload[3]}") elif (msg_subkey := "Echo") and subtype == msg_subcodes[msg_key][msg_subkey]: #Echo self.master.iprint(f"{msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}), {__decode_payload(payload_type, payload)}") elif (msg_subkey := "Success") and subtype == msg_subcodes[msg_key][msg_subkey]: #Success From 33de5b31a44f6a55fbed5f2e89320341e6e86cbc Mon Sep 17 00:00:00 2001 From: Nick Art Date: Tue, 26 Nov 2024 00:39:44 -0500 Subject: [PATCH 05/10] Fixed some major bugs Managed to repair some functionality, complete functionality test pending --- .../inspectionProfiles/profiles_settings.xml | 1 + .../.idea/libraries/MicroPython.xml | 11 + software/networking/.idea/misc.xml | 2 +- software/networking/.idea/modules.xml | 8 + software/networking/.idea/networking.iml | 18 + software/networking/config.py | 64 +- software/networking/examples/example.py | 37 +- software/networking/networking.py | 591 ++++++++++-------- 8 files changed, 436 insertions(+), 296 deletions(-) create mode 100644 software/networking/.idea/libraries/MicroPython.xml create mode 100644 software/networking/.idea/modules.xml create mode 100644 software/networking/.idea/networking.iml diff --git a/software/networking/.idea/inspectionProfiles/profiles_settings.xml b/software/networking/.idea/inspectionProfiles/profiles_settings.xml index 105ce2d..dd4c951 100644 --- a/software/networking/.idea/inspectionProfiles/profiles_settings.xml +++ b/software/networking/.idea/inspectionProfiles/profiles_settings.xml @@ -1,5 +1,6 @@ + diff --git a/software/networking/.idea/libraries/MicroPython.xml b/software/networking/.idea/libraries/MicroPython.xml new file mode 100644 index 0000000..aa131a7 --- /dev/null +++ b/software/networking/.idea/libraries/MicroPython.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/software/networking/.idea/misc.xml b/software/networking/.idea/misc.xml index f4e3a38..6038861 100644 --- a/software/networking/.idea/misc.xml +++ b/software/networking/.idea/misc.xml @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/software/networking/.idea/modules.xml b/software/networking/.idea/modules.xml new file mode 100644 index 0000000..27cf2c6 --- /dev/null +++ b/software/networking/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/software/networking/.idea/networking.iml b/software/networking/.idea/networking.iml new file mode 100644 index 0000000..945fce2 --- /dev/null +++ b/software/networking/.idea/networking.iml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/software/networking/config.py b/software/networking/config.py index e86c6b5..1629372 100644 --- a/software/networking/config.py +++ b/software/networking/config.py @@ -1,9 +1,59 @@ -mysecrets = {"SSID": "Tufts_Robot", "key" : ""} -msg_codes = {"cmd": b'\x01', "inf": b'\x01', "ack": b'\x01'} -msg_subcodes = {"cmd": {"Reboot": b'\x00', "Firmware-Update": b'\x01', "File-Update": b'\x02', "File-Download": b'\x03', "File-Run": b'\x05', "Set-Admin": b'\x06', "Whitelist-Add": b'\x07', "Config-Change": b'\x08', "Ping": b'\x10', "Pair": b'\x11', "Set-Pair": b'\x12', "RSSI/Status/Config-Boop": b'\x13', "Directory-Get": b'\x14', "Echo": b'\x15', "Resend": b'\x16', "WiFi-Connect": b'\x21', "WiFi-Disconnect": b'\x22', "AP-Enable": b'\x23', "AP-Disable": b'\x24', "Pause": b'\x25', "Resume": b'\x26'}, "inf": {"RSSI": b'\x20', "Sensor": b'\x21', "Message": b'\x22', "Directory": b'\x23'}, "ack": {"Pong": b'\x10', "Success": b'\x11', "Fail": b'\x12', "Confirm": b'\x13', "Echo": b'\x15'}} -networking_keys = {"default_handshake_key": "handshake", "handshake_key1": "handshake1", "handshake_key2": "handshake2", "handshake_key3": "handshake3", "handshake_key4": "handshake4", "default_ap_key": "password", "default_wifi_key": "password"} +mysecrets = {"SSID": "Tufts_Robot", "key": ""} +msg_codes = {"cmd": 0x01, "inf": 0x01, "ack": 0x01} +msg_subcodes = { + "cmd": { + "Reboot": 0x00, + "Firmware-Update": 0x01, + "File-Update": 0x02, + "File-Download": 0x03, + "File-Run": 0x05, + "Set-Admin": 0x06, + "Whitelist-Add": 0x07, + "Config-Change": 0x08, + "Ping": 0x10, + "Pair": 0x11, + "Set-Pair": 0x12, + "RSSI/Status/Config-Boop": 0x13, + "Directory-Get": 0x14, + "Echo": 0x15, + "Resend": 0x16, + "WiFi-Connect": 0x21, + "WiFi-Disconnect": 0x22, + "AP-Enable": 0x23, + "AP-Disable": 0x24, + "Pause": 0x25, + "Resume": 0x26, + }, + "inf": { + "RSSI": 0x20, + "Sensor": 0x21, + "Message": 0x22, + "Directory": 0x23, + }, + "ack": { + "Pong": 0x10, + "Success": 0x11, + "Fail": 0x12, + "Confirm": 0x13, + "Echo": 0x15, + }, +} +networking_keys = { + "default_handshake_key": "handshake", + "handshake_key1": "handshake1", + "handshake_key2": "handshake2", + "handshake_key3": "handshake3", + "handshake_key4": "handshake4", + "default_ap_key": "password", + "default_wifi_key": "password" +} configname = "Nickname" config = "AdminModuleConfig" -whitelist = [b'd\xe83\x84\xd8\x18',b'd\xe83\x84\xd8\x19',b'd\xe83\x85\xd3\xbc', b'd\xe83\x85\xd3\xbd', b'd\xe83\x84\xd8\x18', b'd\xe83\x84\xd8\x19'] #each ESP32 has two MAC addresses -i2c_dict = {"0x3C": ["pca9685", 0, "screen"], "0x53" : ["ACCEL", 1, "accelerometer"]} #key is i2c address: ["device name", Output (0) or Input (1), "Description"] -version={"adxl345":3,"files":2, "icons":2, "motor":4, "main":0, "networking":0, "prefs":2, "sensors":4, "servo":2, "ssd1306":2} #motor used to be main \ No newline at end of file +whitelist = [b'd\xe83\x84\xd8\x18', b'd\xe83\x84\xd8\x19', + b'd\xe83\x85\xd3\xbc', b'd\xe83\x85\xd3\xbd', + b'd\xe83\x84\xd8\x18', b'd\xe83\x84\xd8\x19'] #each ESP32 has two MAC addresses +i2c_dict = { + "0x3C": ["pca9685", 0, "screen"], + "0x53": ["ACCEL", 1, "accelerometer"] +} #key is i2c address: ["device name", Output (0) or Input (1), "Description"] +version = {"adxl345": 3, "files": 2, "icons": 2, "motor": 4, "main": 0, "networking": 0, "prefs": 2, "sensors": 4, "servo": 2, "ssd1306": 2} # motor used to be main diff --git a/software/networking/examples/example.py b/software/networking/examples/example.py index 437d831..7c18d72 100644 --- a/software/networking/examples/example.py +++ b/software/networking/examples/example.py @@ -1,55 +1,58 @@ from networking import Networking import time -#Initialise +# Initialise networking = Networking() ###Example code### -recipient_mac = b'\xff\xff\xff\xff\xff\xff' #This mac sends to all -message = b'Boop' +recipient_mac = b'\xff\xff\xff\xff\xff\xff' # This mac sends to all +message = b'Boop' -#Print own mac +# Print own mac print(networking.sta._sta.config('mac')) +print(networking.ap._ap.config('mac')) print() -#Ping, calculates the time until you receive a response from the peer +# Ping, calculates the time until you receive a response from the peer networking.aen.ping(recipient_mac) print() -#Echo, sends a message that will be repeated back by the recipient +# Echo, sends a message that will be repeated back by the recipient networking.aen.echo(recipient_mac, message) print() -#Message, sends the specified message to the recipient, supported formats are bytearrays, bytes, int, float, string, bool, list and dict, if above 241 bytes, it will send in multiple packages: max 60928 bytes +# Message, sends the specified message to the recipient, supported formats are bytearrays, bytes, int, float, string, bool, list and dict, if above 241 bytes, it will send in multiple packages: max 60928 bytes networking.aen.send(recipient_mac, message) print() -#Check if there are any messages in the message buffer +# Check if there are any messages in the message buffer print(networking.aen.check_messages()) print() -#Get Last Received Message -print(networking.aen.return_message()) #Returns none, none, none if there are no messages +# Get Last Received Message +print(networking.aen.return_message()) # Returns none, none, none if there are no messages print() -#Get the RSSI table +# Get the RSSI table print(networking.aen.rssi()) print() -#Get All Recieved Messages +# Get All Recieved Messages messages = networking.aen.return_messages() for mac, message, receive_time in messages: print(mac, message, receive_time) - -#Set up an interrupt which runs a function as soon as possible after receiving a new message + + +# Set up an interrupt which runs a function as soon as possible after receiving a new message def receive(): print("Receive") - for mac, message, rtime in networking.aen.return_messages(): #You can directly iterate over the function + for mac, message, rtime in networking.aen.return_messages(): # You can directly iterate over the function print(mac, message, rtime) -networking.aen.irq(receive) #interrupt handler +networking.aen.irq(receive) # interrupt handler print(networking.aen._irq_function) -time.sleep(0.05)#There is a bug in thonny with some ESP32 devices, which makes this statement necessary. I don't know why, currently discussing and debugging this with thonny devs. \ No newline at end of file +time.sleep( + 0.05) # There is a bug in thonny with some ESP32 devices, which makes this statement necessary. I don't know why, currently discussing and debugging this with thonny devs. diff --git a/software/networking/networking.py b/software/networking/networking.py index c5d7a8b..2ff74cf 100644 --- a/software/networking/networking.py +++ b/software/networking/networking.py @@ -12,7 +12,7 @@ import os -class Networking: +class Networking: def __init__(self, infmsg=False, dbgmsg=False, admin=False, inittime=time.ticks_ms()): gc.collect() self.inittime = inittime @@ -22,14 +22,14 @@ def __init__(self, infmsg=False, dbgmsg=False, admin=False, inittime=time.ticks_ self.infmsg = infmsg self.dbgmsg = dbgmsg self.admin = admin - + self._staif = network.WLAN(network.STA_IF) self._apif = network.WLAN(network.AP_IF) - + self.sta = self.Sta(self, self._staif) self.ap = self.Ap(self, self._apif) self.aen = self.Aen(self) - + self.id = ubinascii.hexlify(machine.unique_id()).decode() self.name = configname if not self.name: @@ -39,13 +39,13 @@ def __init__(self, infmsg=False, dbgmsg=False, admin=False, inittime=time.ticks_ self.version_n = ''.join(str(value) for value in self.version.values()) if infmsg: print(f"{(time.ticks_ms() - self.inittime) / 1000:.3f} seconds: Networking initialised and ready") - + def cleanup(self): self.dprint(".cleanup") self.aen.cleanup() self._staif.active(False) self._apif.active(False) - + def iprint(self, message): if self.infmsg: try: @@ -53,7 +53,7 @@ def iprint(self, message): except Exception as e: print(f"Error printing networking Info: {e}") return - + def dprint(self, message): if self.dbgmsg: try: @@ -61,25 +61,22 @@ def dprint(self, message): except Exception as e: print(f"Error printing networking Debug: {e}") return - - - - class Sta: + class Sta: def __init__(self, master, _staif): self.master = master self._sta = _staif self._sta.active(True) self.master.iprint("STA initialised and ready") - + def scan(self): self.master.dprint("sta.scan") scan_result = self._sta.scan() - if self.infmsg: + if self.master.infmsg: for ap in scan_result: self.master.iprint(f"SSID:%s BSSID:%s Channel:%d Strength:%d RSSI:%d Auth:%d " % ap) return scan_result - + def connect(self, ssid, key="", timeout=10): self.master.dprint("sta.connect") self._sta.connect(ssid, key) @@ -90,34 +87,34 @@ def connect(self, ssid, key="", timeout=10): return time.sleep(0.1) self.master.iprint(f"Failed to connect to WiFi: {self._sta.status()}") - + def disconnect(self): self.master.dprint("sta.disconnect") self._sta.disconnect() - + def ip(self): self.master.dprint("sta.ip") return self._sta.ifconfig() - + def mac(self): self.master.dprint("sta.mac") return bytes(self._sta.config('mac')) - - def mac_decoded(self):#Necessary? + + def mac_decoded(self): # Necessary? self.master.dprint("sta.mac_decoded") return ubinascii.hexlify(self._sta.config('mac'), ':').decode() - + def channel(self): self.master.dprint("sta.channel") return self._sta.config('channel') - + def set_channel(self, number): self.master.dprint("sta.set_channel") if number > 14 or number < 0: number = 0 self._sta.config(channel=number) - self.vprint(f"STA channel set to {number}") - + self.master.dprint(f"STA channel set to {number}") + def get_joke(self): self.master.dprint("sta.get_joke") try: @@ -128,63 +125,59 @@ def get_joke(self): except Exception as e: print('Error fetching joke:', str(e)) return None - - - + class Ap: def __init__(self, master, _apif): self.master = master self._ap = _apif self._ap.active(True) self.master.iprint("AP initialised and ready") - + def set_ap(self, name="", password="", max_clients=10): self.master.dprint("ap.set_ap") if name == "": - name = self.name + name = self.master.name self._ap.active(True) self._ap.config(essid=name) if password: self._ap.config(authmode=network.AUTH_WPA_WPA2_PSK, password=password) self._ap.config(max_clients=max_clients) self.master.iprint(f"Access Point {name} set with max clients {max_clients}") - + def deactivate(self): self.master.dprint("ap.deactivate") self._ap.active(False) self.master.iprint("Access Point deactivated") - + def ip(self): self.master.dprint("ap.ip") return self._ap.ifconfig() - + def mac(self): self.master.dprint("ap.mac") return bytes(self._ap.config('mac')) - + def mac_decoded(self): self.master.dprint("ap.mac_decoded") return ubinascii.hexlify(self._ap.config('mac'), ':').decode() - + def channel(self): self.master.dprint("ap.channel") return self._ap.config('channel') - + def set_channel(self, number): self.master.dprint("ap.set_channel") if number > 14 or number < 0: number = 0 self._ap.config(channel=number) - self.vprint(f"AP channel set to {number}") - - + self.master.dprint(f"AP channel set to {number}") class Aen: def __init__(self, master): self.master = master self._aen = espnow.ESPNow() self._aen.active(True) - + self._peers = {} self._received_messages = [] self._received_messages_size = [] @@ -195,27 +188,27 @@ def __init__(self, master): self._irq_function = None self._pause_function = None self.boops = 0 - self.ifidx = 0 #0 sends via sta, 1 via ap - #self.channel = 0 - + self.ifidx = 0 # 0 sends via sta, 1 via ap + # self.channel = 0 + self._whitelist = whitelist - - #Flags + + # Flags self._pairing_enabled = True self._pairing = False self._paired = False self._paired_macs = [] self._running = True - + self._aen.irq(self._irq) - + self.master.iprint("ESP-NOW initialised and ready") def cleanup(self): self.master.iprint("aen.cleanup") self.irq(None) self._aen.active(False) - #add delete buffers and stuff + # add delete buffers and stuff def update_peer(self, peer_mac, name=None, channel=None, ifidx=None): self.master.dprint("aen.update_peer") @@ -257,19 +250,19 @@ def remove_peer(self, peer_mac): def peers(self): self.master.dprint("aen.peers") return self._peers - + def peer_name(self, key): self.master.dprint("aen.name") if key in self._peers: return self._peers[key]['name'] else: return None - + def rssi(self): self.master.dprint("aen.rssi") return self._aen.peers_table - #Send cmds + # Send cmds def send_command(self, msg_subkey, mac, payload=None, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.send_command") if sudo and isinstance(payload, list): @@ -278,10 +271,10 @@ def send_command(self, msg_subkey, mac, payload=None, channel=None, ifidx=None, payload = ["sudo"] else: payload = [payload, "sudo"] - if (msg_key := msg_codes["cmd"]) and msg_subkey in msg_subcodes[msg_key]: - self._compose(mac, payload, msg_key, msg_subcodes[msg_key][msg_subkey], channel, ifidx) + if (msg_key := "cmd") and msg_subkey in msg_subcodes[msg_key]: self.master.iprint( - f"Sent {msg_subkey} ({msg_subcodes[msg_key][msg_subkey]}) command to {mac} ({self.peer_name(mac)})") + f"Sending {msg_subkey} ({bytes([msg_subcodes[msg_key][msg_subkey]])}) command to {mac} ({self.peer_name(mac)})") + self._compose(mac, payload, msg_codes[msg_key], msg_subcodes[msg_key][msg_subkey], channel, ifidx) else: self.master.iprint(f"Command {msg_subkey} not found") gc.collect() @@ -298,29 +291,29 @@ def file_update(self, mac, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.file_update") self.send_command("File-Update", mac, None, channel, ifidx, sudo) - def file_download(self, mac, link, list=None, channel=None, ifidx=None, sudo=False): + def file_download(self, mac, link, file_list=None, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.file_download") - self.send_command("File-Download", mac, [link, list], None, channel, ifidx, sudo) + self.send_command("File-Download", mac, [link, file_list], channel, ifidx, sudo) def web_repl(self, mac, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.web_repl") self.master.ap.set_ap(ap_name := self.master.name, password := networking_keys["default_ap_key"]) self.send_command("Web-Repl", mac, [ap_name, password], channel, ifidx, sudo) - #await success message and if success False disable AP or try again + # await success message and if success False disable AP or try again def file_run(self, mac, filename, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.file_run") - self.send_command("File-Run", mac, filename, None, channel, ifidx, sudo) + self.send_command("File-Run", mac, filename, channel, ifidx, sudo) def admin_set(self, mac, new_bool, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.admin_set") - self.send_command("Admin-Set", mac, new_bool, None, channel, ifidx, sudo) + self.send_command("Admin-Set", mac, new_bool, channel, ifidx, sudo) - def whitelist_add(self, mac, list=None, channel=None, ifidx=None, sudo=False): + def whitelist_add(self, mac, mac_list=None, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.whitelist_add") - if list is not None: - list = [self.master.sta.mac,self.master.ap.mac] - self.send_command("Whitelist-Add", mac, list, None, channel, ifidx, sudo) + if mac_list is not None: + mac_list = [self.master.sta.mac, self.master.ap.mac] + self.send_command("Whitelist-Add", mac, mac_list, channel, ifidx, sudo) def config_change(self, mac, new_config, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.config_chain") @@ -332,15 +325,16 @@ def ping(self, mac, channel=None, ifidx=None): send_channel = self.master.ap.channel() else: send_channel = self.master.sta.channel() - self.send_command("Ping", mac, [send_channel,self.ifidx,self.master.name], channel, ifidx) # sends channel, ifidx and name + self.send_command("Ping", mac, [send_channel, self.ifidx, self.master.name], channel, + ifidx) # sends channel, ifidx and name def pair(self, mac, key=networking_keys["handshake_key1"], channel=None, ifidx=None): self.master.dprint("aen.pair") self.send_command("Pair", mac, key, channel, ifidx) - def pair_enable(self, mac, bool, channel=None, ifidx=None, sudo=False): + def pair_enable(self, mac, pair_bool, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.pair") - self.send_command("Set-Pair", mac, bool, channel, ifidx, sudo) + self.send_command("Set-Pair", mac, pair_bool, channel, ifidx, sudo) def boop(self, mac, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.boop") @@ -355,11 +349,12 @@ def echo(self, mac, message, channel=None, ifidx=None): try: self.master.iprint(f"Sending echo ({message}) to {mac} ({self.peer_name(mac)})") except Exception as e: - self.master.iprint(f"Sending echo to {mac} ({self.peer_name(mac)}), but error printing message content: {e}") + self.master.iprint( + f"Sending echo to {mac} ({self.peer_name(mac)}), but error printing message content: {e}") self._compose(mac, message, 0x01, 0x15, channel, ifidx) gc.collect() - #resend cmd + # resend cmd def wifi_connect(self, mac, name, password, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.wifi_connect") @@ -371,7 +366,7 @@ def wifi_disconnect(self, mac, channel=None, ifidx=None, sudo=False): def ap_enable(self, mac, name, password, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.ap_enable") - self.send_command("AP-Enable", mac, name, password, channel, ifidx, sudo) + self.send_command("AP-Enable", mac, [name, password], channel, ifidx, sudo) def ap_disable(self, mac, channel=None, ifidx=None, sudo=False): self.master.dprint("aen.ap_disable") @@ -389,40 +384,44 @@ def send(self, mac, message, channel=None, ifidx=None): self.master.dprint("aen.message") if len(str(message)) > 241: try: - self.master.iprint(f"Sending message ({str(message)[:50] + '... (truncated)'}) to {mac} ({self.peer_name(mac)})") + self.master.iprint( + f"Sending message ({str(message)[:50] + '... (truncated)'}) to {mac} ({self.peer_name(mac)})") except Exception as e: - self.master.iprint(f"Sending message to {mac} ({self.peer_name(mac)}), but error printing message content: {e}") + self.master.iprint( + f"Sending message to {mac} ({self.peer_name(mac)}), but error printing message content: {e}") gc.collect() else: self.master.iprint(f"Sending message ({message}) to {mac} ({self.peer_name(mac)})") self._compose(mac, message, 0x02, 0x22, channel, ifidx) gc.collect() self.master.dprint(f"Free memory: {gc.mem_free()}") - + def broadcast(self, message, channel=None, ifidx=None): self.master.dprint("aen.broadcast") mac = b'\xff\xff\xff\xff\xff\xff' self.send(mac, message, channel, ifidx) - def send_sensor(self, mac, message, channel=None, ifidx=None):#message is a dict, key is the sensor type and the value is the sensor value + def send_sensor(self, mac, message, channel=None, + ifidx=None): # message is a dict, key is the sensor type and the value is the sensor value self.master.dprint("aen.message") try: self.master.iprint(f"Sending sensor data ({message}) to {mac} ({self.peer_name(mac)})") except Exception as e: - self.master.iprint(f"Sending sensor data to {mac} ({self.peer_name(mac)}), but error printing message content: {e}") + self.master.iprint( + f"Sending sensor data to {mac} ({self.peer_name(mac)}), but error printing message content: {e}") self._compose(mac, message, 0x02, 0x21, channel, ifidx) def check_messages(self): self.master.dprint("aen.check_message") return len(self._received_messages) > 0 - + def return_message(self): self.master.dprint("aen.return_message") if self.check_messages(): self._received_messages_size.pop() return self._received_messages.pop() return None, None, None - + def return_messages(self): self.master.dprint("aen.return_messages") if self.check_messages(): @@ -432,7 +431,7 @@ def return_messages(self): gc.collect() return messages return [(None, None, None)] - + def _irq(self): self.master.dprint("aen._irq") if self.master.admin: @@ -443,26 +442,27 @@ def _irq(self): gc.collect() return except KeyboardInterrupt: - #machine.disable_irq() #throws errors - self.master.iprint("aen._irq except KeyboardInterrupt") - #self._aen.irq(None) #does not work + # machine.disable_irq() #throws errors + self.master.iprint("aen._irq except KeyboardInterrupt") + # self._aen.irq(None) #does not work self._aen.active(False) - #self.master.cleanup() #network cleanup - #self.cleanup() #aen cleanup - raise SystemExit("Stopping networking execution. ctrl-c or ctrl-d again to stop main code") #in thonny stops library code but main code keeps running, same in terminal + # self.master.cleanup() #network cleanup + # self.cleanup() #aen cleanup + raise SystemExit( + "Stopping networking execution. ctrl-c or ctrl-d again to stop main code") # in thonny stops library code but main code keeps running, same in terminal else: self._receive() if self._irq_function and self.check_messages() and self._running: self._irq_function() gc.collect() return - + def irq(self, func): self.master.dprint("aen.irq") self._irq_function = func - + def _send(self, peers_mac, messages, channel, ifidx): - self.master.dprint("aen._send") + self.master.dprint("aen._send") if isinstance(peers_mac, bytes): peers_mac = [peers_mac] @@ -485,64 +485,59 @@ def _send(self, peers_mac, messages, channel, ifidx): ifidx=self._peers[peer_mac]['ifidx']) else: self._aen.add_peer(peer_mac, channel=0, ifidx=self.ifidx) + self.master.dprint(f"Added {peer_mac} to espnow buffer") except Exception as e: - print(f"Error adding {peer_mac} to buffer: {e}") - - for m in range(len(messages)): - if isinstance(peers_mac, list): - mac = None - else: - mac = peers_mac - for i in range(3): - i += i - try: - self._aen.send(mac, messages[m]) - break - except Exception as e: - print(f"Error sending to {mac}: {e}") - self.master.dprint(f"Sent {messages[m]} to {mac} ({self.peer_name(mac)})") - gc.collect() + self.master.iprint(f"Error adding {peer_mac} to espnow buffer: {e}") + + for m in range(len(messages)): + for i in range(3): + i += i + try: + self._aen.send(peer_mac, messages[m]) + break + except Exception as e: + self.master.iprint(f"Error sending to {peer_mac}: {e}") + self.master.dprint(f"Sent {messages[m]} to {peer_mac} ({self.peer_name(peer_mac)})") + gc.collect() - if isinstance(peers_mac, bytes): - peers_mac = [peers_mac] - for peer_mac in peers_mac: try: self._aen.del_peer(peer_mac) + self.master.dprint(f"Removed {peer_mac} from espnow buffer") except Exception as e: - print(f"Error removing {peer_mac} from buffer: {e}") - + print(f"Error removing {peer_mac} from espnow buffer: {e}") + def _compose(self, peer_mac, payload=None, msg_type=0x02, subtype=0x22, channel=None, ifidx=None): self.master.dprint("aen._compose") - + if isinstance(peer_mac, list): - for peer_macs in peer_mac: - if peer_macs not in self._peers: - self.add_peer(peer_macs, None, channel, ifidx) + for peer_macs in peer_mac: + if peer_macs not in self._peers: + self.add_peer(peer_macs, None, channel, ifidx) elif peer_mac not in self._peers: self.add_peer(peer_mac, None, channel, ifidx) - + def __encode_payload(): self.master.dprint("aen.__encode_payload") - if payload is None: #No payload type + if payload is None: # No payload type return b'\x00', b'' - elif isinstance(payload, bytearray): #bytearray + elif isinstance(payload, bytearray): # bytearray return b'\x01', bytes(payload) - elif isinstance(payload, bytes): #bytes + elif isinstance(payload, bytes): # bytes return b'\x01', payload - elif isinstance(payload, bool): #bool + elif isinstance(payload, bool): # bool return b'\x02', (b'\x01' if payload else b'\x00') - elif isinstance(payload, int): #int + elif isinstance(payload, int): # int return b'\x03', struct.pack('>i', payload) - elif isinstance(payload, float): #float + elif isinstance(payload, float): # float return b'\x04', struct.pack('>f', payload) - elif isinstance(payload, str): #string + elif isinstance(payload, str): # string return b'\x05', payload.encode('utf-8') - elif isinstance(payload, dict) or isinstance(payload, list): #json dict or list + elif isinstance(payload, dict) or isinstance(payload, list): # json dict or list json_payload = json.dumps(payload) return b'\x06', json_payload.encode('utf-8') else: raise ValueError("Unsupported payload type") - + payload_type, payload_bytes = __encode_payload() messages = [] identifier = 0x2a @@ -552,64 +547,62 @@ def __encode_payload(): header[1] = msg_type header[2] = subtype header[3:7] = timestamp.to_bytes(4, 'big') - if len(payload_bytes) < 242: #250-9=241=max_length + if len(payload_bytes) < 242: # 250-9=241=max_length header[7] = payload_type[0] total_length = 1 + 1 + 1 + 4 + 1 + len(payload_bytes) + 1 message = bytearray(total_length) message[:8] = header - message[8:-1] = payload_bytes - message[-1:] = (sum(message) % 256).to_bytes(1, 'big') #Checksum + message[8:-1] = payload_bytes + message[-1:] = (sum(message) % 256).to_bytes(1, 'big') # Checksum self.master.dprint(f"Message {1}/{1}; Length: {len(message)}; Free memory: {gc.mem_free()}") messages.append(message) - else: self.master.dprint("Long message: Splitting!") - max_size = 238 #241-3 - total_chunk_number = (-(-len(payload_bytes)//max_size)) #Round up division + max_size = 238 # 241-3 + total_chunk_number = (-(-len(payload_bytes) // max_size)) # Round up division lba = b'\x07' - header[7] = lba[0] #Long byte array + header[7] = lba[0] # Long byte array if total_chunk_number > 256: raise ValueError("More than 256 chunks, unsupported") for chunk_index in range(total_chunk_number): - message = bytearray(9 + 3 + min(max_size,len(payload_bytes)-chunk_index*max_size)) + message = bytearray(9 + 3 + min(max_size, len(payload_bytes) - chunk_index * max_size)) message[:8] = header message[8:10] = chunk_index.to_bytes(1, 'big') + total_chunk_number.to_bytes(1, 'big') message[10] = payload_type[0] - message[11:-1] = payload_bytes[chunk_index * max_size: (chunk_index + 1) * max_size] - message[-1:] = (sum(message) % 256).to_bytes(1, 'big') #Checksum + message[11:-1] = payload_bytes[chunk_index * max_size: (chunk_index + 1) * max_size] + message[-1:] = (sum(message) % 256).to_bytes(1, 'big') # Checksum self.master.dprint(message) messages.append(bytes(message)) - self.master.dprint(f"Message {chunk_index+1}/{total_chunk_number}; length: {len(message)}; Free memory: {gc.mem_free()}") + self.master.dprint( + f"Message {chunk_index + 1}/{total_chunk_number}; length: {len(message)}; Free memory: {gc.mem_free()}") gc.collect() - gc.collect() self._send(peer_mac, messages, channel, ifidx) - - def _receive(self): #Processes all the messages in the buffer + def _receive(self): # Processes all the messages in the buffer self.master.dprint("aen._receive") - + def __decode_payload(payload_type, payload_bytes): self.master.dprint("aen.__decode_payload") - if payload_type == b'\x00': #None + if payload_type == b'\x00': # None return None - elif payload_type == b'\x01': #bytearray or bytes + elif payload_type == b'\x01': # bytearray or bytes return bytes(payload_bytes) - elif payload_type == b'\x02': #bool + elif payload_type == b'\x02': # bool return payload_bytes[0:1] == b'\x01' - elif payload_type == b'\x03': #int + elif payload_type == b'\x03': # int return struct.unpack('>i', payload_bytes)[0] - elif payload_type == b'\x04': #float + elif payload_type == b'\x04': # float return struct.unpack('>f', payload_bytes)[0] - elif payload_type == b'\x05': #string + elif payload_type == b'\x05': # string return payload_bytes.decode('utf-8') - elif payload_type == b'\x06': #json dict or list - return json.loads(payload_bytes.decode('utf-8')) - elif payload_type == b'\x07': #Long byte array + elif payload_type == b'\x06': # json dict or list + return json.loads(payload_bytes.decode('utf-8')) + elif payload_type == b'\x07': # Long byte array return bytes(payload_bytes) else: raise ValueError(f"Unsupported payload type: {payload_type} Message: {payload_bytes}") - + def __process_message(sender_mac, message, receive_timestamp): self.master.dprint("aen.__process_message") if message[0] != 0x2a: # Unique Message Identifier Check @@ -625,23 +618,24 @@ def __process_message(sender_mac, message, receive_timestamp): payload_type = bytes(message[7:8]) payload = message[8:-1] checksum = message[-1] - self.master.dprint(f"{type(msg_type)}: {msg_type}, {type(subtype)}: {subtype}, {type(send_timestamp)}: {send_timestamp}, {type(payload_type)}: {payload_type}, {type(payload)}: {payload}, {type(checksum)}: {checksum}") - - #Checksum + self.master.dprint( + f"{type(msg_type)}: {msg_type}, {type(subtype)}: {subtype}, {type(send_timestamp)}: {send_timestamp}, {type(payload_type)}: {payload_type}, {type(payload)}: {payload}, {type(checksum)}: {checksum}") + + # Checksum if checksum != sum(message[:-1]) % 256: self.master.dprint("Invalid message: checksum mismatch") return None - + if sender_mac not in self._peers: self.add_peer(sender_mac) - + if payload_type == b'\x07': self.master.dprint("Long message received, processing...") part_n = int.from_bytes(payload[0:1], 'big') total_n = int.from_bytes(payload[1:2], 'big') payload_type = bytes(payload[2:3]) payload = payload[3:] - + # Create a key as a bytearray: (msg_type, subtype, timestamp, payload_type, total_n) key = bytearray() key.extend(msg_type) @@ -651,14 +645,15 @@ def __process_message(sender_mac, message, receive_timestamp): key.append(total_n) key = bytes(key) self.master.dprint(f"Key: {key}") - + # Check if the key already exists in the long buffer if key in self._long_buffer: # If the part is None, add the payload if self._long_buffer[key][part_n] is None: self._long_buffer[key][part_n] = payload self._long_buffer_size[key] = self._long_buffer_size[key] + len(payload) - self.master.dprint(f"Long message: Key found, message added to entry in long_message_buffer, {sum(1 for item in self._long_buffer[key] if item is not None)} out of {total_n} packages received") + self.master.dprint( + f"Long message: Key found, message added to entry in long_message_buffer, {sum(1 for item in self._long_buffer[key] if item is not None)} out of {total_n} packages received") # If there are still missing parts, return if any(value is None for value in self._long_buffer[key]): gc.collect() @@ -669,15 +664,17 @@ def __process_message(sender_mac, message, receive_timestamp): payloads[part_n] = payload self._long_buffer[key] = payloads self._long_buffer_size[key] = len(payload) - self.master.dprint(f"Long message: Key not found and new entry created in long_message_buffer, {sum(1 for item in self._long_buffer[key] if item is not None)} out of {total_n} packages received") - + self.master.dprint( + f"Long message: Key not found and new entry created in long_message_buffer, {sum(1 for item in self._long_buffer[key] if item is not None)} out of {total_n} packages received") + while len(self._long_buffer) > 8 or sum(self._long_buffer_size.values()) > 75000: - self.master.dprint(f"Maximum buffer size reached: {len(self._long_buffer)}, {sum(self._long_buffer_size.values())} bytes; Reducing!") + self.master.dprint( + f"Maximum buffer size reached: {len(self._long_buffer)}, {sum(self._long_buffer_size.values())} bytes; Reducing!") self._long_buffer.popitem(last=False) self._long_buffer_size.popitem(last=False) gc.collect() return - + # If all parts have been received, reconstruct the message if not any(value is None for value in self._long_buffer[key]): payload = bytearray() @@ -690,24 +687,28 @@ def __process_message(sender_mac, message, receive_timestamp): self.master.dprint("Long Message: Safeguard triggered, code should not have gotten here") gc.collect() return - - #Handle the message based on type + + # Handle the message based on type if msg_type == (msg_key := msg_codes["cmd"]): # Command Message - __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload_type, payload if payload else None, msg_key) + __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload_type, + payload if payload else None, msg_key) elif msg_type == (msg_key := msg_codes["inf"]): # Informational Message - __handle_inf(sender_mac, subtype, send_timestamp, receive_timestamp, payload_type, payload if payload else None, msg_key) + __handle_inf(sender_mac, subtype, send_timestamp, receive_timestamp, payload_type, + payload if payload else None, msg_key) elif msg_type == (msg_key := msg_codes["ack"]): # Acknowledgement Message - __handle_ack(sender_mac, subtype, send_timestamp, receive_timestamp, payload_type, payload if payload else None, msg_key) + __handle_ack(sender_mac, subtype, send_timestamp, receive_timestamp, payload_type, + payload if payload else None, msg_key) else: - self.master.iprint(f"Unknown message type from {sender_mac} ({self.peer_name(sender_mac)}): {message}") + self.master.iprint( + f"Unknown message type from {sender_mac} ({self.peer_name(sender_mac)}): {message}") def __check_authorisation(sender_mac, payload): return sender_mac in self._whitelist or payload == "sudo" or payload[-1] == "sudo" - def __send_confirmation(type, recipient_mac, msg_subkey_type, payload=None, error=None): - if type == "Success": + def __send_confirmation(msg_type, recipient_mac, msg_subkey_type, payload=None, error=None): + if msg_type == "Success": self._compose(recipient_mac, [msg_subkey_type, payload], 0x03, 0x11) - elif type == "Fail": + elif msg_type == "Fail": self._compose(recipient_mac, [msg_subkey_type, error, payload], 0x03, 0x12) else: self._compose(recipient_mac, [msg_subkey_type, payload], 0x03, 0x13) @@ -716,15 +717,18 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload self.master.dprint(f"aen.__handle_cmd") payload = __decode_payload(payload_type, payload) if (msg_subkey := "Reboot") and subtype == msg_subcodes[msg_key][msg_subkey]: # Reboot - self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") - if self.__check_authorisation(sender_mac, payload): + self.master.iprint( + f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + if __check_authorisation(sender_mac, payload): __send_confirmation("Confirm", sender_mac, f"{msg_subkey} ({subtype})", payload) machine.reset() else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif (msg_subkey := "Firmware-Update") and subtype == msg_subcodes[msg_key][msg_subkey]: # Firmware-Update - self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") - if self.__check_authorisation(sender_mac, payload): + elif (msg_subkey := "Firmware-Update") and subtype == msg_subcodes[msg_key][ + msg_subkey]: # Firmware-Update + self.master.iprint( + f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + if __check_authorisation(sender_mac, payload): try: # Insert update logic here self.master.iprint("no update logic written just yet") @@ -735,8 +739,9 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") elif (msg_subkey := "File-Update") and subtype == msg_subcodes[msg_key][msg_subkey]: # File-Update - self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") - if self.__check_authorisation(sender_mac, payload): + self.master.iprint( + f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + if __check_authorisation(sender_mac, payload): try: # Insert update logic here self.master.iprint("No update logic written just yet") @@ -746,10 +751,11 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif (msg_subkey := "File-Download") and subtype == msg_subcodes[msg_key][msg_subkey]: #File-Download - self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") - #should return a list with a link and the list of files to download - if self.__check_authorisation(sender_mac, payload): + elif (msg_subkey := "File-Download") and subtype == msg_subcodes[msg_key][msg_subkey]: # File-Download + self.master.iprint( + f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + # should return a list with a link and the list of files to download + if __check_authorisation(sender_mac, payload): try: import mip base = payload[0] @@ -765,10 +771,11 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif (msg_subkey := "Web-Repl") and subtype == msg_subcodes[msg_key][msg_subkey]: #Web-Repl - self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") - #should be a list with name and password - if self.__check_authorisation(sender_mac, payload): + elif (msg_subkey := "Web-Repl") and subtype == msg_subcodes[msg_key][msg_subkey]: # Web-Repl + self.master.iprint( + f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + # should be a list with name and password + if __check_authorisation(sender_mac, payload): try: # add logic to connect to Wi-Fi and set up webrepl self.master.sta.connect(payload[0], payload[1]) @@ -779,20 +786,22 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif (msg_subkey := "File-Run") and subtype == msg_subcodes[msg_key][msg_subkey]: #File-Run - self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") - if self.__check_authorisation(sender_mac, payload): + elif (msg_subkey := "File-Run") and subtype == msg_subcodes[msg_key][msg_subkey]: # File-Run + self.master.iprint( + f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + if __check_authorisation(sender_mac, payload): try: self.master.iprint("Execute logic not implemented") - #insert run logic here + # insert run logic here except Exception as e: self.master.iprint(f"Error: {e} with payload: {payload}") __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif (msg_subkey := "Set-Admin") and subtype == msg_subcodes[msg_key][msg_subkey]: #Set Admin Bool - self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") - if self.__check_authorisation(sender_mac, payload): + elif (msg_subkey := "Set-Admin") and subtype == msg_subcodes[msg_key][msg_subkey]: # Set Admin Bool + self.master.iprint( + f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + if __check_authorisation(sender_mac, payload): self.master.iprint(f"Received Set-Admin command: self.admin set to {payload[0]}") try: self.master.admin = payload[0] @@ -801,10 +810,13 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif (msg_subkey := "Whitelist-Add") and subtype == msg_subcodes[msg_key][msg_subkey]: # Whitelist-Add - Add Admin macs to _whitelist - self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + elif (msg_subkey := "Whitelist-Add") and subtype == msg_subcodes[msg_key][ + msg_subkey]: # Whitelist-Add - Add Admin macs to _whitelist + self.master.iprint( + f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") if __check_authorisation(sender_mac, payload): - self.master.iprint(f"Received add admin macs to _whitelist command, added {payload[0]} and {payload[1]}") + self.master.iprint( + f"Received add admin macs to _whitelist command, added {payload[0]} and {payload[1]}") try: self._whitelist.append(payload[0]) self._whitelist.append(payload[1]) @@ -824,8 +836,9 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif (msg_subkey := "Ping") and subtype == msg_subcodes[msg_key][msg_subkey]: #Ping - self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + elif (msg_subkey := "Ping") and subtype == msg_subcodes[msg_key][msg_subkey]: # Ping + self.master.iprint( + f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") self.add_peer(sender_mac, payload[2], payload[0], payload[1]) if bool(self.ifidx): channel = self.master.ap.channel() @@ -833,17 +846,19 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload channel = self.master.sta.channel() response = [channel, self.ifidx, self.master.name, send_timestamp] self._compose(sender_mac, response, 0x03, 0x10) - elif (msg_subkey := "Pair") and subtype == msg_subcodes[msg_key][msg_subkey]: #Pair #add something that checks that the messages are from the same mac - self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + elif (msg_subkey := "Pair") and subtype == msg_subcodes[msg_key][ + msg_subkey]: # Pair #add something that checks that the messages are from the same mac + self.master.iprint( + f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") if self._pairing_enabled and networking_keys["handshake_key_1"] == payload: self._pairing = True self.pair(sender_mac, networking_keys["handshake_key_2"]) - #some timer for if key 3 is not received to reset states + # some timer for if key 3 is not received to reset states elif self._pairing_enabled and self._pairing and networking_keys["handshake_key_2"] == payload: self._paired = True self._paired_macs.append(sender_mac) self.pair(sender_mac, networking_keys["handshake_key_3"]) - #some timer that sets to false if key 4 is not received + # some timer that sets to false if key 4 is not received elif self._pairing_enabled and self._pairing and networking_keys["handshake_key_3"] == payload: try: # Insert pairing logic here do a reverse handshake @@ -857,12 +872,14 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) elif self._pairing_enabled and self._pairing and networking_keys["handshake_key_3"] == payload: self._paired = True - #remove timer from before + # remove timer from before else: - __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", "Pairing disabled", payload) - elif (msg_subkey := "Set-Pair") and subtype == msg_subcodes[msg_key][msg_subkey]: #Enable pairing mode - self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") - if self.__check_authorisation(sender_mac, payload): + __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", "Pairing disabled", + payload) + elif (msg_subkey := "Set-Pair") and subtype == msg_subcodes[msg_key][msg_subkey]: # Enable pairing mode + self.master.iprint( + f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + if __check_authorisation(sender_mac, payload): try: self._pairing_enabled = payload[0] __send_confirmation("Success", sender_mac, f"{msg_subkey} ({subtype})", payload) @@ -871,15 +888,22 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif (msg_subkey := "RSSI/Status/Config-Boop") and subtype == msg_subcodes[msg_key][msg_subkey]: # RSSI/Status/Config Boop + elif (msg_subkey := "RSSI/Status/Config-Boop") and subtype == msg_subcodes[msg_key][ + msg_subkey]: # RSSI/Status/Config Boop self.boops = self.boops + 1 - self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)}), Received total of {self.boops} boops!") + self.master.iprint( + f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)}), Received total of {self.boops} boops!") try: - self._compose(sender_mac, [self.master.id, self.master.name, self.master.config, self.master.version_n, self.master.version, self.master.sta.mac, self.master.ap.mac, self.rssi()], 0x02, 0x20) #[ID, Name, Config, Version, sta mac, ap mac, rssi] + self._compose(sender_mac, + [self.master.id, self.master.name, self.master.config, self.master.version_n, + self.master.version, self.master.sta.mac, self.master.ap.mac, self.rssi()], 0x02, + 0x20) # [ID, Name, Config, Version, sta mac, ap mac, rssi] except Exception as e: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) - elif (msg_subkey := "Directory-Get") and subtype == msg_subcodes[msg_key][msg_subkey]: #Get List of Files - self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + elif (msg_subkey := "Directory-Get") and subtype == msg_subcodes[msg_key][ + msg_subkey]: # Get List of Files + self.master.iprint( + f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") try: result = [] entries = os.listdir() @@ -892,53 +916,63 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload self._compose(sender_mac, result, 0x02, 0x20) except Exception as e: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) - elif (msg_subkey := "Echo") and subtype == msg_subcodes[msg_key][msg_subkey]: #Echo - self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)}): {__decode_payload(payload_type, payload)}") #Check i or d + elif (msg_subkey := "Echo") and subtype == msg_subcodes[msg_key][msg_subkey]: # Echo + self.master.iprint( + f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)}): {__decode_payload(payload_type, payload)}") # Check i or d self._compose(sender_mac, payload, 0x03, 0x15) - elif (msg_subkey := "Resend") and subtype == msg_subcodes[msg_key][msg_subkey]: #Resend lost long messages - self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + elif (msg_subkey := "Resend") and subtype == msg_subcodes[msg_key][ + msg_subkey]: # Resend lost long messages + self.master.iprint( + f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") self.master.iprint("Long_sent_buffer disabled due to memory constraints") - elif (msg_subkey := "WiFi-Connect") and subtype == msg_subcodes[msg_key][msg_subkey]: #Connect to Wi-Fi - self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") - if self.__check_authorisation(sender_mac, payload): + elif (msg_subkey := "WiFi-Connect") and subtype == msg_subcodes[msg_key][ + msg_subkey]: # Connect to Wi-Fi + self.master.iprint( + f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + if __check_authorisation(sender_mac, payload): try: - self.connect(payload[0], payload[1]) + self.master.sta.connect(payload[0], payload[1]) __send_confirmation("Success", sender_mac, f"{msg_subkey} ({subtype})", payload) except Exception as e: self.master.iprint(f"Error: {e} with payload: {payload}") __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif (msg_subkey := "WiFi-Disconnect") and subtype == msg_subcodes[msg_key][msg_subkey]: #Disconnect from Wi-Fi - self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") - if self.__check_authorisation(sender_mac, payload): + elif (msg_subkey := "WiFi-Disconnect") and subtype == msg_subcodes[msg_key][ + msg_subkey]: # Disconnect from Wi-Fi + self.master.iprint( + f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + if __check_authorisation(sender_mac, payload): try: - self.disconnect() + self.master.sta.disconnect() __send_confirmation("Success", sender_mac, f"{msg_subkey} ({subtype})", payload) except Exception as e: self.master.iprint(f"Error: {e}") __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif (msg_subkey := "AP-Enable") and subtype == msg_subcodes[msg_key][msg_subkey]: #Enable AP - self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") - if self.__check_authorisation(sender_mac, payload): + elif (msg_subkey := "AP-Enable") and subtype == msg_subcodes[msg_key][msg_subkey]: # Enable AP + self.master.iprint( + f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + if __check_authorisation(sender_mac, payload): try: ssid = payload[0] if ssid == "": ssid = self.master.name password = payload[1] - self.setap(ssid, password) + self.master.ap.setap(ssid, password) __send_confirmation("Success", sender_mac, f"{msg_subkey} ({subtype})", payload) except Exception as e: self.master.iprint(f"Error: {e} with payload: {payload}") __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif (msg_subkey := "AP-Disable") and subtype == msg_subcodes[msg_key][msg_subkey]: #Disable AP - self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") - payload = __decode_payload(payload_type, payload) #should return a list of desired name, password and max clients - if self.__check_authorisation(sender_mac, payload): + elif (msg_subkey := "AP-Disable") and subtype == msg_subcodes[msg_key][msg_subkey]: # Disable AP + self.master.iprint( + f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + payload = __decode_payload(payload_type, + payload) # should return a list of desired name, password and max clients + if __check_authorisation(sender_mac, payload): try: self.master.ap.deactivate() __send_confirmation("Success", sender_mac, f"{msg_subkey} ({subtype})", payload) @@ -947,24 +981,26 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif (msg_subkey := "Pause") and subtype == msg_subcodes[msg_key][msg_subkey]: #Set Pause - self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") - if self.__check_authorisation(sender_mac, payload): + elif (msg_subkey := "Pause") and subtype == msg_subcodes[msg_key][msg_subkey]: # Set Pause + self.master.iprint( + f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + if __check_authorisation(sender_mac, payload): try: self.master.iprint(f"Received pause command: {payload[0]}") self._running = False __send_confirmation("Success", sender_mac, f"{msg_subkey} ({subtype})", payload) if self._pause_function: - self._pause_function() #calls the custom set pause function to display a screen + self._pause_function() # calls the custom set pause function to display a screen while not self._running: time.sleep(0.5) except Exception as e: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, e) else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") - elif (msg_subkey := "Resume") and subtype == msg_subcodes[msg_key][msg_subkey]: #Set Continue - self.master.iprint(f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") - if self.__check_authorisation(sender_mac, payload): + elif (msg_subkey := "Resume") and subtype == msg_subcodes[msg_key][msg_subkey]: # Set Continue + self.master.iprint( + f"{msg_subkey} ({subtype}) command received from {sender_mac} ({self.peer_name(sender_mac)})") + if __check_authorisation(sender_mac, payload): try: self.master.iprint(f"Received continue command: {payload}") self.master._running = True @@ -974,74 +1010,87 @@ def __handle_cmd(sender_mac, subtype, send_timestamp, receive_timestamp, payload else: __send_confirmation("Fail", sender_mac, f"{msg_subkey} ({subtype})", payload, "Not authorised") else: - self.master.iprint(f"Unknown command subtype from {sender_mac} ({self.peer_name(sender_mac)}): {subtype}") + self.master.iprint( + f"Unknown command subtype from {sender_mac} ({self.peer_name(sender_mac)}): {subtype}") def __handle_inf(sender_mac, subtype, send_timestamp, receive_timestamp, payload_type, payload, msg_key): self.master.dprint("aen.__handle_inf") payload = __decode_payload(payload_type, payload) - if (msg_subkey := "RSSI") and subtype == msg_subcodes[msg_key][msg_subkey]: #RSSI - #payload["time_sent"] = send_timestamp - #payload["time_recv"] = receive_timestamp - self.master.iprint(f"{msg_subkey} ({subtype}) data received from {sender_mac} ({self.peer_name(sender_mac)}): {payload}") + if (msg_subkey := "RSSI") and subtype == msg_subcodes[msg_key][msg_subkey]: # RSSI + # payload["time_sent"] = send_timestamp + # payload["time_recv"] = receive_timestamp + self.master.iprint( + f"{msg_subkey} ({subtype}) data received from {sender_mac} ({self.peer_name(sender_mac)}): {payload}") self.received_rssi_data[sender_mac] = payload - #__send_confirmation("Confirm", sender_mac, f"{msg_subkey} ({subtype})", payload) #confirm message recv - elif (msg_subkey := "Sensor") and subtype == msg_subcodes[msg_key][msg_subkey]: #Sensor Data + # __send_confirmation("Confirm", sender_mac, f"{msg_subkey} ({subtype})", payload) #confirm message recv + elif (msg_subkey := "Sensor") and subtype == msg_subcodes[msg_key][msg_subkey]: # Sensor Data payload["time_sent"] = send_timestamp payload["time_recv"] = receive_timestamp - self.master.iprint(f"{msg_subkey} ({subtype}) data received from {sender_mac} ({self.peer_name(sender_mac)}): {payload}") + self.master.iprint( + f"{msg_subkey} ({subtype}) data received from {sender_mac} ({self.peer_name(sender_mac)}): {payload}") self.received_sensor_data[sender_mac] = payload - #__send_confirmation("Confirm", sender_mac, f"{msg_subkey} ({subtype})", payload) #confirm message recv - elif (msg_subkey := "Message") and subtype == msg_subcodes[msg_key][msg_subkey]: #Message / Other - self.master.iprint(f"{msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}): {payload}") + # __send_confirmation("Confirm", sender_mac, f"{msg_subkey} ({subtype})", payload) #confirm message recv + elif (msg_subkey := "Message") and subtype == msg_subcodes[msg_key][msg_subkey]: # Message / Other + self.master.iprint( + f"{msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}): {payload}") self._received_messages.append((sender_mac, payload, receive_timestamp)) self._received_messages_size.append(len(payload)) while len(self._received_messages) > 2048 or sum(self._received_messages_size) > 20000: - self.master.dprint(f"Maximum buffer size reached: {len(self._received_messages)}, {sum(self._received_messages_size)} bytes; Reducing!") + self.master.dprint( + f"Maximum buffer size reached: {len(self._received_messages)}, {sum(self._received_messages_size)} bytes; Reducing!") self._received_messages.pop(0) self._received_messages_size.pop(0) - #__send_confirmation("Confirm", sender_mac, f"{msg_subkey} ({subtype})", payload) #confirm message recv - elif (msg_subkey := "Directory") and subtype == msg_subcodes[msg_key][msg_subkey]: #File Directory - self.master.iprint(f"{msg_subkey} ({subtype}) data received from {sender_mac} ({self.peer_name(sender_mac)}): {payload}") - #__send_confirmation("Confirm", sender_mac, f"{msg_subkey} ({subtype})", payload) #confirm message recv + # __send_confirmation("Confirm", sender_mac, f"{msg_subkey} ({subtype})", payload) #confirm message recv + elif (msg_subkey := "Directory") and subtype == msg_subcodes[msg_key][msg_subkey]: # File Directory + self.master.iprint( + f"{msg_subkey} ({subtype}) data received from {sender_mac} ({self.peer_name(sender_mac)}): {payload}") + # __send_confirmation("Confirm", sender_mac, f"{msg_subkey} ({subtype})", payload) #confirm message recv else: - self.master.iprint(f"Unknown info subtype from {sender_mac} ({self.peer_name(sender_mac)}): {subtype}") - + self.master.iprint( + f"Unknown info subtype from {sender_mac} ({self.peer_name(sender_mac)}): {subtype}") + def __handle_ack(sender_mac, subtype, send_timestamp, receive_timestamp, payload_type, payload, msg_key): self.master.dprint("aen.__handle_ack") payload = __decode_payload(payload_type, payload) - if (msg_subkey := "Pong") and subtype == msg_subcodes[msg_key][msg_subkey]: #Pong + if (msg_subkey := "Pong") and subtype == msg_subcodes[msg_key][msg_subkey]: # Pong self.add_peer(sender_mac, payload[2], payload[0], payload[1]) - self.master.iprint(f"{msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}), {receive_timestamp-payload[3]}") - elif (msg_subkey := "Echo") and subtype == msg_subcodes[msg_key][msg_subkey]: #Echo - self.master.iprint(f"{msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}), {__decode_payload(payload_type, payload)}") - elif (msg_subkey := "Success") and subtype == msg_subcodes[msg_key][msg_subkey]: #Success + self.master.iprint( + f"{msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}), {receive_timestamp - payload[3]}") + elif (msg_subkey := "Echo") and subtype == msg_subcodes[msg_key][msg_subkey]: # Echo + self.master.iprint( + f"{msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}), {__decode_payload(payload_type, payload)}") + elif (msg_subkey := "Success") and subtype == msg_subcodes[msg_key][msg_subkey]: # Success # payload should return a list with a cmd type and payload - self.master.iprint(f"Cmd {msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}) for type {payload[0]} with payload {payload[1]}") - #add to ack buffer - elif (msg_subkey := "Fail") and subtype == msg_subcodes[msg_key][msg_subkey]: #Fail + self.master.iprint( + f"Cmd {msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}) for type {payload[0]} with payload {payload[1]}") + # add to ack buffer + elif (msg_subkey := "Fail") and subtype == msg_subcodes[msg_key][msg_subkey]: # Fail # payload should return a list with a cmd type, error and payload - self.master.iprint(f"Cmd {msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}) for type {payload[0]} with error {payload[1]} and payload {payload[2]}") - #add to ack buffer - elif (msg_subkey := "Confirm") and subtype == msg_subcodes[msg_key][msg_subkey]: #Confirmation + self.master.iprint( + f"Cmd {msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}) for type {payload[0]} with error {payload[1]} and payload {payload[2]}") + # add to ack buffer + elif (msg_subkey := "Confirm") and subtype == msg_subcodes[msg_key][msg_subkey]: # Confirmation # payload should return a list with message type and payload - self.master.iprint(f"{msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}) for type {payload[0]} with payload {payload[1]}") - #add to ack buffer + self.master.iprint( + f"{msg_subkey} ({subtype}) received from {sender_mac} ({self.peer_name(sender_mac)}) for type {payload[0]} with payload {payload[1]}") + # add to ack buffer else: - self.master.iprint(f"Unknown ack subtype from {sender_mac} ({self.peer_name(sender_mac)}): {subtype}, Payload: {payload}") + self.master.iprint( + f"Unknown ack subtype from {sender_mac} ({self.peer_name(sender_mac)}): {subtype}, Payload: {payload}") # Insert more acknowledgement logic here and/or add message to acknowledgement buffer - if self._aen.any(): + if self._aen.any(): for mac, data in self._aen: self.master.dprint(f"Received {mac, data}") - if mac is None: # mac, msg will equal (None, None) on timeout + if mac is None: # mac, msg will equal (None, None) on timeout break if data: if mac and data is not None: - #self._received_messages.append((sender_mac, data, receive_timestamp))#Messages will be saved here, this is only for debugging purposes + # self._received_messages.append((sender_mac, data, receive_timestamp))#Messages will be saved here, this is only for debugging purposes __process_message(mac, data, time.ticks_ms()) - if not self._aen.any():#this is necessary as the for loop gets stuck and does not exit properly. + if not self._aen.any(): # this is necessary as the for loop gets stuck and does not exit properly. break +# message structure (what kind of message types do I need?: Command which requires me to do something (ping, pair, change state(update, code, mesh mode, run a certain file), Informational Message (Sharing Sensor Data and RSSI Data) +# | Header (1 byte) | Type (1 byte) | Subtype (1 byte) | Timestamp(ms ticks) (4 bytes) | Payload type (1) | Payload (variable) | Checksum (1 byte) | -#message structure (what kind of message types do I need?: Command which requires me to do something (ping, pair, change state(update, code, mesh mode, run a certain file), Informational Message (Sharing Sensor Data and RSSI Data) -#| Header (1 byte) | Type (1 byte) | Subtype (1 byte) | Timestamp(ms ticks) (4 bytes) | Payload type (1) | Payload (variable) | Checksum (1 byte) | \ No newline at end of file From 54197df056746e271b8d91fd918fed7aed770600 Mon Sep 17 00:00:00 2001 From: Nick Art Date: Tue, 26 Nov 2024 15:32:05 -0500 Subject: [PATCH 06/10] added library files --- .DS_Store | Bin 12292 -> 12292 bytes software/.DS_Store | Bin 8196 -> 10244 bytes software/libraries/README.qmd | 7 + software/libraries/adxl345.py | 53 +++ software/libraries/files.py | 96 +++++ software/libraries/icons.py | 241 +++++++++++ software/libraries/sensors.py | 146 +++++++ software/libraries/servo.py | 33 ++ software/libraries/smartmotor.py | 444 +++++++++++++++++++++ software/libraries/ssd1306.py | 158 ++++++++ software/main/.DS_Store | Bin 0 -> 6148 bytes software/main/README.qmd | 40 ++ software/main/main.py | 45 +++ software/networking/.DS_Store | Bin 6148 -> 6148 bytes software/networking/README.qmd | 2 +- software/release/README.qmd | 48 +++ software/{networking => release}/config.py | 0 17 files changed, 1312 insertions(+), 1 deletion(-) create mode 100644 software/libraries/adxl345.py create mode 100644 software/libraries/files.py create mode 100644 software/libraries/icons.py create mode 100644 software/libraries/sensors.py create mode 100644 software/libraries/servo.py create mode 100644 software/libraries/smartmotor.py create mode 100644 software/libraries/ssd1306.py create mode 100644 software/main/.DS_Store create mode 100644 software/main/README.qmd create mode 100644 software/main/main.py create mode 100644 software/release/README.qmd rename software/{networking => release}/config.py (100%) diff --git a/.DS_Store b/.DS_Store index 8e1d6f29e68dab471ff8f6a184b260484a772ade..d3741d879a680d183d98a096a53a4a23c78504b8 100644 GIT binary patch delta 178 zcmZokXi3;`SDbPCWCO-RHSy|dLmdT6<60esYGV@<104lJVJ!YT~_U->UM diff --git a/software/.DS_Store b/software/.DS_Store index aaa302a02e05ef5ccf713d79ba52bc108f7a0d79..fc1f08db445380c5ccdfdefb3b4fb55e1b7e3b50 100644 GIT binary patch literal 10244 zcmeHNYitx%6h3DubY^%BFBz8CN+n{g^sT(zzChkhTWEPm+1(lG$m~qnnQoDW*oe`9 z5Pv~57(@**Xo87RKqXN$A(Hqu{fV`++%FBH8l+r8ncii9IHVv(SqH5j zcfKO8fxHIpBn^aUFwA}nD2rf_)%xw%Htcj~+_2&Rq0V@xq1#Sb**OdiDi}PZP!Oe| z;f0H&#cg`RGMn{nTDv^b?y$NSQ?W6nrFE^lHDMWDNz-nZMt!<^8I+w9smb+}NNh3Zzt<@7ZiH>GpTG{F7mT9lnQZ~_|Xc^a{cz)RM5hLYM zqsNRLH>GICBNdO%jkYDMWKuI7dzBH3Yes9D%dAuBb9E_=o@$Ft{jO&f%Pm!ZN~fC5 zx~aC9v81+vRWFO#&dN^B)YLQgjaMdwCrXoB)4Hw44Q*Aot~woSVs=6^Ro&dQiUhT- z!YC{e0DK=K64FAdcmQt52lEdjd>@Dwqe2 zum)78dA*o|9p8}{IKd;wp?owy5k<6hi{ui&e=A78^m z_zu3yM;BtdkEJD?WS)4UBvLWEdV5Kvr@W%NtRyn4x@`M)Q5aWLI=88Pvyn8d-JBOQ zUl^W|_2?d=h3;LHfDYQ(Y0!*K<;}D^I$aL@yuCk1(yFiLJ066(9nmM=N}j68#iiZ= zS7(Q>w@@SNG>45XHmro#BVC`sdYk#To0vc@iFmi|StT6HSmoJ_RTc_Eg(sWI44a*p z(`DDjQtMc$#j=ce<~_oQMqGBlD5v>nUITdz^w+>ds>|KnX2u2M9sWG5CySa9^cbbUJ{vI z$^6aAsw(m~%PT7?vK-ExTz3OHoV)zf3AmbE@ak0ks%==&VU+f`s`a(^DKuAmP>t@# zB`_)A;*eu+QSfCmQz&f8axLE@PQPoJQ|9hihMZFiED5%;*i}wG|MCn`#7}l^b(d!V z-oB-}9&cdTLQ(2IcmL_;lxbMzCTeF_od`|PK)(y>VL8#6WG`xPVetxa1s66bv8BIE zh<)8JQ%KuJqX>XT)@XxvcWi^KNd-0l&7V>hhkxn6cysv)&ocXQ^)33qT!H20y$vP{ zwdl_PJ8KDFA_o6*_&9^3{%t>T`da-XZaz5&D_6UlHNep~+T0w0k)nGn^YP}N_kaeN zyF84nzLWk~1TaDG4pED)kn3&J0p)z>$H%u4qqwQtJWRKF+3f1u5oh(p+42y3PY7{>mIJeo#VbStYgpub{+{VdKJ685;4}yqbke zR-EAwg(R(|pB$#c@P<@2ijYAU+yFks_(fNUum`2BE3R+p(w%4IB0+F#Cr(nN0C+)Y z0_TrRQWQVV;R!r2U6EYKgK!4U_)xJVxsV5;3%q7#sibhggpdo~Pi2*)WY81BFL>pw z*^+VN|f+l!dZJna5wL4-dZDlw8DwDtT>K9SHiy2W116&$Z-LX<$ z<5HT+8V1GGsH&z?r95KfaHUac669|L!ijVt=Wqu;k9!F7IDoI?K|G8f;88q=$MGb7i)ZjVyoi_Z2mBF#$3O5-yd083LqlUj z6GCBjh*NaU3wA*pFK3>ihcj=tLI0Hi_Lo!1m zLkW=1-z>->#G}o~O)=Qj>Wk;u*J1o+nVKDpp->prc@BWLm4E zP;F^sq@!SBY*t&#$sww&Zygk$os*lF-!VB}MxL<~s7q$DljNPr-`FlP?f~glm#D5b zF)#t@u`q_{2bzVczYDCtd$ItF_~dCas*{xj(kHVBiB5hhXg@hyVjqaT`HPS& 32767: + x -= 65536 + return x + + @property + def yValue(self): + buff = self.i2c.readfrom_mem(self.addr,regAddress,TO_READ) + y = (int(buff[3]) << 8) | buff[2] + if y > 32767: + y -= 65536 + return y + + @property + def zValue(self): + buff = self.i2c.readfrom_mem(self.addr,regAddress,TO_READ) + z = (int(buff[5]) << 8) | buff[4] + if z > 32767: + z -= 65536 + return z + + def RP_calculate(self,x,y,z): + roll = math.atan2(y , z) * 57.3 + pitch = math.atan2((- x) , math.sqrt(y * y + z * z)) * 57.3 + return roll,pitch + + + diff --git a/software/libraries/files.py b/software/libraries/files.py new file mode 100644 index 0000000..38efd56 --- /dev/null +++ b/software/libraries/files.py @@ -0,0 +1,96 @@ +import sys +def savetofile(pointstosave): # the points to save should have format of [[light, pot],[light,pot]] + import os + if(os.listdir().count('data.py')): + import data + datapoints=[] + del sys.modules["data"] + import data + try: + datapoints=data.points + datapoints.append(pointstosave) + except: + datapoints.append(pointstosave) + del sys.modules["data"] + #getting ready to reimporting data file + else: + datapoints=[] + datapoints.append(pointstosave) + print("new file") + + #writing files to the data.py + f=open("data.py","w") + f.write("points="+str(datapoints)+"\r\n") + f.close() + + +def cleardatafile(): # the points to save should have format of [[light, pot],[light,pot]] + import os + f=open("data.py","w") + f.write("points=[]") + f.close() + + +def replacefile(pointstosave): + import os + if(os.listdir().count('data.py')): + f=open("data.py","w") + f.write("points="+str(pointstosave)+"\r\n") + f.close() + else: + return 0 + + + +def readfile(): + + import os + if(os.listdir().count('data.py')): + import data + if(data.points): + return(data.points) + else: + print("returning blank") + return([]) + else: + return([]) + + #also make this go home + +def resetlog(): + import os + try: + os.remove("log.py") + except: + print("no log file to remove") + +def resetprefs(): + f=open("prefs.py","w") + f.write("log=False\r\n") + f.close() + + + +def setprefs(): + f=open("prefs.py","w") + f.write("log=True\r\n") + f.close() + + +def savetolog(*logtext): # the points to save should have format of [[light, pot],[light,pot]] + import os + if(os.listdir().count('log.py')): + f=open("log.py","a") + try: + print("writing",logtext) + f.write(str(logtext)+"\r\n") + except: + print("errr") + else: + f=open("log.py","w") + f.write(str(logtext)+",") + + #writing files to the data.py + f.close() + + diff --git a/software/libraries/icons.py b/software/libraries/icons.py new file mode 100644 index 0000000..f60745b --- /dev/null +++ b/software/libraries/icons.py @@ -0,0 +1,241 @@ +import framebuf +import ssd1306 +from machine import Pin +import time + + +MAX_BATTERY=2900 +MIN_BATTERY=2600 + + +#define icons here +def createIcons(iconSize, iconFrames, offsetx=0, offsety=0, direction=0): + icons=[] + padding=2 + spacingV=int((screenHeight - iconSize*len(iconFrames))/ (len(iconFrames))-padding) + spacingH=int((screenWidth - iconSize*len(iconFrames))/ (len(iconFrames))-padding) + + for i in range(len(iconFrames)): + Iconx=offsetx + i * (spacingH + iconSize) * ((direction+1)%2) + Icony=offsety# + i * (spacingV + iconSize) * ((direction)%2) + + icons.append([Iconx,Icony,iconFrames[i]]) + return icons + + + + +#Homescreen icons +Icons=[] + +screenWidth=128 +screenHeight=120 + +#logo +fb_SMLOGO = framebuf.FrameBuffer(bytearray(b'\x00\x00\x01\xe0\x00\x00\x00\x00\x00\xe1\xe1\xc0\x00\x00\x00\x00\xff\xff\xc0\x00\x00\x00\x00\xff\xff\xc0\x00\x00\x00\x11\xff\xff\xe2\x00\x00\x00\x7f\xff\xff\xff\x80\x00\x00\x7f\xff\xff\xff\x80\x00\x00?\xff\xff\xff\x00\x00\x00\x7f\xff\xff\xff\x80\x00\x06\xff\xf0\x03\xff\xd8\x00\x07\xff\xc0\x00\xff\xf8\x00\x0f\xff\x00\x00?\xfc\x00\x07\xfe\x00\x00\x1f\xf8\x00\x07\xfc\x00\x00\x0f\xf8\x00\x07\xf8\x00\x00\x07\xf8\x00\x0f\xf0\x00\x00\x03\xfc\x00\x7f\xe0\x00\x00\x01\xff\x80\x7f\xe0\x00\x00\x01\xff\x80\x7f\xc0\x00\x00\x00\xff\x80?\xc0\x00\x00\x00\xff\x00\x1f\xc0\x00\x00\x00\xfe\x00\x1f\x80\x00\x00\x00~\x00?\x80\x00\x00\x00\x7f\x00\xff\x80\x00\x079\xbf\xc0\xff\x80\x00\x07\xbd\xbf\xc0\xff\x80\x00\x079\xbf\xc0\xff\x80\x00\x00\x00\xff\xc0?\x80\x00\x00\x00\x7f\x00\x1f\xc0\x00\x00\x00\xfe\x00\x1f\xc0\x00\x00\x00\xfe\x00?\xc0\x00\x00\x00\xff\x00\x7f\xe0\x00\x00\x01\xff\x80\x7f\xe0\x00\x00\x01\xff\x80\x7f\xf0\x00\x00\x03\xff\x80\x0f\xf0\x00\x00\x03\xfc\x00\x07\xf8\x00\x00\x07\xf8\x00\x03\xfc\x00\x00\x0f\xf0\x00\x07\xff\x00\x00?\xf8\x00\x0f\xff\x80\x00\x7f\xfc\x00\x07\xff\xe0\x01\xff\xf8\x00\x06\x7f\xfe\x1f\xff\x98\x00\x00?\xff\xff\xff\x00\x00\x00?\xff\xff\xff\x00\x00\x00\x7f\xff\xff\xff\x80\x00\x00{\xff\xff\xf7\x80\x00\x00\x10\xff\xff\xc2\x00\x00\x00\x00\xff\xff\xc0\x00\x00\x00\x00\xf1\xe3\xc0\x00\x00\x00\x00\xe1\xe1\xc0\x00\x00\x00\x00\x01\xe0\x00\x00\x00'), 50, 50, framebuf.MONO_HLSB) +#plug +fb_battcharging = framebuf.FrameBuffer(bytearray(b'?\xff\xff\xc0 \x00\x00@ \x06\x00@\xe0\x07\x80@\xe0\x7f\xc0@\xe0<\x00@\xe0\x0c\x00@ \x00\x00@ \x00\x00@?\xff\xff\xc0'), 26, 10, framebuf.MONO_HLSB) +fb_batthigh = framebuf.FrameBuffer(bytearray(b'?\xff\xff\xc0 \x00\x00@/\xef\xef@\xef\xef\xef@\xef\xef\xef@\xef\xef\xef@\xef\xef\xef@/\xef\xef@ \x00\x00@?\xff\xff\xc0'), 26, 10, framebuf.MONO_HLSB) +fb_battmid = framebuf.FrameBuffer(bytearray(b'?\xff\xff\xc0 \x00\x00@ \x0f\xef@\xe0\x0f\xef@\xe0\x0f\xef@\xe0\x0f\xef@\xe0\x0f\xef@ \x0f\xef@ \x00\x00@?\xff\xff\xc0'), 26, 10, framebuf.MONO_HLSB) +fb_battlow = framebuf.FrameBuffer(bytearray(b'?\xff\xff\xc0 \x00\x00@ \x00\x0f@\xe0\x00\x0f@\xe0\x00\x0f@\xe0\x00\x0f@\xe0\x00\x0f@ \x00\x0f@ \x00\x00@?\xff\xff\xc0'), 26, 10, framebuf.MONO_HLSB) + +#HomeScreen Icons +fb_Train = framebuf.FrameBuffer(bytearray(b'\xff\xff\xff\xff\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\xff\xff\x01\x80\x80\x01\x01\x80\x80\x01\x01\x80\xe0\x01\x01\x81\xf0\x01\x01\x81\xf8\x01\x01\x83\xf8\x01\x01\x81\xf0\x01\x01\x81\xf0A\x01\x80\xe0\x81\x01\x81\xf1\x81\x01\x83\xfb\x01\x01\x83\xfe\x01\x01\x87\xfc\x01\x01\x87\xfc\x01\x01\x87\xff\xff\x01\x87\xfc\x00\x01\x87\xfc\x00\x01\x87\xfc\x00\x01\x83\xf8\x00\x01\x83\xf8\x00\x01\x81\xf0\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\xff\xff\xff\xff'), 32, 32, framebuf.MONO_HLSB) +fb_Setting = framebuf.FrameBuffer(bytearray(b'\xff\xff\xff\xff\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x01\xc3\x01\x81\xc3\xc7\x81\x81\xe3\xc7\x81\x81\xff\xef\x01\x81\xff\xff\x01\x80\xff\xfe\x19\x80\xfc?9\xb9\xf0\x0f\xfd\xbf\xe0\x07\xfd\xbf\xc0\x03\xfd\xbf\x80\x01\xf1\x93\x80\x01\xc1\x83\x80\x01\xc1\x83\x80\x01\xd9\xbf\x80\x01\xfd\xbf\xc0\x03\xfd\xbf\xe0\x07\xfd\xbf\xf0\x0f\x85\x9c\xfc?\x01\x80\x7f\xff\x81\x80\x7f\xff\xc1\x80\xff\xef\x81\x81\xf1\xe3\x81\x81\xe3\xe1\x81\x80\xe3\xe0\x01\x80\x00\x00\x01\x80\x00\x00\x01\xff\xff\xff\xff'), 32, 32, framebuf.MONO_HLSB) +fb_Play = framebuf.FrameBuffer(bytearray(b'\xff\xff\xff\xff\x80\x00\x00\x01\x81\x00\x00\x01\x81\xc0\x00\x01\x81\xe0\x00\x01\x81\xf8\x00\x01\x81\xfe\x00\x01\x81\xff\x00\x01\x81\xff\xc0\x01\x81\xff\xe0\x01\x81\xff\xf8\x01\x81\xff\xfe\x01\x81\xff\xff\x01\x81\xff\xff\xc1\x81\xff\xff\xe1\x81\xff\xff\xf9\x81\xff\xff\xe1\x81\xff\xff\xc1\x81\xff\xff\x01\x81\xff\xfe\x01\x81\xff\xf8\x01\x81\xff\xe0\x01\x81\xff\xc0\x01\x81\xff\x00\x01\x81\xfe\x00\x01\x81\xf8\x00\x01\x81\xe0\x00\x01\x81\xc0\x00\x01\x81\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\xff\xff\xff\xff'), 32, 32, framebuf.MONO_HLSB) + +#TrainScreen Icons +fb_add = framebuf.FrameBuffer(bytearray(b'\xff\xff\xff\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x1e\x00\x80\x80\x1e\x00\x80\x80\x1e\x00\x80\x80\x1e\x00\x80\x83\xff\xe0\x80\x83\xff\xe0\x80\x83\xff\xe0\x80\x83\xff\xe0\x80\x80\x1e\x00\x80\x80\x1e\x00\x80\x80\x1e\x00\x80\x80\x1e\x00\x80\x80\x1e\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\xff\xff\xff\x80'), 25, 25, framebuf.MONO_HLSB) +fb_delete = framebuf.FrameBuffer(bytearray(b'\xff\xff\xff\x80\x80\x00\x00\x80\x80\x00\x00\x80\x8c\x00\x18\x80\x9e\x00<\x80\x8f\x00x\x80\x87\x80\xf0\x80\x83\xc1\xe0\x80\x81\xe3\xc0\x80\x80\xf7\x80\x80\x80\x7f\x00\x80\x80>\x00\x80\x80>\x00\x80\x80\x7f\x00\x80\x80\xff\x80\x80\x81\xe3\xc0\x80\x83\xc1\xe0\x80\x87\x80\xf0\x80\x8f\x00x\x80\x9f\x00|\x80\x8c\x00\x18\x80\x8c\x00\x18\x80\x80\x00\x00\x80\x80\x00\x00\x80\xff\xff\xff\x80'), 25, 25, framebuf.MONO_HLSB) +fb_smallplay = framebuf.FrameBuffer(bytearray(b'\xff\xff\xff\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x83\x00\x00\x80\x83\xc0\x00\x80\x83\xf0\x00\x80\x83\xf8\x00\x80\x83\xfe\x00\x80\x83\xff\x80\x80\x83\xff\xc0\x80\x83\xff\xf0\x80\x83\xff\xf0\x80\x83\xff\xc0\x80\x83\xff\x80\x80\x83\xfe\x00\x80\x83\xf8\x00\x80\x83\xf0\x00\x80\x83\xc0\x00\x80\x83\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\xff\xff\xff\x80'), 25, 25, framebuf.MONO_HLSB) +fb_back = framebuf.FrameBuffer(bytearray(b'\xff\xff\xff\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x07\x80\x80\x80\x0f\x80\x80\x80\x1f\x80\x80\x80>\x00\x80\x80~\x00\x80\x80\xf8\x00\x80\x81\xf8\x00\x80\x83\xe0\x00\x80\x83\xe0\x00\x80\x81\xf8\x00\x80\x80\xf8\x00\x80\x80~\x00\x80\x80>\x00\x80\x80\x1f\x80\x80\x80\x0f\x80\x80\x80\x07\x80\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\xff\xff\xff\x80'), 25, 25, framebuf.MONO_HLSB) + +fb_upnobox = framebuf.FrameBuffer(bytearray(b'\x04\x00\x0e\x00\x1f\x00?\x80\x7f\xc0\xff\xe0\x1f\x00\x1f\x00'), 11, 8, framebuf.MONO_HLSB) +fb_downnobox = framebuf.FrameBuffer(bytearray(b'\x1f\x00\x1f\x00\xff\xe0\x7f\xc0?\x80\x1f\x00\x0e\x00\x04\x00'), 11, 8, framebuf.MONO_HLSB) + +#PlayScreen Icons +fb_home = framebuf.FrameBuffer(bytearray(b'\xff\xff\xff\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80>\x00\x80\x80\x7f\x00\x80\x80\xff\x80\x80\x81\xff\xc0\x80\x83\xff\xe0\x80\x87\xff\xf0\x80\x8f\xff\xf8\x80\x9f\xff\xfc\x80\xbf\xff\xfe\x80\x87\xff\xf0\x80\x87\xff\xf0\x80\x87\xc1\xf0\x80\x87\xc1\xf0\x80\x87\xc1\xf0\x80\x87\xc1\xf0\x80\x87\xc1\xf0\x80\x87\xc1\xf0\x80\x87\xc1\xf0\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\xff\xff\xff\x80'), 25, 25, framebuf.MONO_HLSB) +fb_pause = framebuf.FrameBuffer(bytearray(b'\xff\xff\xff\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\xc1\x80\x80\x81\xe3\xc0\x80\x81\xe3\xc0\x80\x81\xe3\xc0\x80\x81\xe3\xc0\x80\x81\xe3\xc0\x80\x81\xe3\xc0\x80\x81\xe3\xc0\x80\x81\xe3\xc0\x80\x81\xe3\xc0\x80\x81\xe3\xc0\x80\x81\xe3\xc0\x80\x80\xc1\x80\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\xff\xff\xff\x80'), 25, 25, framebuf.MONO_HLSB) +fb_save = framebuf.FrameBuffer(bytearray(b'\xff\xff\xff\x80\x80\x00\x00\x80\x80\x00\x00\x80\x9f\xfe\x00\x80\x9f\xff\x00\x80\x9c\x03\x80\x80\x9c\x03\xc0\x80\x9c\x03\xe0\x80\x9c\x03\xf0\x80\x9c\x03\xf8\x80\x9f\xff\xf8\x80\x9f\xff\xfc\x80\x9f\xff\xfc\x80\x9f\xfc<\x80\x9f\xf8\x1c\x80\x9f\xf8\x1c\x80\x9f\xf8\x1c\x80\x9f\xf8\x1c\x80\x9f\xfc<\x80\x9f\xff\xfc\x80\x9f\xff\xfc\x80\x9f\xff\xfc\x80\x80\x00\x00\x80\x80\x00\x00\x80\xff\xff\xff\x80'), 25, 25, framebuf.MONO_HLSB) +fb_toggle = framebuf.FrameBuffer(bytearray(b'\xff\xff\xff\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x87\xf8\x00\x80\x84\x08\x00\x80\x84\x08\x00\x80\x84\x08\x00\x80\x84\x08\x00\x80\x84\x08\x00\x80\x9c\x0f\xfc\x80\x9c\x0f\xfc\x80\x9c\x0f\xfc\x80\x84\x08\x00\x80\x84\x08\x00\x80\x84\x08\x00\x80\x84\x08\x00\x80\x84\x08\x00\x80\x87\xf8\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\xff\xff\xff\x80'), 25, 25, framebuf.MONO_HLSB) +fb_settings_small = framebuf.FrameBuffer(bytearray(b'\xff\xff\xff\x80\x80\x00\x00\x80\x80\x00\x00\x80\x87\x00\x00\x80\x9d\xff\xfc\x80\x9d\xff\xfc\x80\x9d\xff\xfc\x80\x87\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x07\x00\x80\x9f\xfd\xfc\x80\x9f\xfd\xfc\x80\x9f\xfd\xfc\x80\x80\x07\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80p\x00\x80\x9f\xdf\xfc\x80\x9f\xdf\xfc\x80\x9f\xdf\xfc\x80\x80p\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\xff\xff\xff\x80'), 25, 25, framebuf.MONO_HLSB) +fb_help = framebuf.FrameBuffer(bytearray(b'\xff\xff\xff\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x87\xff\xf0\x80\x87\xff\xf0\x80\x87\xff\xf0\x80\x80\x00p\x80\x80\x00p\x80\x80\x00p\x80\x80\x7f\xf0\x80\x80\x7f\xf0\x80\x80\x7f\xf0\x80\x80p\x00\x80\x80p\x00\x80\x80p\x00\x80\x80p\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80p\x00\x80\x80p\x00\x80\x80p\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\xff\xff\xff\x80'), 25, 25, framebuf.MONO_HLSB) + +#load saved files +fb_prev = framebuf.FrameBuffer(bytearray(b'\xff\xff\xff\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x07\x80\x80\x80\x0f\x80\x80\x80\x1f\x80\x80\x80>\x00\x80\x80~\x00\x80\x80\xf8\x00\x80\x81\xff\xf0\x80\x83\xff\xf0\x80\x83\xff\xf0\x80\x81\xff\xf0\x80\x80\xf8\x00\x80\x80~\x00\x80\x80>\x00\x80\x80\x1f\x80\x80\x80\x0f\x80\x80\x80\x07\x80\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\xff\xff\xff\x80'), 25, 25, framebuf.MONO_HLSB) +fb_next = framebuf.FrameBuffer(bytearray(b'\xff\xff\xff\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\xf0\x00\x80\x80\xf8\x00\x80\x80\xfc\x00\x80\x80>\x00\x80\x80?\x00\x80\x80\x0f\x80\x80\x87\xff\xc0\x80\x87\xff\xe0\x80\x87\xff\xe0\x80\x87\xff\xc0\x80\x80\x0f\x80\x80\x80?\x00\x80\x80>\x00\x80\x80\xfc\x00\x80\x80\xf8\x00\x80\x80\xf0\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\x80\x00\x00\x80\xff\xff\xff\x80'), 25, 25, framebuf.MONO_HLSB) +fb_load = framebuf.FrameBuffer(bytearray(b'\xff\xff\xff\x80\x80\x00\x00\x80\x80\x7f\x00\x80\x80\x7f\x00\x80\x80\x7f\x00\x80\x80\x7f\x00\x80\x80\x7f\x00\x80\x80\x7f\x00\x80\x80\x7f\x00\x80\x80\x7f\x00\x80\x83\xff\xe0\x80\x81\xff\xc0\x80\xb0\xff\x86\x80\xb0\xff\x86\x80\xb0\x7f\x06\x80\xb0>\x06\x80\xb0>\x06\x80\xb0\x1c\x06\x80\xb0\x18\x06\x80\xb0\x08\x06\x80\xbf\xff\xfe\x80\xbf\xff\xfe\x80\x80\x00\x00\x80\x80\x00\x00\x80\xff\xff\xff\x80'), 25, 25, framebuf.MONO_HLSB) + +#Settings +fb_BIGHome = framebuf.FrameBuffer(bytearray(b'\xff\xff\xff\xff\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x01\x80\x01\x80\x03\xc0\x01\x80\x0f\xf0\x01\x80\x1f\xf8\x01\x80?\xfc\x01\x80\x7f\xfe\x01\x81\xff\xff\x81\x83\xff\xff\xc1\x87\xff\xff\xe1\x8f\xff\xff\xf1\x83\xff\xff\xc1\x83\xff\xff\xc1\x83\xff\xff\xc1\x83\xd7\x1f\xc1\x83\xff\x1f\xc1\x83\xd7\x1f\xc1\x83\xff\x1f\xc1\x83\xff\x1f\xc1\x83\xff\x1f\xc1\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\xff\xff\xff\xff'), 32, 32, framebuf.MONO_HLSB) +fb_Lead = framebuf.FrameBuffer(bytearray(b'\xff\xff\xff\xff\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x83\xf8\x0f\xe1\x82\x00\x00!\x82\x00\x00!\x82x\x0f!\x82@\x01!\x82@\x01!\x82L\x19!\x82H\t!\x82I\xc9!\x82I\xc9!\x82I\xc9!\x82H\x89!\x82@\x81!\x82@\x81!\x82p\x87!\x82\x00\x80!\x82\x00\x80!\x83\xf8\x8f\xe1\x80\x00\x80\x01\x80\x00\x80\x01\x80\x00\x80\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\xff\xff\xff\xff'), 32, 32, framebuf.MONO_HLSB) +fb_Follow = framebuf.FrameBuffer(bytearray(b'\xff\xff\xff\xff\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x07\xe0\x01\x80\x0c0\x01\x80\x10\x08\x01\x80 \x04\x01\x80@\x02\x01\x80@\x02\x01\x80@\x02\x01\x80@\x02\x01\x80@\x02\x01\x80 \x04\x01\x80\x10\x0c\x01\x80\x0c<\x01\x80\x07\xee\x01\x80\x00\x07\x01\x80\x00\x03\x81\x80\x00\x01\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\xff\xff\xff\xff'), 32, 32, framebuf.MONO_HLSB) + +#Add the icons to the array, add iconsizes add the direction 0 - horizontal , 1 - vertical +#iconFrames=[[fb_Train,fb_Play,fb_Setting],[fb_add,fb_delete,fb_smallplay,fb_home],[fb_save,fb_pause,fb_home,fb_toggle],[fb_next,fb_delete,fb_home,fb_toggle],[fb_Lead,fb_Follow, fb_BIGHome]] +#iconFrames=[[fb_Train,fb_Play],[fb_add,fb_delete,fb_smallplay,fb_home],[fb_save,fb_home],[fb_next,fb_delete,fb_home]] +#iconFrames=[[fb_Train,fb_Play],[fb_smallplay,fb_add,fb_delete,fb_settings_small,fb_help],[fb_next,fb_delete,fb_home]] +iconFrames=[[fb_Train,fb_Play],[fb_smallplay,fb_add,fb_delete],[fb_next,fb_delete,fb_home]] + +iconSize=[32,25,25] +offsets= [(20,20),(102,29),(102,29)] #where you want to display your first icon +direction=[0,1,1] # 0 horizonal and 1 vertical arrangement + +for index,icon in enumerate(iconFrames): + icons = createIcons(iconSize[index], icon, offsetx=offsets[index][0], offsety=offsets[index][1] , direction=direction[index]) + Icons.append(icons) + +class SSD1306_SMART(ssd1306.SSD1306_I2C): + def __init__(self, width, height, i2c, addr=0x3C, external_vcc=False, scale = 8, mode = 0, plotsize = [[3,3],[100,60]]): + self.scale = scale + self.mode = mode # 0 for learn, 1 for repeat + self.plotsize = plotsize + self.ranges = {'light': [0, 4095], 'motor': [0, 180], 'screenx': [4, 96], 'screeny': [59, 5]} # screeny is backwards because it is from top to bottom + #Battery + + super().__init__(width, height, i2c, addr = 0x3C, external_vcc = external_vcc) + self.graphx=27 + self.graphy=0 + + self.iconx=0 + self.icony=29 + + self.color=0 + self.graphwidthx=100 + self.graphwidthy=64 + self.iconwidth=25 + self.updownwidth=10 + self.updownx=self.iconx+int(self.iconwidth/2-self.updownwidth/2) + self.upy=self.icony - self.updownwidth + self.downy=self.icony + self.iconwidth + 1 + + + + + + def displayscreen(self,whereamI): + for IconX,IconY,frame in Icons[whereamI]: + self.blit(frame, IconX, IconY, 0) + self.show() + + def selector(self,whereamI,icon,previcon): + print("icon and previcon and whereamI",icon,previcon, whereamI) + if(direction[whereamI]==0): + padding=3 + width=height=iconSize[whereamI]+2*padding + self.rect(Icons[whereamI][previcon][0]-padding,Icons[whereamI][previcon][1]-padding,width,height, 0) #delete previous selector icon + self.rect(Icons[whereamI][icon][0]-padding,Icons[whereamI][icon][1]-padding,width,height, 1) #display current selector + self.displayscreen(whereamI) + else: + + + self.fill_rect(self.iconx,self.icony,self.iconwidth,self.iconwidth, 0) #delete previous selector icon + self.blit(fb_upnobox,self.updownx,self.upy,0) + self.blit(Icons[whereamI][icon][2], self.iconx, self.icony, 0) + self.blit(fb_downnobox,self.updownx,self.downy,0) + #self.blit(fb_DOWN, 102, 49, 0) + self.show() + + + def showbattery(self, batterylevel): + length=20 + width=6 + gap=2 + # if ( batterylevel>3000): #charging + if(batterylevel=="charging"): #charging + self.blit(fb_battcharging,self.iconx,0,0) + elif(batterylevel=="full"): #full charge + self.blit(fb_batthigh,self.iconx,0,0) + elif(batterylevel=="half"): #medium charge + self.blit(fb_battmid,self.iconx,0,0) + elif(batterylevel=="low"): # low charge + self.blit(fb_battlow,self.iconx,0,0) + else: + pass + self.show() + + + + def transform(self,initial, final, value): + initial = self.ranges[initial] + final = self.ranges[final] + return int((final[1]-final[0]) / (initial[1]-initial[0]) * (value - initial[0]) + final[0]) + + def graph(self, oldpoint,point, points, color): + if color==self.color: + #don't change + pass + else: + self.color=color + #clear the screen with the latest color + self.fill_rect(self.graphx,self.graphy,self.graphwidthx,self.graphwidthy,color) + + + rectsize=8 + dotsize=4 + + + ox,oy=oldpoint + x,y=point + + ox=self.transform('light', 'screenx', ox)+self.graphx + oy=self.transform('motor','screeny',oy)+self.graphy + x=self.transform('light', 'screenx', x)+self.graphx + y=self.transform('motor','screeny',y)+self.graphy + self.rect(self.graphx,self.graphy,self.graphwidthx,self.graphwidthy,(color+1)%2) + + self.line(self.graphx,oy,self.graphx+self.graphwidthx,oy,color%2) + self.line(ox,self.graphy,ox,self.graphy+self.graphwidthy,color%2) + + self.line(self.graphx,y,self.graphx+self.graphwidthx,y,(color+1)%2) + self.line(x,self.graphy,x,self.graphy+self.graphwidthy,(color+1)%2) + + self.rect(ox-int(rectsize/2),oy-int(rectsize/2),rectsize,rectsize,color%2) + self.rect(x-int(rectsize/2),y-int(rectsize/2),rectsize,rectsize,(color+1)%2) + for i in points: + x,y=i + x=self.transform('light', 'screenx', x)+self.graphx + y=self.transform('motor','screeny',y)+self.graphy + self.fill_rect(x-int(dotsize/2),y-int(dotsize/2),dotsize,dotsize,(color+1)%2) + self.show() + + def cleargraph(self): + self.fill_rect(self.graphx+1,self.graphy+1,self.graphwidthx-2,self.graphwidthy-2,0) + self.rect(self.graphx,self.graphy,self.graphwidthx,self.graphwidthy,1) + + + + def showmessage(self,msg): + + self.fill_rect(30,10,90,50,0) + self.text(msg,35,20,1) + self.show() + time.sleep(2) + self.fill_rect(30,10,90,50,0) + #self.fill(0) + self.show() + + + def welcomemessage(self): + self.fill(1) + self.show() + + for a in range(32): + i=2*a + self.fill_rect(64-(2*i),32-i,4*i,2*i,0) + self.blit(fb_SMLOGO,39,7,0) + self.show() + ''' + for i in range(80): + self.fill(0) + self.blit(fb_SMLOGO,38-i,7,0) + self.blit(fb_SMLOGO,40+i,7,0) + self.show() + ''' + self.clear() + self.show() + + def clear(self): + self.fill(0) + self.show() + diff --git a/software/libraries/sensors.py b/software/libraries/sensors.py new file mode 100644 index 0000000..96cd1e8 --- /dev/null +++ b/software/libraries/sensors.py @@ -0,0 +1,146 @@ +from machine import Pin,I2C +from machine import Pin, SoftI2C, PWM, ADC +import adxl345 +import time + +i2c = SoftI2C(scl = Pin(7), sda = Pin(6)) + + + +class SENSORS: + def __init__(self,connection=i2c): + self.i2c=connection + self.adx = adxl345.ADXL345(self.i2c) + + self.initial = [0, 4095] + self.final = [0, 180] + self.pot = ADC(Pin(3)) + self.pot.atten(ADC.ATTN_11DB) # the pin expects a voltage range up to 3.3V + + + self.attached = False + self.selectsensor() + + time.sleep(1) + if self.attached: + self.light = ADC(Pin(5)) + self.light.atten(ADC.ATTN_11DB) # the pin expects a voltage range up to 3.3V\ + + + + self.battery = ADC(Pin(4)) + self.battery.atten(ADC.ATTN_11DB) # the pin expects a voltage range up to 3.3V + + self.x=None + self.y=None + self.z=None + self.roll=None + self.pitch=None + + def selectsensor(self): + p_digital = Pin(5, Pin.OUT) #set pin as digital + p_digital.value(0) #set pin low + p_analog = ADC(Pin(5)) # set pin 5 to analog + p_analog.atten(ADC.ATTN_11DB) # the pin expects a voltage range up to 3.3V + low = p_analog.read() # read value + + + p_digital = Pin(5, Pin.OUT) #set pin as digital + p_digital.value(1) #set pin high + p_analog = ADC(Pin(5)) #set pin to analog + p_analog.atten(ADC.ATTN_11DB) # the pin expects a voltage range up to 3.3V + high = p_analog.read() #read value + + if(low<200 and high>4000): + self.attached = False + + else: + self.attached = True + + def map_angle_to_range(self, angle): + if 90 <= angle <= 180: + # Normalize range 90 to 180 to 0 to 90 + normalized_angle = angle - 90 + elif -180 <= angle < -90: + # Normalize range -180 to -90 to 90 to 180 + normalized_angle = angle + 270 # -180 + 270 = 90, -90 + 270 = 180 + elif -90 <= angle < 0: + return 4095 + else: + return 0 + # Now normalized_angle is in the range [0, 180] + # Map this range to [0, 4095] + mapped_value = int((normalized_angle / 180.0) * 4095) + + + return mapped_value + def readlight(self): + return self.light.read() + + + def readpot(self): + return self.pot.read() + + def accel(self): + self.x =self.adx.xValue + self.y =self.adx.yValue + self.z =self.adx.zValue + + + def readaccel(self): + self.accel() + return self.x, self.y,self.z + + def readroll(self): + self.accel() + self.roll, self.pitch = self.adx.RP_calculate(self.x,self.y,self.z) + return self.roll,self.pitch + + + def readpoint(self): + l=[] + p=[] + + for i in range(100): + if self.attached: + l.append(self.readlight()) + p.append(self.readpot()) + + l.sort() + p.sort() + if self.attached: + l=l[30:60] + avlight=sum(l)/len(l) + else: + avlight = self.map_angle_to_range(self.readroll()[0]) + + p=p[30:60] + avpos=sum(p)/len(p) + + point = avlight, self.mappot(avpos) + return point + + def mappot(self, value): + return int((self.final[1]-self.final[0]) / (self.initial[1]-self.initial[0]) * (value - self.initial[0]) + self.final[0]) + + def readbattery(self): + batterylevel=self.battery.read() + + if(batterylevel>2850): #charging + return 'charging' + + elif(batterylevel>2700 and batterylevel <2875): #full charge + return 'full' + elif(batterylevel>2500 and batterylevel <2700): #medium charge + return 'half' + elif(batterylevel<2500): # low charge + return 'low' + else: + pass + + return "" + + + + + diff --git a/software/libraries/servo.py b/software/libraries/servo.py new file mode 100644 index 0000000..7237b17 --- /dev/null +++ b/software/libraries/servo.py @@ -0,0 +1,33 @@ +from machine import PWM +import math + +# originally by Radomir Dopieralski http://sheep.art.pl +# from https://bitbucket.org/thesheep/micropython-servo + +class Servo: + def __init__(self, pin, freq=50, min_us=600, max_us=2400, angle=180): + self.min_us = min_us + self.max_us = max_us + self.us = 0 + self.freq = freq + self.angle = angle + self.pwm = PWM(pin, freq=freq, duty=0) + + def write_us(self, us): + #"""Set the signal to be ``us`` microseconds long. Zero disables it.""" + if us == 0: + self.pwm.duty(0) + return + us = min(self.max_us, max(self.min_us, us)) + duty = us * 1024 * self.freq // 1000000 + self.pwm.duty(duty) + + def write_angle(self, degrees=None, radians=None): + #"""Move to the specified angle in ``degrees`` or ``radians``.""" + if degrees is None: + degrees = math.degrees(radians) + degrees = degrees % 360 + total_range = self.max_us - self.min_us + us = self.min_us + total_range * degrees // self.angle + self.write_us(us) + diff --git a/software/libraries/smartmotor.py b/software/libraries/smartmotor.py new file mode 100644 index 0000000..b2649a9 --- /dev/null +++ b/software/libraries/smartmotor.py @@ -0,0 +1,444 @@ +from machine import Pin, SoftI2C, PWM, ADC +from files import * +import time +from machine import Timer +import servo +import icons +import os +import sys +import ubinascii +import machine + + +import sensors +sens=sensors.SENSORS() + +#unique name + +ID= ubinascii.hexlify(machine.unique_id()).decode() +numberofIcons=[len(icons.iconFrames[i]) for i in range(len(icons.iconFrames))] #[homescreen, trainscreen, playscreen, playthefilesscreen, settingsscreen] +highlightedIcon=[] +for numberofIcon in numberofIcons: + highlightedIcon.append([0,numberofIcon]) + +screenID=1 +lastPressed=0 +previousIcon=0 +filenumber=0 + + +currentlocaltime=0 +oldlocaltime=0 + +points = [] + + +#Defining all flags +#flags +flags=[False,False,False,False, False] +playFlag=False +triggered=False +LOGGING=True + + +#switch flags +switch_state_up = False +switch_state_down = False +switch_state_select = False + +last_switch_state_up = False +last_switch_state_down = False +last_switch_state_select = False + +switched_up = False +switched_down = False +switched_select = False + + +#mainloop flags +clearscreen=False + + +#define buttons , sensors and motors +#servo +s = servo.Servo(Pin(2)) + +#nav switches +switch_down = Pin(8, Pin.IN) +switch_select = Pin(9, Pin.IN) +switch_up= Pin(10, Pin.IN) + +i2c = SoftI2C(scl = Pin(7), sda = Pin(6)) +display = icons.SSD1306_SMART(128, 64, i2c,switch_up) + + +#highlightedIcon=[(ICON,TotalIcons),...] +#screenID gives the SCREEN number I am at +#SCREENID +#0 - HOMESCREEN +#1 - PlaySCREEN +#2 - TrainSCREEN +#3 - Playthefiles +#4 - ConnectSCREEN + +#highligtedIcons[screenID][0] which icon is highlighted on screenID screen +#highligtedIcons[screenID][0] =1 # First Icon selected +#highligtedIcons[screenID][0] =2 #Second +#highligtedIcons[screenID][0] =3 #Third + +#interrupt functions + +def downpressed(count=-1): + global playFlag + global triggered + playFlag = False + time.sleep(0.05) + if(time.ticks_ms()-lastPressed>200): + displayselect(count) + + triggered=True #log file + + +def uppressed(count=1): + global playFlag + global triggered + playFlag = False + time.sleep(0.05) + if(time.ticks_ms()-lastPressed>200): + displayselect(count) + triggered=True #log file + + +def displayselect(selectedIcon): + global screenID + global highlightedIcon + global lastPressed + global previousIcon + + highlightedIcon[screenID][0]=(highlightedIcon[screenID][0]+selectedIcon)%highlightedIcon[screenID][1] + display.selector(screenID,highlightedIcon[screenID][0],previousIcon) #draw circle at selection position, and remove from the previousIconious position + previousIcon=highlightedIcon[screenID][0] + + lastPressed=time.ticks_ms() + +def selectpressed(): + #declare all global variables, include all flags + global flags + global triggered + time.sleep(0.05) + flags[highlightedIcon[screenID][0]]=True + triggered=True #log file + + + + +def resettohome(): + global screenID + global highlightedIcon + global previousIcon + global clearscreen + screenID=0 + previousIcon=0 + for numberofIcon in numberofIcons: + highlightedIcon.append([0,numberofIcon]) + display.selector(screenID,highlightedIcon[screenID][0],0) + #display.fill(0) # clear screen + clearscreen=True + +def check_switch(p): + global switch_state_up + global switch_state_down + global switch_state_select + + global switched_up + global switched_down + global switched_select + + global last_switch_state_up + global last_switch_state_down + global last_switch_state_select + + switch_state_up = switch_up.value() + switch_state_down = switch_down.value() + switch_state_select = switch_select.value() + + if switch_state_up != last_switch_state_up: + switched_up = True + + elif switch_state_down != last_switch_state_down: + switched_down = True + + elif switch_state_select != last_switch_state_select: + switched_select = True + + if switched_up: + if switch_state_up == 0: + uppressed() + switched_up = False + elif switched_down: + if switch_state_down == 0: + downpressed() + switched_down = False + elif switched_select: + if switch_state_select == 0: + selectpressed() + switched_select = False + + last_switch_state_up = switch_state_up + last_switch_state_down = switch_state_down + last_switch_state_select = switch_state_select + + + +def displaybatt(p): + batterycharge=sens.readbattery() + display.showbattery(batterycharge) + if LOGGING: + savetolog(time.time(),screenID,highlightedIcon, point,points) + return batterycharge + + + +def nearestNeighbor(data, point): + try: + point = point[0] + except TypeError: + pass + if len(data) == 0: + return 0 + diff = 10000 + test = None + for i in data: + if abs(i[0] - point) <= diff: + diff = abs(i[0] - point) + test = i + return (point, test[1]) + +def resetflags(): + global flags + for i in range(len(flags)): + flags[i]=False + + +def shakemotor(point): + motorpos=point[1] + for i in range(2): + s.write_angle(min(180,motorpos+5)) + time.sleep(0.1) + s.write_angle(max(0,motorpos-5)) + time.sleep(0.1) + + + + +def readdatapoints(): + datapoints=readfile() + if(datapoints): + numberofdata=len(datapoints) + return datapoints[-1] + else: + return ([]) + + +def setloggingmode(): + #sets pref to log by default + if not switch_down.value() and not switch_up.value() and not switch_select.value(): + resetlog() #delete all the previous logs + setprefs() #sets preference file to True + display.showmessage("LOG: ON") + print("resetting the log file") + + + #resets prefs to not log by default + if not switch_down.value() and not switch_up.value() and switch_select.value(): + resetprefs() #resets preference file to False + print("turn OFF the logging") + display.showmessage("LOG: OFF") + + + if switch_down.value() and switch_up.value() and switch_select.value(): + print("default: turn ON the logging") + + + import prefs + return prefs.log + + + +points=readdatapoints() +if points==[]: + highlightedIcon[1][0]=1 #go to add if there are no data saved + +#setting up Timers +tim = Timer(0) +tim.init(period=50, mode=Timer.PERIODIC, callback=check_switch) +batt = Timer(2) +batt.init(period=3000, mode=Timer.PERIODIC, callback=displaybatt) + + +display.welcomemessage() + + + + + +LOGGING=setloggingmode() + +#setup with homescreen #starts with screenID=0 +display.selector(screenID,highlightedIcon[screenID][0],-1) +oldpoint=[-1,-1] + + +while True: + #log + point = sens.readpoint() + if(triggered): + if LOGGING: + savetolog(time.time(),screenID,highlightedIcon, point,points) + triggered=False + + + #broadcast(point, screenID, highlightedIcon[screenID][0],ID) + + #Homepage + #[fb_Train,fb_Play] + + if(screenID==0): + if(flags[0]): + points=[] #empty the points arrray + screenID=1 + clearscreen=True + display.graph(oldpoint, point, points,0) #normal color + resetflags() + + elif(flags[1]): + screenID=2 + clearscreen=True + datapoints=readfile() + if (datapoints==[]): + display.showmessage("No data saved") + resettohome() + else: + display.graph(oldpoint, point, points,0) #normal color + resetflags() + + # Training Screen + # [fb_add,fb_delete,fb_smallplay,fb_home] + elif(screenID==1): + if(flags[0]): # Play button is pressed + if (points): + playFlag=True + savetofile(points) + shakemotor(point) + #screenID=2 # trigger play screen + #uppressed(count=4) + else: + cleardatafile() + display.showmessage("NO DATA") + resetflags() + + + elif(flags[1]): # add button is pressed + points.append(list(point)) + display.graph(oldpoint, point, points,0) + shakemotor(point) + resetflags() + + elif(flags[2]): #delete button is pressed + if(points): #delete only when there is something + points.pop() + display.cleargraph() + display.graph(oldpoint, point, points,0) + resetflags() + + + elif(flags[3]): # change this to settings icon save button is pressed + # This is where we can put other advanced settings, maybe call the main screen + #screenId=0 + #savetofile(points) + #resettohome() + + print("some settings stuff") + resetflags() + + elif(flags[4]): # help button is prssed + # quit to home + display.showmessage("This is for help whatever you need") + # resettohome() + resetflags() + + + if(playFlag): #only when point is different now + if(not point==oldpoint): #only when point is different now + point = nearestNeighbor(points,point) + s.write_angle(point[1]) + display.graph(oldpoint, point, points,1) #inverted color + + + + else: + if(not point==oldpoint): #only when point is different now + s.write_angle(point[1]) + display.graph(oldpoint, point, points,0) #normal color + + + + + # Load saved files screen + #[fb_next,fb_delete,fb_home,fb_toggle] + elif(screenID==2): + datapoints=readfile() + if(datapoints): + numberofdata=len(datapoints) + points=datapoints[filenumber] + + if(flags[0]): + filenumber=((filenumber+1)%numberofdata) + points=datapoints[filenumber] + display.cleargraph() + resetflags() + + elif(flags[1]): + del datapoints[filenumber] + replacefile(datapoints) + filenumber=0 + display.cleargraph() + resetflags() + + elif(flags[2]): + resettohome() + resetflags() + + if(not point==oldpoint): #only when point is different now + point = nearestNeighbor(points,point) + s.write_angle(point[1]) + display.graph(oldpoint, point, points,0) #normal color + else: + display.showmessage("No files to show") + resettohome() + + # Settings Screen + #[fb_Lead,fb_Follow, fb_BIGHome] + elif(screenID==4): + if(flags[0]): + display.showmessage(ID) + waitforconnection() + resetflags() + + elif(flags[1]): + print("I shall follow you") + resetflags() + + elif(flags[2]): + resettohome() + resetflags() + + oldpoint=point + if clearscreen: + display.fill(0) + display.selector(screenID,highlightedIcon[screenID][0],-1) + clearscreen=False + + + + diff --git a/software/libraries/ssd1306.py b/software/libraries/ssd1306.py new file mode 100644 index 0000000..d046b25 --- /dev/null +++ b/software/libraries/ssd1306.py @@ -0,0 +1,158 @@ +# This is an ssd1306 package we found on the internet. +# https://github.com/stlehmann/micropython-ssd1306/blob/master/ssd1306.py +# Do not edit this file. +# MicroPython SSD1306 OLED driver, I2C and SPI interfaces +from micropython import const +import framebuf + + +# register definitions +SET_CONTRAST = const(0x81) +SET_ENTIRE_ON = const(0xA4) +SET_NORM_INV = const(0xA6) +SET_DISP = const(0xAE) +SET_MEM_ADDR = const(0x20) +SET_COL_ADDR = const(0x21) +SET_PAGE_ADDR = const(0x22) +SET_DISP_START_LINE = const(0x40) +SET_SEG_REMAP = const(0xA0) +SET_MUX_RATIO = const(0xA8) +SET_COM_OUT_DIR = const(0xC0) +SET_DISP_OFFSET = const(0xD3) +SET_COM_PIN_CFG = const(0xDA) +SET_DISP_CLK_DIV = const(0xD5) +SET_PRECHARGE = const(0xD9) +SET_VCOM_DESEL = const(0xDB) +SET_CHARGE_PUMP = const(0x8D) + +# Subclassing FrameBuffer provides support for graphics primitives +# http://docs.micropython.org/en/latest/pyboard/library/framebuf.html +class SSD1306(framebuf.FrameBuffer): + def __init__(self, width, height, external_vcc): + self.width = width + self.height = height + self.external_vcc = external_vcc + self.pages = self.height // 8 + self.buffer = bytearray(self.pages * self.width) + super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB) + self.init_display() + + def init_display(self): + for cmd in ( + SET_DISP | 0x00, # off + # address setting + SET_MEM_ADDR, + 0x00, # horizontal + # resolution and layout + SET_DISP_START_LINE | 0x00, + SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0 + SET_MUX_RATIO, + self.height - 1, + SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0 + SET_DISP_OFFSET, + 0x00, + SET_COM_PIN_CFG, + 0x02 if self.width > 2 * self.height else 0x12, + # timing and driving scheme + SET_DISP_CLK_DIV, + 0x80, + SET_PRECHARGE, + 0x22 if self.external_vcc else 0xF1, + SET_VCOM_DESEL, + 0x30, # 0.83*Vcc + # display + SET_CONTRAST, + 0xFF, # maximum + SET_ENTIRE_ON, # output follows RAM contents + SET_NORM_INV, # not inverted + # charge pump + SET_CHARGE_PUMP, + 0x10 if self.external_vcc else 0x14, + SET_DISP | 0x01, + ): # on + self.write_cmd(cmd) + self.fill(0) + self.show() + + def poweroff(self): + self.write_cmd(SET_DISP | 0x00) + + def poweron(self): + self.write_cmd(SET_DISP | 0x01) + + def contrast(self, contrast): + self.write_cmd(SET_CONTRAST) + self.write_cmd(contrast) + + def invert(self, invert): + self.write_cmd(SET_NORM_INV | (invert & 1)) + + def show(self): + x0 = 0 + x1 = self.width - 1 + if self.width == 64: + # displays with width of 64 pixels are shifted by 32 + x0 += 32 + x1 += 32 + self.write_cmd(SET_COL_ADDR) + self.write_cmd(x0) + self.write_cmd(x1) + self.write_cmd(SET_PAGE_ADDR) + self.write_cmd(0) + self.write_cmd(self.pages - 1) + self.write_data(self.buffer) + + +class SSD1306_I2C(SSD1306): + def __init__(self, width, height, i2c, addr=0x3C, external_vcc=False): + self.i2c = i2c + self.addr = addr + self.temp = bytearray(2) + self.write_list = [b"\x40", None] # Co=0, D/C#=1 + super().__init__(width, height, external_vcc) + + def write_cmd(self, cmd): + self.temp[0] = 0x80 # Co=1, D/C#=0 + self.temp[1] = cmd + self.i2c.writeto(self.addr, self.temp) + + def write_data(self, buf): + self.write_list[1] = buf + self.i2c.writevto(self.addr, self.write_list) + + +class SSD1306_SPI(SSD1306): + def __init__(self, width, height, spi, dc, res, cs, external_vcc=False): + self.rate = 10 * 1024 * 1024 + dc.init(dc.OUT, value=0) + res.init(res.OUT, value=0) + cs.init(cs.OUT, value=1) + self.spi = spi + self.dc = dc + self.res = res + self.cs = cs + import time + + self.res(1) + time.sleep_ms(1) + self.res(0) + time.sleep_ms(10) + self.res(1) + super().__init__(width, height, external_vcc) + + def write_cmd(self, cmd): + self.spi.init(baudrate=self.rate, polarity=0, phase=0) + self.cs(1) + self.dc(0) + self.cs(0) + self.spi.write(bytearray([cmd])) + self.cs(1) + + def write_data(self, buf): + self.spi.init(baudrate=self.rate, polarity=0, phase=0) + self.cs(1) + self.dc(1) + self.cs(0) + self.spi.write(buf) + self.cs(1) + diff --git a/software/main/.DS_Store b/software/main/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T01000): + lastPressed = time.ticks_ms() + networking.aen.ping(peer_mac) + networking.aen.echo(peer_mac, message) + networking.aen.send(peer_mac, message) + print(f"{(time.ticks_ms() - networking.inittime) / 1000:.3f} Networking Tool: Sent {message} to {peer_mac}") + print(f"{(time.ticks_ms() - networking.inittime) / 1000:.3f} Networking Tool: RSSI table: {networking.aen.rssi()}") + +switch_select = Pin(9, Pin.IN, Pin.PULL_UP) + +#Buttons +switch_select = Pin(9, Pin.IN, Pin.PULL_UP) +switch_select.irq(trigger=Pin.IRQ_FALLING, handler=boop) + +def heartbeat(timer): + print("") + print(f"{(time.ticks_ms() - networking.inittime) / 1000:.3f} Networking Tool Heartbeat: {gc.mem_free()} bytes") + print("") + gc.collect() + +timer = machine.Timer(0) +timer.init(period=5000, mode=machine.Timer.PERIODIC, callback=heartbeat) diff --git a/software/networking/.DS_Store b/software/networking/.DS_Store index 346290cd66f41088a0de4d3ae3d8b210042da08e..370708d08128bce47e3dd3d9685bae38dab6caf9 100644 GIT binary patch delta 89 zcmV-f0H*(hFoZCWPXP_FP`d*G4U-H6gOkAoOaZ!+4h3;38hd*&FgZ0WATl{MeJmh* vF)}qUEFd^FFnxUq2o)nQJ5pb3Y;A6DjFYAX9|4WC#sxtFk$^C>2MGNSf@KWQKf(JccxeOons@J%$2?O3$49 Date: Tue, 26 Nov 2024 15:46:17 -0500 Subject: [PATCH 07/10] added actions back --- .DS_Store | Bin 12292 -> 14340 bytes .github/.DS_Store | Bin 0 -> 6148 bytes .github/workflows/release-pipeline.yml | 72 +++++++++++++++++++++++++ .github/workflows/render-README.yml | 47 ++++++++++++++++ 4 files changed, 119 insertions(+) create mode 100644 .github/.DS_Store create mode 100644 .github/workflows/release-pipeline.yml create mode 100644 .github/workflows/render-README.yml diff --git a/.DS_Store b/.DS_Store index d3741d879a680d183d98a096a53a4a23c78504b8..8dc02ebafedc0ec1bf36c81b919354e1f41d288c 100644 GIT binary patch delta 552 zcmZokXem%&U|?W$DortDU@!nOIe-{M3-ADmHU? zIX|~xVxjV6105DtMxZ3i{ZG0%EW;3KR zR8HQe(8^?KJlR&!X|ts85pFv{WE)Yb?UL*&gsRjj5QoeJ34k#SC;3j1P zgD;OEALx!$RPz`dF#;t8s16u0lNYKBZ(gi$j%{+hxcue_@kVw@R-lSCM1f8z1N~GV)ILRH)uutN4m-;shD6DGCDelix|W$N-IH1!5r3;06+| w$d1~0@jdfoeiL0CkTl2v4Il;(0NG4XngvROyaWioyxF0D>q@p7bOlMEfevm7_8HDTp3)NfXUV>#^56 zwmik#w*YMOxmyD(086?fzI~XR@4L_Jt|CUH^Nc+PjQGNFcbsMa9dPag86!S$_|1PG z-o|n8ZJ8910#ZN7!Kn+ zdI@6l0I?TNiHy)Jsl=pOwHTIk##`m}!YMK7uxdW6Zno-BENN(xAUn^M3Q+n4QzPpaBFdz{zWMt`My&WY~Ec~Ce+IVMIq=EBSI dQzT_x^Evl>;glG3#)D4O&w%S9lLFUP;0L2O71{s* literal 0 HcmV?d00001 diff --git a/.github/workflows/release-pipeline.yml b/.github/workflows/release-pipeline.yml new file mode 100644 index 0000000..88330b0 --- /dev/null +++ b/.github/workflows/release-pipeline.yml @@ -0,0 +1,72 @@ +name: Check and Copy Updated Files + +on: + push: + branches: + - main + +jobs: + check-and-copy: + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Parse File List from software/release/README.qmd + id: parse + run: | + cd software + cd release + + # Extract the table section and parse the file paths + raw_file_list=$(awk '/\| name/ {f=1; next} /\|----/ {next} f && /\|/ {print $2}' README.qmd | tr -d ' ') + + # Add the software/ prefix to each file path + file_list=$(echo "$raw_file_list" | sed 's/^/software\//') + + # Output the file list + echo "Files to monitor:" + echo "$file_list" + + # Save to an environment variable for later use + echo "file_list=$file_list" >> $GITHUB_ENV + + - name: Identify Changed Files + id: changes + run: | + # Identify changed files in this push + changed_files=$(git diff --name-only ${{ github.event.before }} HEAD) + + # Filter to include only monitored files + updated_files=() + for file in $file_list; do + if echo "$changed_files" | grep -q "^$file$"; then + updated_files+=("$file") + fi + done + + # Save the list of updated files to an output file + if [ ${#updated_files[@]} -eq 0 ]; then + echo "No monitored files were updated." + echo "updated_files=" >> $GITHUB_ENV + else + echo "The following monitored files were updated:" + printf "%s\n" "${updated_files[@]}" + printf "%s\n" "${updated_files[@]}" > updated_files.txt + echo "updated_files=$(printf "%s " "${updated_files[@]}")" >> $GITHUB_ENV + fi + + - name: Copy Updated Files to Release Folder + if: ${{ env.updated_files != '' }} + run: | + mkdir -p release # Ensure the release folder exists + while read file; do + cp "$file" release/ # Copy files directly to the root of the release folder + done < updated_files.txt + + - name: List Files in Release Folder + if: ${{ env.updated_files != '' }} + run: | + echo "Files copied to the release folder:" + find release -type f diff --git a/.github/workflows/render-README.yml b/.github/workflows/render-README.yml new file mode 100644 index 0000000..7702980 --- /dev/null +++ b/.github/workflows/render-README.yml @@ -0,0 +1,47 @@ +name: Render README.qmd to Markdown + +on: + push: + branches: + - main + +jobs: + render: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + ssh-key: ${{ secrets.RENDER_KEY }} + #persist-credentials: false + - name: Set up R + uses: r-lib/actions/setup-r@v2 + + - name: Install Required R Packages + run: | + Rscript -e 'if (!requireNamespace("rmarkdown", quietly = TRUE)) install.packages("rmarkdown", repos = "https://cloud.r-project.org/")' + Rscript -e 'if (!requireNamespace("knitr", quietly = TRUE)) install.packages("knitr", repos = "https://cloud.r-project.org/")' + + - name: Set up Quarto + uses: quarto-dev/quarto-actions/setup@v2 + + - name: Find and Render README.qmd Files + run: | + find . -name "README.qmd" | while read qmd_file; do + quarto render "$qmd_file" --to gfm + done + + - name: Commit and Push Rendered Files + run: | + git config --local user.name "$GITHUB_ACTOR" + git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" + git add . + git commit -m "Render README.qmd files to gfm" || echo "No changes to commit" + + git fetch origin + #git checkout stage || git checkout -b stage + + git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git + + git push origin main \ No newline at end of file From 2c4b04be85da6c6b09e3c0d710fb4e25ee545429 Mon Sep 17 00:00:00 2001 From: Nick Art Date: Tue, 26 Nov 2024 15:47:38 -0500 Subject: [PATCH 08/10] Update .DS_Store --- .DS_Store | Bin 14340 -> 14340 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/.DS_Store b/.DS_Store index 8dc02ebafedc0ec1bf36c81b919354e1f41d288c..d89ec1a9996a5d8ad7bf187bfcabc17ab70ff264 100644 GIT binary patch delta 14 VcmZoEXerp>s>sN&*-deu7yu~V1nvL; delta 14 VcmZoEXerp>s>sN=*-deu7yu~b1n&R< From 68b85da33e3de609068c9847e1e883da491f6ec6 Mon Sep 17 00:00:00 2001 From: Nick Art Date: Tue, 26 Nov 2024 15:49:14 -0500 Subject: [PATCH 09/10] Update DS Store --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 08d1dcf..bbc19dc 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,5 @@ .Rhistory .RData .Ruserdata -keys/ACTIONS_RENDER.pub keys/ACTIONS_RENDER +keys/ACTIONS_RENDER.pub From 1be3b63a6bbaa379f4374a48c52394ea1766ed33 Mon Sep 17 00:00:00 2001 From: Nick Art Date: Tue, 26 Nov 2024 15:52:59 -0500 Subject: [PATCH 10/10] cries --- .DS_Store | Bin 14340 -> 14340 bytes .github/.DS_Store | Bin 6148 -> 6148 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/.DS_Store b/.DS_Store index d89ec1a9996a5d8ad7bf187bfcabc17ab70ff264..bd69ca850dd50101a09d30d952273cad25b78bf0 100644 GIT binary patch delta 102 zcmZoEXepTB&uFtTU^hRb*5m|1kcDMjQ43 delta 64 zcmZoEXepTB&uG0dU^hRb=HvuHk diff --git a/.github/.DS_Store b/.github/.DS_Store index 36b372c72cba58418798b30534145e40b446efdb..127299e8a826f391959f5c9d0ab1f804f003e56d 100644 GIT binary patch delta 18 acmZoMXfc?uYU9Q*_K6Mbo7p-3@&f=#j0Z>n delta 20 ccmZoMXfc?uiji^S#xVAY4Q!j)IsWnk08ZxzNdN!<