Improvements, sortable list

This commit is contained in:
Djuri Baars 2024-06-08 13:34:49 +02:00
parent fbf24b0b87
commit 796befd831
2 changed files with 103 additions and 11 deletions

View file

@ -0,0 +1,37 @@
import esptool
import serial
class FwUpdate:
def get_serial_ports(self):
ports = serial.tools.list_ports.comports()
available_ports = []
for port, desc, hwid in sorted(ports):
available_ports.append((port, desc, hwid))
print(f"Port: {port}, Description: {desc}, Hardware ID: {hwid}")
return available_ports
def flash_firmware(port, baud, firmware_path):
try:
# Initialize the serial port
serial_port = serial.Serial(port, baud)
# Initialize the ESP32ROM with the serial port
esp = esptool.ESP32ROM(serial_port)
# Connect to the ESP32
esp.connect()
# Perform the flashing operation
esp.flash_file(firmware_path, offset=0x1000)
# Optionally, verify the flash
esp.verify_flash(firmware_path, offset=0x1000)
print("Firmware flashed successfully!")
except esptool.FatalError as e:
print(f"Failed to flash firmware: {e}")
finally:
# Ensure the serial port is closed
if serial_port.is_open:
serial_port.close()

View file

@ -1,7 +1,10 @@
import random import random
from threading import Thread from threading import Thread
import threading import threading
import serial
import wx import wx
import wx.lib.mixins.listctrl
from zeroconf import ServiceBrowser, Zeroconf from zeroconf import ServiceBrowser, Zeroconf
import requests import requests
import os import os
@ -9,23 +12,49 @@ import webbrowser
from app import espota from app import espota
from app.api import ApiHandler from app.api import ApiHandler
from app.fw_update import FwUpdate
from app.zeroconf_listener import ZeroconfListener from app.zeroconf_listener import ZeroconfListener
from app.espota import FLASH,SPIFFS from app.espota import FLASH,SPIFFS
class DevicesPanel(wx.ListCtrl): class SerialPortsComboBox(wx.ComboBox):
def __init__(self, parent, fw_update):
self.fw_update = fw_update
self.ports = serial.tools.list_ports.comports()
wx.ComboBox.__init__(self,parent, choices=[port.device for port in self.ports])
class DevicesPanel(wx.ListCtrl,wx.lib.mixins.listctrl.ColumnSorterMixin, wx.lib.mixins.listctrl.ListCtrlAutoWidthMixin,
):
def __init__(self, parent): def __init__(self, parent):
wx.ListCtrl.__init__(self, parent, style=wx.LC_REPORT) wx.ListCtrl.__init__(self, parent, style=wx.LC_REPORT)
self.InsertColumn(0, 'Name', width=150) self.column_headings = ["name", "Version", "SW Revision", "HW Revision", "IP", "FS Version"]
self.InsertColumn(1, 'Version', width=50) wx.lib.mixins.listctrl.ColumnSorterMixin.__init__(
self.InsertColumn(2, 'SW Revision', width=310) self,
self.InsertColumn(3, 'HW Revision', width=130) len(self.column_headings),
self.InsertColumn(4, 'IP', width=110) )
self.InsertColumn(5, 'FS version', width=110) wx.lib.mixins.listctrl.ListCtrlAutoWidthMixin.__init__(self)
for column, heading in enumerate(self.column_headings):
self.AppendColumn(heading)
self.itemDataMap = {}
def OnSortOrderChanged(self):
"""Method to handle changes to the sort order"""
column, ascending = self.GetSortState()
self.ShowSortIndicator(column, ascending)
self.SortListItems(column, ascending)
def GetListCtrl(self):
"""Method required by the ColumnSorterMixin"""
return self
class BTClockOTAUpdater(wx.Frame): class BTClockOTAUpdater(wx.Frame):
release_name = "" release_name = ""
commit_hash = "" commit_hash = ""
currentlyUpdating = False
updatingName = ""
def __init__(self, parent, title): def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title, size=(800,500)) wx.Frame.__init__(self, parent, title=title, size=(800,500))
@ -33,7 +62,7 @@ class BTClockOTAUpdater(wx.Frame):
ubuntu_it = wx.Font(32, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, faceName="Ubuntu") ubuntu_it = wx.Font(32, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, faceName="Ubuntu")
# "Ubuntu-RI.ttf") # "Ubuntu-RI.ttf")
self.fw_update = FwUpdate()
panel = wx.Panel(self) panel = wx.Panel(self)
@ -42,6 +71,9 @@ class BTClockOTAUpdater(wx.Frame):
vbox = wx.BoxSizer(wx.VERTICAL) vbox = wx.BoxSizer(wx.VERTICAL)
vbox.Add(self.title, 0, wx.EXPAND | wx.ALL, 20, 0) vbox.Add(self.title, 0, wx.EXPAND | wx.ALL, 20, 0)
# serialPorts = SerialPortsComboBox(panel, self.fw_update)
# vbox.Add(serialPorts, 0, wx.EXPAND | wx.ALL, 20, 0)
self.device_list = DevicesPanel(panel) self.device_list = DevicesPanel(panel)
self.device_list.Bind(wx.EVT_LIST_ITEM_SELECTED, self.on_item_selected) self.device_list.Bind(wx.EVT_LIST_ITEM_SELECTED, self.on_item_selected)
self.device_list.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.on_item_deselected) self.device_list.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.on_item_deselected)
@ -140,6 +172,10 @@ class BTClockOTAUpdater(wx.Frame):
self.device_list.SetItem(index, 3, info.properties.get(b"hw_rev").decode()) self.device_list.SetItem(index, 3, info.properties.get(b"hw_rev").decode())
self.device_list.SetItem(index, 4, info.parsed_addresses()[0]) self.device_list.SetItem(index, 4, info.parsed_addresses()[0])
self.device_list.SetItem(index, 5, self.api_handler.check_fs_hash(info.parsed_addresses()[0])) self.device_list.SetItem(index, 5, self.api_handler.check_fs_hash(info.parsed_addresses()[0]))
self.device_list.SetItemData(index, index)
self.device_list.itemDataMap[index] = [name, info.properties.get(b"version").decode(), info.properties.get(b"rev").decode(), info.properties.get(b"hw_rev").decode(), info.parsed_addresses()[0]]
for col in range(0, len(self.device_list.column_headings)):
self.device_list.SetColumnWidth(col, wx.LIST_AUTOSIZE_USEHEADER)
elif state == "Removed": elif state == "Removed":
if index != wx.NOT_FOUND: if index != wx.NOT_FOUND:
self.device_list.DeleteItem(index) self.device_list.DeleteItem(index)
@ -180,11 +216,12 @@ class BTClockOTAUpdater(wx.Frame):
espota.serve(address, "0.0.0.0", 3232, random.randint(10000,60000), "", firmware_file, type, self.call_progress) espota.serve(address, "0.0.0.0", 3232, random.randint(10000,60000), "", firmware_file, type, self.call_progress)
wx.CallAfter(self.update_progress, 100) wx.CallAfter(self.update_progress, 100)
self.currentlyUpdating = False
self.SetStatusText(f"Finished!") self.SetStatusText(f"Finished!")
def call_progress(self, progress): def call_progress(self, progress):
progressPerc = int(progress*100) progressPerc = int(progress*100)
self.SetStatusText(f"Progress: {progressPerc}%") self.SetStatusText(f"{self.updatingName} - Progress: {progressPerc}%")
wx.CallAfter(self.update_progress, progress) wx.CallAfter(self.update_progress, progress)
def update_progress(self, progress): def update_progress(self, progress):
@ -196,6 +233,10 @@ class BTClockOTAUpdater(wx.Frame):
if selected_index != -1: if selected_index != -1:
service_name = self.device_list.GetItemText(selected_index, 0) service_name = self.device_list.GetItemText(selected_index, 0)
info = self.listener.services.get(service_name) info = self.listener.services.get(service_name)
if self.currentlyUpdating:
wx.MessageBox("Please wait, already updating", "Error", wx.ICON_ERROR)
return
if info: if info:
address = info.parsed_addresses()[0] if info.parsed_addresses() else "N/A" address = info.parsed_addresses()[0] if info.parsed_addresses() else "N/A"
self.start_fs_update(address) self.start_fs_update(address)
@ -213,6 +254,9 @@ class BTClockOTAUpdater(wx.Frame):
local_filename = f"firmware/{self.release_name}_{model_name}_firmware.bin" local_filename = f"firmware/{self.release_name}_{model_name}_firmware.bin"
self.updatingName = address
self.currentlyUpdating = True
if os.path.exists(os.path.abspath(local_filename)): if os.path.exists(os.path.abspath(local_filename)):
thread = Thread(target=self.run_fs_update, args=(address, os.path.abspath(local_filename), FLASH)) thread = Thread(target=self.run_fs_update, args=(address, os.path.abspath(local_filename), FLASH))
thread.start() thread.start()
@ -222,6 +266,9 @@ class BTClockOTAUpdater(wx.Frame):
self.SetStatusText(f"Starting filesystem update") self.SetStatusText(f"Starting filesystem update")
local_filename = f"firmware/{self.release_name}_littlefs.bin" local_filename = f"firmware/{self.release_name}_littlefs.bin"
self.updatingName = address
self.currentlyUpdating = True
if os.path.exists(os.path.abspath(local_filename)): if os.path.exists(os.path.abspath(local_filename)):
thread = Thread(target=self.run_fs_update, args=(address, os.path.abspath(local_filename), SPIFFS)) thread = Thread(target=self.run_fs_update, args=(address, os.path.abspath(local_filename), SPIFFS))
thread.start() thread.start()
@ -267,7 +314,15 @@ class BTClockOTAUpdater(wx.Frame):
response = requests.get(ref_url) response = requests.get(ref_url)
response.raise_for_status() response.raise_for_status()
ref_info = response.json() ref_info = response.json()
self.commit_hash = ref_info["object"]["sha"] if (ref_info["object"]["type"] == "commit"):
self.commit_hash = ref_info["object"]["sha"]
else:
tag_url = f"https://api.github.com/repos/{repo}/git/tags/{ref_info["object"]["sha"]}"
response = requests.get(tag_url)
response.raise_for_status()
tag_info = response.json()
self.commit_hash = tag_info["object"]["sha"]
self.fw_label.SetLabelText(f"Downloaded firmware version: {self.release_name}\nCommit: {self.commit_hash}") self.fw_label.SetLabelText(f"Downloaded firmware version: {self.release_name}\nCommit: {self.commit_hash}")
@ -310,4 +365,4 @@ class BTClockOTAUpdater(wx.Frame):
dlg.Destroy() dlg.Destroy()
def OnExit(self,e): def OnExit(self,e):
self.Close(True) self.Close(False)