Compare commits

...

2 Commits

Author SHA1 Message Date
Brent Perteet
19e8ca30c3 everything working and tested on separate computer 2025-10-27 18:27:55 -05:00
Brent Perteet
de7041c1f5 EXE working but getting logging error 2025-10-25 11:52:11 -05:00
3 changed files with 96 additions and 32 deletions

View File

@@ -0,0 +1,9 @@
{
"permissions": {
"allow": [
"Bash(python:*)"
],
"deny": [],
"ask": []
}
}

View File

@@ -6,8 +6,14 @@ block_cipher = None
import os
import sys
# Hardcode the venv esptool path since PyInstaller might run from different env
esptool_dir = os.path.join(os.path.dirname(SPECPATH), 'venv', 'Lib', 'site-packages', 'esptool')
# Find esptool installation dynamically
try:
import esptool
esptool_dir = os.path.dirname(esptool.__file__)
print(f"Found esptool at: {esptool_dir}")
except ImportError:
print("Warning: esptool not found, stub files will not be included")
esptool_dir = None
# Build datas list - include all esptool data files
datas_list = [
@@ -16,8 +22,10 @@ datas_list = [
]
# Add esptool targets directory (includes stub_flasher JSON files)
if os.path.exists(os.path.join(esptool_dir, 'targets')):
datas_list.append((os.path.join(esptool_dir, 'targets'), 'esptool/targets'))
if esptool_dir and os.path.exists(os.path.join(esptool_dir, 'targets')):
targets_dir = os.path.join(esptool_dir, 'targets')
datas_list.append((targets_dir, 'esptool/targets'))
print(f"Including esptool targets from: {targets_dir}")
a = Analysis(
['web_flasher.py'],

View File

@@ -177,6 +177,8 @@ def flash_worker(temp_dir, port, chip, baud, flash_mode, flash_freq, flash_size)
"""Background worker for flashing firmware"""
global flash_status
import re
import io
from contextlib import redirect_stdout, redirect_stderr
try:
# Define file paths
@@ -194,9 +196,8 @@ def flash_worker(temp_dir, port, chip, baud, flash_mode, flash_freq, flash_size)
flash_status['running'] = False
return
# Build esptool command
cmd = [
sys.executable, "-m", "esptool",
# Build esptool command arguments
esptool_args = [
"--chip", chip,
"--port", port,
"--baud", baud,
@@ -212,48 +213,88 @@ def flash_worker(temp_dir, port, chip, baud, flash_mode, flash_freq, flash_size)
"0x8000", partition
]
flash_status['output'].append(f"Running: {' '.join(cmd)}")
flash_status['output'].append(f"Running esptool with args: {' '.join(esptool_args)}")
flash_status['output'].append("")
# Run esptool
process = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
bufsize=1,
universal_newlines=True
)
# Import and run esptool directly (works in both script and EXE)
import esptool
# Fix esptool data path for PyInstaller
if getattr(sys, 'frozen', False):
# Running as compiled executable
bundle_dir = sys._MEIPASS
esptool_targets = os.path.join(bundle_dir, 'esptool', 'targets')
if os.path.exists(esptool_targets):
# Override esptool's resource path
esptool.RESOURCES_DIR = bundle_dir
# Capture stdout/stderr
output_buffer = io.StringIO()
# Backup original sys.argv and replace with our arguments
original_argv = sys.argv
sys.argv = ['esptool.py'] + esptool_args
# Run esptool and capture output
return_code = 0
# Regex to parse progress lines
# Example: "Writing at 0x0011325c... (85 %)"
# or "Writing at 0x0011325c [========================> ] 85.3% 622592/730050 bytes..."
progress_pattern = re.compile(r'(\d+(?:\.\d+)?)\s*%')
# Stream output
for line in process.stdout:
line_stripped = line.rstrip()
flash_status['output'].append(line_stripped)
# Save original stdout/stderr
original_stdout = sys.stdout
original_stderr = sys.stderr
# Try to extract progress percentage
match = progress_pattern.search(line_stripped)
if match:
try:
percent = float(match.group(1))
flash_status['progress'] = percent
except ValueError:
try:
# Custom output class to capture and stream esptool output
class OutputCapture:
def __init__(self):
self.buffer = []
def write(self, text):
if text and text.strip():
lines = text.rstrip().split('\n')
for line in lines:
flash_status['output'].append(line)
self.buffer.append(line)
# Try to extract progress percentage
match = progress_pattern.search(line)
if match:
try:
percent = float(match.group(1))
flash_status['progress'] = percent
except ValueError:
pass
return len(text)
def flush(self):
pass
process.wait()
capture = OutputCapture()
if process.returncode == 0:
# Redirect stdout/stderr to our capture object
with redirect_stdout(capture), redirect_stderr(capture):
esptool.main()
except SystemExit as e:
return_code = e.code if e.code is not None else 0
finally:
# Restore original sys.argv and stdout/stderr
sys.argv = original_argv
sys.stdout = original_stdout
sys.stderr = original_stderr
if return_code == 0:
flash_status['output'].append("")
flash_status['output'].append("✓ Flash completed successfully!")
flash_status['success'] = True
flash_status['progress'] = 100
else:
flash_status['output'].append("")
flash_status['output'].append(f"✗ Flash failed with return code {process.returncode}")
flash_status['output'].append(f"✗ Flash failed with return code {return_code}")
flash_status['success'] = False
except Exception as e:
@@ -274,6 +315,12 @@ def open_browser(port):
def main():
"""Run the web server"""
import logging
# Disable Flask request logging to avoid colorama issues with stdout redirection
log = logging.getLogger('werkzeug')
log.setLevel(logging.ERROR)
port = get_free_port()
print(f"Starting ESP32 Flasher on port {port}...")
print(f"Open your browser to: http://127.0.0.1:{port}")
@@ -286,7 +333,7 @@ def main():
# Run Flask server with SocketIO
try:
socketio.run(app, host='127.0.0.1', port=port, debug=False, allow_unsafe_werkzeug=True)
socketio.run(app, host='127.0.0.1', port=port, debug=False, allow_unsafe_werkzeug=True, log_output=False)
except KeyboardInterrupt:
print('\nShutting down...')
except SystemExit: