Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
4101cba
Initial STM32 Ethernet support
pmantoine Aug 8, 2024
30dfc65
STM32 upload now done via SWD serial instead of DFU
pmantoine Aug 30, 2024
9610828
Added MDNS and STM32Ethernet library support
pmantoine Oct 14, 2024
9be08b4
STM32 Windows driver now supported for Nucleo
Oct 15, 2024
5ecba2f
Fix F439 support and update version
pmantoine Oct 15, 2024
9b2d892
Win64 binary
Oct 15, 2024
ae8779c
MacOS universal binary
pmantoine Oct 15, 2024
378b1c3
Linux64 binary
pmantoine Oct 25, 2024
d3c7149
Test version of Win64 with 900 second timeout
Oct 26, 2024
28318fd
Fix builds for Mega etc.
pmantoine Nov 21, 2024
d585e0c
CSB1 wifi_led and booster support - nearly finished
pmantoine Nov 28, 2024
0c828d1
STM32 revert to DFU upload, ESP32 wifi_led
pmantoine Dec 2, 2024
2c4ede5
Win64 binary
Dec 2, 2024
f91ab91
MacOS ARM64 binary
pmantoine Dec 2, 2024
07cca4a
MacOS Universal binary
pmantoine Dec 2, 2024
d74b9e4
Updated STM32duino core to v2.9.0 for F4x9ZI Custom PeripheralPins
pmantoine Mar 4, 2025
742ee6f
Win64 EXE binary
Mar 5, 2025
6004e10
Initial testing success
peteGSX May 5, 2025
0625939
ISS Updates
peteGSX May 9, 2025
4a159d2
Initial testing success
peteGSX May 5, 2025
aca2720
ISS Updates
peteGSX May 9, 2025
fd880bd
Merge branch 'inno-setup' of https://github.com/peteGSX/EX-Installer-…
peteGSX May 9, 2025
5fb6918
Clean up
peteGSX May 9, 2025
1bf2043
Neaten up ISS
peteGSX May 10, 2025
06c1061
Update Inno Setup instructions
peteGSX May 11, 2025
699bb13
Merge pull request #194 from peteGSX:inno-setup
peteGSX May 11, 2025
e145d72
Start on release script
peteGSX May 12, 2025
ac9eda3
Release process notes
peteGSX May 13, 2025
3eb5387
Capture progress on release script
peteGSX May 14, 2025
7ae95d0
Capture release script progress
peteGSX May 14, 2025
b44684b
Release manager script done
peteGSX May 18, 2025
2c0c4c4
Remove excess print
peteGSX May 18, 2025
abd5f5d
Disable platforms, CSB1 note
peteGSX May 18, 2025
b9fcbb8
Merge pull request #195 from DCC-EX:disable-platform-sliders
peteGSX May 18, 2025
d8003e0
Nucleo Ethernet can now be disabled and wifi enabled
pmantoine May 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
GITHUB_TOKEN="personal_access_token"
REPO="DCC-EX/EX-Installer"
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ share/python-wheels/
*.egg
MANIFEST
.DS_Store
python/
dist/

# PyInstaller
# Usually these files are written by a python script from a template
Expand Down
47 changes: 47 additions & 0 deletions InnoSetup/INNOSETUP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Building and Distributing Windows Versions with Inno Setup

As of version 0.0.21, EX-Installer will no long be distributed as a single .exe built with PyInstaller due to the myriad of issues encountered with anti-virus applications and Windows Defender.

Instead, [Inno Setup](https://jrsoftware.org/isinfo.php) is used to build an installer, which users can use to install EX-Installer.

Given this will no longer provide a standalone, independent version of Python, [WinPython](https://winpython.github.io/) is included in the installer built with Inno Setup. This mitigates users having to install Python when they don't know how, and also prevents conflicts with other existing versions.

## Building the Windows Installer

**NOTE** Until this part can be automated, you **must** manually edit `InnoSetup\ex-installer.iss` and set "MyAppVersion" to the current version of EX-Installer.

### WinPython

Download the WinPython zip file and copy the included "python" directory to the root of the EX-Installer directory. WinPython releases are [here](https://winpython.github.io/).

Use the latest stable 64bit zip file eg. "Winpython64-3.13.0dot.zip".

The copied "python" directory should be at the same level in the directory structure as "dist", "docs", "ex_installer", and "InnoSetup".

To reduce the size of the compiled .exe file, deleting the "python\Doc" directory is recommended.

### Install WinPython Requirements

Ensure the required Python packages are installed:

```
python\python.exe -m pip install -r InnoSetup\winpython-requirements.txt
```

Be careful to run this using the WinPython's python.exe, not any other installed version.

### Test EX-Installer

At this point, EX-Installer should run as a module with WinPython using:

```
python\python.exe -m ex_installer
```

### Inno Setup

Download and install [Inno Setup 6](https://jrsoftware.org/isdl.php) (6.4.3 at time of writing), and note there is a VSCode Extension "Inno Setup" that will help with syntax etc.

Open Inno Setup and open the file "InnoSetup\ex-installer.iss".

To compile the installer, simply click the "Compile" button. Provided there are no errors, "EX-Installer-Setup-Win64.exe" will be compiled and located in the "dist" folder, ready to be added to the release.
60 changes: 60 additions & 0 deletions InnoSetup/ex-installer.iss
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!

#define MyAppName "EX-Installer"
#define MyAppVersion "0.0.21"
#define MyAppPublisher "DCC-EX"
#define MyAppURL "https://dcc-ex.com"
#define MyModuleName "ex_installer"
#define MyIconFile "ex_installer\images\dccex.ico"
#define MyPython "python\pythonw.exe"
#define MyLicenseFile "LICENSE"
#define MyDCCEXLogo "ex_installer\images\dccex-logo.bmp"
#define MyImg "..\ex_installer\images"

[Setup]
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{D2F27D1F-526B-43FD-95A9-C210A82AC7CF}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={autopf}\{#MyAppName}
DefaultGroupName={#MyAppPublisher}
DisableDirPage=auto
DisableProgramGroupPage=auto
; Uncomment the following line to run in non administrative install mode (install for current user only).
;PrivilegesRequired=lowest
OutputBaseFilename="EX-Installer-Setup-Win64"
SolidCompression=yes
WizardStyle=modern
WizardImageFile="..\{#MyDCCEXLogo}"
WizardImageStretch=no
WizardSmallImageFile="{#MyImg}\dccex-58.bmp,{#MyImg}\dccex-71.bmp,{#MyImg}\dccex-85.bmp,{#MyImg}\dccex-103.bmp,{#MyImg}\dccex-112.bmp,{#MyImg}\dccex-129.bmp,{#MyImg}\dccex-147.bmp"
SetupIconFile="..\{#MyIconFile}"
OutputDir="..\dist"
ArchitecturesAllowed=x64compatible
ArchitecturesInstallIn64BitMode=x64compatible
LicenseFile="..\{#MyLicenseFile}"

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"

[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"

[Files]
Source: "..\python\*"; DestDir: "{app}\python"; Flags: recursesubdirs
Source: "..\{#MyModuleName}\*"; DestDir: "{app}\{#MyModuleName}"; Flags: recursesubdirs; Excludes: "__pycache__"
; NOTE: Don't use "Flags: ignoreversion" on any shared system files

[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyPython}"; WorkingDir: "{app}"; Parameters: "-m {#MyModuleName}"; IconFilename: "{app}\{#MyIconFile}"
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyPython}"; WorkingDir: "{app}"; Parameters: "-m {#MyModuleName}"; IconFilename: "{app}\{#MyIconFile}"

[Run]
Filename: "{app}\{#MyPython}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; WorkingDir: "{app}"; Parameters: "-m {#MyModuleName}"; Flags: shellexec postinstall skipifsilent
14 changes: 14 additions & 0 deletions InnoSetup/winpython-requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
certifi==2025.4.26
cffi==1.17.1
charset-normalizer==3.4.2
CTkMessagebox==2.7
customtkinter==5.2.2
darkdetect==0.8.0
idna==3.10
packaging==25.0
pillow==11.2.1
pycparser==2.22
pygit2==1.18.0
pyserial==3.5
requests==2.32.3
urllib3==2.4.0
81 changes: 63 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@ EX-Installer is a Python based, cross-platform installer for the various Arduino

Binaries will be made available to allow EX-Installer to be run on:

- Windows 10/11
- Linux graphical environments
- Windows 10/11 (64 bit only)
- Linux graphical environments (64 bit only, not Raspberry Pi)
- macOS

## What's in this repository?

This repository includes all source code of EX-Installer, along with related documentation and screen captures of the initial design ideas.

The binaries are kept in the /dist directory of the repository, and will also be hosted on the [DCC-EX website](https://dcc-ex.com).
The binaries are attached to each version's release of EX-Installer, and will also be linked from the [DCC-EX website](https://dcc-ex.com).

### EX-Installer-Configs repository
<!-- ### EX-Installer-Configs repository

In addition to this EX-Installer repository, there is a separate repository [EX-Installer-Configs](https://github.com/DCC-EX/EX-Installer-Configs) which contains various configuration information that EX-Installer relies on.

This enables product and device configuration information to be updated without necessarily needing to build a new release of EX-Installer binaries.
This enables product and device configuration information to be updated without necessarily needing to build a new release of EX-Installer binaries. -->

## Operating principles and modules

Expand All @@ -43,19 +43,19 @@ The main Python modules in use are:

## Supported products

Initially, EX-Installer will be focused on basic configuration and installation of EX-CommandStation only in order to be able to replace the previous version of EX-Installer.

Once stable, it will be expanded to be able to configure and install all of our Arduino based products including:
Currently, EX-Installer configures and installs:

- EX-CommandStation
- EX-IOExpander
- EX-Turntable

## Running EX-Installer

To run EX-Installer, simply download the appropriate executable or binary file for the Operating System in use.
To run EX-Installer on macOS or Linux, simply download the appropriate executable or binary file for the Operating System in use from the release.

On Windows, download the installation setup file "EX-Installer-Setup-Win64.exe" to install EX-Installer.

If downloading directly from GitHub, use the "raw" file download.
### Run as a Python module

Alternatively, if desired, it can be run using a local Python install as a Python module.

Expand All @@ -82,7 +82,9 @@ Once all binaries for a specific version have been built and published, a GitHub

## How to build binaries

PyInstaller is used to build Windows executables and binaries for Linux/macOS.
**NOTE** that for Windows users, InnoSetup is now used to distribute a setup file instead, refer to `InnoSetup\INNOSETUP.md` for details on how this works.

PyInstaller is used to build binaries for Linux/macOS.

The use of CustomTkinter dictates that some extra options need to be defined to ensure non-Python files are included in the binary, otherwise they will not execute correctly.

Expand All @@ -97,7 +99,7 @@ The script will refer to the "version.py" file mentioned above, so this needs to
To run the script, you need to pass the EX-Installer repository directory and the platform being built for:

```shell
python -m build_app -D <Directory path> -P <Win32|Win64|Linux64|macOS>
python -m build_app -D <Directory path> -P <Linux64|macOS>
```

### Building manually
Expand All @@ -109,17 +111,60 @@ These directories are referenced in the commands below:
- \<repository\> - This is the directory containing the locally cloned EX-Installer repository
- \<python version\> - This is the directory containing the Python version's local packages
- \<platform\> - This is the platform the binary is built for:
- Win64 - Windows 64 bit
- Win32 - Windows 32 bit
- Linux64 - Linux 64 bit
- macOS - macOS (64 bit only)

The build commands should be executed in a command prompt or terminal window in the directory containing the cloned repository.

Windows command:
Linux/macOS command:

`pyinstaller --windowed --clean --onefile --icon=ex_installer\images\dccex-logo.png ex_installer\__main__.py --name "EX-Installer-<platform>" --add-data "<repository>\ex_installer\images\*;images" --add-data "<repository>\ex_installer\theme\dcc-ex-theme.json;theme/." --add-data "<repository>\venv\Lib\site-packages\customtkinter;customtkinter"`
`pyinstaller --windowed --clean --onefile --icon=ex_installer/images/dccex-logo.png ex_installer/__main__.py --name "EX-Installer-<platform>" --add-data "<repository>/ex_installer/images/*:images" --add-data "<repository>/ex_installer/theme/dcc-ex-theme.json:theme/." --add-data "<repository>/venv/lib/python3.8/site-packages/customtkinter:customtkinter" --hidden-import="PIL._tkinter_finder"`

Linux command:
## EX-Installer Release Manager

`pyinstaller --windowed --clean --onefile --icon=ex_installer/images/dccex-logo.png ex_installer/__main__.py --name "EX-Installer-<platform>" --add-data "<repository>/ex_installer/images/*:images" --add-data "<repository>/ex_installer/theme/dcc-ex-theme.json:theme/." --add-data "<repository>/venv/lib/python3.8/site-packages/customtkinter:customtkinter" --hidden-import="PIL._tkinter_finder"`
To simplify the release process and ensure releases are consistent, use the provided script "ex_installer_release.py".

This script automates the release management process for EX-Installer and takes care of:

- Creating the required GitHub tag
- Creating the required GitHub release
- Uploading the required distribution files to the release
- Publishing the release

Each release will be versioned consistently based on the version defined in "ex_installer/version.py":

- Releases 0.y.z will automatically be marked "Devel"
- Releases 1.y.z or later, where y is an even number will be marked "Prod"
- Releases 1.y.z or later, where y is an odd number will be marked "Devel"

Examples:

- 0.0.21 will become "v0.0.21-Devel"
- 1.0.0 will become "v1.0.0-Prod"
- 1.1.0 will become "v1.1.0-Devel"

### Running the script

To run this script, you must copy the provided '.env.example' file to '.env' and update it.

It must contain a valid GitHub personal access token with these privileges on the DCC-EX/EX-Installer repository:

- Contents - read/write
- Deployments - read/write
- Metadata - read

When running this script, you must specify at least one of:

- -F|--files: A comma separated list of files to upload, which must be located in your local EX-Installer/dist folder
- -D|--delete: A file to be deleted from the release
- -P|--publish: If specified, the release will be published, otherwise it will be created as a draft

Note: You cannot specify both -F|--files and -D|--delete at the same time.

To publish an EX-Installer release, three distribution files are expected to be attached as assets:

- EX-Installer-Linux64 - 64bit Linux binary
- EX-Installer-macOS - macOS binary
- EX-Installer-Setup-Win64.exe - Windows 64bit installer executable built by Inno Setup

When publishing, if any of these are not present, a warning will be generated, with a prompt to continue or cancel.
4 changes: 2 additions & 2 deletions build_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
# Create the argument parser and add the various required arguments
parser = argparse.ArgumentParser()

parser.add_argument("-P", "--platform", help="Platform type: Win32|Win64|Linux64|macOS",
choices=["Win32", "Win64", "Linux64", "macOS"], required=True,
parser.add_argument("-P", "--platform", help="Platform type: Linux64|macOS",
choices=["Linux64", "macOS"], required=True,
dest="platform")
parser.add_argument("-D", "--directory", help="Directory containing the cloned repository and virtual environment",
required=True,
Expand Down
Binary file removed dist/EX-Installer-Linux64
Binary file not shown.
Binary file removed dist/EX-Installer-Win32.exe
Binary file not shown.
Binary file removed dist/EX-Installer-Win64.exe
Binary file not shown.
Binary file removed dist/EX-Installer-macOS
Binary file not shown.
28 changes: 20 additions & 8 deletions ex_installer/arduino_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,17 +247,17 @@ class ArduinoCLI:
}

- ESP32 locked to 2.0.17 as 3.x causes compile errors for EX-CommandStation
- STM32 locked to 2.7.1 because 2.8.0 introduces new output that needs logic to deal with
- STM32 locked to 2.9.0 as 2.8.0 introduced new output that needs logic to deal with, and 2.9.0 supports F429ZI/F439ZI variants
"""
extra_platforms = {
"Espressif ESP32": {
"Espressif ESP32 (EX-CSB1)": {
"platform_id": "esp32:esp32",
"version": "2.0.17",
"url": "https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json"
},
"STMicroelectronics Nucleo/STM32": {
"STMicroelectronics (Nucleo/STM32F4xx)": {
"platform_id": "STMicroelectronics:stm32",
"version": "2.7.1",
"version": "2.9.0",
"url": "https://github.com/stm32duino/BoardManagerFiles/raw/main/package_stmicroelectronics_index.json"
}
}
Expand All @@ -274,20 +274,25 @@ class ArduinoCLI:
Note that these were previously an attribute of a product in the product_details module but are now here.
"""
arduino_libraries = {
"STM32duino STM32Ethernet": "1.4.0",
"MDNS_Generic": "1.4.2",
"Ethernet": "2.0.2"
}

"""
Dictionary of devices supported with EX-Installer to enable selection when detecting unknown devices.
"""
supported_devices = {
"DCC-EX EX-CSB1": "esp32:esp32:esp32",
"Arduino Mega or Mega 2560": "arduino:avr:mega",
"Arduino Uno": "arduino:avr:uno",
"Arduino Nano": "arduino:avr:nano",
"DCC-EX EX-CSB1": "esp32:esp32:esp32",
"ESP32 Dev Kit": "esp32:esp32:esp32",
"STMicroelectronics Nucleo F411RE": "STMicroelectronics:stm32:Nucleo_64:pnum=NUCLEO_F411RE",
"STMicroelectronics Nucleo F446RE": "STMicroelectronics:stm32:Nucleo_64:pnum=NUCLEO_F446RE"
"STMicroelectronics Nucleo F446RE": "STMicroelectronics:stm32:Nucleo_64:pnum=NUCLEO_F446RE",
"STMicroelectronics Nucleo F446ZE": "STMicroelectronics:stm32:Nucleo_144:pnum=NUCLEO_F446ZE",
"STMicroelectronics Nucleo F429ZI": "STMicroelectronics:stm32:Nucleo_144:pnum=NUCLEO_F429ZI",
"STMicroelectronics Nucleo F439ZI": "STMicroelectronics:stm32:Nucleo_144:pnum=NUCLEO_F439ZI"
}

"""
Expand Down Expand Up @@ -539,9 +544,16 @@ def upload_sketch(self, file_path, fqbn, port, sketch_dir, queue):
"""
Compiles and uploads the sketch in the specified directory to the provided board/port.
"""
params = ["upload", "-v", "-t", "-b", fqbn, "-p", port, sketch_dir, "--format", "jsonmini"]
if fqbn.startswith('esp32:esp32'):
params = params + ["--board-options", "UploadSpeed=115200"]
params = ["upload", "-v", "-t", "-b", fqbn, "-p", port, sketch_dir, "--format", "jsonmini"] #, "--before", "default_reset", "--after", "hard_reset"]
params = params + ["--board-options", "UploadSpeed=115200"]#, "--before", "default_reset", "--after", "hard_reset"] # upload speeds of 230400 and 460800 are possible, but for now go slow
elif fqbn.startswith('STMicroelectronics:stm32:'):
fqbn_nucleo = fqbn
# fqbn_nucleo += ",upload_method=swdMethod" # this allows use of SWD upload, sadly this requires STM32CubeProgrammer to be installed
# defaults to using DFU upload as a "virtual USB disk"
params = ["upload", "-v", "-t", "-b", fqbn_nucleo, "-p", port, sketch_dir, "--format", "jsonmini"]
else:
params = ["upload", "-v", "-t", "-b", fqbn, "-p", port, sketch_dir, "--format", "jsonmini"]
acli = ThreadedArduinoCLI(file_path, params, queue)
acli.start()

Expand Down
Loading
Loading