Compare commits

..

25 Commits
v2.2 ... master

Author SHA1 Message Date
Marcel Stör
0f1b1099b6
Update shields 2025-02-07 17:33:52 +01:00
Marcel Stör
2d5daab9f1 Migrate to esptool v4
Fixes #105
2025-01-30 22:27:32 +01:00
amelted
31584f693b Fix Windows hovering issue with popup (#104) 2024-07-14 22:27:28 +02:00
Marcel Stör
f22d7857a0 Version bumps 2024-07-14 22:27:28 +02:00
Marcel Stör
2fbc40315d Bump PyInstaller to 4.8
Fixes #77
2022-01-18 22:39:26 +01:00
Marcel Stör
eef9f3a58d Fix the Windows + Python 3.8+ + wxPython 4.1 locale issue
Fixes #78
2022-01-18 22:30:28 +01:00
Marcel Stör
4899c16d4e Properly embed version into executables 2021-04-10 16:47:33 +02:00
Marcel Stör
0122639652 Replace reload button
Use a regular one instead of the bitmap button.
2021-04-08 23:20:07 +02:00
Marcel Stör
d742c2ff13 Bump versions 2021-02-03 08:28:10 +01:00
Utkarsh Sethi
d7c61bd814
Bump Year (#59)
2020
2020-03-01 11:16:53 +01:00
Marcel Stör
1887e38bb1
Upgrade pyinstaller to 3.6 due to CVE-2019-16784 2020-02-22 22:41:26 +01:00
Marcel Stör
4954c93602 Upgrade GUI screen shot 2019-02-17 15:53:47 +01:00
Marcel Stör
4500d940ae Improve console text control by specifying font size in pixels not points 2019-02-17 15:05:42 +01:00
Marcel Stör
29b7193fcf Improve esptool command assembler to support " " in file paths 2019-02-17 15:00:00 +01:00
Marcel Stör
9dc749d768 Bump versions 2019-02-12 22:18:06 +01:00
Marcel Stör
6b4a50835a Bump wxPython to 4.0.4
Fixes #45
2019-02-12 21:59:12 +01:00
Marcel Stör
0345939f08 Bump esptool.py to 2.6
Fixes #43
2019-02-12 21:27:32 +01:00
Marcel Stör
c8bfcc11f2 Bump year 2019-02-12 21:25:09 +01:00
Murilo Polese
fd0122053c Add requirements.txt and update instructions (#40) 2018-11-23 12:09:22 +01:00
Marcel Stör
0e5e250ade Reintroduce the serial port dropdown, add auto-select option 2018-11-22 21:17:51 +01:00
Marcel Stör
861f75415c Upgrade to esptool 2.5.1 with auto-port detection
Remove dropdown for serial port selection.
2018-11-12 23:39:23 +01:00
Marcel Stör
6df7c813e2 Add missing EOF newline 2018-02-12 21:32:54 +01:00
Marcel Stör
cb3606e00d Add .dmg for macOS 2018-02-11 00:54:09 +01:00
Marcel Stör
0fd2b7b7f7 Update to reflect status with 3.0 2018-02-10 17:41:29 +01:00
Marcel Stör
2eeb9893db Major upgrade of all components
- wxPython 4.0.1, finally...
- Python 3
- esptool.py 2.2.1
2018-02-10 00:05:03 +01:00
14 changed files with 296 additions and 2739 deletions

2
.gitignore vendored
View File

@ -1,4 +1,5 @@
.idea/
.DS_Store
# Byte-compiled / optimized / DLL files
__pycache__/
@ -83,6 +84,7 @@ celerybeat-schedule
# virtualenv
venv/
ENV/
.venv
# Spyder project settings
.spyderproject

View File

@ -1,7 +1,10 @@
# coding=utf-8
import sys, os, wx
import sys
import datetime
import os
import wx
import wx.html
import wx.lib.wxpTag
import webbrowser
@ -29,10 +32,12 @@ class AboutDlg(wx.Dialog):
<p>
As with everything I offer for free, this is donation-ware.
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=HFN4ZMET5XS2Q"><img src="{0}/images/paypal-256.png" width="256" height="88" alt="Donate with PayPal"></a>
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=HFN4ZMET5XS2Q">
<img src="{0}/images/paypal-256.png" width="256" height="88" alt="Donate with PayPal">
</a>
</p>
<p>&copy; 2017 Marcel St&ouml;r. Licensed under MIT.</p>
<p>&copy; {2} Marcel St&ouml;r. Licensed under MIT.</p>
<p>
<wxp module="wx" class="Button">
@ -50,16 +55,18 @@ class AboutDlg(wx.Dialog):
html = HtmlWindow(self, wx.ID_ANY, size=(420, -1))
if "gtk2" in wx.PlatformInfo or "gtk3" in wx.PlatformInfo:
html.SetStandardFonts()
txt = self.text.format(self._get_bundle_dir(), __version__)
txt = self.text.format(self._get_bundle_dir(), __version__, datetime.datetime.now().year)
html.SetPage(txt)
ir = html.GetInternalRepresentation()
html.SetSize((ir.GetWidth() + 25, ir.GetHeight() + 25))
self.SetClientSize(html.GetSize())
self.CentreOnParent(wx.BOTH)
def _get_bundle_dir(self):
@staticmethod
def _get_bundle_dir():
# set by PyInstaller, see http://pyinstaller.readthedocs.io/en/v3.2/runtime-information.html
if getattr(sys, 'frozen', False):
# noinspection PyUnresolvedReferences,PyProtectedMember
return sys._MEIPASS
else:
return os.path.dirname(os.path.abspath(__file__))

View File

@ -27,4 +27,4 @@ class HtmlPopupTransientWindow(wx.PopupTransientWindow):
def OnLinkClicked(self, link):
# get a hold of the PopupTransientWindow to close it
self.GetParent().GetParent().Dismiss()
webbrowser.open(link.GetHref())
webbrowser.open(link.GetHref())

157
Main.py
View File

@ -1,20 +1,24 @@
#!/usr/bin/env python
import wx
import wx.adv
import wx.lib.inspection
import wx.lib.mixins.inspection
import sys, os
import sys
import os
import esptool
import threading
import json
import images as images
from serial import SerialException
from serial.tools import list_ports
from esptool import ESPLoader
from esptool import NotImplementedInROMError
from argparse import Namespace
import locale
__version__ = "2.2"
# see https://discuss.wxpython.org/t/wxpython4-1-1-python3-8-locale-wxassertionerror/35168
locale.setlocale(locale.LC_ALL, 'C')
__version__ = "5.1.0"
__flash_help__ = '''
<p>This setting is highly dependent on your device!<p>
<p>
@ -29,6 +33,8 @@ __flash_help__ = '''
</ul>
</p>
'''
__auto_select__ = "Auto-select"
__auto_select_explanation__ = "(first port with Espressif device)"
__supported_baud_rates__ = [9600, 57600, 74880, 115200, 230400, 460800, 921600]
# ---------------------------------------------------------------------------
@ -50,9 +56,16 @@ class RedirectText:
else:
wx.CallAfter(self.__out.AppendText, string)
# noinspection PyMethodMayBeStatic
def flush(self):
# noinspection PyStatementEffect
None
# esptool >=3 handles output differently of the output stream is not a TTY
# noinspection PyMethodMayBeStatic
def isatty(self):
return True
# ---------------------------------------------------------------------------
@ -66,43 +79,36 @@ class FlashingThread(threading.Thread):
def run(self):
try:
initial_baud = min(ESPLoader.ESP_ROM_BAUD, self._config.baud)
command = []
esp = ESPLoader.detect_chip(self._config.port, initial_baud)
print("Chip is %s" % (esp.get_chip_description()))
if not self._config.port.startswith(__auto_select__):
command.append("--port")
command.append(self._config.port)
esp = esp.run_stub()
if self._config.baud > initial_baud:
try:
esp.change_baud(self._config.baud)
except NotImplementedInROMError:
print("WARNING: ROM doesn't support changing baud rate. Keeping initial baud rate %d." %
initial_baud)
args = Namespace()
args.flash_size = "detect"
args.flash_mode = self._config.mode
args.flash_freq = "40m"
args.no_progress = False
args.no_stub = False
args.verify = False # TRUE is deprecated
args.compress = True
args.addr_filename = [[int("0x00000", 0), open(self._config.firmware_path, 'rb')]]
print("Configuring flash size...")
esptool.detect_flash_size(esp, args)
esp.flash_set_parameters(esptool.flash_size_bytes(args.flash_size))
command.extend(["--baud", str(self._config.baud),
"--after", "no_reset",
"write_flash",
# https://github.com/espressif/esptool/issues/599
"--flash_size", "detect",
"--flash_mode", self._config.mode,
"0x00000", self._config.firmware_path])
if self._config.erase_before_flash:
esptool.erase_flash(esp, args)
esptool.write_flash(esp, args)
# The last line printed by esptool is "Leaving..." -> some indication that the process is done is needed
print("\nDone.")
command.append("--erase-all")
print("Command: esptool.py %s\n" % " ".join(command))
esptool.main(command)
# The last line printed by esptool is "Staying in bootloader." -> some indication that the process is
# done is needed
print("\nFirmware successfully flashed. Unplug/replug or reset device \nto switch back to normal boot "
"mode.")
except SerialException as e:
self._parent.report_error(e.strerror)
raise e
# ---------------------------------------------------------------------------
@ -148,7 +154,7 @@ class FlashConfig:
class NodeMcuFlasher(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, -1, title, size=(700, 650),
wx.Frame.__init__(self, parent, -1, title, size=(725, 650),
style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE)
self._config = FlashConfig.load(self._get_config_file_path())
@ -159,9 +165,11 @@ class NodeMcuFlasher(wx.Frame):
sys.stdout = RedirectText(self.console_ctrl)
self.SetMinSize((640, 480))
self.Centre(wx.BOTH)
self.Show(True)
print("Connect your device")
print("\nIf you chose the serial port auto-select feature you might need to ")
print("turn off Bluetooth")
def _init_ui(self):
def on_reload(event):
@ -199,6 +207,15 @@ class NodeMcuFlasher(wx.Frame):
panel = wx.Panel(self)
# Fix popup that never goes away.
def onHover(event):
global hovered
if(len(hovered) != 0 ):
hovered[0].Dismiss()
hovered = []
panel.Bind(wx.EVT_MOTION,onHover)
hbox = wx.BoxSizer(wx.HORIZONTAL)
fgs = wx.FlexGridSizer(7, 2, 10, 10)
@ -206,19 +223,17 @@ class NodeMcuFlasher(wx.Frame):
self.choice = wx.Choice(panel, choices=self._get_serial_ports())
self.choice.Bind(wx.EVT_CHOICE, on_select_port)
self._select_configured_port()
bmp = images.Reload.GetBitmap()
reload_button = wx.BitmapButton(panel, id=wx.ID_ANY, bitmap=bmp,
size=(bmp.GetWidth() + 7, bmp.GetHeight() + 7))
reload_button = wx.Button(panel, label="Reload")
reload_button.Bind(wx.EVT_BUTTON, on_reload)
reload_button.SetToolTipString("Reload serial device list")
reload_button.SetToolTip("Reload serial device list")
file_picker = wx.FilePickerCtrl(panel, style=wx.FLP_USE_TEXTCTRL)
file_picker.Bind(wx.EVT_FILEPICKER_CHANGED, on_pick_file)
serial_boxsizer = wx.BoxSizer(wx.HORIZONTAL)
serial_boxsizer.Add(self.choice, 1, wx.EXPAND)
serial_boxsizer.AddStretchSpacer(0)
serial_boxsizer.Add(reload_button, 0, wx.ALIGN_RIGHT, 20)
serial_boxsizer.Add(self.choice, 1, wx.EXPAND)
serial_boxsizer.Add(reload_button, flag=wx.LEFT, border=10)
baud_boxsizer = wx.BoxSizer(wx.HORIZONTAL)
@ -269,10 +284,11 @@ class NodeMcuFlasher(wx.Frame):
button.Bind(wx.EVT_BUTTON, on_clicked)
self.console_ctrl = wx.TextCtrl(panel, style=wx.TE_MULTILINE | wx.TE_READONLY | wx.HSCROLL)
self.console_ctrl.SetFont(wx.Font(13, wx.FONTFAMILY_TELETYPE, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL))
self.console_ctrl.SetBackgroundColour(wx.BLACK)
self.console_ctrl.SetForegroundColour(wx.RED)
self.console_ctrl.SetDefaultStyle(wx.TextAttr(wx.RED))
self.console_ctrl.SetFont(wx.Font((0, 13), wx.FONTFAMILY_TELETYPE, wx.FONTSTYLE_NORMAL,
wx.FONTWEIGHT_NORMAL))
self.console_ctrl.SetBackgroundColour(wx.WHITE)
self.console_ctrl.SetForegroundColour(wx.BLUE)
self.console_ctrl.SetDefaultStyle(wx.TextAttr(wx.BLUE))
port_label = wx.StaticText(panel, label="Serial port")
file_label = wx.StaticText(panel, label="NodeMCU firmware")
@ -280,15 +296,19 @@ class NodeMcuFlasher(wx.Frame):
flashmode_label = wx.StaticText(panel, label="Flash mode")
def on_info_hover(event):
from HtmlPopupTransientWindow import HtmlPopupTransientWindow
win = HtmlPopupTransientWindow(self, wx.SIMPLE_BORDER, __flash_help__, "#FFB6C1", (410, 140))
global hovered
if(len(hovered) == 0):
from HtmlPopupTransientWindow import HtmlPopupTransientWindow
win = HtmlPopupTransientWindow(self, wx.SIMPLE_BORDER, __flash_help__, "#FFB6C1", (410, 140))
image = event.GetEventObject()
image_position = image.ClientToScreen((0, 0))
image_size = image.GetSize()
win.Position(image_position, (0, image_size[1]))
image = event.GetEventObject()
image_position = image.ClientToScreen((0, 0))
image_size = image.GetSize()
win.Position(image_position, (0, image_size[1]))
win.Popup()
hovered = [win]
win.Popup()
icon = wx.StaticBitmap(panel, wx.ID_ANY, images.Info.GetBitmap())
icon.Bind(wx.EVT_MOTION, on_info_hover)
@ -296,7 +316,7 @@ class NodeMcuFlasher(wx.Frame):
flashmode_label_boxsizer = wx.BoxSizer(wx.HORIZONTAL)
flashmode_label_boxsizer.Add(flashmode_label, 1, wx.EXPAND)
flashmode_label_boxsizer.AddStretchSpacer(0)
flashmode_label_boxsizer.Add(icon, 0, wx.ALIGN_RIGHT, 20)
flashmode_label_boxsizer.Add(icon)
erase_label = wx.StaticText(panel, label="Erase flash")
console_label = wx.StaticText(panel, label="Console")
@ -322,8 +342,9 @@ class NodeMcuFlasher(wx.Frame):
break
count += 1
def _get_serial_ports(self):
ports = [""]
@staticmethod
def _get_serial_ports():
ports = [__auto_select__ + " " + __auto_select_explanation__]
for port, desc, hwid in sorted(list_ports.comports()):
ports.append(port)
return ports
@ -332,7 +353,7 @@ class NodeMcuFlasher(wx.Frame):
self.SetIcon(images.Icon.GetIcon())
def _build_status_bar(self):
self.statusBar = self.CreateStatusBar(2, wx.ST_SIZEGRIP)
self.statusBar = self.CreateStatusBar(2, wx.STB_SIZEGRIP)
self.statusBar.SetStatusWidths([-2, -1])
status_text = "Welcome to NodeMCU PyFlasher %s" % __version__
self.statusBar.SetStatusText(status_text, 0)
@ -356,7 +377,8 @@ class NodeMcuFlasher(wx.Frame):
self.SetMenuBar(self.menuBar)
def _get_config_file_path(self):
@staticmethod
def _get_config_file_path():
return wx.StandardPaths.Get().GetUserConfigDir() + "/nodemcu-pyflasher.json"
# Menu methods
@ -380,13 +402,14 @@ class NodeMcuFlasher(wx.Frame):
# ---------------------------------------------------------------------------
class MySplashScreen(wx.SplashScreen):
class MySplashScreen(wx.adv.SplashScreen):
def __init__(self):
wx.SplashScreen.__init__(self, images.Splash.GetBitmap(),
wx.SPLASH_CENTRE_ON_SCREEN | wx.SPLASH_TIMEOUT,
2500, None, -1)
global hovered
hovered = []
wx.adv.SplashScreen.__init__(self, images.Splash.GetBitmap(),
wx.adv.SPLASH_CENTRE_ON_SCREEN | wx.adv.SPLASH_TIMEOUT, 2500, None, -1)
self.Bind(wx.EVT_CLOSE, self._on_close)
self.__fc = wx.FutureCall(2000, self._show_main)
self.__fc = wx.CallLater(2000, self._show_main)
def _on_close(self, evt):
# Make sure the default handler runs too so this window gets
@ -412,7 +435,9 @@ class MySplashScreen(wx.SplashScreen):
# ----------------------------------------------------------------------------
class App(wx.App, wx.lib.mixins.inspection.InspectionMixin):
def OnInit(self):
wx.SystemOptions.SetOptionInt("mac.window-plain-transition", 1)
# see https://discuss.wxpython.org/t/wxpython4-1-1-python3-8-locale-wxassertionerror/35168
self.ResetLocale()
wx.SystemOptions.SetOption("mac.window-plain-transition", 1)
self.SetAppName("NodeMCU PyFlasher")
# Create and show the splash screen. It will then create and
@ -435,6 +460,8 @@ def main():
app.MainLoop()
# ---------------------------------------------------------------------------
if __name__ == '__main__':
__name__ = 'Main'
main()

View File

@ -1,23 +1,20 @@
# NodeMCU PyFlasher
[![License](https://marcelstoer.github.io/nodemcu-pyflasher/images/mit-license-badge.svg)](https://github.com/marcelstoer/nodemcu-pyflasher/blob/master/LICENSE)
[![Github Releases](https://img.shields.io/github/downloads/marcelstoer/nodemcu-pyflasher/total.svg?style=flat)](https://github.com/marcelstoer/nodemcu-pyflasher/releases)
[![PayPal Donation](https://marcelstoer.github.io/nodemcu-pyflasher/images/donate-paypal-badge.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=HFN4ZMET5XS2Q)
[![Twitter URL](https://marcelstoer.github.io/nodemcu-pyflasher/images/twitter-badge.svg)](https://twitter.com/intent/tweet?text=Wow:&url=https%3A%2F%2Fgithub.com%2Fmarcelstoer%2Fnodemcu-pyflasher)
[![Facebook URL](https://marcelstoer.github.io/nodemcu-pyflasher/images/facebook-badge.svg)](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fgithub.com%2Fmarcelstoer%2Fnodemcu-pyflasher)
[![Github Downloads (all assets, all releases)](https://img.shields.io/github/downloads/marcelstoer/nodemcu-pyflasher/total.svg?style=flat)](https://github.com/marcelstoer/nodemcu-pyflasher/releases)
[![GitHub Downloads (all assets, latest release)](https://img.shields.io/github/downloads/marcelstoer/nodemcu-pyflasher/latest/total?style=flat)](https://github.com/marcelstoer/nodemcu-pyflasher/releases)
[![PayPal Donation](https://img.shields.io/badge/donate_through-PayPal-%23009cde?logo=paypal)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=HFN4ZMET5XS2Q)
Self-contained [NodeMCU](https://github.com/nodemcu/nodemcu-firmware) flasher with GUI based on [esptool.py](https://github.com/espressif/esptool) and [wxPython](https://www.wxpython.org/).
![Image of NodeMCU PyFlasher GUI](images/gui.png)
## Installation
NodeMCU PyFlasher doesn't have to be installed, just double-click it and it'll start. Check the [releases section](https://github.com/marcelstoer/nodemcu-pyflasher/releases) for downloads for your platform. For every release there's at least a .exe file for Windows.
NodeMCU PyFlasher doesn't have to be installed, just double-click it and it'll start. Check the [releases section](https://github.com/marcelstoer/nodemcu-pyflasher/releases) for downloads for your platform. For every release there's at least a .exe file for Windows. Starting from 3.0 there's also a .dmg for macOS.
## Status
Scan the [list of open issues](https://github.com/marcelstoer/nodemcu-pyflasher/issues) for bugs and pending features.
- Due to [pyinstaller/pyinstaller#2355](https://github.com/pyinstaller/pyinstaller/issues/2355) I can't provide an app bundle for macOS yet. The PyInstaller `.spec` file and the build script are ready, though. Of course you can still *run* the application on macOS. Clone this repo and then do `python nodemcu-pyflasher.py` (see "[Build it yourself](#build-it-yourself)" for pre-requisits).
**Note**
**Note**
This is my first Python project. If you have constructive feedback as for how to improve the code please do reach out to me.
@ -32,9 +29,19 @@ All open-source development by the author is donationware. Show your love and su
## Build it yourself
If you want to build this application yourself you need to:
- Install Python
- Install [wxPython 3.x](https://sourceforge.net/projects/wxpython/files/wxPython/) (not 4.0 betas!)
- Install [esptool.py](https://github.com/espressif/esptool#easy-installation) which brings pySerial or install pySerial standalone
- Install [Python 3.x](https://www.python.org/downloads/) and [Pip](https://pip.pypa.io/en/stable/installing/) (it comes with Python if installed from `python.org`).
- Create a virtual environment with `python -m venv venv`
- Activate the virtual environment with `. venv/bin/activate` (`. venv/Scripts/activate` if you are on Windows with [Cygwin](https://www.cygwin.com/) or [Mingw](http://mingw.org/))
- Run `pip install -r requirements.txt`
**A note on Linux:** As described on the [downloads section of `wxPython`](https://www.wxpython.org/pages/downloads/), wheels for Linux are complicated and may require you to run something like this to install `wxPython` correctly:
```bash
# Assuming you are running it on Ubuntu 18.04 LTS with GTK3
pip install -U \
-f https://extras.wxpython.org/wxPython4/extras/linux/gtk3/ubuntu-18.04 \
wxPython
```
## Why this project exists

View File

@ -1,31 +1,60 @@
# -*- mode: python -*-
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
import os
# We need to add the flasher stub JSON files explicitly: https://github.com/espressif/esptool/issues/1059
venv_python_folder_name = next(d for d in os.listdir('./.venv/lib') if d.startswith('python') and os.path.isdir(os.path.join('./.venv/lib', d)))
local_stub_flasher_path = "./.venv/lib/{}/site-packages/esptool/targets/stub_flasher".format(venv_python_folder_name)
a = Analysis(['nodemcu-pyflasher.py'],
binaries=None,
datas=[("images", "images")],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
name='NodeMCU-PyFlasher',
debug=False,
strip=False,
upx=True,
console=False , icon='images/icon-256.icns')
app = BUNDLE(exe,
name='NodeMCU-PyFlasher.app',
icon='./images/icon-256.icns',
bundle_identifier='com.frightanic.nodemcu-pyflasher')
a = Analysis(
['nodemcu-pyflasher.py'],
pathex=[],
binaries=[],
datas=[
("images", "images"),
("{}/1".format(local_stub_flasher_path), "./esptool/targets/stub_flasher/1"),
("{}/2".format(local_stub_flasher_path), "./esptool/targets/stub_flasher/2")
],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
[],
exclude_binaries=True,
name='NodeMCU PyFlasher',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
coll = COLLECT(
exe,
a.binaries,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='NodeMCU PyFlasher',
icon='images/icon-256.icns'
)
app = BUNDLE(
coll,
name='NodeMCU PyFlasher.app',
version='5.1.0',
icon='images/icon-256.icns',
bundle_identifier='com.frightanic.nodemcu-pyflasher')

View File

@ -1,26 +1,46 @@
# -*- mode: python -*-
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
# We need to add the flasher stub JSON files explicitly: https://github.com/espressif/esptool/issues/1059
local_stub_flasher_path = "./.venv/Lib/site-packages/esptool/targets/stub_flasher"
a = Analysis(['nodemcu-pyflasher.py'],
binaries=[],
datas=[("images", "images")],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
name='NodeMCU-PyFlasher',
debug=False,
strip=False,
upx=True,
console=False , icon='images\\icon-256.ico')
a = Analysis(
['nodemcu-pyflasher.py'],
pathex=[],
binaries=[],
datas=[
("images", "images"),
("{}/1".format(local_stub_flasher_path), "./esptool/targets/stub_flasher/1"),
("{}/2".format(local_stub_flasher_path), "./esptool/targets/stub_flasher/2")
],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='NodeMCU-PyFlasher',
version='windows-version-info.txt',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
icon='images\\icon-256.ico',
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)

View File

@ -1,5 +1,13 @@
#!/usr/bin/env bash
#rm -fr build dist
# rm -fr build dist
VERSION=5.1.0
NAME="NodeMCU PyFlasher"
DIST_NAME="NodeMCU-PyFlasher"
pyinstaller --log-level=DEBUG \
--noconfirm \
build-on-mac.spec
# https://github.com/sindresorhus/create-dmg
create-dmg "dist/$NAME.app"
mv "$NAME $VERSION.dmg" "dist/$DIST_NAME.dmg"

View File

@ -1,12 +0,0 @@
If esptool.py is installed using python setup.py` from a checked out version it creates something like the following
in the Python environment
esptool.py file containing
#!/usr/local/opt/python/bin/python2.7
# EASY-INSTALL-SCRIPT: 'esptool==1.3.dev0','esptool.py'
__requires__ = 'esptool==1.3.dev0'
__import__('pkg_resources').run_script('esptool==1.3.dev0', 'esptool.py')
PyInstaller (and cx_Freeze) doesn't support pkg_resources and complains about 'ImportError: "No module named
pkg_resources"'. This can be avoided if the application maintains a local copy of esptool.py.

2592
esptool.py

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 405 KiB

After

Width:  |  Height:  |  Size: 83 KiB

6
requirements.txt Normal file
View File

@ -0,0 +1,6 @@
esptool==4.8.1
pyserial~=3.5
wxPython==4.2.2
PyInstaller==6.11.1
httplib2>=0.18.1
pyinstaller-versionfile>=2.0.0

9
windows-metadata.yaml Normal file
View File

@ -0,0 +1,9 @@
# https://github.com/DudeNr33/pyinstaller-versionfile
# create-version-file windows-metadata.yaml --outfile windows-version-info.txt
Version: 5.1.0
CompanyName: Marcel Stör
FileDescription: NodeMCU PyFlasher
InternalName: NodeMCU PyFlasher
LegalCopyright: © Marcel Stör. All rights reserved.
OriginalFilename: NodeMCU-PyFlasher.exe
ProductName: NodeMCU PyFlasher

46
windows-version-info.txt Normal file
View File

@ -0,0 +1,46 @@
# GENERATED FILE. DO NOT EDIT. Created by running create-version-file windows-metadata.yaml --outfile windows-version-info.txt
#
# UTF-8
#
# For more details about fixed file info 'ffi' see:
# http://msdn.microsoft.com/en-us/library/ms646997.aspx
VSVersionInfo(
ffi=FixedFileInfo(
# filevers and prodvers should be always a tuple with four items: (1, 2, 3, 4)
# Set not needed items to zero 0. Must always contain 4 elements.
filevers=(5,1,0,0),
prodvers=(5,1,0,0),
# Contains a bitmask that specifies the valid bits 'flags'r
mask=0x3f,
# Contains a bitmask that specifies the Boolean attributes of the file.
flags=0x0,
# The operating system for which this file was designed.
# 0x4 - NT and there is no need to change it.
OS=0x40004,
# The general type of file.
# 0x1 - the file is an application.
fileType=0x1,
# The function of the file.
# 0x0 - the function is not defined for this fileType
subtype=0x0,
# Creation date and time stamp.
date=(0, 0)
),
kids=[
StringFileInfo(
[
StringTable(
u'040904B0',
[StringStruct(u'CompanyName', u'Marcel Stör'),
StringStruct(u'FileDescription', u'NodeMCU PyFlasher'),
StringStruct(u'FileVersion', u'5.1.0.0'),
StringStruct(u'InternalName', u'NodeMCU PyFlasher'),
StringStruct(u'LegalCopyright', u'© Marcel Stör. All rights reserved.'),
StringStruct(u'OriginalFilename', u'NodeMCU-PyFlasher.exe'),
StringStruct(u'ProductName', u'NodeMCU PyFlasher'),
StringStruct(u'ProductVersion', u'5.1.0.0')])
]),
VarFileInfo([VarStruct(u'Translation', [1033, 1200])])
]
)