Code Library


Welcome (welcome.py)

class ex_installer.welcome.Welcome(*args: Any, **kwargs: Any)

Class for the Welcome view

set_text()

EX-Installer (ex_installer.py)

class ex_installer.ex_installer.EXInstaller(*args: Any, **kwargs: Any)

EX-Installer root window

about()

Message box popup for the Info -> About menu item

acli = <ex_installer.arduino_cli.ArduinoCLI object>
app_version = '0.0.20'
enable_fake_device()

If specified, enable a fake Arduino device

exception_handler(exc_type, exc_value, exc_traceback)

Handler for uncaught exceptions

git = <ex_installer.git_client.GitClient object>
instructions()

Link to EX-Installer instructions from the Info menu

news()

Link to DCC-EX News articles for EX-Installer

preferences = {}
save_preference(key, value)

Method to save the specified key/value pair to the user preference file

set_scaling()

Function to set the screen scaling value

switch_view(view_class, product=None, version=None)

Function to switch views

These views require a product parameter to be supplied: - compile_upload - select_version_config - advanced_config

These views should get version info if available: - ex_commandstation

Version should ideally contain semantic numbering, but any name will work If semantic numbering is used, the product configuration screens can determine options based on those numbers

For semantic numbering to work, it must match GitHub tag format: vX.Y.Z-Prod|Devel

Version info will be available in: self.product_version_name self.product_major_version self.product_minor_version self.product_patch_version

All default to None if not defined

toggle_debug()

Function to enable/disable debug logging from the menu

website()

Link to the DCC-EX website from the Info menu

Manage Arduino CLI (manage_arduino_cli.py)

class ex_installer.manage_arduino_cli.ManageArduinoCLI(*args: Any, **kwargs: Any)
_check_cli_version()

Method to check the version of CLI that is present (if installed).

If we need to start, call the acli.get_version() method.

If it was successful, call _get_platforms().

Any other status is an error.

_delete_cli()

Method to delete an unsupported version of the CLI if detected.

To enforce users only using the correct version of the CLI, old or newer versions must be deleted.

If successful, this must trigger the install process.

If unsuccessful, we must tell the users to close everything and try again, otherwise delete manually.

_download_cli()

Method to start downloading the Arduino CLI.

If we need to start, call the acli.download_cli() method.

If it was successful, call _extract_cli().

Any other status is an error.

_extract_cli()

Method to start extracting the Arduino CLI, which relies on the downloaded file being available in the process_data attribute.

If we need to start, call the acli.install_cli() method.

If it was successful, call _init_cli().

Any other status is an error.

_generate_check_cli()

Generates an event to start checking the state of the Arduino CLI.

For some reason this doesn’t generate the event, call check_arduino_cli method with None argument for now.

_generate_install_cli()

Generates an event to start installing the Arduino CLI.

_generate_refresh_cli()

Generates an event to start refreshing the Arduino CLI.

_get_installed_libraries()

Method to obtain the currently installed Arduino libraries.

If we need to start call the acli.get_libraries() method.

If successful:

  • If a library is installed at the specified version, mark installed

  • If a library is installed but not the specified version, mark as not_installed

  • If a library is not installed but should be, mark as not_installed

Any other status is an error.

_get_installed_platforms()

Method to obtain the currently installed Arduino platforms.

If we need to start call the acli.get_platforms() method.

If successful:

  • Set the extra_platforms_frame CTKSwitch widgets to the correct state

  • If a package is installed at the specified version, mark installed

  • If a package is installed but not the specified version, mark as not_installed

  • If a package is not installed but should be, mark as not_installed

Any other status is an error.

_get_library_install_count()

Get the number of libraries that need to be installed.

This is all libraries with state “not_installed”.

_get_package_install_count()

Get the number of packages that need to be installed.

This is all packages with state “not_installed” and selection “on”.

_init_cli()

Method to start the CLI initialisation process.

Note that this must cycle through each widget in the “extra_platforms_frame” frame to be able to flag each additional platform that needs to be installed.

If we need to start, call the acli.initialise_config() method.

If successful, call _update_core_index().

Any other status is an error.

_install_libraries()

Method to start installing the required libraries.

This needs to cycle through each library to install them.

If we need to start, call _install_single_library().

Any other status is an error.

_install_packages()

Method to process installing all required packages.

This needs to cycle through each package to install them.

If we need to start, call _install_single_package().

Any other status is an error.

_install_single_library(library_name, version)

Method to start installing the specified library.

Flag the library as installed here but that should be validated in a later version.

_install_single_package(package_name, platform_id, version)

Method to start installing the specified package.

We flag the package as installed here to prevent an endless loop, but this should be improved in future.

_process_error()

Method to deal with an error in the process.

_process_finished()

Method to finalise the processes on successful completion.

_refresh_boards()

Method to start refreshing the list of attached boards.

If we need to start, call the acli.list_boards() method.

If successful, call _process_finished().

Any other status is an error.

_update_core_index()

Method to start the core index update process.

If we need to start, call the acli.update_index() method.

If successful, call _upgrade_platforms().

Any other status is an error.

check_arduino_cli(event)

Check the version of the Arduino CLI, and if additional platforms are installed.

install_instruction_text = 'To install the Arduino CLI, simply click the install button.\n\nIf you are using an Espressif or STMicroelectronics device (as opposed to the more common Uno or Mega based Arduinos), you will need to enable support for these by selecting the appropriate additional platform option.\n\nNote that enabling additional platforms is likely to add several minutes to the installation process. Maybe grab a cup of tea or a coffee!'
installed_text = 'The Arduino CLI is installed'
intro_text = 'We use the Arduino Command Line Interface (CLI) to upload the DCC-EX products to your Arduino. The CLI eliminates the need to install the more daunting Arduino IDE. EX-Installer is able to manage the installation and updating of the Arduino CLI for you at the click of a button.'
manage_cli(event)

Method to manage the state of the Arduino CLI.

If not installed, it must:

  • Download the latest CLI

  • Extract the CLI

  • Initialise the CLI config with the selected platform types

  • Update the CLI core index

  • Install required packages to the specified version

  • Install required libraries to the specified version

  • Refresh the list of attached boards

If already installed, it must:

  • Update the CLI core index

  • Install required packages to the specified version

  • Install required libraries to the specified version

  • Refresh the list of attached boards

not_installed_text = 'The Arduino CLI is not installed'
refresh_instruction_text = 'While the Arduino CLI is installed, it is recommended to refresh it periodically (eg. weekly) to ensure support for the various devices is kept up to date. To refresh the CLI, simply click the refresh button.\n\nNote that enabling any of the additional platforms is likely to add several minutes to the refresh process. Maybe grab a cup of tea or a coffee!'

Class for the Manage Arduino CLI view.

Managing the CLI should all be driven by events.

There are two event callbacks:

  • <<Check_Arduino_CLI>> - used to check if the Arduino is installed and if so, which version

  • <<Manage_CLI>> - used to manage installation and updates of the Arduino CLI

Workflow for this module:

  • Object creation and set initial widget states

  • If CLI not installed, disable next and main button triggers install CLI

  • If CLI is installed:

    • Enable next, and main button triggers refresh CLI

    • Check installed package versions and if not at correct version, flag install

    • Check installed library versions and if not at correct version, flag install

  • When enabling a platform type, trigger installation of that package

set_state()
update_package_list(switch)

Maintain the list of packages to install/refresh when switches are turned on/off.

This must cause a platform to be installed if it isn’t already so a user doesn’t need to click refresh.


Select Device (select_device.py)

class ex_installer.select_device.SelectDevice(*args: Any, **kwargs: Any)

Class for the Select Device view

get_port_description(unknown_port)

Function to obtain USB/serial port descriptions using pyserial for ports the CLI doesn’t identify

instruction_text = "Ensure your Arduino device is connected to your computer's USB port.\n\nIf the device detected matches multiple devices, select the correct one from the pulldown list provided.\n\nIf you have a generic or clone device, it likely appears as “Unknown”. In this instance, you will need to select the appropriate device from the pulldown list provided."
list_devices(event)

Use the Arduino CLI to list attached devices

select_device()
set_state()
update_board(name, index)

Select Product (select_product.py)

class ex_installer.select_product.SelectProduct(*args: Any, **kwargs: Any)

Class for the Select Product view

check_product_device(product)

Method to validate the selected device is compatible with the selected product.


Serial Monitor (serial_monitor.py)

class ex_installer.serial_monitor.SerialMonitor(*args: Any, **kwargs: Any)

Class to define a window for the serial monitor

browse_log_dir()

Opens a directory browser dialogue to select the folder to save the device log to

close_monitor()

Close the monitor window nicely:

  • If serial port open, close it

  • If thread running, join/end it

  • Destroy this object

exception_handler(exc_type, exc_value, exc_traceback)

Handler for uncaught exceptions

monitor(event=None)

Function to monitoring using PySerial

Starts the process, and then creates a thread to read the output continuously

read_output()

Function to read serial output

save_log_file()

Function to save the device log file to the chosen location, and open it

send_command(event=None)

Function to send a command to the serial port

show_save_log_popup()

Function to show the message box to select the folder to save device log

update_textbox(output)

Function to update the textbox with output from the Arduino CLI in monitor mode


EX-CommandStation

ex_commandstation.py

class ex_installer.ex_commandstation.EXCommandStation(*args: Any, **kwargs: Any)

Class for the EX-CommandStation view

check_invalid_wifi_password()

Checks for an invalid WiFi password

If in access point mode: - Must be between 8 and 64 characters

In either mode, must not contain or “ # noqa: W605

Returns tuple of (True|False, message)

check_motor_driver(value)

Function ensure a motor driver has been selected

check_selected_device()

Sets recommended device options based on selected device

Disables EEPROM option for boards without it also

create_config_files()

Function to create config.h and myAutomation.h files and progress to upload - Checks for file creation failures

current_override()

Function to enable overriding current limit

decrement_channel()

Function to decrement the WiFi channel

default_config_options = ['#define IP_PORT 2560\n', '#define SCROLLMODE 1\n']
default_myAutomation_options = []
delete_config_files()
Function to delete config files from product directory

needed on subsequent passes thru the logic

display_config_screen()

Displays the configuration options frame

generate_config()

Function to validate options and return any errors

Validates all parameters have been set and generates config.h defines

Returns a tuple of (True|False, error_list|config_list)

generate_myAutomation()

Function to validate options and return any errors

Validates all parameters have been set and generates myAutomation.h defines

Returns a tuple of (True|False, error_list|config_list)

get_motor_drivers()

Method to read the defined motor driver definition from MotorDrivers.h and populate the pulldown options.

If a DCC-EX specific Arduino device is selected, this list will be limited to matching motor driver definitions only, otherwise all DCC-EX specific definitions will be removed, presenting only generic driver options to select.

hardware_text = 'Select the appropriate options on this page to suit the hardware devices you are using with your EX-CommandStation device.\n\nIf you are enabling WiFi or configuring TrackManager, enable the appropriate option and navigate to the appropriate tab to configure the relevant options.'
increment_channel()

Function to increment the WiFi channel

remove_all_dccex_motor_drivers(driver_list)

Method to remove all DCC-EX specific motor driver definitions from the provided list.

This provides an appropriate driver list for generic Arduino devices. Any driver definition starting with a device name in the dccex_devices dictionary will be removed from the available list when selecting a generic Arduino device.

restrict_dccex_motor_drivers(driver_list)

Method to remove generic motor driver definitions from the provided list.

Utilises the class attribute dccex_device to limit the available selections. Only driver definitions starting with the device name of a selected DCC-EX specific Arduino device will be available to select.

set_a_mode(event=None)

If setting track A to DC or DCX, allow setting loco/cab ID

set_advanced_config()

Sets advanced config on or off, locally and globally

set_b_mode(event=None)

If setting track B to DC or DCX, allow setting loco/cab ID

set_display()

Sets display options on or off

set_ethernet()

Function to enable Ethernet support

set_product_version(version, major=None, minor=None, patch=None)

Function to be called by the switch_frame function to set the chosen version

This allows configuration options to be set based on the chosen version

Eg. if self.product_major_version >=4 and self.product_minor_version >= 2: - function_enables_track_manager() else: - function_disables_track_manager()

set_track_modes()

Sets track mode options on or off

set_wifi()

Sets WiFi options on or off

set_wifi_widgets()

Function to display correct widgets for WiFi config

setup_config_frame()

Setup the container frame for configuration options

supported_displays = {'LCD 16 columns x 2 rows': '#define LCD_DRIVER 0x27,16,2\n', 'LCD 20 columns x 4 rows': '#define LCD_DRIVER 0x27,20,4\n', 'OLED 128 x 32': '#define OLED_DRIVER 128,32\n', 'OLED 128 x 64': '#define OLED_DRIVER 128,64\n', 'OLED 132 x 64': '#define OLED_DRIVER 132,64\n'}
trackmanager_modes = {'DC': 'DC', 'DCX': 'DCX', 'MAIN': 'MAIN', 'PROG': 'PROG'}

Select Version (select_version_config.py)

class ex_installer.select_version_config.SelectVersionConfig(*args: Any, **kwargs: Any)

Class for selecting the version and config directory

browse_configdir()

Opens a file browser dialogue to allow user to select a config file to use

Uses directory of this file to set the config directory

This is a workaround for “askdirectory()” not showing files, which is confusing for users

copy_config_files()

Function to copy config files from selected directory to product directory also switches view to advanced_config if copy is successful

delete_config_files()

Function to delete config files from product directory needed on subsequent passes thru the logic

resolve_local_changes(changes)

Function to prompt the user to resolve locally detected repository changes

Resolution means perforing a git hard reset, cancel means exiting the app

set_next_config()

Function to select what configuration to do next

set_product(product)

Function to set the product details to manage the repository

set_select_version(value)

Function to set select a specific version when setting via combobox

set_version()

Function to checkout the selected version according to the radio buttons

set_versions(repo)

Function to obtain versions available in the repo

Once versions obtained, set appropriately

setup_local_repo(event)

Function to setup the local repository

Process: - check if the product directory already exists - if so

  • if the product directory is already a cloned repo

  • any locally modified files that would interfere with Git commands (prompt to resolve)

  • delete any existing configuration files

  • if not, clone repo

  • get list of versions, latest prod, and latest devel versions

setup_version_frame()
validate_config_dir()

Function to validate the selected directory for config files:

  • Is a valid directory

  • Contains at least the specified minimum config files

version_text = "For most users we recommend staying with the latest Production release, however you can install other versions if you know what you're doing, or if a version has been suggested by the DCC-EX team."

Advanced Config (advanced_config.py)

class ex_installer.advanced_config.AdvancedConfig(*args: Any, **kwargs: Any)

Class for the Edit Config Files view

reload_view()

Build/Refresh items for this view, including the dynamic list of edit boxes

If two config files, display side by side which is quite practical

If more than two config files, use CTkTabview for a nicer editing experience

save_config_files()
set_product(product)
Function to set/reset the product, called from ex_installer when switching views

used to trigger screen refresh


EX-IOExpander (ex_ioexpander.py)

class ex_installer.ex_ioexpander.EXIOExpander(*args: Any, **kwargs: Any)

Class for the EX-IOExpander view

decrement_address()

Function to decrement the I2C address

diag_test_options()
generate_config()

Validates all configuration parameters and if valid generates myConfig.h

Any invalid parameters will prevent continuing and flag as errors

increment_address()

Function to increment the I2C address

set_one_test(test)
set_product_version(version, major=None, minor=None, patch=None)

Function to be called by the switch_frame function to set the chosen version

This allows configuration options to be set based on the chosen version

Eg. if self.product_major_version >=4 and self.product_minor_version >= 2: - function_enables_track_manager() else: - function_disables_track_manager()

setup_config_frame()

Setup the container frame for configuration options

Default config parameters from myConfig.example.h: - #define I2C_ADDRESS 0x65 - // #define DIAG - #define DIAG_CONFIG_DELAY 5 - // #define TEST_MODE ANALOGUE_TEST - // #define TEST_MODE INPUT_TEST - // #define TEST_MODE OUTPUT_TEST - // #define TEST_MODE PULLUP_TEST - // #define DISABLE_I2C_PULLUPS

validate_i2c_address(event=None)

Function to validate the I2C address


EX-Turntable (ex_turntable.py)

class ex_installer.ex_turntable.EXTurntable(*args: Any, **kwargs: Any)

Class for the EX-Turntable view

check_stepper(value)

Function to ensure a motor driver has been selected

decrement_address()

Function to decrement the I2C address

generate_config()

Validates all configuration parameters and if valid generates myConfig.h

Any invalid parameters will prevent continuing and flag as errors

get_steppers()

Function to read the defined stepper definitions from standard_steppers.h

increment_address()

Function to increment the I2C address

set_advanced_config()

Sets next screen to be config editing rather than compile/upload

set_forward_only()

Ensures reverse only switch is deselected if forward only is set

set_home()

Highlight the chosen option for the home sensor toggle switch

set_limit()

Highlight the chosen option for the limit sensor toggle switch

set_mode()

Highlight the chosen option for the mode toggle switch

In traverser mode, ensure forward/reverse only options are deselected and disabled

set_phase_switching()

Function to hide/display phase switching angle

set_product_version(version, major=None, minor=None, patch=None)

Function to be called by the switch_frame function to set the chosen version

This allows configuration options to be set based on the chosen version

Eg. if self.product_major_version >=4 and self.product_minor_version >= 2: - function_enables_track_manager() else: - function_disables_track_manager()

set_relay()

Highlight the chosen option for the relay toggle switch

set_reverse_only()

Ensures forward only switch is deselected if reverse only is set

setup_config_frame()

Setup the container frame for configuration options

Default config parameters from config.example.h: - #define I2C_ADDRESS 0x60 - General - #define TURNTABLE_EX_MODE TURNTABLE - General - // #define TURNTABLE_EX_MODE TRAVERSER - General - // #define SENSOR_TESTING - General - #define HOME_SENSOR_ACTIVE_STATE LOW - General - #define LIMIT_SENSOR_ACTIVE_STATE LOW - General - #define RELAY_ACTIVE_STATE HIGH - General - #define PHASE_SWITCHING AUTO - General - #define PHASE_SWITCH_ANGLE 45 - General - #define STEPPER_DRIVER ULN2003_HALF_CW - Stepper - #define DISABLE_OUTPUTS_IDLE - Stepper - #define STEPPER_MAX_SPEED 200 - Stepper - #define STEPPER_ACCELERATION 25 - Stepper

New in 0.6.0: - #define STEPPER_GEARING_FACTOR 1 - Stepper

New in 0.7.0: - // #define INVERT_DIRECTION - Stepper - // #define INVERT_STEP - Stepper - // #define INVERT_ENABLE - Stepper - // #define ROTATE_FORWARD_ONLY - Stepper - // #define ROTATE_REVERSE_ONLY - Stepper

Advanced: - #define LED_FAST 100 - Advanced - #define LED_SLOW 500 - Advanced - // #define DEBUG - Advanced - // #define SANITY_STEPS 10000 - Advanced - // #define HOME_SENSITIVITY 300 - Advanced - // #define FULL_STEP_COUNT 4096 - Advanced - // #define DEBOUNCE_DELAY 10 - Advanced

validate_i2c_address(event=None)

Function to validate the I2C address


Arduino CLI (arduino_cli.py)

class ex_installer.arduino_cli.ThreadedArduinoCLI(acli_path, params, queue, time_limit=300)

Class to run Arduino CLI commands in a separate thread, returning results to the provided queue

There is a default timeout of 5 minutes (300 seconds) for any thread being started, after which they will be terminated

Specifying the “time_limit” parameter will override this if necessary

arduino_cli_lock = <unlocked _thread.lock object>
run(*args, **kwargs)

Override for Thread.run()

Creates a thread and executes with the provided parameters

Results are placed in the provided queue object

class ex_installer.arduino_cli.ArduinoCLI(selected_device=None)

Class for the Arduino CLI model

This class exposes the various methods to interact with the Arduino CLI including:

  • cli_file_path() - returns the full file path to where the Arduino CLI should reside

  • is_installed() - checks the CLI is installed and executable, returns True/False

  • get_version() - gets the Arduino CLI version, returns to the provided queue

  • get_platforms() - gets the list of installed platforms

  • download_cli() - downloads the appropriate CLI for the operating system, returns the file path

  • install_cli() - extracts the CLI to the specified file path from download file path

  • delete_cli() - deletes the CLI, returns True|False

  • initialise_config() - adds additional URLs to the CLI config

  • update_index() - performs the core update-index and initial board list

  • install_package() - installs the provided packages

  • upgrade_platforms() - performs the core upgrade to ensure all are up to date

  • list_boards() - lists all connected boards, returns list of dictionaries for boards

  • compile_sketch() - compiles the sketch in the provided directory ready for upload

  • upload_sketch() - uploads the sketch in the provided directory to the provided device

arduino_cli_version = '0.35.3'

Dictionary for the base board/platform support for the Arduino CLI.

This should really just be Arduino AVR, and must specify the version.

Note this used to be defined in the manage_arduino_cli module but is now centralised here.

This format is consistent with extra_platforms, but without the URL.

base_platforms = {
“Platform Name”: {

“platform_id”: “<packager>:<arch>”, “version”: “<version>”

}

}

arduino_downloads = {'Darwin64': 'https://github.com/arduino/arduino-cli/releases/download/v0.35.3/arduino-cli_0.35.3_macOS_64bit.tar.gz', 'Linux64': 'https://github.com/arduino/arduino-cli/releases/download/v0.35.3/arduino-cli_0.35.3_Linux_64bit.tar.gz', 'Windows32': 'https://github.com/arduino/arduino-cli/releases/download/v0.35.3/arduino-cli_0.35.3_Windows_32bit.zip', 'Windows64': 'https://github.com/arduino/arduino-cli/releases/download/v0.35.3/arduino-cli_0.35.3_Windows_64bit.zip'}

Expose the currently supported version of the Arduino CLI to use.

arduino_libraries = {'Ethernet': '2.0.2'}

Dictionary of devices supported with EX-Installer to enable selection when detecting unknown devices.

base_platforms = {'Arduino AVR': {'platform_id': 'arduino:avr', 'version': '1.8.6'}}

Dictionary for additional board/platform support for the Arduino CLI.

These must be tied to a specific version to avoid future unknown issues:

extra_platforms = {
“Platform Name”: {

“platform_id”: “<packager>:<arch>”, “version”: “<version>”, “url”: “<url>”

}

}

  • 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

cli_file_path()

Function to get the full path and filename of the Arduino CLI.

Cross-platform, returns the full file path or False if there is an error.

For example: - Linux - /home/<user>/ex-installer/arduino-cli/arduino-cli - Windows - C:Users<user>ex-installerarduino-cliarduino-cli.exe

compile_sketch(file_path, fqbn, sketch_dir, queue)

Compiles the sketch ready to upload

dccex_devices = {'DCC-EX EX-CSB1': 'EXCSB1'}
delete_cli()

Deletes all files in the provided directory.

This is required to remove an unsupported version of the Arduino CLI.

download_cli(queue)

Download the Arduino CLI

If successful, the archive’s path will be in the queue’s “data” field

If error, the error will be in the queue’s “data” field

extra_platforms = {'Espressif ESP32': {'platform_id': 'esp32:esp32', 'url': 'https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json', 'version': '2.0.17'}, 'STMicroelectronics Nucleo/STM32': {'platform_id': 'STMicroelectronics:stm32', 'url': 'https://github.com/stm32duino/BoardManagerFiles/raw/main/package_stmicroelectronics_index.json', 'version': '2.7.1'}}

Dictionary of required Arduino libraries to be installed.

These must be tied to a specific version to avoid future unknown issues:

arduino_libraries = {

“<library name>”: “<version>”

}

Note that these were previously an attribute of a product in the product_details module but are now here.

get_libraries(file_path, queue)

Function to retrieve the current libraries installed with the Arduino CLI

If successful, the list will be in the queue’s “data” field

get_platforms(file_path, queue)

Function to retrieve the current platforms installed with the Arduino CLI

If successful, the list will be in the queue’s “data” field

get_version(file_path, queue)

Function to retrieve the version of the Arduino CLI

If obtaining the version is successful it will be in the queue’s “data” field

initialise_config(file_path, queue)

Initialises the Arduino CLI configuration with the provided additional boards.

Overwrites existing configuration options.

install_cli(download_file, file_path, queue)

Install the Arduino CLI by extracting to the specified directory

install_library(file_path, library, queue)

Install the specified Arduino library

install_package(file_path, package, queue)

Install packages for the listed Arduino platforms

is_installed(file_path)

Function to check if the Arduino CLI in installed in the provided file path

Also checks to ensure it is executable.

Returns True or False

list_boards(file_path, queue)

Returns a list of attached boards

supported_devices = {'Arduino Mega or Mega 2560': 'arduino:avr:mega', 'Arduino Nano': 'arduino:avr:nano', 'Arduino Uno': 'arduino:avr:uno', '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'}

Dictionary of DCC-EX specific devices, used to preselect or exclude motor driver definitions.

While this isn’t ideal, it makes it easier with the current implementation to control what users can and can’t select for motor drivers.

Future additions must start with “DCC-EX” in order to be used for this purpose.

update_index(file_path, queue)

Update the Arduino CLI core index

upgrade_platforms(file_path, queue)

Upgrade Arduino CLI platforms

upload_sketch(file_path, fqbn, port, sketch_dir, queue)

Compiles and uploads the sketch in the specified directory to the provided board/port.

urlbase = 'https://github.com/arduino/arduino-cli/releases/download/v0.35.3/arduino-cli_0.35.3_'

Utility/Common

file_manager.py

class ex_installer.file_manager.ThreadedDownloader(url, target, queue)
download_lock = <unlocked _thread.lock object>
run(*args, **kwargs)

Method representing the thread’s activity.

You may override this method in a subclass. The standard run() method invokes the callable object passed to the object’s constructor as the target argument, if any, with sequential and keyword arguments taken from the args and kwargs arguments, respectively.

class ex_installer.file_manager.ThreadedExtractor(archive_file, target_dir, queue)
extractor_lock = <unlocked _thread.lock object>
run(*args, **kwargs)

Method representing the thread’s activity.

You may override this method in a subclass. The standard run() method invokes the callable object passed to the object’s constructor as the target argument, if any, with sequential and keyword arguments taken from the args and kwargs arguments, respectively.

class ex_installer.file_manager.FileManager

Class for managing files and directories

static copy_config_files(source_dir, dest_dir, file_list)

Copy the specified list of files from source to destination directory

Returns None if successful, otherwise a list of files that failed to copy

static delete_config_files(dir, file_list)

Delete the specified list of files from sepcified directory

Returns None if successful, otherwise a list of files that failed to copy

static dir_is_empty(dir)

Check if directory is empty

Returns True if so, False if not

static get_base_dir()

Returns the base directory for EX-Installer

static get_config_files(dir, pattern_list)

Function to check for the existence of existing configuration files

Returns False if no files, otherwise a list of file names matching the provided list of patterns

Pattern list can contain either: - a valid Python regular expression with grouping, where a match is made on one group only (group 1) - a file name

This is a valid example of a pattern: r”^my.*.[^?]*example.h$|(^my.*.h$)” # noqa: W605 This is an invalid example of a pattern: r”^config.h$” # noqa: W605 This would be valid, but better to just provide filename: r”^(config.h)$” # noqa: W605

static get_filepath(dir, filename)
static get_install_dir(product_name)

Returns the path to extract software into

static get_list_from_file(file_path, pattern)
static get_temp_dir()

Returns the temp directory

static get_user_preferences()

Method to the dictionary of user preferences

Reads the JSON user preference file and returns the dictionary

static is_valid_dir(dir)

Simply checks directory exists and that it is a directory

Returns True or False

log = <Logger ex_installer.file_manager (WARNING)>
static read_config_file(file_path)

Function to read and return file contents Pass the full path to the file Returns the text from the file path if successful, otherwise the exception error message

static read_version(version_file)

Function to read a version string from a file

Not recommended over obtaining versions from GitHub tags, however can be used if those are not defined Returns False if no version defined, or a string containing the version

static rename_dir(source_dir, target_dir)
static save_user_preferences(preferences)

Method to save user preferences to the user preference file

Call this method with the user preferences dictionary, which will save these

user_preference_dir = 'user-config'
user_preference_file = 'ex-installer-preferences.json'
static write_config_file(file_path, contents)

Function to write the list of contents to a config file

Pass the full path to the file and the list of lines to write Writes utf-8 encoded

Returns the same file path if successful, otherwise the exception error message


common_fonts.py

class ex_installer.common_fonts.CommonFonts(*args: Any, **kwargs: Any)

Class to define common fonts used across all application modules/classes

default_font = 'FreeSans'

common_widgets.py

class ex_installer.common_widgets.WindowLayout(*args: Any, **kwargs: Any)

Class to define the window layout used throughout the application.

All views must inherit from this.

disable_input_states(widget)

Stores current state of all child input widgets then sets to disabled

static get_exception(error)

Get an exception into text to add to the queue

monitor_queue(queue, event)

Monitor the provided queue for status updates

process_error(message)

Stops the progress bar, sets status text, and makes font red.

We must restore the previously recorded input states.

process_start(next_phase, activity, event)

Starts a background process that requires monitoring and a progress bar.

If this is a new process, we must record and disable the current input states.

process_stop()

Stops the progress bar and resets status text.

We must restore the previously recorded input states.

restore_input_states()

Restores the state of all widgets

Function to update the title logo

Call and pass a logo as defined in the images module

set_title_text(text)

Function to update the title text

class ex_installer.common_widgets.NextBack(*args: Any, **kwargs: Any)

Class for defining and managing the next and back buttons

disable_back()

Disable back button

disable_next()

Disable next button

enable_back()

Enable back button

enable_next()

Enable next button

hide_back()

Hide back button

hide_log_button()
hide_monitor_button()

Function to hide the monitor button

hide_next()

Hide next button

monitor()

Function to open the serial monitor window

set_back_command(command)
set_back_text(text)

Update back button text

set_next_command(command)
set_next_text(text)

Update next button text

show_back()

Show back button

show_log()
show_log_button()
show_monitor_button()

Function to show the monitor button

show_next()

Show next button

class ex_installer.common_widgets.FormattedTextbox(*args: Any, **kwargs: Any)

Class for formatting a CustomTkinter textbox

Allows for bullet points only to start

Usage example: textbox = FormattedTextbox(master, arguments) textbox.insert_bullet(“insert”, “Bullet list item”)

For a number of bullet list items: bullet_list = [ “Item 1”, “Item 2”, “Item 3 ] for item in bullet_list: - textbox.insert_bullet(“insert”, item)

insert_bullet(index, text)

Function to insert a bullet point

class ex_installer.common_widgets.CreateToolTip(widget, text='widget info', url=None)

Create a tooltip for a given widget with an optional URL

To use, simply include this class and call it as such:

from .common_widgets import CreateToolTip

self.widget = <CustomTkinter widget creation> CreateTooltip(self.widget, “Tool tip contextual help text”[, URL])

enter_widget(event=None)

When hovered/entered widget, schedule it to start

hide_tooltip()

Hides the tooltip

leave_widget(event=None)

When leaving the widget, schedule the hide

open_url(url)

Open the provided URL using the webbrowser module

schedule_tooltip()

Schedule the tip to appear

show_tooltip(event=None)

Show the tooltip

unschedule_tooltip()

Cancel the schedule


git_client.py

class ex_installer.git_client.ThreadedGitClient(task_name, task, queue, *args)

Class for running pygit2 tasks in a separate thread

api_lock = <unlocked _thread.lock object>
run(*args, **kwargs)

Method representing the thread’s activity.

You may override this method in a subclass. The standard run() method invokes the callable object passed to the object’s constructor as the target argument, if any, with sequential and keyword arguments taken from the args and kwargs arguments, respectively.

class ex_installer.git_client.GitClient

Class for cloning code and selecting specific versions from DCC-EX repositories

static check_local_changes(repo)

Function to check for local changes to files in the provided repo

If file “.DS_Store” is added/modified, this is forcefully discarded as it should be in .gitignore

Returns False (no changes) or a list of changed files

static clone_repo(repo_url, repo_dir, queue)

Clone a remote repo using a separate thread

Returns the repo instance in queue data if successful

static dir_is_git_repo(dir)

Check if directory exists and contains a .git file

Returns True if so, False if not

static extract_version_details(version_string)

Extracts major, minor, and patch versions from a GitHub tag style version string

Returns a tuple (major, minor, patch) or None

version_string must match a GitHub version style tag to work vX.Y.Z-Prod|Devel

static get_branch_ref(repo, name)

Gets the ref for the named branch

static get_latest_devel(repo, tag_name='Devel')

Retrieves the latest Development tagged version from the repo

If no tags or no Devel tags, returns False

static get_latest_prod(repo, tag_name='Prod')

Retrieves the latest Production tagged version from the repo

If no tags or no Prod tags, returns False

static get_repo(repo_dir)

Validate the provided directory is a repo

Returns a tuple of (True|False, None|message)

static get_repo_versions(repo)

Gets all version tags from the specified repo

Returns either an ordered dictionary (descending) or False if there are no tags

static git_hard_reset(repo)

Performs a hard reset of the provided repository to the current HEAD

log = <Logger ex_installer.git_client (WARNING)>
static pull(repo, remote_name='origin', branch='master')

Function to pull the latest updates from the provided repo

Expects a pygit2 repo object and a branch name

static pull_latest(repo, branch, queue)

Pull latest updates from a repo

Threaded version of pull

Requires a pygit2 repo object and a branch name