diff --git a/.ecrc b/.ecrc
index 1cad9435..496b83c2 100644
--- a/.ecrc
+++ b/.ecrc
@@ -1,9 +1,9 @@
 {
   "Exclude": [
-    "^indexes/download/testdata/module_firmware_index\\.json$",
+    "^indexes/download/testdata/plugin_firmware_index\\.json$",
     "^indexes/download/testdata/package_index\\.json$",
-    "^indexes/firmwareindex/testdata/module_firmware_index\\.json$",
     "^indexes/testdata/package_index\\.json$",
+    "^indexes/firmwareindex/testdata/plugin_firmware_index\\.json$",
     "^LICENSE\\.txt$",
     "^poetry\\.lock$",
     "^\\.licenses/",
diff --git a/.github/workflows/generate-index.yml b/.github/workflows/generate-index.yml
index 5d069a1c..b0dc81a4 100644
--- a/.github/workflows/generate-index.yml
+++ b/.github/workflows/generate-index.yml
@@ -36,27 +36,13 @@ jobs:
       - name: Install Poetry
         run: pip install poetry
 
-      - name: Install Arduino CLI
-        uses: arduino/setup-arduino-cli@v1
-
-      - name: Install platforms
-        run: |
-          arduino-cli core update-index -v
-          arduino-cli version
-          arduino-cli core install arduino:samd@${{ env.SAMD_V }} -v
-        env:
-          SAMD_V: 1.8.11
-
       - name: Install dependencies
         run: |
           cd $GITHUB_WORKSPACE
           task poetry:install-deps
 
       - name: Generate plugin firmware index
-        run: poetry run ./generator.py -a $(which arduino-cli)
-
-      - name: Generate module firmware index
-        run: poetry run ./generator.py -a $(which arduino-cli) --no-new
+        run: poetry run ./generator.py
 
         # fix `gpg: signing failed: Inappropriate ioctl for device`
         # https://github.com/keybase/keybase-issues/issues/2798
@@ -68,13 +54,6 @@ jobs:
 
         # disable gpg pass prompt
         # https://stackoverflow.com/questions/49072403/suppress-the-passphrase-prompt-in-gpg-command
-      - name: sign the module firmware index json
-        run: |
-          gpg \
-            --pinentry-mode=loopback \
-            --passphrase "${{ secrets.PASSPHRASE }}" \
-            --output boards/module_firmware_index.json.sig \
-            --detach-sign boards/module_firmware_index.json
 
       - name: sign the plugin firmware index json
         run: |
@@ -85,7 +64,7 @@ jobs:
             --detach-sign boards/plugin_firmware_index.json
 
       - name: create the gzip
-        run: gzip --keep boards/module_firmware_index.json boards/plugin_firmware_index.json
+        run: gzip --keep boards/plugin_firmware_index.json
 
       - name: s3 sync
         run: |
diff --git a/.prettierignore b/.prettierignore
index 37449cf6..fe500adf 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -4,9 +4,9 @@
 .vs/
 .ionide/
 
-indexes/download/testdata/module_firmware_index.json
+indexes/download/testdata/plugin_firmware_index.json
 indexes/download/testdata/package_index.json
-indexes/firmwareindex/testdata/module_firmware_index.json
+indexes/firmwareindex/testdata/plugin_firmware_index.json
 indexes/testdata/package_index.json
 
 # Generated files
diff --git a/README.md b/README.md
index 683a2ffb..65d3d1bb 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 # Arduino Firmware Uploader
 
 The Arduino Firmware Uploader is a tool made to update the firmware and/or add SSL certificates for any Arduino board
-equipped with WINC or NINA Wi-Fi module.
+equipped with ESP32-S3 or NINA Wi-Fi module.
 
 [![Test Go status](https://github.com/arduino/arduino-fwuploader/actions/workflows/test-go-task.yml/badge.svg)](https://github.com/arduino/arduino-fwuploader/actions/workflows/test-go-task.yml)
 [![Codecov](https://codecov.io/gh/arduino/arduino-fwuploader/branch/main/graph/badge.svg)](https://codecov.io/gh/arduino/arduino-fwuploader)
diff --git a/cli/arguments/arguments.go b/cli/arguments/arguments.go
index 357ee6fe..c058f5c9 100644
--- a/cli/arguments/arguments.go
+++ b/cli/arguments/arguments.go
@@ -31,6 +31,6 @@ type Flags struct {
 
 // AddToCommand adds the flags used to set address and fqbn to the specified Command
 func (f *Flags) AddToCommand(cmd *cobra.Command) {
-	cmd.Flags().StringVarP(&f.Fqbn, "fqbn", "b", "", "Fully Qualified Board Name, e.g.: arduino:samd:mkr1000, arduino:mbed_nano:nanorp2040connect")
+	cmd.Flags().StringVarP(&f.Fqbn, "fqbn", "b", "", "Fully Qualified Board Name, e.g.: arduino:samd:mkrwifi1010, arduino:mbed_nano:nanorp2040connect")
 	cmd.Flags().StringVarP(&f.Address, "address", "a", "", "Upload port, e.g.: COM10, /dev/ttyACM0")
 }
diff --git a/cli/certificates/flash.go b/cli/certificates/flash.go
index 1c1c0b5f..d6579642 100644
--- a/cli/certificates/flash.go
+++ b/cli/certificates/flash.go
@@ -24,8 +24,6 @@ import (
 	"fmt"
 	"io"
 	"os"
-	"strings"
-	"time"
 
 	"github.com/arduino/arduino-fwuploader/certificates"
 	"github.com/arduino/arduino-fwuploader/cli/arguments"
@@ -33,8 +31,6 @@ import (
 	"github.com/arduino/arduino-fwuploader/cli/feedback"
 	"github.com/arduino/arduino-fwuploader/cli/globals"
 	"github.com/arduino/arduino-fwuploader/flasher"
-	"github.com/arduino/arduino-fwuploader/indexes/download"
-	"github.com/arduino/arduino-fwuploader/indexes/firmwareindex"
 	"github.com/arduino/arduino-fwuploader/plugin"
 	"github.com/arduino/go-paths-helper"
 	"github.com/sirupsen/logrus"
@@ -54,9 +50,9 @@ func NewFlashCommand() *cobra.Command {
 		Short: "Flashes certificates to board.",
 		Long:  "Flashes specified certificates to board at specified address.",
 		Example: "" +
-			"  " + os.Args[0] + " certificates flash --fqbn arduino:samd:mkr1000 --address COM10 --url arduino.cc:443 --file /home/me/Digicert.cer\n" +
-			"  " + os.Args[0] + " certificates flash -b arduino:samd:mkr1000 -a COM10 -u arduino.cc:443 -u google.com:443\n" +
-			"  " + os.Args[0] + " certificates flash -b arduino:samd:mkr1000 -a COM10 -f /home/me/VeriSign.cer -f /home/me/Digicert.cer\n",
+			"  " + os.Args[0] + " certificates flash --fqbn arduino:samd:mkrwifi1010 --address COM10 --url arduino.cc:443 --file /home/me/Digicert.cer\n" +
+			"  " + os.Args[0] + " certificates flash -b arduino:renesas_uno:unor4wifi -a COM10 -u arduino.cc:443 -u google.com:443\n" +
+			"  " + os.Args[0] + " certificates flash -b arduino:samd:mkrwifi1010 -a COM10 -f /home/me/VeriSign.cer -f /home/me/Digicert.cer\n",
 		Args: cobra.NoArgs,
 		Run: func(cmd *cobra.Command, args []string) {
 			runFlash(certificateURLs, certificatePaths)
@@ -81,25 +77,19 @@ func runFlash(certificateURLs, certificatePaths []string) {
 	board := common.GetBoard(firmwareIndex, commonFlags.Fqbn)
 	uploadToolDir := common.DownloadRequiredToolsForBoard(packageIndex, board)
 
-	var res *flasher.FlashResult
-	var flashErr error
-	if !board.IsPlugin() {
-		res, flashErr = flashCertificates(board, uploadToolDir, certificateURLs, certificatePaths)
-	} else {
-		uploader, err := plugin.NewFWUploaderPlugin(uploadToolDir)
-		if err != nil {
-			feedback.Fatal(fmt.Sprintf("Could not open uploader plugin: %s", err), feedback.ErrGeneric)
-		}
-		res, flashErr = flashCertificatesWithPlugin(uploader, certificateURLs, certificatePaths)
+	uploader, err := plugin.NewFWUploaderPlugin(uploadToolDir)
+	if err != nil {
+		feedback.Fatal(fmt.Sprintf("Could not open uploader plugin: %s", err), feedback.ErrGeneric)
 	}
 
+	res, flashErr := flashCertificates(uploader, certificateURLs, certificatePaths)
 	feedback.PrintResult(res)
 	if flashErr != nil {
 		os.Exit(int(feedback.ErrGeneric))
 	}
 }
 
-func flashCertificatesWithPlugin(uploader *plugin.FwUploader, certificateURLs, certificatePaths []string) (*flasher.FlashResult, error) {
+func flashCertificates(uploader *plugin.FwUploader, certificateURLs, certificatePaths []string) (*flasher.FlashResult, error) {
 	tmp, err := paths.MkTempDir("", "")
 	if err != nil {
 		return nil, err
@@ -161,69 +151,3 @@ func flashCertificatesWithPlugin(uploader *plugin.FwUploader, certificateURLs, c
 		},
 	}, err
 }
-
-func flashCertificates(board *firmwareindex.IndexBoard, uploadToolDir *paths.Path, certificateURLs, certificatePaths []string) (*flasher.FlashResult, error) {
-	loaderSketchPath, err := download.DownloadSketch(board.LoaderSketch)
-	if err != nil {
-		feedback.Fatal(fmt.Sprintf("Error downloading loader sketch from %s: %s", board.LoaderSketch.URL, err), feedback.ErrGeneric)
-	}
-	logrus.Debugf("loader sketch downloaded in %s", loaderSketchPath.String())
-
-	loaderSketch := strings.ReplaceAll(loaderSketchPath.String(), loaderSketchPath.Ext(), "")
-	programmerOut, programmerErr, err := common.FlashSketch(board, loaderSketch, uploadToolDir, commonFlags.Address)
-	if err != nil {
-		feedback.FatalError(err, feedback.ErrGeneric)
-	}
-
-	// Wait a bit after flashing the loader sketch for the board to become
-	// available again.
-	logrus.Debug("sleeping for 3 sec")
-	time.Sleep(3 * time.Second)
-
-	// Get flasher depending on which module to use
-	var f flasher.Flasher
-	moduleName := board.Module
-
-	// This matches the baudrate used in the FirmwareUpdater.ino sketch
-	// https://github.com/arduino-libraries/WiFiNINA/blob/master/examples/Tools/FirmwareUpdater/FirmwareUpdater.ino
-	const baudRate = 1000000
-	switch moduleName {
-	case "NINA":
-		// we use address and not bootloaderPort because the board should not be in bootloader mode
-		f, err = flasher.NewNinaFlasher(commonFlags.Address, baudRate, 30)
-	case "WINC1500":
-		f, err = flasher.NewWincFlasher(commonFlags.Address, baudRate, 30)
-	default:
-		err = fmt.Errorf("unknown module: %s", moduleName)
-	}
-	if err != nil {
-		feedback.Fatal(fmt.Sprintf("Error during certificates flashing: %s", err), feedback.ErrGeneric)
-	}
-	defer f.Close()
-
-	// now flash the certificate
-	certFileList := paths.NewPathList(certificatePaths...)
-	flasherOut := new(bytes.Buffer)
-	flasherErr := new(bytes.Buffer)
-	if feedback.GetFormat() == feedback.JSON {
-		err = f.FlashCertificates(&certFileList, certificateURLs, flasherOut)
-		if err != nil {
-			flasherErr.Write([]byte(fmt.Sprintf("Error during certificates flashing: %s", err)))
-		}
-	} else {
-		err = f.FlashCertificates(&certFileList, certificateURLs, io.MultiWriter(flasherOut, os.Stdout))
-		if err != nil {
-			os.Stderr.Write([]byte(fmt.Sprintf("Error during certificates flashing: %s", err)))
-		}
-	}
-	return &flasher.FlashResult{
-		Programmer: &flasher.ExecOutput{
-			Stdout: programmerOut.String(),
-			Stderr: programmerErr.String(),
-		},
-		Flasher: &flasher.ExecOutput{
-			Stdout: flasherOut.String(),
-			Stderr: flasherErr.String(),
-		},
-	}, err
-}
diff --git a/cli/common/common.go b/cli/common/common.go
index 10a1c13d..18f37400 100644
--- a/cli/common/common.go
+++ b/cli/common/common.go
@@ -18,22 +18,15 @@
 package common
 
 import (
-	"bytes"
 	"fmt"
-	"os"
-	"path/filepath"
-	"strings"
 
 	"github.com/arduino/arduino-cli/arduino/cores/packagemanager"
-	"github.com/arduino/arduino-cli/arduino/serialutils"
 	"github.com/arduino/arduino-fwuploader/cli/feedback"
 	"github.com/arduino/arduino-fwuploader/cli/globals"
 	"github.com/arduino/arduino-fwuploader/indexes"
 	"github.com/arduino/arduino-fwuploader/indexes/download"
 	"github.com/arduino/arduino-fwuploader/indexes/firmwareindex"
-	programmer "github.com/arduino/arduino-fwuploader/programmers"
 	"github.com/arduino/go-paths-helper"
-	"github.com/arduino/go-properties-orderedmap"
 	"github.com/sirupsen/logrus"
 )
 
@@ -59,24 +52,19 @@ func InitIndexes() (*packagemanager.PackageManager, *firmwareindex.Index) {
 	}
 
 	// Load main firmware index and optional additional indexes
-	firmwareIndex, err := indexes.GetFirmwareIndex(globals.ModuleFirmwareIndexGZURL, true)
+	pluginFirmwareIndex, err := indexes.GetFirmwareIndex(globals.PluginFirmwareIndexGZURL, true)
 	if err != nil {
-		feedback.Fatal(fmt.Sprintf("Can't load firmware index: %s", err), feedback.ErrGeneric)
-	}
-	if pluginIndex, err := indexes.GetFirmwareIndex(globals.PluginFirmwareIndexGZURL, true); err != nil {
 		feedback.Fatal(fmt.Sprintf("Can't load (plugin) firmware index: %s", err), feedback.ErrGeneric)
-	} else {
-		firmwareIndex.MergeWith(pluginIndex)
 	}
 	for _, additionalURL := range AdditionalFirmwareIndexURLs {
 		additionalIndex, err := indexes.GetFirmwareIndex(additionalURL, false)
 		if err != nil {
 			feedback.Fatal(fmt.Sprintf("Can't load firmware index: %s", err), feedback.ErrGeneric)
 		}
-		firmwareIndex.MergeWith(additionalIndex)
+		pluginFirmwareIndex.MergeWith(additionalIndex)
 	}
 
-	return pmbuilder.Build(), firmwareIndex
+	return pmbuilder.Build(), pluginFirmwareIndex
 }
 
 // CheckFlags runs a basic check, errors if the flags are not defined
@@ -105,11 +93,6 @@ func GetBoard(firmwareIndex *firmwareindex.Index, fqbn string) *firmwareindex.In
 // DownloadRequiredToolsForBoard is an helper function that downloads the correct tool to flash a board,
 // it returns the path of the downloaded tool
 func DownloadRequiredToolsForBoard(pm *packagemanager.PackageManager, board *firmwareindex.IndexBoard) *paths.Path {
-	if !board.IsPlugin() {
-		// Just download the upload tool for integrated uploaders
-		return downloadTool(pm, board.Uploader)
-	}
-
 	// Download the plugin
 	toolDir := downloadTool(pm, board.UploaderPlugin)
 
@@ -133,56 +116,3 @@ func downloadTool(pm *packagemanager.PackageManager, tool string) *paths.Path {
 	logrus.Debugf("upload tool downloaded in %s", toolDir.String())
 	return toolDir
 }
-
-// FlashSketch is the business logic that handles the flashing procedure,
-// it returns using a buffer the stdout and the stderr of the programmer
-func FlashSketch(board *firmwareindex.IndexBoard, sketch string, uploadToolDir *paths.Path, address string) (programmerOut, programmerErr *bytes.Buffer, err error) {
-	bootloaderPort, err := GetNewAddress(board, address)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	uploaderCommand := board.GetUploaderCommand()
-	uploaderCommand = strings.ReplaceAll(uploaderCommand, "{tool_dir}", filepath.FromSlash(uploadToolDir.String()))
-	uploaderCommand = strings.ReplaceAll(uploaderCommand, "{serial.port.file}", bootloaderPort)
-	uploaderCommand = strings.ReplaceAll(uploaderCommand, "{loader.sketch}", sketch) // we leave that name here because it's only a template,
-
-	logrus.Debugf("uploading with command: %s", uploaderCommand)
-	commandLine, err := properties.SplitQuotedString(uploaderCommand, "\"", false)
-	if err != nil {
-		feedback.Fatal(fmt.Sprintf(`Error splitting command line "%s": %s`, uploaderCommand, err), feedback.ErrGeneric)
-	}
-
-	// Flash the actual sketch
-	programmerOut = new(bytes.Buffer)
-	programmerErr = new(bytes.Buffer)
-	if feedback.GetFormat() == feedback.JSON {
-		err = programmer.Flash(commandLine, programmerOut, programmerErr)
-	} else {
-		err = programmer.Flash(commandLine, os.Stdout, os.Stderr)
-	}
-	if err != nil {
-		return nil, nil, fmt.Errorf("error during sketch flashing: %s", err)
-	}
-	return programmerOut, programmerErr, err
-}
-
-// GetNewAddress is a function used to reset a board and put it in bootloader mode
-// it could happen that the board is assigned to a different serial port, after the reset,
-// this fuction handles also this possibility
-func GetNewAddress(board *firmwareindex.IndexBoard, oldAddress string) (string, error) {
-	// Check if board needs a 1200bps touch for upload
-	bootloaderPort := oldAddress
-	if board.UploadTouch {
-		logrus.Info("Putting board into bootloader mode")
-		newUploadPort, err := serialutils.Reset(oldAddress, board.UploadWait, nil, false)
-		if err != nil {
-			return "", fmt.Errorf("error during sketch flashing: missing board address. %s", err)
-		}
-		if newUploadPort != "" {
-			logrus.Infof("Found port to upload: %s", newUploadPort)
-			bootloaderPort = newUploadPort
-		}
-	}
-	return bootloaderPort, nil
-}
diff --git a/cli/firmware/flash.go b/cli/firmware/flash.go
index b4bd9ebd..e533b3c8 100644
--- a/cli/firmware/flash.go
+++ b/cli/firmware/flash.go
@@ -19,7 +19,6 @@
 package firmware
 
 import (
-	"bytes"
 	"fmt"
 	"io"
 	"os"
@@ -53,15 +52,15 @@ func NewFlashCommand() *cobra.Command {
 		Short: "Flashes firmwares to board.",
 		Long:  "Flashes specified module firmware to board at specified address. Module name and version can be omitted to install latest version.",
 		Example: "" +
-			"  " + os.Args[0] + " firmware flash --fqbn arduino:samd:mkr1000 --address COM10 --module WINC1500@19.5.2\n" +
-			"  " + os.Args[0] + " firmware flash -b arduino:samd:mkr1000 -a COM10 -m WINC15000\n" +
-			"  " + os.Args[0] + " firmware flash -b arduino:samd:mkr1000 -a COM10\n" +
-			"  " + os.Args[0] + " firmware flash -b arduino:samd:mkr1000 -a COM10 -i firmware.bin\n",
+			"  " + os.Args[0] + " firmware flash --fqbn arduino:samd:mkrwifi1010 --address COM10 --module NINA@1.4.8\n" +
+			"  " + os.Args[0] + " firmware flash -b arduino:renesas_uno:unor4wifi -a COM10 -m ESP32-S3\n" +
+			"  " + os.Args[0] + " firmware flash -b arduino:renesas_uno:unor4wifi -a COM10\n" +
+			"  " + os.Args[0] + " firmware flash -b arduino:samd:mkrwifi1010 -a COM10 -i firmware.bin\n",
 		Args: cobra.NoArgs,
 		Run:  runFlash,
 	}
 	commonFlags.AddToCommand(command)
-	command.Flags().StringVarP(&module, "module", "m", "", "Firmware module ID, e.g.: WINC1500, NINA")
+	command.Flags().StringVarP(&module, "module", "m", "", "Firmware module ID, e.g.: ESP32-S3, NINA")
 	command.Flags().IntVar(&retries, "retries", 9, "Number of retries in case of upload failure (default 9)")
 	command.Flags().StringVarP(&fwFile, "input-file", "i", "", "Path of the firmware to upload")
 	return command
@@ -120,21 +119,9 @@ func runFlash(cmd *cobra.Command, args []string) {
 		logrus.Debugf("firmware file downloaded in %s", firmwareFilePath.String())
 	}
 
-	loaderSketch := ""
-	var uploader *plugin.FwUploader
-	if !board.IsPlugin() {
-		loaderSketchPath, err := download.DownloadSketch(board.LoaderSketch)
-		if err != nil {
-			feedback.Fatal(fmt.Sprintf("Error downloading loader sketch from %s: %s", board.LoaderSketch.URL, err), feedback.ErrGeneric)
-		}
-		logrus.Debugf("loader sketch downloaded in %s", loaderSketchPath.String())
-		loaderSketch = strings.ReplaceAll(loaderSketchPath.String(), loaderSketchPath.Ext(), "")
-	} else {
-		var err error
-		uploader, err = plugin.NewFWUploaderPlugin(uploadToolDir)
-		if err != nil {
-			feedback.Fatal(fmt.Sprintf("Could not open uploader plugin: %s", err), feedback.ErrGeneric)
-		}
+	uploader, err := plugin.NewFWUploaderPlugin(uploadToolDir)
+	if err != nil {
+		feedback.Fatal(fmt.Sprintf("Could not open uploader plugin: %s", err), feedback.ErrGeneric)
 	}
 
 	retry := 0
@@ -142,13 +129,7 @@ func runFlash(cmd *cobra.Command, args []string) {
 		retry++
 		logrus.Infof("Uploading firmware (try %d of %d)", retry, retries)
 
-		var res *flasher.FlashResult
-		var err error
-		if !board.IsPlugin() {
-			res, err = updateFirmware(board, loaderSketch, moduleName, uploadToolDir, firmwareFilePath)
-		} else {
-			res, err = updateFirmwareWithPlugin(uploader, firmwareFilePath)
-		}
+		res, err := updateFirmware(uploader, firmwareFilePath)
 		if err == nil {
 			feedback.PrintResult(res)
 			logrus.Info("Operation completed: success! :-)")
@@ -165,7 +146,7 @@ func runFlash(cmd *cobra.Command, args []string) {
 	}
 }
 
-func updateFirmwareWithPlugin(uploader *plugin.FwUploader, fwPath *paths.Path) (*flasher.FlashResult, error) {
+func updateFirmware(uploader *plugin.FwUploader, fwPath *paths.Path) (*flasher.FlashResult, error) {
 	var stdout, stderr io.Writer
 	if feedback.GetFormat() == feedback.Text {
 		stdout = os.Stdout
@@ -183,64 +164,6 @@ func updateFirmwareWithPlugin(uploader *plugin.FwUploader, fwPath *paths.Path) (
 	}, nil
 }
 
-func updateFirmware(board *firmwareindex.IndexBoard, loaderSketch, moduleName string, uploadToolDir, firmwareFile *paths.Path) (*flasher.FlashResult, error) {
-	programmerOut, programmerErr, err := common.FlashSketch(board, loaderSketch, uploadToolDir, commonFlags.Address)
-	if err != nil {
-		return nil, err
-	}
-	// Wait a bit after flashing the loader sketch for the board to become
-	// available again.
-	logrus.Debug("sleeping for 3 sec")
-	time.Sleep(3 * time.Second)
-
-	// Get flasher depending on which module to use
-	var f flasher.Flasher
-
-	// This matches the baudrate used in the FirmwareUpdater.ino sketch
-	// https://github.com/arduino-libraries/WiFiNINA/blob/master/examples/Tools/FirmwareUpdater/FirmwareUpdater.ino
-	const baudRate = 1000000
-	switch moduleName {
-	case "NINA":
-		// we use address and not bootloaderPort because the board should not be in bootloader mode
-		f, err = flasher.NewNinaFlasher(commonFlags.Address, baudRate, 30)
-	case "WINC1500":
-		f, err = flasher.NewWincFlasher(commonFlags.Address, baudRate, 30)
-	default:
-		err = fmt.Errorf("unknown module: %s", moduleName)
-		feedback.Fatal(fmt.Sprintf("Error during firmware flashing: %s", err), feedback.ErrGeneric)
-	}
-	if err != nil {
-		return nil, fmt.Errorf("error during firmware flashing: %s", err)
-	}
-	defer f.Close()
-
-	// now flash the actual firmware
-	flasherOut := new(bytes.Buffer)
-	flasherErr := new(bytes.Buffer)
-	if feedback.GetFormat() == feedback.JSON {
-		err = f.FlashFirmware(firmwareFile, flasherOut)
-	} else {
-		f.SetProgressCallback(printProgress)
-		err = f.FlashFirmware(firmwareFile, os.Stdout)
-	}
-	if err != nil {
-		flasherErr.Write([]byte(fmt.Sprintf("Error during firmware flashing: %s", err)))
-		return nil, err
-	}
-
-	// Print the results
-	return &flasher.FlashResult{
-		Programmer: (&flasher.ExecOutput{
-			Stdout: programmerOut.String(),
-			Stderr: programmerErr.String(),
-		}),
-		Flasher: (&flasher.ExecOutput{
-			Stdout: flasherOut.String(),
-			Stderr: flasherErr.String(),
-		}),
-	}, nil
-}
-
 // callback used to print the progress
 func printProgress(progress int) {
 	fmt.Printf("Flashing progress: %d%%\r", progress)
diff --git a/cli/firmware/getversion.go b/cli/firmware/getversion.go
index 16b1ab47..357ea614 100644
--- a/cli/firmware/getversion.go
+++ b/cli/firmware/getversion.go
@@ -21,22 +21,14 @@ package firmware
 import (
 	"fmt"
 	"io"
-	"log"
 	"os"
-	"strings"
-	"time"
 
 	"github.com/arduino/arduino-fwuploader/cli/common"
 	"github.com/arduino/arduino-fwuploader/cli/feedback"
 	"github.com/arduino/arduino-fwuploader/cli/globals"
 	"github.com/arduino/arduino-fwuploader/flasher"
-	"github.com/arduino/arduino-fwuploader/indexes/download"
-	"github.com/arduino/arduino-fwuploader/indexes/firmwareindex"
 	"github.com/arduino/arduino-fwuploader/plugin"
-	"github.com/arduino/go-paths-helper"
-	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
-	semver "go.bug.st/relaxed-semver"
 )
 
 // NewGetVersionCommand creates a new `get-version` command
@@ -46,8 +38,8 @@ func NewGetVersionCommand() *cobra.Command {
 		Short: "Gets the version of the firmware the board is using.",
 		Long:  "Flashes a sketch to a board to obtain the firmware version used by the board",
 		Example: "" +
-			"  " + os.Args[0] + " firmware get-version --fqbn arduino:samd:mkr1000 --address COM10\n" +
-			"  " + os.Args[0] + " firmware get-version -b arduino:samd:mkr1000 -a COM10\n",
+			"  " + os.Args[0] + " firmware get-version --fqbn arduino:samd:mkrwifi1010 --address COM10\n" +
+			"  " + os.Args[0] + " firmware get-version -b arduino:renesas_uno:unor4wifi -a COM10\n",
 		Args: cobra.NoArgs,
 		Run:  runGetVersion,
 	}
@@ -64,26 +56,20 @@ func runGetVersion(cmd *cobra.Command, args []string) {
 	board := common.GetBoard(firmwareIndex, commonFlags.Fqbn)
 	uploadToolDir := common.DownloadRequiredToolsForBoard(packageIndex, board)
 
-	var result *flasher.FlashResult
-	if !board.IsPlugin() {
-		result = getVersion(board, uploadToolDir)
-	} else {
-		uploader, err := plugin.NewFWUploaderPlugin(uploadToolDir)
-		if err != nil {
-			feedback.Fatal(fmt.Sprintf("Could not open uploader plugin: %s", err), feedback.ErrGeneric)
-		}
-		result = getVersionWithPlugin(uploader)
+	uploader, err := plugin.NewFWUploaderPlugin(uploadToolDir)
+	if err != nil {
+		feedback.Fatal(fmt.Sprintf("Could not open uploader plugin: %s", err), feedback.ErrGeneric)
 	}
 
+	result := getVersion(uploader)
 	if feedback.GetFormat() == feedback.Text {
 		fmt.Printf("Firmware version installed: %s", result.Version)
 	} else {
-		// Print the results
 		feedback.PrintResult(result)
 	}
 }
 
-func getVersionWithPlugin(uploader *plugin.FwUploader) *flasher.FlashResult {
+func getVersion(uploader *plugin.FwUploader) *flasher.FlashResult {
 	var stdout, stderr io.Writer
 	if feedback.GetFormat() == feedback.Text {
 		stdout = os.Stdout
@@ -102,62 +88,3 @@ func getVersionWithPlugin(uploader *plugin.FwUploader) *flasher.FlashResult {
 		Version: res.FirmwareVersion.String(),
 	}
 }
-
-func getVersion(board *firmwareindex.IndexBoard, uploadToolDir *paths.Path) *flasher.FlashResult {
-	versionSketchPath, err := download.DownloadSketch(board.VersionSketch)
-	if err != nil {
-		feedback.Fatal(fmt.Sprintf("Error downloading loader sketch from %s: %s", board.LoaderSketch.URL, err), feedback.ErrGeneric)
-	}
-	logrus.Debugf("version sketch downloaded in %s", versionSketchPath.String())
-
-	versionSketch := strings.ReplaceAll(versionSketchPath.String(), versionSketchPath.Ext(), "")
-
-	programmerOut, programmerErr, err := common.FlashSketch(board, versionSketch, uploadToolDir, commonFlags.Address)
-	if err != nil {
-		feedback.FatalError(err, feedback.ErrGeneric)
-	}
-
-	// Wait a bit after flashing the sketch for the board to become available again.
-	logrus.Debug("sleeping for 3 sec")
-	time.Sleep(3 * time.Second)
-
-	// 9600 is the baudrate used in the CheckVersion sketch
-	port, err := flasher.OpenSerial(commonFlags.Address, 9600, 2)
-	if err != nil {
-		feedback.FatalError(err, feedback.ErrGeneric)
-	}
-
-	buff := make([]byte, 200)
-	serialResult := make([]byte, 0)
-	for {
-		n, err := port.Read(buff)
-		if err != nil {
-			log.Fatal(err)
-			break
-		}
-		serialResult = append(serialResult, buff[:n]...)
-		if n == 0 { // exit when done reading from serial
-			break
-		}
-		logrus.Info(string(buff[:n]))
-	}
-	lines := strings.Split(string(serialResult), "\n")
-	for _, line := range lines {
-		if strings.HasPrefix(line, "Firmware version installed: ") {
-			version := strings.TrimSpace(strings.Replace(line, "Firmware version installed: ", "", 1))
-			semver := semver.ParseRelaxed(version)
-			return &flasher.FlashResult{
-				Programmer: (&flasher.ExecOutput{
-					Stdout: programmerOut.String(),
-					Stderr: programmerErr.String(),
-				}),
-				Version: semver.String(),
-			}
-		}
-		if strings.HasPrefix(line, "Communication with WiFi module failed!") {
-			feedback.Fatal("communication with WiFi module failed", feedback.ErrGeneric)
-		}
-	}
-	feedback.Fatal("could not find the version string to parse", feedback.ErrGeneric)
-	return nil
-}
diff --git a/cli/firmware/list.go b/cli/firmware/list.go
index 97531551..2a2a4278 100644
--- a/cli/firmware/list.go
+++ b/cli/firmware/list.go
@@ -35,7 +35,7 @@ func newListCommand() *cobra.Command {
 		Use:     "list",
 		Short:   "List available firmwares",
 		Long:    "Displays the availale firmwares, is it possible to filter results for a specific board.",
-		Example: "  " + os.Args[0] + " firmware list -b arduino:samd:mkr1000",
+		Example: "  " + os.Args[0] + " firmware list -b arduino:renesas_uno:unor4wifi",
 		Args:    cobra.NoArgs,
 		Run: func(cmd *cobra.Command, args []string) {
 			list(*fqbn)
diff --git a/cli/globals/globals.go b/cli/globals/globals.go
index 424fb7c5..38f4bfc7 100644
--- a/cli/globals/globals.go
+++ b/cli/globals/globals.go
@@ -26,7 +26,6 @@ import (
 
 var (
 	PackageIndexGZURL        = "https://downloads.arduino.cc/packages/package_index.json.gz"
-	ModuleFirmwareIndexGZURL = "https://downloads.arduino.cc/arduino-fwuploader/boards/module_firmware_index.json.gz"
 	PluginFirmwareIndexGZURL = "https://downloads.arduino.cc/arduino-fwuploader/boards/plugin_firmware_index.json.gz"
 	FwUploaderPath           = paths.TempDir().Join("fwuploader")
 	Verbose                  bool
diff --git a/cli/globals/keys/module_firmware_index_public.gpg.key b/cli/globals/keys/plugin_firmware_index_public.gpg.key
similarity index 100%
rename from cli/globals/keys/module_firmware_index_public.gpg.key
rename to cli/globals/keys/plugin_firmware_index_public.gpg.key
diff --git a/docs/deprecated.md b/docs/deprecated.md
new file mode 100644
index 00000000..5dbf79ea
--- /dev/null
+++ b/docs/deprecated.md
@@ -0,0 +1,18 @@
+# Deprecated boards
+
+## MKR 1000
+
+The [Arduino MKR 1000] has been deprecated during the migration to the [plugin] system because the board has reached
+it's EOL state. If you wish to update the firmware it's still possible by using version [2.3.0] of the Arduino Firmware
+Uploader.
+
+## MKR Vidor 4000
+
+The [Arduino MKR Vidor 4000] has been deprecated during the migration to the [plugin] system because the board has
+reached it's EOL state. If you wish to update the firmware it's still possible by using version [2.3.0] of the Arduino
+Firmware Uploader.
+
+[Arduino MKR 1000]: https://docs.arduino.cc/hardware/mkr-1000-wifi
+[Arduino MKR Vidor 4000]: https://docs.arduino.cc/hardware/mkr-vidor-4000
+[2.3.0]: https://github.com/arduino/arduino-fwuploader/releases/tag/2.3.0
+[plugin]: plugins.md
diff --git a/docs/index.md b/docs/index.md
index 02a69311..f2ac9dd1 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,5 +1,5 @@
 The Arduino Firmware Uploader is a tool made to update the firmware and/or add SSL certificates for any Arduino board
-equipped with WINC or NINA Wi-Fi module.
+equipped with ESP32-S3 or NINA Wi-Fi module.
 
 ## Installation
 
diff --git a/docs/usage.md b/docs/usage.md
index a3872788..62298ec4 100644
--- a/docs/usage.md
+++ b/docs/usage.md
@@ -15,18 +15,18 @@ version are specified **the latest version of the firmware** will be used.
 
 If you want to flash a specific version of a firmware you can use the `-m` or `--module` flag
 
-For example to flash the WINC module present on the MKR 1000 with version 19.6.1 of the firmware you can run something
-like:
+For example to flash the ESP32-S3 module present on the UNO R4 WiFi with version 0.2.1 of the firmware you can run
+something like:
 
 ```
-./arduino-fwuploader firmware flash -b arduino:samd:mkr1000 -a /dev/ttyACM0 -m WINC1500@19.6.1
+./arduino-fwuploader firmware flash -b arduino:renesas_uno:unor4wifi -a /dev/ttyACM0 -m ESP32-S3@0.2.1
 ```
 
 Or if you want upload a local firmware you can use the `-i` or `--input-file` flag followed by the path of that
 firmware.
 
 ```
-./arduino-fwuploader firmware flash -i custom_fw.bin -b arduino:samd:mkr1000 -a /dev/ttyACM0
+./arduino-fwuploader firmware flash -i custom_fw.bin -b arduino:renesas_uno:unor4wifi -a /dev/ttyACM0
 ```
 
 There is a retry mechanism because the flashing process uses serial communication, which sometimes can be a bit
diff --git a/firmwares/WINC1500/19.4.4/WINC1500-arduino.samd.mkr1000.bin b/firmwares/WINC1500/19.4.4/WINC1500-arduino.samd.mkr1000.bin
deleted file mode 100644
index 49041e0c..00000000
Binary files a/firmwares/WINC1500/19.4.4/WINC1500-arduino.samd.mkr1000.bin and /dev/null differ
diff --git a/firmwares/WINC1500/19.4.4/m2m_aio_2b0.bin b/firmwares/WINC1500/19.4.4/m2m_aio_2b0.bin
deleted file mode 100644
index 1c6ac8e9..00000000
Binary files a/firmwares/WINC1500/19.4.4/m2m_aio_2b0.bin and /dev/null differ
diff --git a/firmwares/WINC1500/19.5.2/WINC1500-arduino.samd.mkr1000.bin b/firmwares/WINC1500/19.5.2/WINC1500-arduino.samd.mkr1000.bin
deleted file mode 100644
index d4995bef..00000000
Binary files a/firmwares/WINC1500/19.5.2/WINC1500-arduino.samd.mkr1000.bin and /dev/null differ
diff --git a/firmwares/WINC1500/19.5.4/WINC1500-arduino.samd.mkr1000.bin b/firmwares/WINC1500/19.5.4/WINC1500-arduino.samd.mkr1000.bin
deleted file mode 100755
index f4b1f366..00000000
Binary files a/firmwares/WINC1500/19.5.4/WINC1500-arduino.samd.mkr1000.bin and /dev/null differ
diff --git a/firmwares/WINC1500/19.6.1/WINC1500-arduino.samd.mkr1000.bin b/firmwares/WINC1500/19.6.1/WINC1500-arduino.samd.mkr1000.bin
deleted file mode 100644
index 99f0679b..00000000
Binary files a/firmwares/WINC1500/19.6.1/WINC1500-arduino.samd.mkr1000.bin and /dev/null differ
diff --git a/firmwares/getversion/arduino.samd.mkr1000/CheckWifi101FirmwareVersion.ino.bin b/firmwares/getversion/arduino.samd.mkr1000/CheckWifi101FirmwareVersion.ino.bin
deleted file mode 100644
index 55538f75..00000000
Binary files a/firmwares/getversion/arduino.samd.mkr1000/CheckWifi101FirmwareVersion.ino.bin and /dev/null differ
diff --git a/firmwares/getversion/arduino.samd.mkrvidor4000/CheckFirmwareVersion.ino.bin b/firmwares/getversion/arduino.samd.mkrvidor4000/CheckFirmwareVersion.ino.bin
deleted file mode 100644
index 5cbc438a..00000000
Binary files a/firmwares/getversion/arduino.samd.mkrvidor4000/CheckFirmwareVersion.ino.bin and /dev/null differ
diff --git a/firmwares/loader/arduino.samd.mkr1000/loader.bin b/firmwares/loader/arduino.samd.mkr1000/loader.bin
deleted file mode 100644
index d2eb0d4f..00000000
Binary files a/firmwares/loader/arduino.samd.mkr1000/loader.bin and /dev/null differ
diff --git a/firmwares/loader/arduino.samd.mkrvidor4000/loader.bin b/firmwares/loader/arduino.samd.mkrvidor4000/loader.bin
deleted file mode 100755
index 1d7e75e5..00000000
Binary files a/firmwares/loader/arduino.samd.mkrvidor4000/loader.bin and /dev/null differ
diff --git a/flasher/certificate.go b/flasher/certificate.go
deleted file mode 100644
index 355409bd..00000000
--- a/flasher/certificate.go
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
-	arduino-fwuploader
-	Copyright (c) 2021 Arduino LLC.  All right reserved.
-
-	This program is free software: you can redistribute it and/or modify
-	it under the terms of the GNU Affero General Public License as published
-	by the Free Software Foundation, either version 3 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU Affero General Public License for more details.
-
-	You should have received a copy of the GNU Affero General Public License
-	along with this program.  If not, see <https://www.gnu.org/licenses/>.
-*/
-
-package flasher
-
-import (
-	"bytes"
-	"crypto/rsa"
-	"crypto/sha1"
-	"crypto/x509"
-	"crypto/x509/pkix"
-	"encoding/asn1"
-	"encoding/binary"
-	"time"
-
-	"github.com/sirupsen/logrus"
-)
-
-func calculateNameSha1(cert *x509.Certificate) (b []byte, err error) {
-	nameSha1 := sha1.New()
-
-	var subjectDistinguishedNameSequence pkix.RDNSequence
-
-	if _, err = asn1.Unmarshal(cert.RawSubject, &subjectDistinguishedNameSequence); err != nil {
-		logrus.Error(err)
-		return nil, err
-	}
-
-	for _, dn := range subjectDistinguishedNameSequence {
-		nameSha1.Write([]byte(dn[0].Value.(string)))
-	}
-
-	b = nameSha1.Sum(nil)
-
-	return
-}
-
-func convertTime(time time.Time) ([]byte, error) {
-	asn1Bytes, err := asn1.Marshal(time)
-	if err != nil {
-		logrus.Error(err)
-		return nil, err
-	}
-
-	b := bytes.Repeat([]byte{0x00}, 20) // value must be zero bytes
-	copy(b, asn1Bytes[2:])              // copy but drop the first two bytes
-
-	return b, err
-}
-
-func modulusN(publicKey rsa.PublicKey) []byte {
-	return publicKey.N.Bytes()
-}
-
-func publicExponent(publicKey rsa.PublicKey) []byte {
-	b := make([]byte, 4)
-	binary.BigEndian.PutUint32(b, uint32(publicKey.E))
-	// strip leading zeros
-	for b[0] == 0 {
-		b = b[1:]
-	}
-	return b
-}
-
-func uint16ToBytes(i int) []byte {
-	b := make([]byte, 2)
-	binary.LittleEndian.PutUint16(b, uint16(i))
-	return b
-}
diff --git a/flasher/flasher.go b/flasher/flasher.go
index 60a7de73..31db55e9 100644
--- a/flasher/flasher.go
+++ b/flasher/flasher.go
@@ -18,66 +18,6 @@
 
 package flasher
 
-import (
-	"fmt"
-	"io"
-	"time"
-
-	"github.com/arduino/go-paths-helper"
-	"github.com/sirupsen/logrus"
-	"go.bug.st/serial"
-)
-
-type CommandData struct {
-	Command byte
-	Address uint32
-	Value   uint32
-	Payload []byte
-}
-
-func (d CommandData) String() string {
-	return fmt.Sprintf("%+v, %+v, %+v, %+v", d.Command, d.Address, d.Value, d.Payload)
-}
-
-type FlasherError struct {
-	err string
-}
-
-func (e FlasherError) Error() string {
-	return e.err
-}
-
-type Flasher interface {
-	FlashFirmware(firmwareFile *paths.Path, flasherOut io.Writer) error
-	FlashCertificates(certificatePaths *paths.PathList, URLs []string, flasherOut io.Writer) error
-	Close() error
-	SetProgressCallback(func(progress int))
-
-	hello() error
-	write(address uint32, buffer []byte) error
-	flashChunk(offset int, buffer []byte) error
-	getMaximumPayloadSize() (uint16, error)
-	serialFillBuffer(buffer []byte) error
-	sendCommand(data CommandData) error
-}
-
-// OpenSerial opens a new serial connection with the specified portAddress
-func OpenSerial(portAddress string, baudRate int, readTimeout int) (serial.Port, error) {
-
-	port, err := serial.Open(portAddress, &serial.Mode{BaudRate: baudRate})
-	if err != nil {
-		return nil, err
-	}
-	logrus.Infof("Opened port %s at %d", portAddress, baudRate)
-
-	if err := port.SetReadTimeout(time.Duration(readTimeout) * time.Second); err != nil {
-		err = fmt.Errorf("could not set timeout on serial port: %s", err)
-		logrus.Error(err)
-		return nil, err
-	}
-	return port, nil
-}
-
 // FlashResult contains the result of the flashing procedure
 type FlashResult struct {
 	Programmer *ExecOutput `json:"programmer"`
diff --git a/flasher/nina.go b/flasher/nina.go
deleted file mode 100644
index 6296f697..00000000
--- a/flasher/nina.go
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
-	arduino-fwuploader
-	Copyright (c) 2021 Arduino LLC.  All right reserved.
-
-	This program is free software: you can redistribute it and/or modify
-	it under the terms of the GNU Affero General Public License as published
-	by the Free Software Foundation, either version 3 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU Affero General Public License for more details.
-
-	You should have received a copy of the GNU Affero General Public License
-	along with this program.  If not, see <https://www.gnu.org/licenses/>.
-*/
-
-package flasher
-
-import (
-	"bytes"
-	"crypto/md5"
-	"encoding/binary"
-	"fmt"
-	"io"
-	"time"
-
-	"github.com/arduino/arduino-fwuploader/certificates"
-	"github.com/arduino/go-paths-helper"
-	"github.com/sirupsen/logrus"
-	"go.bug.st/serial"
-)
-
-// NewNinaFlasher creates an new instance of NinaFlasher
-func NewNinaFlasher(portAddress string, baudRate, readTimeout int) (*NinaFlasher, error) {
-	port, err := OpenSerial(portAddress, baudRate, readTimeout)
-	if err != nil {
-		logrus.Error(err)
-		return nil, err
-	}
-	time.Sleep(2 * time.Second)
-	f := &NinaFlasher{port: port}
-	payloadSize, err := f.getMaximumPayloadSize()
-	if err != nil {
-		logrus.Error(err)
-		return nil, err
-	}
-	if payloadSize < 1024 {
-		err = fmt.Errorf("programmer reports %d as maximum payload size (1024 is needed)", payloadSize)
-		logrus.Error(err)
-		return nil, err
-	}
-	f.payloadSize = int(payloadSize)
-	return f, nil
-}
-
-type NinaFlasher struct {
-	port             serial.Port
-	payloadSize      int
-	progressCallback func(int)
-}
-
-// FlashFirmware in board connected to port using data from firmwareFile
-func (f *NinaFlasher) FlashFirmware(firmwareFile *paths.Path, flasherOut io.Writer) error {
-	logrus.Infof("Flashing firmware %s", firmwareFile)
-	flasherOut.Write([]byte(fmt.Sprintf("Flashing firmware %s\n", firmwareFile)))
-	if err := f.hello(); err != nil {
-		logrus.Error(err)
-		return err
-	}
-
-	logrus.Debugf("Reading file %s", firmwareFile)
-	data, err := firmwareFile.ReadFile()
-	if err != nil {
-		logrus.Error(err)
-		return err
-	}
-
-	logrus.Debugf("Flashing chunks")
-	firmwareOffset := 0x0000
-	if err := f.flashChunk(firmwareOffset, data); err != nil {
-		logrus.Error(err)
-		return err
-	}
-
-	logrus.Debugf("Checking md5")
-	if err := f.md5sum(data); err != nil {
-		logrus.Error(err)
-		return err
-	}
-	logrus.Infof("Flashed all the things")
-	flasherOut.Write([]byte("Flashing progress: 100%\n"))
-	return nil
-}
-
-func (f *NinaFlasher) FlashCertificates(certificatePaths *paths.PathList, URLs []string, flasherOut io.Writer) error {
-	var certificatesData []byte
-	for _, certPath := range *certificatePaths {
-		logrus.Infof("Converting and flashing certificate %s", certPath)
-		flasherOut.Write([]byte(fmt.Sprintf("Converting and flashing certificate %s\n", certPath)))
-
-		certs, err := certificates.LoadCertificatesFromFile(certPath)
-		if err != nil {
-			return err
-		}
-		for _, cert := range certs {
-			data := certificates.EncodeCertificateAsPEM(cert)
-			certificatesData = append(certificatesData, data...)
-		}
-	}
-
-	for _, URL := range URLs {
-		logrus.Infof("Converting and flashing certificate from %s", URL)
-		flasherOut.Write([]byte(fmt.Sprintf("Converting and flashing certificate from %s\n", URL)))
-		rootCertificate, err := certificates.ScrapeRootCertificatesFromURL(URL)
-		if err != nil {
-			return err
-		}
-		data := certificates.EncodeCertificateAsPEM(rootCertificate)
-		certificatesData = append(certificatesData, data...)
-	}
-
-	certificatesDataLimit := 0x20000
-	if len(certificatesData) > certificatesDataLimit {
-		err := fmt.Errorf("certificates data %d exceeds limit of %d bytes", len(certificatesData), certificatesDataLimit)
-		logrus.Error(err)
-		return err
-	}
-
-	// Pad certificatesData to flash page
-	for len(certificatesData)%int(f.payloadSize) != 0 {
-		certificatesData = append(certificatesData, 0)
-	}
-
-	certificatesOffset := 0x10000
-	if err := f.flashChunk(certificatesOffset, certificatesData); err != nil {
-		logrus.Error(err)
-		return err
-	}
-	logrus.Infof("Flashed all the things")
-	flasherOut.Write([]byte("Flashed all the things\n"))
-	return nil
-}
-
-// Close the port used by this flasher
-func (f *NinaFlasher) Close() error {
-	return f.port.Close()
-}
-
-// Ping the programmer to see if it is alive.
-// Also check if the version of the programmer protocol match the uploader
-func (f *NinaFlasher) hello() error {
-	// "HELLO" command
-	err := f.sendCommand(CommandData{
-		Command: 0x99,
-		Address: 0x11223344,
-		Value:   0x55667788,
-		Payload: nil,
-	})
-	if err != nil {
-		logrus.Error(err)
-		return err
-	}
-
-	// Wait a bit
-	time.Sleep(100 * time.Millisecond)
-
-	// Receive response
-	res := make([]byte, 65535)
-	n, err := f.port.Read(res)
-	if err != nil {
-		logrus.Error(err)
-		return err
-	}
-	// flush eventual leftover from the rx buffer
-	if n >= 6 {
-		res = res[n-6 : n]
-	}
-
-	if res[0] != 'v' {
-		err = FlasherError{err: "Programmer is not responding"}
-		logrus.Error(err)
-		return err
-	}
-	if string(res) != "v10000" {
-		// TODO: Do we really need this check? What is it trying to verify?
-		err = FlasherError{err: fmt.Sprintf("Programmer version mismatch, v10000 needed: %s", res)}
-		logrus.Error(err)
-		return err
-	}
-	return nil
-}
-
-// flashChunk flashes a chunk of data
-func (f *NinaFlasher) flashChunk(offset int, buffer []byte) error {
-	chunkSize := int(f.payloadSize)
-	bufferLength := len(buffer)
-
-	if err := f.erase(uint32(offset), uint32(bufferLength)); err != nil {
-		logrus.Error(err)
-		return err
-	}
-
-	for i := 0; i < bufferLength; i += chunkSize {
-		progress := (i * 100) / bufferLength
-		logrus.Debugf("Flashing chunk: %d%%", progress)
-		if f.progressCallback != nil {
-			f.progressCallback(progress)
-		}
-		start := i
-		end := i + chunkSize
-		if end > bufferLength {
-			end = bufferLength
-		}
-		if err := f.write(uint32(offset+i), buffer[start:end]); err != nil {
-			logrus.Error(err)
-			return err
-		}
-	}
-
-	return nil
-}
-
-// getMaximumPayloadSize asks the board the maximum payload size
-func (f *NinaFlasher) getMaximumPayloadSize() (uint16, error) {
-	// "MAX_PAYLOAD_SIZE" command
-	err := f.sendCommand(CommandData{
-		Command: 0x50,
-		Address: 0,
-		Value:   0,
-		Payload: nil,
-	})
-	if err != nil {
-		logrus.Error(err)
-		return 0, err
-	}
-
-	// Receive response
-	res := make([]byte, 2)
-	if err := f.serialFillBuffer(res); err != nil {
-		logrus.Error(err)
-		return 0, err
-	}
-	return (uint16(res[0]) << 8) + uint16(res[1]), nil
-}
-
-// serialFillBuffer fills buffer with data read from the serial port
-func (f *NinaFlasher) serialFillBuffer(buffer []byte) error {
-	read := 0
-	for read < len(buffer) {
-		n, err := f.port.Read(buffer[read:])
-		if err != nil {
-			logrus.Error(err)
-			return err
-		}
-		if n == 0 {
-			err = FlasherError{err: "Serial port closed unexpectedly"}
-			logrus.Error(err)
-			return err
-		}
-		read += n
-	}
-	return nil
-}
-
-// sendCommand sends the data over serial port to connected board
-func (f *NinaFlasher) sendCommand(data CommandData) error {
-	logrus.Debugf("sending command data %s", data)
-	buff := new(bytes.Buffer)
-	if err := binary.Write(buff, binary.BigEndian, data.Command); err != nil {
-		err = fmt.Errorf("writing command: %s", err)
-		logrus.Error(err)
-		return err
-	}
-	if err := binary.Write(buff, binary.BigEndian, data.Address); err != nil {
-		err = fmt.Errorf("writing address: %s", err)
-		logrus.Error(err)
-		return err
-	}
-	if err := binary.Write(buff, binary.BigEndian, data.Value); err != nil {
-		err = fmt.Errorf("writing value: %s", err)
-		logrus.Error(err)
-		return err
-	}
-	var length uint16
-	if data.Payload == nil {
-		length = 0
-	} else {
-		length = uint16(len(data.Payload))
-	}
-	if err := binary.Write(buff, binary.BigEndian, length); err != nil {
-		err = fmt.Errorf("writing payload length: %s", err)
-		logrus.Error(err)
-		return err
-	}
-	if data.Payload != nil {
-		buff.Write(data.Payload)
-	}
-	bufferData := buff.Bytes()
-	for {
-		sent, err := f.port.Write(bufferData)
-		if err != nil {
-			err = fmt.Errorf("writing data: %s", err)
-			logrus.Error(err)
-			return err
-		}
-		if sent == len(bufferData) {
-			break
-		}
-		logrus.Debugf("Sent %d bytes out of %d", sent, len(bufferData))
-		bufferData = bufferData[sent:]
-	}
-	return nil
-}
-
-// read a block of flash memory
-func (f *NinaFlasher) read(address uint32, length uint32) ([]byte, error) {
-	// "FLASH_READ" command
-	err := f.sendCommand(CommandData{
-		Command: 0x01,
-		Address: address,
-		Value:   length,
-		Payload: nil,
-	})
-	if err != nil {
-		logrus.Error(err)
-		return nil, err
-	}
-
-	// Receive response
-	result := make([]byte, length)
-	if err := f.serialFillBuffer(result); err != nil {
-		logrus.Error(err)
-		return nil, err
-	}
-	ack := make([]byte, 2)
-	if err := f.serialFillBuffer(ack); err != nil {
-		logrus.Error(err)
-		return nil, err
-	}
-	if string(ack) != "OK" {
-		err = FlasherError{err: fmt.Sprintf("Missing ack on read: %s, result: %s", ack, result)}
-		logrus.Error(err)
-		return nil, err
-	}
-	return result, nil
-}
-
-// write a block of flash memory
-func (f *NinaFlasher) write(address uint32, buffer []byte) error {
-	// "FLASH_WRITE" command
-	err := f.sendCommand(CommandData{
-		Command: 0x02,
-		Address: address,
-		Value:   0,
-		Payload: buffer,
-	})
-	if err != nil {
-		logrus.Error(err)
-		return err
-	}
-
-	// wait acknowledge
-	ack := make([]byte, 2)
-	if err := f.serialFillBuffer(ack); err != nil {
-		logrus.Error(err)
-		return err
-	}
-	if string(ack) != "OK" {
-		err = FlasherError{err: fmt.Sprintf("Missing ack on write: %s", ack)}
-		logrus.Error(err)
-		return err
-	}
-	return nil
-}
-
-// erase a block of flash memory
-func (f *NinaFlasher) erase(address uint32, length uint32) error {
-	// "FLASH_ERASE" command
-	err := f.sendCommand(CommandData{
-		Command: 0x03,
-		Address: address,
-		Value:   length,
-		Payload: nil,
-	})
-	if err != nil {
-		logrus.Error(err)
-		return err
-	}
-
-	// wait acknowledge
-	ack := make([]byte, 2)
-	if err := f.serialFillBuffer(ack); err != nil {
-		logrus.Error(err)
-		return err
-	}
-	if string(ack) != "OK" {
-		err = FlasherError{err: fmt.Sprintf("Missing ack on erase: %s", ack)}
-		logrus.Error(err)
-		return err
-	}
-	return nil
-}
-
-func (f *NinaFlasher) md5sum(data []byte) error {
-	hasher := md5.New()
-	hasher.Write(data)
-
-	// Get md5sum
-	err := f.sendCommand(CommandData{
-		Command: 0x04,
-		Address: 0,
-		Value:   uint32(len(data)),
-		Payload: nil,
-	})
-	if err != nil {
-		logrus.Error(err)
-		return err
-	}
-
-	// Wait acknowledge
-	ack := make([]byte, 2)
-	if err := f.serialFillBuffer(ack); err != nil {
-		logrus.Error(err)
-		return err
-	}
-	if string(ack) != "OK" {
-		err := FlasherError{err: fmt.Sprintf("Missing ack on md5sum: %s", ack)}
-		logrus.Error(err)
-		return err
-	}
-
-	// Wait md5
-	md5sumfromdevice := make([]byte, 16)
-	if err := f.serialFillBuffer(md5sumfromdevice); err != nil {
-		return err
-	}
-
-	md5sum := hasher.Sum(nil)
-	logrus.Debugf("md5 read from device %s", md5sumfromdevice)
-	logrus.Debugf("md5 of data %s", md5sum)
-
-	for i := 0; i < 16; i++ {
-		if md5sum[i] != md5sumfromdevice[i] {
-			err := FlasherError{err: "MD5sum failed"}
-			logrus.Error(err)
-			return err
-		}
-	}
-
-	return nil
-}
-
-func (f *NinaFlasher) SetProgressCallback(callback func(progress int)) {
-	f.progressCallback = callback
-}
diff --git a/flasher/winc.go b/flasher/winc.go
deleted file mode 100644
index 9d67743a..00000000
--- a/flasher/winc.go
+++ /dev/null
@@ -1,444 +0,0 @@
-/*
-	arduino-fwuploader
-	Copyright (c) 2021 Arduino LLC.  All right reserved.
-
-	This program is free software: you can redistribute it and/or modify
-	it under the terms of the GNU Affero General Public License as published
-	by the Free Software Foundation, either version 3 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU Affero General Public License for more details.
-
-	You should have received a copy of the GNU Affero General Public License
-	along with this program.  If not, see <https://www.gnu.org/licenses/>.
-*/
-
-package flasher
-
-import (
-	"bytes"
-	"crypto/rsa"
-	"crypto/x509"
-	"encoding/binary"
-	"errors"
-	"fmt"
-	"io"
-	"time"
-
-	"github.com/arduino/arduino-fwuploader/certificates"
-	"github.com/arduino/go-paths-helper"
-	"github.com/sirupsen/logrus"
-	"go.bug.st/serial"
-)
-
-func NewWincFlasher(portAddress string, baudRate, readTimeout int) (*WincFlasher, error) {
-	port, err := OpenSerial(portAddress, baudRate, readTimeout)
-	if err != nil {
-		logrus.Error(err)
-		return nil, err
-	}
-	f := &WincFlasher{port: port}
-	payloadSize, err := f.getMaximumPayloadSize()
-	if err != nil {
-		logrus.Error(err)
-		return nil, err
-	}
-	if payloadSize < 1024 {
-		return nil, fmt.Errorf("programmer reports %d as maximum payload size (1024 is needed)", payloadSize)
-	}
-	f.payloadSize = int(payloadSize)
-	return f, nil
-}
-
-type WincFlasher struct {
-	port             serial.Port
-	payloadSize      int
-	progressCallback func(int)
-}
-
-func (f *WincFlasher) FlashFirmware(firmwareFile *paths.Path, flasherOut io.Writer) error {
-	logrus.Infof("Flashing firmware %s", firmwareFile)
-	flasherOut.Write([]byte(fmt.Sprintf("Flashing firmware %s\n", firmwareFile)))
-	data, err := firmwareFile.ReadFile()
-	if err != nil {
-		logrus.Error(err)
-		return err
-	}
-	firmwareOffset := 0x0000
-	if err = f.flashChunk(firmwareOffset, data); err != nil {
-		logrus.Error(err)
-		return err
-	}
-	logrus.Infof("Flashed all the things")
-	flasherOut.Write([]byte("Flashing progress: 100%\n"))
-	return nil
-}
-
-func (f *WincFlasher) FlashCertificates(certificatePaths *paths.PathList, URLs []string, flasherOut io.Writer) error {
-	var certificatesData []byte
-	for _, certPath := range *certificatePaths {
-		logrus.Infof("Converting and flashing certificate %s", certPath)
-		flasherOut.Write([]byte(fmt.Sprintf("Converting and flashing certificate %s\n", certPath)))
-
-		// Needed to mantain backword compatability
-		if certPath.Ext() == ".pem" {
-			certData, err := certPath.ReadFile()
-			if err != nil {
-				return err
-			}
-			certificatesData = append(certificatesData, certData...)
-			continue
-		}
-
-		certs, err := certificates.LoadCertificatesFromFile(certPath)
-		if err != nil {
-			return err
-		}
-		for _, cert := range certs {
-			data, err := f.getCertificateData(cert)
-			if err != nil {
-				return err
-			}
-			certificatesData = append(certificatesData, data...)
-		}
-	}
-
-	for _, URL := range URLs {
-		logrus.Infof("Converting and flashing certificate from %s", URL)
-		flasherOut.Write([]byte(fmt.Sprintf("Converting and flashing certificate from %s\n", URL)))
-		rootCertificate, err := certificates.ScrapeRootCertificatesFromURL(URL)
-		if err != nil {
-			return err
-		}
-		data, err := f.getCertificateData(rootCertificate)
-		if err != nil {
-			return err
-		}
-		certificatesData = append(certificatesData, data...)
-	}
-
-	certificatesOffset := 0x4000
-	if err := f.flashChunk(certificatesOffset, certificatesData); err != nil {
-		logrus.Error(err)
-		return err
-	}
-	logrus.Infof("Flashed all the things")
-	flasherOut.Write([]byte("Flashed all the things\n"))
-	return nil
-}
-
-func (f *WincFlasher) getCertificateData(cert *x509.Certificate) ([]byte, error) {
-	b := []byte{}
-	nameSHA1Bytes, err := calculateNameSha1(cert)
-	if err != nil {
-		return nil, err
-	}
-
-	notBeforeBytes, err := convertTime(cert.NotBefore)
-	if err != nil {
-		return nil, err
-	}
-
-	notAfterBytes, err := convertTime(cert.NotAfter)
-	if err != nil {
-		return nil, err
-	}
-
-	rsaPublicKey := *cert.PublicKey.(*rsa.PublicKey)
-
-	rsaModulusNBytes := modulusN(rsaPublicKey)
-	rsaPublicExponentBytes := publicExponent(rsaPublicKey)
-
-	rsaModulusNLenBytes := uint16ToBytes(len(rsaModulusNBytes))
-	rsaPublicExponentLenBytes := uint16ToBytes(len(rsaPublicExponentBytes))
-
-	b = append(b, nameSHA1Bytes...)
-	b = append(b, rsaModulusNLenBytes...)
-	b = append(b, rsaPublicExponentLenBytes...)
-	b = append(b, notBeforeBytes...)
-	b = append(b, notAfterBytes...)
-	b = append(b, rsaModulusNBytes...)
-	b = append(b, rsaPublicExponentBytes...)
-	for (len(b) & 3) != 0 {
-		b = append(b, 0xff) // padding
-	}
-	return b, nil
-}
-
-func (f *WincFlasher) Close() error {
-	return f.port.Close()
-}
-
-func (f *WincFlasher) hello() error {
-	// "HELLO" command
-	err := f.sendCommand(CommandData{
-		Command: 0x99,
-		Address: 0x11223344,
-		Value:   0x55667788,
-		Payload: nil,
-	})
-	if err != nil {
-		logrus.Error(err)
-		return err
-	}
-
-	// Wait a bit
-	time.Sleep(100 * time.Millisecond)
-
-	// Receive response
-	res := make([]byte, 65535)
-	n, err := f.port.Read(res)
-	if err != nil {
-		logrus.Error(err)
-		return err
-	}
-	// flush eventual leftover from the rx buffer
-	if n >= 6 {
-		res = res[n-6 : n]
-	}
-
-	if res[0] != 'v' {
-		err = FlasherError{err: "Programmer is not responding"}
-		logrus.Error(err)
-		return err
-	}
-	if string(res) != "v10000" {
-		// TODO: Do we really need this check? What is it trying to verify?
-		err = FlasherError{err: fmt.Sprintf("Programmer version mismatch, v10000 needed: %s", res)}
-		logrus.Error(err)
-		return err
-	}
-	return nil
-}
-
-func (f *WincFlasher) write(address uint32, buffer []byte) error {
-	// "FLASH_WRITE" command
-	err := f.sendCommand(CommandData{
-		Command: 0x02,
-		Address: address,
-		Value:   0,
-		Payload: buffer,
-	})
-	if err != nil {
-		logrus.Error(err)
-		return err
-	}
-
-	// wait acknowledge
-	ack := make([]byte, 2)
-	if err := f.serialFillBuffer(ack); err != nil {
-		logrus.Error(err)
-		return err
-	}
-	if string(ack) != "OK" {
-		err = FlasherError{err: fmt.Sprintf("Missing ack on write: %s", ack)}
-		logrus.Error(err)
-		return err
-	}
-	return nil
-}
-
-func (f *WincFlasher) flashChunk(offset int, buffer []byte) error {
-	bufferLength := len(buffer)
-
-	if err := f.erase(uint32(offset), uint32(bufferLength)); err != nil {
-		logrus.Error(err)
-		return err
-	}
-
-	for i := 0; i < bufferLength; i += f.payloadSize {
-		progress := ((i * 100) / bufferLength)
-		logrus.Debugf("Flashing chunk: %d%%", progress)
-		if f.progressCallback != nil {
-			f.progressCallback(progress)
-		}
-		start := i
-		end := i + f.payloadSize
-		if end > bufferLength {
-			end = bufferLength
-		}
-		if err := f.write(uint32(offset+i), buffer[start:end]); err != nil {
-			logrus.Error(err)
-			return err
-		}
-	}
-
-	var flashData []byte
-	for i := 0; i < bufferLength; i += f.payloadSize {
-		readLength := f.payloadSize
-		if (i + f.payloadSize) > bufferLength {
-			readLength = bufferLength % f.payloadSize
-		}
-
-		data, err := f.read(uint32(offset+i), uint32(readLength))
-		if err != nil {
-			logrus.Error(err)
-			return err
-		}
-
-		flashData = append(flashData, data...)
-	}
-
-	if !bytes.Equal(buffer, flashData) {
-		err := errors.New("flash data does not match written")
-		logrus.Error(err)
-		return err
-	}
-
-	return nil
-}
-
-func (f *WincFlasher) getMaximumPayloadSize() (uint16, error) {
-	// "MAX_PAYLOAD_SIZE" command
-	err := f.sendCommand(CommandData{
-		Command: 0x50,
-		Address: 0,
-		Value:   0,
-		Payload: nil,
-	})
-	if err != nil {
-		logrus.Error(err)
-		return 0, err
-	}
-
-	// Receive response
-	res := make([]byte, 2)
-	if err := f.serialFillBuffer(res); err != nil {
-		logrus.Error(err)
-		return 0, err
-	}
-	return (uint16(res[0]) << 8) + uint16(res[1]), nil
-}
-
-func (f *WincFlasher) serialFillBuffer(buffer []byte) error {
-	read := 0
-	for read < len(buffer) {
-		n, err := f.port.Read(buffer[read:])
-		if err != nil {
-			logrus.Error(err)
-			return err
-		}
-		if n == 0 {
-			err = FlasherError{err: "Serial port closed unexpectedly"}
-			logrus.Error(err)
-			return err
-		}
-		read += n
-	}
-	return nil
-}
-
-func (f *WincFlasher) sendCommand(data CommandData) error {
-	logrus.Debugf("sending command data %s", data)
-	buff := new(bytes.Buffer)
-	if err := binary.Write(buff, binary.BigEndian, data.Command); err != nil {
-		logrus.Error(err)
-		return err
-	}
-	if err := binary.Write(buff, binary.BigEndian, data.Address); err != nil {
-		logrus.Error(err)
-		return err
-	}
-	if err := binary.Write(buff, binary.BigEndian, data.Value); err != nil {
-		logrus.Error(err)
-		return err
-	}
-	var length uint16
-	if data.Payload == nil {
-		length = 0
-	} else {
-		length = uint16(len(data.Payload))
-	}
-	if err := binary.Write(buff, binary.BigEndian, length); err != nil {
-		logrus.Error(err)
-		return err
-	}
-	if data.Payload != nil {
-		buff.Write(data.Payload)
-	}
-
-	bufferData := buff.Bytes()
-	for {
-		sent, err := f.port.Write(bufferData)
-		if err != nil {
-			logrus.Error(err)
-			return err
-		}
-		if sent == len(bufferData) {
-			break
-		}
-		logrus.Debugf("Sent %d bytes out of %d", sent, len(bufferData))
-		bufferData = bufferData[sent:]
-	}
-	return nil
-}
-
-// Read a block of flash memory
-func (f *WincFlasher) read(address uint32, length uint32) ([]byte, error) {
-	// "FLASH_READ" command
-	err := f.sendCommand(CommandData{
-		Command: 0x01,
-		Address: address,
-		Value:   length,
-		Payload: nil,
-	})
-	if err != nil {
-		logrus.Error(err)
-		return nil, err
-	}
-
-	// Receive response
-	result := make([]byte, length)
-	if err := f.serialFillBuffer(result); err != nil {
-		logrus.Error(err)
-		return nil, err
-	}
-	ack := make([]byte, 2)
-	if err := f.serialFillBuffer(ack); err != nil {
-		logrus.Error(err)
-		return nil, err
-	}
-	if string(ack) != "OK" {
-		err = FlasherError{err: fmt.Sprintf("Missing ack on read: %s", ack)}
-		logrus.Error(err)
-		return nil, err
-	}
-	return result, nil
-}
-
-// Erase a block of flash memory
-func (f *WincFlasher) erase(address uint32, length uint32) error {
-	// "FLASH_ERASE" command
-	err := f.sendCommand(CommandData{
-		Command: 0x03,
-		Address: address,
-		Value:   length,
-		Payload: nil,
-	})
-	if err != nil {
-		logrus.Error(err)
-		return err
-	}
-
-	logrus.Debugf("Erasing %d bytes from address 0x%X\n", length, address)
-
-	// wait acknowledge
-	ack := make([]byte, 2)
-	if err := f.serialFillBuffer(ack); err != nil {
-		logrus.Error(err)
-		return err
-	}
-	if string(ack) != "OK" {
-		err = FlasherError{err: fmt.Sprintf("Missing ack on erase: %s", ack)}
-		logrus.Error(err)
-		return err
-	}
-	return nil
-}
-
-func (f *WincFlasher) SetProgressCallback(callback func(progress int)) {
-	f.progressCallback = callback
-}
diff --git a/generator/boards.json b/generator/boards.json
deleted file mode 100644
index 159abd26..00000000
--- a/generator/boards.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "arduino:samd:mkr1000": {
-    "moduleName": "WINC1500",
-    "versions": ["19.4.4", "19.5.2", "19.5.4", "19.6.1"]
-  },
-  "arduino:samd:mkrvidor4000": {
-    "moduleName": "NINA",
-    "versions": ["1.0.0", "1.1.0"]
-  }
-}
diff --git a/generator/generator.py b/generator/generator.py
index 4ec1116c..fa416e4f 100755
--- a/generator/generator.py
+++ b/generator/generator.py
@@ -16,8 +16,6 @@
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 import argparse
-import subprocess
-import sys
 import json
 import hashlib
 import shutil
@@ -35,12 +33,6 @@ def get_firmware_file(module, simple_fqbn, version):
     return firmware_full_path / f"{module}.bin"
 
 
-# Runs arduino-cli, doesn't handle errors at all because am lazy
-def arduino_cli(cli_path, args=[]):
-    res = subprocess.run([cli_path, *args], capture_output=True, text=True)
-    return res.stdout
-
-
 # Generates file SHA256
 def sha2(file_path):
     with open(file_path, "rb") as f:
@@ -53,31 +45,6 @@ def split_property_and_drop_first_level(s):
     return (k, v)
 
 
-# Generate and copy precompiled Sketch binary data for specified board
-# (sketch type could be either "loader" or "getversion")
-def create_precomp_sketch_data(simple_fqbn, sketch_type):
-
-    sketch_dir = Path(__file__).parent / ".." / "firmwares" / sketch_type / simple_fqbn
-    sketch_files = list(sketch_dir.iterdir())
-    if len(sketch_files) != 1:
-        print(f"Invalid loader files found in {sketch_dir}")
-        sys.exit(1)
-    sketch_file = sketch_files[0]  # lets assume there's only a single file
-
-    sketch_dest = f"firmwares/{sketch_type}/{simple_fqbn}/{sketch_type}{sketch_file.suffix}"
-    sketch_dest_path = Path(__file__).parent / sketch_dest
-    sketch_dest_path.parent.mkdir(parents=True, exist_ok=True)
-    shutil.copyfile(sketch_file, sketch_dest_path)
-
-    file_hash = sha2(sketch_dest_path)
-
-    return {
-        "url": f"{DOWNLOAD_URL}/{sketch_dest}",
-        "checksum": f"SHA-256:{file_hash}",
-        "size": f"{sketch_dest_path.stat().st_size}",
-    }
-
-
 # Generate and copy all firmware binary data for specified board
 def create_firmware_data(binary, module, version):
     binary_name = binary.name
@@ -97,181 +64,6 @@ def create_firmware_data(binary, module, version):
     }
 
 
-def get_uploader_id(tools, tool_name):
-    for t in tools:
-        if t["name"] == tool_name:
-            packager = t["packager"]
-            name = t["name"]
-            version = t["version"]
-            return f"{packager}:{name}@{version}"
-
-
-def create_upload_data(fqbn, installed_cores):  # noqa: C901
-    upload_data = {}
-    # Assume we're on Linux
-    arduino15 = Path.home() / ".arduino15"
-
-    board_id = fqbn.split(":")[2]
-    core_id = ":".join(fqbn.split(":")[:2])
-
-    # Get the core install dir
-    core = installed_cores[core_id]
-    (maintainer, arch) = core_id.split(":")
-    core_install_dir = arduino15 / "packages" / maintainer / "hardware" / arch / core["installed"]
-
-    with open(core_install_dir / "boards.txt") as f:
-        boards_txt = f.readlines()
-
-    board_upload_data = {}
-    for line in boards_txt:
-        if line.startswith(f"{board_id}."):
-            (k, v) = split_property_and_drop_first_level(line)
-            board_upload_data[k] = v
-
-    tool = board_upload_data["upload.tool"]
-
-    with open(core_install_dir / "platform.txt") as f:
-        platform_txt = f.readlines()
-
-    platform_upload_data = {}
-    for line in platform_txt:
-        if line.startswith(f"tools.{tool}."):
-            (k, v) = split_property_and_drop_first_level(line)
-            platform_upload_data[k] = v
-
-    # We assume the installed.json exist
-    with open(core_install_dir / "installed.json") as f:
-        installed_json_data = json.load(f)
-
-    if f"{tool}.cmd" in platform_upload_data:
-        tool_executable_generic = platform_upload_data[f"{tool}.cmd"]
-        tool_executable_linux = platform_upload_data.get(f"{tool}.cmd.linux", tool_executable_generic)
-        tool_executable_windows = platform_upload_data.get(f"{tool}.cmd.windows", "")
-        tool_executable_macosx = platform_upload_data.get(f"{tool}.cmd.macosx", "")
-        tool_name = tool_executable_generic
-    elif f"{tool}.cmd.path" in platform_upload_data:
-        tool_executable_generic = "/".join(platform_upload_data[f"{tool}.cmd.path"].split("/")[1:])
-        tool_executable_linux = platform_upload_data.get(f"{tool}.cmd.path.linux", tool_executable_generic)
-        tool_executable_windows = platform_upload_data.get(f"{tool}.cmd.path.windows", "")
-        tool_executable_macosx = platform_upload_data.get(f"{tool}.cmd.path.macosx", "")
-        tool_name = tool_executable_generic.split("/")[-1]
-
-    tool_config_path = ""
-    if f"{tool}.config.path" in platform_upload_data:
-        tool_config_path = "/".join(platform_upload_data[f"{tool}.config.path"].split("/")[1:])
-
-    if tool_name == "rp2040load":
-        tool_name = "rp2040tools"
-
-    tools = installed_json_data["packages"][0]["platforms"][0]["toolsDependencies"]
-    upload_data["uploader"] = get_uploader_id(tools, tool_name)
-
-    if "upload.use_1200bps_touch" in board_upload_data:
-        upload_data["upload.use_1200bps_touch"] = bool(board_upload_data["upload.use_1200bps_touch"])
-
-    if "upload.wait_for_upload_port" in board_upload_data:
-        upload_data["upload.wait_for_upload_port"] = bool(board_upload_data["upload.wait_for_upload_port"])
-
-    # Get the command used to upload and modifies it a bit
-    command = (
-        platform_upload_data[f"{tool}.upload.pattern"]
-        .replace("{path}/{cmd}", "{uploader}")
-        .replace("{cmd.path}", "{uploader}")
-        .replace("{build.path}/{build.project_name}", "{loader.sketch}")
-        .replace("{config.path}", f"{{tool_dir}}/{tool_config_path}")
-        .replace('\\"', "")
-    )
-
-    if fqbn == "arduino:megaavr:uno2018":
-        # Long story short if we don't do this we'd have to host also the bootloader
-        # for the Uno WiFi rev2 and we don't want to, so we just remove this field
-        # and use a precompiled Loader Sketh binary that includes the bootloader.
-        command = command.replace("{upload.extra_files}", "")
-
-    # Get the rest of the params
-    params = {}
-    for k, v in platform_upload_data.items():
-        if f"{tool}.upload.params." in k:
-            param = k.split(".")[-1]
-            params[f"upload.{param}"] = v
-        elif f"{tool}.upload." in k:
-            k = ".".join(k.split(".")[1:])
-            params[k] = v
-
-    # Prepare the command
-    for k, v in {**board_upload_data, **params}.items():
-        command = command.replace(f"{{{k}}}", v)
-
-    # This is ugly as hell and I don't care
-    upload_data["uploader.command"] = {}
-    if tool_executable_linux:
-        upload_data["uploader.command"]["linux"] = command.replace(
-            "{uploader}", f"{{tool_dir}}/{tool_executable_linux}"
-        )
-
-    if tool_executable_windows:
-        upload_data["uploader.command"]["windows"] = command.replace(
-            "{uploader}", f"{{tool_dir}}\\{tool_executable_windows}"
-        )
-
-    if tool_executable_macosx:
-        upload_data["uploader.command"]["macosx"] = command.replace(
-            "{uploader}", f"{{tool_dir}}/{tool_executable_macosx}"
-        )
-
-    return upload_data
-
-
-def generate_boards_json(input_data, arduino_cli_path):
-    boards = {
-        "arduino:samd:mkr1000": {"fqbn": "arduino:samd:mkr1000", "firmware": []},
-        "arduino:samd:mkrvidor4000": {
-            "fqbn": "arduino:samd:mkrvidor4000",
-            "firmware": [],
-        },
-    }
-
-    # Gets the installed cores
-    res = arduino_cli(cli_path=arduino_cli_path, args=["core", "list", "--format", "json"])
-    installed_cores = {c["id"]: c for c in json.loads(res)}
-
-    # Verify all necessary cores are installed
-    # TODO: Should we check that the latest version is installed too?
-    for fqbn, data in input_data.items():
-        core_id = ":".join(fqbn.split(":")[:2])
-        if core_id not in installed_cores:
-            print(f"Board {fqbn} is not installed, install its core {core_id}")
-            sys.exit(1)
-
-        simple_fqbn = fqbn.replace(":", ".")
-
-        # List of old boards that need precompiled sketch data and uploader information obtained through platform.txt.
-        boards[fqbn]["loader_sketch"] = create_precomp_sketch_data(simple_fqbn, "loader")
-        boards[fqbn]["version_sketch"] = create_precomp_sketch_data(simple_fqbn, "getversion")
-        boards[fqbn].update(create_upload_data(fqbn, installed_cores))
-        # Gets the old_board name
-        res = arduino_cli(
-            cli_path=arduino_cli_path,
-            args=["board", "search", fqbn, "--format", "json"],
-        )
-        for board in json.loads(res):
-            if board["fqbn"] == fqbn:
-                boards[fqbn]["name"] = board["name"]
-                break
-
-        for firmware_version in data["versions"]:
-            module = data["moduleName"]
-            firmware_file = get_firmware_file(module, simple_fqbn, firmware_version)
-            boards[fqbn]["firmware"].append(create_firmware_data(firmware_file, module, firmware_version))
-            boards[fqbn]["module"] = module
-
-    boards_json = []
-    for _, b in boards.items():
-        boards_json.append(b)
-
-    return boards_json
-
-
 def generate_new_boards_json(input_data):
     # init the boards dict
     boards = {}
@@ -300,70 +92,13 @@ def generate_new_boards_json(input_data):
 
 if __name__ == "__main__":
     parser = argparse.ArgumentParser(prog="generator.py")
-    parser.add_argument(
-        "-a",
-        "--arduino-cli",
-        default="arduino-cli",
-        help="Path to arduino-cli executable",
-        required=True,
-    )
-    parser.add_argument(
-        "--new",
-        action=argparse.BooleanOptionalAction,
-        default=True,
-        help="Generate the index for old boards",
-    )
-    args = parser.parse_args(sys.argv[1:])
 
-    if args.new:
-        input_file = "new_boards.json"
-        output_file = "plugin_firmware_index.json"
-    else:
-        input_file = "boards.json"
-        output_file = "module_firmware_index.json"
-
-    # raw_boards.json has been generated using --get_available_for FirmwareUploader (version 0.1.8) flag.
-    # It has been edited a bit to better handle parsing.
-    with open(input_file, "r") as f:
+    with open("new_boards.json", "r") as f:
         boards = json.load(f)
 
-    if args.new:
-        boards_json = generate_new_boards_json(boards)
-    else:
-        boards_json = generate_boards_json(boards, args.arduino_cli)
+    boards_json = generate_new_boards_json(boards)
 
     Path("boards").mkdir(exist_ok=True)
 
-    with open("boards/" + output_file, "w") as f:
+    with open("boards/plugin_firmware_index.json", "w") as f:
         json.dump(boards_json, f, indent=2)
-
-# board_index.json must be formatted like so:
-#
-# {
-#     "name": "MKR 1000",
-#     "fqbn": "arduino:samd:mkr1000",
-#     "module": "WINC_1500",
-#     "firmware": [
-#         {
-#             "version": "19.6.1",
-#             "url": "https://downloads.arduino.cc/firmwares/WINC_1500/19.6.1/m2m_aio_3a0.bin",
-#             "checksum": "SHA-256:de0c6b1621aa15996432559efb5d8a29885f62bde145937eee99883bfa129f97",
-#             "size": "359356",
-#         },
-#         {
-#             "version": "19.5.4",
-#             "url": "https://downloads.arduino.cc/firmwares/WINC_1500/19.5.4/m2m_aio_3a0.bin",
-#             "checksum": "SHA-256:71e5a805e60f96e6968414670d8a414a03cb610fd4b020f47ab53f5e1ff82a13",
-#             "size": "413604",
-#         },
-#     ],
-#     "loader_sketch": {
-#         "url": "https://downloads.arduino.cc/firmwares/loader/arduino.samd.mkr1000/loader.bin",
-#         "checksum": "SHA-256:71e5a805e60f96e6968414670d8a414a03cb610fd4b020f47ab53f5e1ff82a13",
-#         "size": "39287",
-#     },
-#     "uploader": "arduino:bossac@1.7.0",
-#     "uploader.command": "{uploader} --port={upload.port} -U true -i -e -w -v {loader.sketch} -R",
-#     "uploader.requires_1200_bps_touch": "true",
-#     "uploader.requires_port_change": "true",
-# }
diff --git a/indexes/download/download.go b/indexes/download/download.go
index 7b415d6c..c4fdf437 100644
--- a/indexes/download/download.go
+++ b/indexes/download/download.go
@@ -286,10 +286,8 @@ func verifyIndex(indexPath *paths.Path, URL *url.URL) error {
 	signaturePath := paths.New(fmt.Sprintf("%s.sig", indexPath))
 	if index == "package_index.json.gz" {
 		valid, err = verifyPackageIndex(indexPath, signaturePath)
-	} else if index == "module_firmware_index.json.gz" {
-		valid, err = verifyModuleFirmwareIndex(indexPath, signaturePath)
 	} else if index == "plugin_firmware_index.json.gz" {
-		valid, err = verifyModuleFirmwareIndex(indexPath, signaturePath)
+		valid, err = verifyPluginFirmwareIndex(indexPath, signaturePath)
 	} else {
 		return fmt.Errorf("index %s not supported", URL.Path)
 	}
@@ -316,9 +314,9 @@ func verifyPackageIndex(indexPath, signaturePath *paths.Path) (bool, error) {
 	return valid, nil
 }
 
-// verifyModuleFirmwareIndex verify if the signature is valid for the provided module firmware index
-func verifyModuleFirmwareIndex(indexPath, signaturePath *paths.Path) (bool, error) {
-	arduinoKeyringFile, err := globals.Keys.Open("keys/module_firmware_index_public.gpg.key")
+// verifyPluginFirmwareIndex verify if the signature is valid for the provided plugin firmware index
+func verifyPluginFirmwareIndex(indexPath, signaturePath *paths.Path) (bool, error) {
+	arduinoKeyringFile, err := globals.Keys.Open("keys/plugin_firmware_index_public.gpg.key")
 	if err != nil {
 		return false, fmt.Errorf("could not find bundled signature keys: %s", err)
 	}
diff --git a/indexes/download/download_test.go b/indexes/download/download_test.go
index 8a75c4cf..22e32eb4 100644
--- a/indexes/download/download_test.go
+++ b/indexes/download/download_test.go
@@ -34,7 +34,7 @@ import (
 
 var defaultIndexGZURL = []string{
 	"https://downloads.arduino.cc/packages/package_index.json.gz",
-	"https://downloads.arduino.cc/arduino-fwuploader/boards/module_firmware_index.json.gz",
+	"https://downloads.arduino.cc/arduino-fwuploader/boards/plugin_firmware_index.json.gz",
 }
 
 func TestDownloadIndex(t *testing.T) {
@@ -130,7 +130,7 @@ func TestDownloadTool(t *testing.T) {
 
 func TestDownloadFirmware(t *testing.T) {
 	defer os.RemoveAll(globals.FwUploaderPath.String())
-	indexFile := paths.New("testdata/module_firmware_index.json")
+	indexFile := paths.New("testdata/plugin_firmware_index.json")
 	t.Logf("testing with index: %s", indexFile)
 	index, e := firmwareindex.LoadIndexNoSign(indexFile)
 	require.NoError(t, e)
@@ -140,16 +140,3 @@ func TestDownloadFirmware(t *testing.T) {
 	require.NotEmpty(t, firmwarePath)
 	require.FileExists(t, firmwarePath.String())
 }
-
-func TestDownloadLoaderSketch(t *testing.T) {
-	defer os.RemoveAll(globals.FwUploaderPath.String())
-	indexFile := paths.New("testdata/module_firmware_index.json")
-	t.Logf("testing with index: %s", indexFile)
-	index, e := firmwareindex.LoadIndexNoSign(indexFile)
-	require.NoError(t, e)
-	require.NotEmpty(t, index)
-	loaderPath, err := DownloadSketch(index.Boards[0].LoaderSketch)
-	require.NoError(t, err)
-	require.NotEmpty(t, loaderPath)
-	require.FileExists(t, loaderPath.String())
-}
diff --git a/indexes/download/testdata/module_firmware_index.json.sig b/indexes/download/testdata/module_firmware_index.json.sig
deleted file mode 100644
index 96c4f7f8..00000000
Binary files a/indexes/download/testdata/module_firmware_index.json.sig and /dev/null differ
diff --git a/indexes/download/testdata/module_firmware_index.json b/indexes/download/testdata/plugin_firmware_index.json
similarity index 57%
rename from indexes/download/testdata/module_firmware_index.json
rename to indexes/download/testdata/plugin_firmware_index.json
index a54a59fb..ab1703aa 100644
--- a/indexes/download/testdata/module_firmware_index.json
+++ b/indexes/download/testdata/plugin_firmware_index.json
@@ -1,492 +1,457 @@
 [
   {
-    "fqbn": "arduino:samd:mkr1000",
+    "fqbn": "arduino:renesas_uno:unor4wifi",
     "firmware": [
       {
-        "version": "19.4.4",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/WINC1500/19.4.4/m2m_aio_3a0.bin",
-        "checksum": "SHA-256:f8be2a5ef10e109f685b7550d211ed11c07487de430b0e5994ca557160116c27",
-        "size": "412308",
-        "module": "WINC1500"
+        "version": "0.1.0",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/ESP32-S3/0.1.0/ESP32-S3.bin",
+        "checksum": "SHA-256:37c4f003373448504d49d5e3c1754d1d90b9bba3f8f3b529b435d331ca6900b1",
+        "size": "3951616",
+        "module": "ESP32-S3"
       },
       {
-        "version": "19.5.2",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/WINC1500/19.5.2/m2m_aio_3a0.bin",
-        "checksum": "SHA-256:e2e5aa2cf185745582002e2fed27c079d4228bc8d756281f43638c72061c9110",
-        "size": "413604",
-        "module": "WINC1500"
+        "version": "0.2.0",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/ESP32-S3/0.2.0/ESP32-S3.bin",
+        "checksum": "SHA-256:cb535826ba96d4f51bdac33d252c24bd9c692a7bef56710ec0431979cef09fc3",
+        "size": "3951616",
+        "module": "ESP32-S3"
       },
       {
-        "version": "19.5.4",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/WINC1500/19.5.4/m2m_aio_3a0.bin",
-        "checksum": "SHA-256:146d3d5fccf65ff6d732e34077e56f1f0b2f69584fd8499db914ea11ed463042",
-        "size": "413604",
-        "module": "WINC1500"
-      },
-      {
-        "version": "19.6.1",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/WINC1500/19.6.1/m2m_aio_3a0.bin",
-        "checksum": "SHA-256:629a2553cb738be1424eaa707c00403ebce179fdb94008acec1f185a19a60c81",
-        "size": "359356",
-        "module": "WINC1500"
+        "version": "0.2.1",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/ESP32-S3/0.2.1/ESP32-S3.bin",
+        "checksum": "SHA-256:8fad86ac6b44ba16853c41644338ba61e64383904c757b37d8adaeca9b76da03",
+        "size": "3951616",
+        "module": "ESP32-S3"
       }
     ],
-    "loader_sketch": {
-      "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/loader/arduino.samd.mkr1000/loader.bin",
-      "checksum": "SHA-256:1d904bf745c8df448358d70837a36ee8dec4c2a01e0e3b2ef8ef51c6a6c9d385",
-      "size": "16328"
-    },
-    "module": "WINC1500",
-    "name": "Arduino MKR1000",
-    "uploader": "arduino:bossac@1.7.0-arduino3",
-    "upload.use_1200bps_touch": true,
-    "upload.wait_for_upload_port": true,
-    "uploader.command": {
-      "linux": "\"{tool_dir}/bossac\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R",
-      "windows": "\"{tool_dir}\\bossac.exe\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R"
-    }
+    "uploader_plugin": "arduino:uno-r4-wifi-fwuploader-plugin@1.0.0",
+    "additional_tools": [
+      "arduino:espflash@2.0.0",
+      "arduino:bossac@1.9.1-arduino5"
+    ],
+    "module": "ESP32-S3",
+    "name": "Arduino UNO R4 WiFi"
   },
   {
     "fqbn": "arduino:samd:mkrwifi1010",
     "firmware": [
       {
         "version": "1.0.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.0.0/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.0.0/NINA.bin",
         "checksum": "SHA-256:3fe2cd90a0774e271624d42ab1b238d92c7495648e9918ad49dea3b20379905e",
         "size": "736256",
         "module": "NINA"
       },
       {
         "version": "1.1.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.1.0/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.1.0/NINA.bin",
         "checksum": "SHA-256:3b38f44a2e2e2d28995973f432bc2795f7c58a14e8638f55e3f024ffa499bcf8",
         "size": "814080",
         "module": "NINA"
       },
       {
         "version": "1.2.1",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.1/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.1/NINA.bin",
         "checksum": "SHA-256:3121bf4074fce0248946810c4d03f5d3fb1296cd4667aeb801b5d066e1b07ff3",
         "size": "880640",
         "module": "NINA"
       },
       {
         "version": "1.2.2",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.2/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.2/NINA.bin",
         "checksum": "SHA-256:71d0a49a4d79aa46dff6f434383133b4365581407846d709fbd961e2b770eb3c",
         "size": "893952",
         "module": "NINA"
       },
       {
         "version": "1.2.3",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.3/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.3/NINA.bin",
         "checksum": "SHA-256:9c908f33cc05831972833a274f65baf84da35c61fc081856959211ae3504c899",
         "size": "893952",
         "module": "NINA"
       },
       {
         "version": "1.2.4",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.4/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.4/NINA.bin",
         "checksum": "SHA-256:8b9c07abdaa5647c47466aa3c575e743495a295fd8db2fe91b7e28fe4135ffad",
         "size": "917504",
         "module": "NINA"
       },
       {
         "version": "1.3.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.3.0/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.3.0/NINA.bin",
         "checksum": "SHA-256:aa37c920df18aabc6544df93c64bea6b3b97841b68ff4a6a53d2b800b265d2b5",
         "size": "986112",
         "module": "NINA"
       },
       {
         "version": "1.4.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.0/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.0/NINA.bin",
         "checksum": "SHA-256:ca5ed0b5efd727dd3c507f39a744e171ce690ef17b116c0571f18d1fea17aa85",
         "size": "1035264",
         "module": "NINA"
       },
       {
         "version": "1.4.1",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.1/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.1/NINA.bin",
         "checksum": "SHA-256:b20f213bc886a95556fc5cec5003c7ebc617da83581ba20fb9f96db003063bbd",
         "size": "1208320",
         "module": "NINA"
       },
       {
         "version": "1.4.2",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.2/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.2/NINA.bin",
         "checksum": "SHA-256:61d0acbd3d2eeb45b6971448d9537f7c4fa27f264e20970ad5dfdd4cbfdd8ee0",
         "size": "1125376",
         "module": "NINA"
       },
       {
         "version": "1.4.3",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.3/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.3/NINA.bin",
         "checksum": "SHA-256:8c10c3ee3b8fb2ade3a650b41a3081566fc160e89b32e5d0ee040e63647692b8",
         "size": "1125376",
         "module": "NINA"
       },
       {
         "version": "1.4.4",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.4/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.4/NINA.bin",
         "checksum": "SHA-256:c8678e00ab9b2dc99cdc45ef577b77498dac802c3f5b99961da190374fddcef8",
         "size": "1125376",
         "module": "NINA"
       },
       {
         "version": "1.4.5",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.5/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.5/NINA.bin",
         "checksum": "SHA-256:7c2814c8f879e62d234d7ac3a9c28f9a2d1e1dbc3569bd740761ca796247a4c9",
         "size": "1127424",
         "module": "NINA"
+      },
+      {
+        "version": "1.4.6",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.6/NINA.bin",
+        "checksum": "SHA-256:9f3df8446bb5038437bfd25b4fe06cb84b32bff29c5ba8eea852b49d059837f7",
+        "size": "1127424",
+        "module": "NINA"
+      },
+      {
+        "version": "1.4.7",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.7/NINA.bin",
+        "checksum": "SHA-256:22cfa44b41bf4219a025b93a33752528735ba82cb638999ff4015c5579a46cef",
+        "size": "1127424",
+        "module": "NINA"
+      },
+      {
+        "version": "1.4.8",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.8/NINA.bin",
+        "checksum": "SHA-256:6b75e118fedc8d1f45ac5667d59effe227d651f38e77ed2dac45f9a7593c07f6",
+        "size": "1127424",
+        "module": "NINA"
+      },
+      {
+        "version": "1.5.0",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.5.0/NINA.bin",
+        "checksum": "SHA-256:12e915d44f3acfc26f2b9d266228afd11ad795fe37b7a4ba98a1eddc91a0eed1",
+        "size": "1129472",
+        "module": "NINA"
       }
     ],
-    "loader_sketch": {
-      "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/loader/arduino.samd.mkrwifi1010/loader.bin",
-      "checksum": "SHA-256:a4f9b0586bf78b8e1c5a6660df6b749d1ad4e3ee79ee4928371a465899a4a1c4",
-      "size": "13688"
-    },
+    "uploader_plugin": "arduino:nina-fwuploader-plugin@1.0.0",
+    "additional_tools": [
+      "arduino:bossac@1.7.0-arduino3"
+    ],
     "module": "NINA",
-    "name": "Arduino MKR WiFi 1010",
-    "uploader": "arduino:bossac@1.7.0-arduino3",
-    "upload.use_1200bps_touch": true,
-    "upload.wait_for_upload_port": true,
-    "uploader.command": {
-      "linux": "\"{tool_dir}/bossac\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R",
-      "windows": "\"{tool_dir}\\bossac.exe\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R"
-    }
+    "name": "Arduino MKR WiFi 1010"
   },
   {
     "fqbn": "arduino:samd:nano_33_iot",
     "firmware": [
       {
         "version": "1.0.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.0.0/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.0.0/NINA.bin",
         "checksum": "SHA-256:3fe2cd90a0774e271624d42ab1b238d92c7495648e9918ad49dea3b20379905e",
         "size": "736256",
         "module": "NINA"
       },
       {
         "version": "1.1.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.1.0/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.1.0/NINA.bin",
         "checksum": "SHA-256:3b38f44a2e2e2d28995973f432bc2795f7c58a14e8638f55e3f024ffa499bcf8",
         "size": "814080",
         "module": "NINA"
       },
       {
         "version": "1.2.1",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.1/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.1/NINA.bin",
         "checksum": "SHA-256:3121bf4074fce0248946810c4d03f5d3fb1296cd4667aeb801b5d066e1b07ff3",
         "size": "880640",
         "module": "NINA"
       },
       {
         "version": "1.2.2",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.2/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.2/NINA.bin",
         "checksum": "SHA-256:71d0a49a4d79aa46dff6f434383133b4365581407846d709fbd961e2b770eb3c",
         "size": "893952",
         "module": "NINA"
       },
       {
         "version": "1.2.3",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.3/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.3/NINA.bin",
         "checksum": "SHA-256:9c908f33cc05831972833a274f65baf84da35c61fc081856959211ae3504c899",
         "size": "893952",
         "module": "NINA"
       },
       {
         "version": "1.2.4",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.4/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.4/NINA.bin",
         "checksum": "SHA-256:8b9c07abdaa5647c47466aa3c575e743495a295fd8db2fe91b7e28fe4135ffad",
         "size": "917504",
         "module": "NINA"
       },
       {
         "version": "1.3.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.3.0/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.3.0/NINA.bin",
         "checksum": "SHA-256:aa37c920df18aabc6544df93c64bea6b3b97841b68ff4a6a53d2b800b265d2b5",
         "size": "986112",
         "module": "NINA"
       },
       {
         "version": "1.4.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.0/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.0/NINA.bin",
         "checksum": "SHA-256:ca5ed0b5efd727dd3c507f39a744e171ce690ef17b116c0571f18d1fea17aa85",
         "size": "1035264",
         "module": "NINA"
       },
       {
         "version": "1.4.1",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.1/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.1/NINA.bin",
         "checksum": "SHA-256:b20f213bc886a95556fc5cec5003c7ebc617da83581ba20fb9f96db003063bbd",
         "size": "1208320",
         "module": "NINA"
       },
       {
         "version": "1.4.2",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.2/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.2/NINA.bin",
         "checksum": "SHA-256:61d0acbd3d2eeb45b6971448d9537f7c4fa27f264e20970ad5dfdd4cbfdd8ee0",
         "size": "1125376",
         "module": "NINA"
       },
       {
         "version": "1.4.3",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.3/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.3/NINA.bin",
         "checksum": "SHA-256:8c10c3ee3b8fb2ade3a650b41a3081566fc160e89b32e5d0ee040e63647692b8",
         "size": "1125376",
         "module": "NINA"
       },
       {
         "version": "1.4.4",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.4/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.4/NINA.bin",
         "checksum": "SHA-256:c8678e00ab9b2dc99cdc45ef577b77498dac802c3f5b99961da190374fddcef8",
         "size": "1125376",
         "module": "NINA"
       },
       {
         "version": "1.4.5",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.5/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.5/NINA.bin",
         "checksum": "SHA-256:7c2814c8f879e62d234d7ac3a9c28f9a2d1e1dbc3569bd740761ca796247a4c9",
         "size": "1127424",
         "module": "NINA"
-      }
-    ],
-    "loader_sketch": {
-      "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/loader/arduino.samd.nano_33_iot/loader.bin",
-      "checksum": "SHA-256:f643fd763ba6aec835bb708669a6a5f5709357990d9eab6f4e6d5223ea3ca2a3",
-      "size": "14348"
-    },
-    "module": "NINA",
-    "name": "Arduino NANO 33 IoT",
-    "uploader": "arduino:bossac@1.7.0-arduino3",
-    "upload.use_1200bps_touch": true,
-    "upload.wait_for_upload_port": true,
-    "uploader.command": {
-      "linux": "\"{tool_dir}/bossac\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R",
-      "windows": "\"{tool_dir}\\bossac.exe\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R"
-    }
-  },
-  {
-    "fqbn": "arduino:samd:mkrvidor4000",
-    "firmware": [
-      {
-        "version": "1.0.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.0.0/NINA_W102.bin",
-        "checksum": "SHA-256:3fe2cd90a0774e271624d42ab1b238d92c7495648e9918ad49dea3b20379905e",
-        "size": "736256",
-        "module": "NINA"
-      },
-      {
-        "version": "1.1.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.1.0/NINA_W102.bin",
-        "checksum": "SHA-256:3b38f44a2e2e2d28995973f432bc2795f7c58a14e8638f55e3f024ffa499bcf8",
-        "size": "814080",
-        "module": "NINA"
-      },
-      {
-        "version": "1.2.1",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.1/NINA_W102.bin",
-        "checksum": "SHA-256:3121bf4074fce0248946810c4d03f5d3fb1296cd4667aeb801b5d066e1b07ff3",
-        "size": "880640",
-        "module": "NINA"
-      },
-      {
-        "version": "1.2.2",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.2/NINA_W102.bin",
-        "checksum": "SHA-256:71d0a49a4d79aa46dff6f434383133b4365581407846d709fbd961e2b770eb3c",
-        "size": "893952",
-        "module": "NINA"
-      },
-      {
-        "version": "1.2.3",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.3/NINA_W102.bin",
-        "checksum": "SHA-256:9c908f33cc05831972833a274f65baf84da35c61fc081856959211ae3504c899",
-        "size": "893952",
-        "module": "NINA"
-      },
-      {
-        "version": "1.2.4",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.4/NINA_W102.bin",
-        "checksum": "SHA-256:8b9c07abdaa5647c47466aa3c575e743495a295fd8db2fe91b7e28fe4135ffad",
-        "size": "917504",
-        "module": "NINA"
-      },
-      {
-        "version": "1.3.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.3.0/NINA_W102.bin",
-        "checksum": "SHA-256:aa37c920df18aabc6544df93c64bea6b3b97841b68ff4a6a53d2b800b265d2b5",
-        "size": "986112",
-        "module": "NINA"
-      },
-      {
-        "version": "1.4.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.0/NINA_W102.bin",
-        "checksum": "SHA-256:ca5ed0b5efd727dd3c507f39a744e171ce690ef17b116c0571f18d1fea17aa85",
-        "size": "1035264",
-        "module": "NINA"
-      },
-      {
-        "version": "1.4.1",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.1/NINA_W102.bin",
-        "checksum": "SHA-256:b20f213bc886a95556fc5cec5003c7ebc617da83581ba20fb9f96db003063bbd",
-        "size": "1208320",
-        "module": "NINA"
       },
       {
-        "version": "1.4.2",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.2/NINA_W102.bin",
-        "checksum": "SHA-256:61d0acbd3d2eeb45b6971448d9537f7c4fa27f264e20970ad5dfdd4cbfdd8ee0",
-        "size": "1125376",
+        "version": "1.4.6",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.6/NINA.bin",
+        "checksum": "SHA-256:9f3df8446bb5038437bfd25b4fe06cb84b32bff29c5ba8eea852b49d059837f7",
+        "size": "1127424",
         "module": "NINA"
       },
       {
-        "version": "1.4.3",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.3/NINA_W102.bin",
-        "checksum": "SHA-256:8c10c3ee3b8fb2ade3a650b41a3081566fc160e89b32e5d0ee040e63647692b8",
-        "size": "1125376",
+        "version": "1.4.7",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.7/NINA.bin",
+        "checksum": "SHA-256:22cfa44b41bf4219a025b93a33752528735ba82cb638999ff4015c5579a46cef",
+        "size": "1127424",
         "module": "NINA"
       },
       {
-        "version": "1.4.4",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.4/NINA_W102.bin",
-        "checksum": "SHA-256:c8678e00ab9b2dc99cdc45ef577b77498dac802c3f5b99961da190374fddcef8",
-        "size": "1125376",
+        "version": "1.4.8",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.8/NINA.bin",
+        "checksum": "SHA-256:6b75e118fedc8d1f45ac5667d59effe227d651f38e77ed2dac45f9a7593c07f6",
+        "size": "1127424",
         "module": "NINA"
       },
       {
-        "version": "1.4.5",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.5/NINA_W102.bin",
-        "checksum": "SHA-256:7c2814c8f879e62d234d7ac3a9c28f9a2d1e1dbc3569bd740761ca796247a4c9",
-        "size": "1127424",
+        "version": "1.5.0",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.5.0/NINA.bin",
+        "checksum": "SHA-256:12e915d44f3acfc26f2b9d266228afd11ad795fe37b7a4ba98a1eddc91a0eed1",
+        "size": "1129472",
         "module": "NINA"
       }
     ],
+    "uploader_plugin": "arduino:nina-fwuploader-plugin@1.0.0",
+    "additional_tools": [
+      "arduino:bossac@1.7.0-arduino3"
+    ],
     "module": "NINA",
-    "name": "Arduino MKR Vidor 4000",
-    "uploader": "arduino:bossac@1.7.0-arduino3",
-    "upload.use_1200bps_touch": true,
-    "upload.wait_for_upload_port": true,
-    "uploader.command": {
-      "linux": "\"{tool_dir}/bossac\" -i -d --port={serial.port.file} -I -U true -i -e -w \"{loader.sketch}.bin\" -R",
-      "windows": "\"{tool_dir}\\bossac.exe\" -i -d --port={serial.port.file} -I -U true -i -e -w \"{loader.sketch}.bin\" -R"
-    }
+    "name": "Arduino NANO 33 IoT"
   },
   {
     "fqbn": "arduino:megaavr:uno2018",
     "firmware": [
       {
         "version": "1.2.1",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.1/NINA_W102-Uno_WiFi_Rev2.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.1/NINA-arduino.megaavr.uno2018.bin",
         "checksum": "SHA-256:bac23326dd4c3b6358ee88ff322da8c16e24e9917b8b0bbd18f663aacfb758cf",
         "size": "880640",
         "module": "NINA"
       },
       {
         "version": "1.2.2",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.2/NINA_W102-Uno_WiFi_Rev2.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.2/NINA-arduino.megaavr.uno2018.bin",
         "checksum": "SHA-256:d1f496b185eff6b2ab2f839f6673afc80e1b3e3b2056fc8d9290a74895baf0e5",
         "size": "893952",
         "module": "NINA"
       },
       {
         "version": "1.2.3",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.3/NINA_W102-Uno_WiFi_Rev2.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.3/NINA-arduino.megaavr.uno2018.bin",
         "checksum": "SHA-256:53668eb76be80fffdd67ced7cbb8ab231638b9ee428ae83568dfe48359008bb4",
         "size": "893952",
         "module": "NINA"
       },
       {
         "version": "1.2.4",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.4/NINA_W102-Uno_WiFi_Rev2.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.4/NINA-arduino.megaavr.uno2018.bin",
         "checksum": "SHA-256:37b042cf759b52a96304c35af6a066038184533cc6256f795e92ed1b4fbda3d5",
         "size": "917504",
         "module": "NINA"
       },
       {
         "version": "1.3.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.3.0/NINA_W102-Uno_WiFi_Rev2.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.3.0/NINA-arduino.megaavr.uno2018.bin",
         "checksum": "SHA-256:c538028f428b3fc219d2f7c0d9debacd07bababf43dbc28680ed452225ff4629",
         "size": "986112",
         "module": "NINA"
       },
       {
         "version": "1.4.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.0/NINA_W102-Uno_WiFi_Rev2.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.0/NINA-arduino.megaavr.uno2018.bin",
         "checksum": "SHA-256:fe852e28eb0547a324069194dcce524b5a9f18adce2983bbe11a818a7ae8200a",
         "size": "1041408",
         "module": "NINA"
       },
       {
         "version": "1.4.1",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.1/NINA_W102-Uno_WiFi_Rev2.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.1/NINA-arduino.megaavr.uno2018.bin",
         "checksum": "SHA-256:f11deb8ce5abe908353eebca7253c18359eb8ea2a601908d5cdb56bf035b4158",
         "size": "1044480",
         "module": "NINA"
       },
       {
         "version": "1.4.2",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.2/NINA_W102-Uno_WiFi_Rev2.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.2/NINA-arduino.megaavr.uno2018.bin",
         "checksum": "SHA-256:7adff887267297dccc6c3ce77f41a986a23a1f7dfce9e8f3b70b3aa038371d47",
         "size": "1132544",
         "module": "NINA"
       },
       {
         "version": "1.4.3",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.3/NINA_W102-Uno_WiFi_Rev2.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.3/NINA-arduino.megaavr.uno2018.bin",
         "checksum": "SHA-256:c026f967bd3add27716a1afaf729d669a5e093771098329bab2477980d6879b5",
         "size": "1132544",
         "module": "NINA"
       },
       {
         "version": "1.4.4",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.4/NINA_W102-Uno_WiFi_Rev2.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.4/NINA-arduino.megaavr.uno2018.bin",
         "checksum": "SHA-256:6b7809357a57946638b271dd1b0b43a84cbcbea9b854d3ff093752fa0fe7b818",
         "size": "1132544",
         "module": "NINA"
       },
       {
         "version": "1.4.5",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.5/NINA_W102-Uno_WiFi_Rev2.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.5/NINA-arduino.megaavr.uno2018.bin",
         "checksum": "SHA-256:b641c4f6f76ab4c7a529848da54f15b9b9857a9627920129a0a6f65edc465c67",
         "size": "1133568",
         "module": "NINA"
+      },
+      {
+        "version": "1.4.6",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.6/NINA-arduino.megaavr.uno2018.bin",
+        "checksum": "SHA-256:9a0c9e5f4b63dbc468f1458dd01d4d33be272e0436055efeea033dd7e2b11880",
+        "size": "1133568",
+        "module": "NINA"
+      },
+      {
+        "version": "1.4.7",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.7/NINA-arduino.megaavr.uno2018.bin",
+        "checksum": "SHA-256:b560dd7bfef78513b3c468999da1f83b6185aa319a9da544260bc6a74aa8b89b",
+        "size": "1133568",
+        "module": "NINA"
+      },
+      {
+        "version": "1.4.8",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.8/NINA-arduino.megaavr.uno2018.bin",
+        "checksum": "SHA-256:89cbfbeb776437c15691c29da269cde63a13f8994a7ba2f3bba8e9fb1ef6efcb",
+        "size": "1133568",
+        "module": "NINA"
+      },
+      {
+        "version": "1.5.0",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.5.0/NINA-arduino.megaavr.uno2018.bin",
+        "checksum": "SHA-256:9687f9491d4f804487055dd1db3b8932567050c18552e4be109f096dea4201ca",
+        "size": "1135616",
+        "module": "NINA"
       }
     ],
-    "loader_sketch": {
-      "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/loader/arduino.megaavr.uno2018/loader.hex",
-      "checksum": "SHA-256:0d4c2bf93da575245e92595b1d0f55db1fa79583f1c3361646da051dab020afe",
-      "size": "18954"
-    },
+    "uploader_plugin": "arduino:nina-fwuploader-plugin@1.0.0",
+    "additional_tools": [
+      "arduino:avrdude@6.3.0-arduino17"
+    ],
     "module": "NINA",
-    "name": "Arduino Uno WiFi Rev2",
-    "uploader": "arduino:avrdude@6.3.0-arduino17",
-    "uploader.command": {
-      "linux": "\"{tool_dir}/bin/avrdude\" \"-C{tool_dir}/etc/avrdude.conf\" -v  -patmega4809 -cxplainedmini_updi -Pusb  -b115200 -e -D \"-Uflash:w:{loader.sketch}.hex:i\" \"-Ufuse2:w:0x01:m\" \"-Ufuse5:w:0xC9:m\" \"-Ufuse8:w:0x02:m\" "
-    }
+    "name": "Arduino Uno WiFi Rev2"
   },
   {
     "fqbn": "arduino:mbed_nano:nanorp2040connect",
     "firmware": [
       {
         "version": "1.4.5",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.5/NINA_W102-Nano_RP2040_Connect.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.5/NINA-arduino.mbed_nano.nanorp2040connect.bin",
         "checksum": "SHA-256:5cc391414abd2233001923221a0103dd5ca37222cf885dace065962c962ccd2b",
         "size": "1127424",
         "module": "NINA"
+      },
+      {
+        "version": "1.4.6",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.6/NINA-arduino.mbed_nano.nanorp2040connect.bin",
+        "checksum": "SHA-256:6b46f3cd771d6a322819855690b2703c51f15fa00894e94c77bad3f8c216be58",
+        "size": "1127424",
+        "module": "NINA"
+      },
+      {
+        "version": "1.4.7",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.7/NINA-arduino.mbed_nano.nanorp2040connect.bin",
+        "checksum": "SHA-256:d3fb2da91f46803e3dfed552d328e7d4d495be8b2773504bc695aefff3d114cb",
+        "size": "1127424",
+        "module": "NINA"
+      },
+      {
+        "version": "1.4.8",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.8/NINA-arduino.mbed_nano.nanorp2040connect.bin",
+        "checksum": "SHA-256:922b3c156498c4493272e15548fdf587ee957a1f400bd44d444e68890ad12eba",
+        "size": "1127424",
+        "module": "NINA"
+      },
+      {
+        "version": "1.5.0",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.5.0/NINA-arduino.mbed_nano.nanorp2040connect.bin",
+        "checksum": "SHA-256:f456ff99fc3d697ffd4c715a75172d793abd3d98c16b76589c4de92b6f787cf0",
+        "size": "1129472",
+        "module": "NINA"
       }
     ],
-    "loader_sketch": {
-      "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/loader/arduino.mbed_nano.nanorp2040connect/loader.elf",
-      "checksum": "SHA-256:4b67381122df67a210c29d01f01153f34cdeea77593f7e5e12259e3c85b472f0",
-      "size": "1639020"
-    },
+    "uploader_plugin": "arduino:nina-fwuploader-plugin@1.0.0",
+    "additional_tools": [
+      "arduino:rp2040tools@1.0.6"
+    ],
     "module": "NINA",
-    "name": "Arduino Nano RP2040 Connect",
-    "uploader": "arduino:rp2040tools@1.0.2",
-    "upload.use_1200bps_touch": true,
-    "upload.wait_for_upload_port": true,
-    "uploader.command": {
-      "linux": "\"{tool_dir}/rp2040load\" -v -D \"{loader.sketch}.elf\""
-    }
+    "name": "Arduino Nano RP2040 Connect"
   }
 ]
\ No newline at end of file
diff --git a/indexes/download/testdata/plugin_firmware_index.json.sig b/indexes/download/testdata/plugin_firmware_index.json.sig
new file mode 100644
index 00000000..9218e3c7
Binary files /dev/null and b/indexes/download/testdata/plugin_firmware_index.json.sig differ
diff --git a/indexes/firmwareindex/firmwareindex.go b/indexes/firmwareindex/firmwareindex.go
index c88e961a..b1375e5a 100644
--- a/indexes/firmwareindex/firmwareindex.go
+++ b/indexes/firmwareindex/firmwareindex.go
@@ -21,7 +21,6 @@ package firmwareindex
 import (
 	"encoding/json"
 	"fmt"
-	"runtime"
 
 	"github.com/arduino/arduino-cli/arduino/security"
 	"github.com/arduino/arduino-fwuploader/cli/globals"
@@ -39,22 +38,12 @@ type Index struct {
 
 // IndexBoard represents a single entry from module_firmware_index.json file.
 type IndexBoard struct {
-	Fqbn      string           `json:"fqbn"`
-	Firmwares []*IndexFirmware `json:"firmware"`
-	Module    string           `json:"module"`
-	Name      string           `json:"name"`
-
-	// Fields required for integrated uploaders (deprecated)
-	LoaderSketch    *IndexSketch          `json:"loader_sketch"`
-	VersionSketch   *IndexSketch          `json:"version_sketch"`
-	Uploader        string                `json:"uploader"`
-	UploadTouch     bool                  `json:"upload.use_1200bps_touch"`
-	UploadWait      bool                  `json:"upload.wait_for_upload_port"`
-	UploaderCommand *IndexUploaderCommand `json:"uploader.command"`
-
-	// Fields required for plugin uploaders
-	UploaderPlugin  string   `json:"uploader_plugin"`
-	AdditionalTools []string `json:"additional_tools"`
+	Fqbn            string           `json:"fqbn"`
+	Firmwares       []*IndexFirmware `json:"firmware"`
+	Module          string           `json:"module"`
+	Name            string           `json:"name"`
+	UploaderPlugin  string           `json:"uploader_plugin"`
+	AdditionalTools []string         `json:"additional_tools"`
 }
 
 // IndexUploaderCommand represents the command-line to use for different OS
@@ -88,7 +77,7 @@ func LoadIndex(jsonIndexFile *paths.Path) (*Index, error) {
 	}
 
 	jsonSignatureFile := jsonIndexFile.Parent().Join(jsonIndexFile.Base() + ".sig")
-	arduinoKeyringFile, err := globals.Keys.Open("keys/module_firmware_index_public.gpg.key")
+	arduinoKeyringFile, err := globals.Keys.Open("keys/plugin_firmware_index_public.gpg.key")
 	if err != nil {
 		return nil, fmt.Errorf("could not find bundled signature keys: %s", err)
 
@@ -167,17 +156,6 @@ func (b *IndexBoard) GetFirmware(version string) *IndexFirmware {
 	return nil
 }
 
-// GetUploaderCommand returns the command to use for the upload
-func (b *IndexBoard) GetUploaderCommand() string {
-	if runtime.GOOS == "windows" && b.UploaderCommand.Windows != "" {
-		return b.UploaderCommand.Linux
-	} else if runtime.GOOS == "darwin" && b.UploaderCommand.Macosx != "" {
-		return b.UploaderCommand.Macosx
-	}
-	// The linux uploader command is considere to be the generic one
-	return b.UploaderCommand.Linux
-}
-
 // LatestFirmware returns the latest firmware version for the IndexBoard
 func (b *IndexBoard) LatestFirmware() *IndexFirmware {
 	var latest *IndexFirmware
@@ -188,8 +166,3 @@ func (b *IndexBoard) LatestFirmware() *IndexFirmware {
 	}
 	return latest
 }
-
-// IsPlugin returns true if the IndexBoard uses the plugin system
-func (b *IndexBoard) IsPlugin() bool {
-	return b.UploaderPlugin != ""
-}
diff --git a/indexes/firmwareindex/firmwareindex_test.go b/indexes/firmwareindex/firmwareindex_test.go
index f0f8204f..e6721b09 100644
--- a/indexes/firmwareindex/firmwareindex_test.go
+++ b/indexes/firmwareindex/firmwareindex_test.go
@@ -26,7 +26,7 @@ import (
 )
 
 func TestIndexParsing(t *testing.T) {
-	indexFile := paths.New("testdata/module_firmware_index.json")
+	indexFile := paths.New("testdata/plugin_firmware_index.json")
 	t.Logf("testing with index: %s", indexFile)
 	index, e := LoadIndexNoSign(indexFile)
 	require.NoError(t, e)
@@ -38,15 +38,15 @@ func TestIndexParsing(t *testing.T) {
 }
 
 func TestGetBoard(t *testing.T) {
-	indexFile := paths.New("testdata/module_firmware_index.json")
+	indexFile := paths.New("testdata/plugin_firmware_index.json")
 	t.Logf("testing with index: %s", indexFile)
 	index, e := LoadIndexNoSign(indexFile)
 	require.NoError(t, e)
 	require.NotEmpty(t, index)
 
-	board := index.GetBoard("arduino:samd:mkr1000")
+	board := index.GetBoard("arduino:samd:mkrwifi1010")
 	require.NotNil(t, board)
-	require.Equal(t, board.Fqbn, "arduino:samd:mkr1000")
+	require.Equal(t, board.Fqbn, "arduino:samd:mkrwifi1010")
 
 	board = index.GetBoard("arduino:samd:nano_33_iot")
 	require.NotNil(t, board)
@@ -57,29 +57,29 @@ func TestGetBoard(t *testing.T) {
 }
 
 func TestGetLatestFirmware(t *testing.T) {
-	indexFile := paths.New("testdata/module_firmware_index.json")
+	indexFile := paths.New("testdata/plugin_firmware_index.json")
 	t.Logf("testing with index: %s", indexFile)
 	index, e := LoadIndexNoSign(indexFile)
 	require.NoError(t, e)
 	require.NotEmpty(t, index)
 
-	firmware := index.GetBoard("arduino:samd:mkr1000").LatestFirmware()
-	require.Equal(t, firmware.Version.String(), "19.6.1")
+	firmware := index.GetBoard("arduino:samd:mkrwifi1010").LatestFirmware()
+	require.Equal(t, firmware.Version.String(), "1.5.0")
 }
 
 func TestGetFirmware(t *testing.T) {
-	indexFile := paths.New("testdata/module_firmware_index.json")
+	indexFile := paths.New("testdata/plugin_firmware_index.json")
 	t.Logf("testing with index: %s", indexFile)
 	index, e := LoadIndexNoSign(indexFile)
 	require.NoError(t, e)
 	require.NotEmpty(t, index)
 
-	firmware := index.GetBoard("arduino:samd:mkr1000").GetFirmware("19.6.1")
-	require.Equal(t, firmware.Version.String(), "19.6.1")
+	firmware := index.GetBoard("arduino:samd:mkrwifi1010").GetFirmware("1.5.0")
+	require.Equal(t, firmware.Version.String(), "1.5.0")
 
-	firmware = index.GetBoard("arduino:samd:mkr1000").GetFirmware("19.5.2")
-	require.Equal(t, firmware.Version.String(), "19.5.2")
+	firmware = index.GetBoard("arduino:samd:mkrwifi1010").GetFirmware("1.4.8")
+	require.Equal(t, firmware.Version.String(), "1.4.8")
 
-	firmware = index.GetBoard("arduino:samd:mkr1000").GetFirmware("0.0.0")
+	firmware = index.GetBoard("arduino:samd:mkrwifi1010").GetFirmware("0.0.0")
 	require.Nil(t, firmware)
 }
diff --git a/indexes/firmwareindex/testdata/module_firmware_index.json.sig b/indexes/firmwareindex/testdata/module_firmware_index.json.sig
deleted file mode 100644
index 14918da8..00000000
Binary files a/indexes/firmwareindex/testdata/module_firmware_index.json.sig and /dev/null differ
diff --git a/indexes/firmwareindex/testdata/module_firmware_index.json b/indexes/firmwareindex/testdata/plugin_firmware_index.json
similarity index 57%
rename from indexes/firmwareindex/testdata/module_firmware_index.json
rename to indexes/firmwareindex/testdata/plugin_firmware_index.json
index a54a59fb..ab1703aa 100644
--- a/indexes/firmwareindex/testdata/module_firmware_index.json
+++ b/indexes/firmwareindex/testdata/plugin_firmware_index.json
@@ -1,492 +1,457 @@
 [
   {
-    "fqbn": "arduino:samd:mkr1000",
+    "fqbn": "arduino:renesas_uno:unor4wifi",
     "firmware": [
       {
-        "version": "19.4.4",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/WINC1500/19.4.4/m2m_aio_3a0.bin",
-        "checksum": "SHA-256:f8be2a5ef10e109f685b7550d211ed11c07487de430b0e5994ca557160116c27",
-        "size": "412308",
-        "module": "WINC1500"
+        "version": "0.1.0",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/ESP32-S3/0.1.0/ESP32-S3.bin",
+        "checksum": "SHA-256:37c4f003373448504d49d5e3c1754d1d90b9bba3f8f3b529b435d331ca6900b1",
+        "size": "3951616",
+        "module": "ESP32-S3"
       },
       {
-        "version": "19.5.2",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/WINC1500/19.5.2/m2m_aio_3a0.bin",
-        "checksum": "SHA-256:e2e5aa2cf185745582002e2fed27c079d4228bc8d756281f43638c72061c9110",
-        "size": "413604",
-        "module": "WINC1500"
+        "version": "0.2.0",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/ESP32-S3/0.2.0/ESP32-S3.bin",
+        "checksum": "SHA-256:cb535826ba96d4f51bdac33d252c24bd9c692a7bef56710ec0431979cef09fc3",
+        "size": "3951616",
+        "module": "ESP32-S3"
       },
       {
-        "version": "19.5.4",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/WINC1500/19.5.4/m2m_aio_3a0.bin",
-        "checksum": "SHA-256:146d3d5fccf65ff6d732e34077e56f1f0b2f69584fd8499db914ea11ed463042",
-        "size": "413604",
-        "module": "WINC1500"
-      },
-      {
-        "version": "19.6.1",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/WINC1500/19.6.1/m2m_aio_3a0.bin",
-        "checksum": "SHA-256:629a2553cb738be1424eaa707c00403ebce179fdb94008acec1f185a19a60c81",
-        "size": "359356",
-        "module": "WINC1500"
+        "version": "0.2.1",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/ESP32-S3/0.2.1/ESP32-S3.bin",
+        "checksum": "SHA-256:8fad86ac6b44ba16853c41644338ba61e64383904c757b37d8adaeca9b76da03",
+        "size": "3951616",
+        "module": "ESP32-S3"
       }
     ],
-    "loader_sketch": {
-      "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/loader/arduino.samd.mkr1000/loader.bin",
-      "checksum": "SHA-256:1d904bf745c8df448358d70837a36ee8dec4c2a01e0e3b2ef8ef51c6a6c9d385",
-      "size": "16328"
-    },
-    "module": "WINC1500",
-    "name": "Arduino MKR1000",
-    "uploader": "arduino:bossac@1.7.0-arduino3",
-    "upload.use_1200bps_touch": true,
-    "upload.wait_for_upload_port": true,
-    "uploader.command": {
-      "linux": "\"{tool_dir}/bossac\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R",
-      "windows": "\"{tool_dir}\\bossac.exe\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R"
-    }
+    "uploader_plugin": "arduino:uno-r4-wifi-fwuploader-plugin@1.0.0",
+    "additional_tools": [
+      "arduino:espflash@2.0.0",
+      "arduino:bossac@1.9.1-arduino5"
+    ],
+    "module": "ESP32-S3",
+    "name": "Arduino UNO R4 WiFi"
   },
   {
     "fqbn": "arduino:samd:mkrwifi1010",
     "firmware": [
       {
         "version": "1.0.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.0.0/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.0.0/NINA.bin",
         "checksum": "SHA-256:3fe2cd90a0774e271624d42ab1b238d92c7495648e9918ad49dea3b20379905e",
         "size": "736256",
         "module": "NINA"
       },
       {
         "version": "1.1.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.1.0/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.1.0/NINA.bin",
         "checksum": "SHA-256:3b38f44a2e2e2d28995973f432bc2795f7c58a14e8638f55e3f024ffa499bcf8",
         "size": "814080",
         "module": "NINA"
       },
       {
         "version": "1.2.1",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.1/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.1/NINA.bin",
         "checksum": "SHA-256:3121bf4074fce0248946810c4d03f5d3fb1296cd4667aeb801b5d066e1b07ff3",
         "size": "880640",
         "module": "NINA"
       },
       {
         "version": "1.2.2",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.2/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.2/NINA.bin",
         "checksum": "SHA-256:71d0a49a4d79aa46dff6f434383133b4365581407846d709fbd961e2b770eb3c",
         "size": "893952",
         "module": "NINA"
       },
       {
         "version": "1.2.3",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.3/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.3/NINA.bin",
         "checksum": "SHA-256:9c908f33cc05831972833a274f65baf84da35c61fc081856959211ae3504c899",
         "size": "893952",
         "module": "NINA"
       },
       {
         "version": "1.2.4",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.4/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.4/NINA.bin",
         "checksum": "SHA-256:8b9c07abdaa5647c47466aa3c575e743495a295fd8db2fe91b7e28fe4135ffad",
         "size": "917504",
         "module": "NINA"
       },
       {
         "version": "1.3.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.3.0/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.3.0/NINA.bin",
         "checksum": "SHA-256:aa37c920df18aabc6544df93c64bea6b3b97841b68ff4a6a53d2b800b265d2b5",
         "size": "986112",
         "module": "NINA"
       },
       {
         "version": "1.4.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.0/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.0/NINA.bin",
         "checksum": "SHA-256:ca5ed0b5efd727dd3c507f39a744e171ce690ef17b116c0571f18d1fea17aa85",
         "size": "1035264",
         "module": "NINA"
       },
       {
         "version": "1.4.1",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.1/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.1/NINA.bin",
         "checksum": "SHA-256:b20f213bc886a95556fc5cec5003c7ebc617da83581ba20fb9f96db003063bbd",
         "size": "1208320",
         "module": "NINA"
       },
       {
         "version": "1.4.2",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.2/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.2/NINA.bin",
         "checksum": "SHA-256:61d0acbd3d2eeb45b6971448d9537f7c4fa27f264e20970ad5dfdd4cbfdd8ee0",
         "size": "1125376",
         "module": "NINA"
       },
       {
         "version": "1.4.3",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.3/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.3/NINA.bin",
         "checksum": "SHA-256:8c10c3ee3b8fb2ade3a650b41a3081566fc160e89b32e5d0ee040e63647692b8",
         "size": "1125376",
         "module": "NINA"
       },
       {
         "version": "1.4.4",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.4/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.4/NINA.bin",
         "checksum": "SHA-256:c8678e00ab9b2dc99cdc45ef577b77498dac802c3f5b99961da190374fddcef8",
         "size": "1125376",
         "module": "NINA"
       },
       {
         "version": "1.4.5",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.5/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.5/NINA.bin",
         "checksum": "SHA-256:7c2814c8f879e62d234d7ac3a9c28f9a2d1e1dbc3569bd740761ca796247a4c9",
         "size": "1127424",
         "module": "NINA"
+      },
+      {
+        "version": "1.4.6",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.6/NINA.bin",
+        "checksum": "SHA-256:9f3df8446bb5038437bfd25b4fe06cb84b32bff29c5ba8eea852b49d059837f7",
+        "size": "1127424",
+        "module": "NINA"
+      },
+      {
+        "version": "1.4.7",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.7/NINA.bin",
+        "checksum": "SHA-256:22cfa44b41bf4219a025b93a33752528735ba82cb638999ff4015c5579a46cef",
+        "size": "1127424",
+        "module": "NINA"
+      },
+      {
+        "version": "1.4.8",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.8/NINA.bin",
+        "checksum": "SHA-256:6b75e118fedc8d1f45ac5667d59effe227d651f38e77ed2dac45f9a7593c07f6",
+        "size": "1127424",
+        "module": "NINA"
+      },
+      {
+        "version": "1.5.0",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.5.0/NINA.bin",
+        "checksum": "SHA-256:12e915d44f3acfc26f2b9d266228afd11ad795fe37b7a4ba98a1eddc91a0eed1",
+        "size": "1129472",
+        "module": "NINA"
       }
     ],
-    "loader_sketch": {
-      "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/loader/arduino.samd.mkrwifi1010/loader.bin",
-      "checksum": "SHA-256:a4f9b0586bf78b8e1c5a6660df6b749d1ad4e3ee79ee4928371a465899a4a1c4",
-      "size": "13688"
-    },
+    "uploader_plugin": "arduino:nina-fwuploader-plugin@1.0.0",
+    "additional_tools": [
+      "arduino:bossac@1.7.0-arduino3"
+    ],
     "module": "NINA",
-    "name": "Arduino MKR WiFi 1010",
-    "uploader": "arduino:bossac@1.7.0-arduino3",
-    "upload.use_1200bps_touch": true,
-    "upload.wait_for_upload_port": true,
-    "uploader.command": {
-      "linux": "\"{tool_dir}/bossac\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R",
-      "windows": "\"{tool_dir}\\bossac.exe\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R"
-    }
+    "name": "Arduino MKR WiFi 1010"
   },
   {
     "fqbn": "arduino:samd:nano_33_iot",
     "firmware": [
       {
         "version": "1.0.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.0.0/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.0.0/NINA.bin",
         "checksum": "SHA-256:3fe2cd90a0774e271624d42ab1b238d92c7495648e9918ad49dea3b20379905e",
         "size": "736256",
         "module": "NINA"
       },
       {
         "version": "1.1.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.1.0/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.1.0/NINA.bin",
         "checksum": "SHA-256:3b38f44a2e2e2d28995973f432bc2795f7c58a14e8638f55e3f024ffa499bcf8",
         "size": "814080",
         "module": "NINA"
       },
       {
         "version": "1.2.1",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.1/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.1/NINA.bin",
         "checksum": "SHA-256:3121bf4074fce0248946810c4d03f5d3fb1296cd4667aeb801b5d066e1b07ff3",
         "size": "880640",
         "module": "NINA"
       },
       {
         "version": "1.2.2",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.2/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.2/NINA.bin",
         "checksum": "SHA-256:71d0a49a4d79aa46dff6f434383133b4365581407846d709fbd961e2b770eb3c",
         "size": "893952",
         "module": "NINA"
       },
       {
         "version": "1.2.3",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.3/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.3/NINA.bin",
         "checksum": "SHA-256:9c908f33cc05831972833a274f65baf84da35c61fc081856959211ae3504c899",
         "size": "893952",
         "module": "NINA"
       },
       {
         "version": "1.2.4",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.4/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.4/NINA.bin",
         "checksum": "SHA-256:8b9c07abdaa5647c47466aa3c575e743495a295fd8db2fe91b7e28fe4135ffad",
         "size": "917504",
         "module": "NINA"
       },
       {
         "version": "1.3.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.3.0/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.3.0/NINA.bin",
         "checksum": "SHA-256:aa37c920df18aabc6544df93c64bea6b3b97841b68ff4a6a53d2b800b265d2b5",
         "size": "986112",
         "module": "NINA"
       },
       {
         "version": "1.4.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.0/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.0/NINA.bin",
         "checksum": "SHA-256:ca5ed0b5efd727dd3c507f39a744e171ce690ef17b116c0571f18d1fea17aa85",
         "size": "1035264",
         "module": "NINA"
       },
       {
         "version": "1.4.1",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.1/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.1/NINA.bin",
         "checksum": "SHA-256:b20f213bc886a95556fc5cec5003c7ebc617da83581ba20fb9f96db003063bbd",
         "size": "1208320",
         "module": "NINA"
       },
       {
         "version": "1.4.2",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.2/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.2/NINA.bin",
         "checksum": "SHA-256:61d0acbd3d2eeb45b6971448d9537f7c4fa27f264e20970ad5dfdd4cbfdd8ee0",
         "size": "1125376",
         "module": "NINA"
       },
       {
         "version": "1.4.3",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.3/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.3/NINA.bin",
         "checksum": "SHA-256:8c10c3ee3b8fb2ade3a650b41a3081566fc160e89b32e5d0ee040e63647692b8",
         "size": "1125376",
         "module": "NINA"
       },
       {
         "version": "1.4.4",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.4/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.4/NINA.bin",
         "checksum": "SHA-256:c8678e00ab9b2dc99cdc45ef577b77498dac802c3f5b99961da190374fddcef8",
         "size": "1125376",
         "module": "NINA"
       },
       {
         "version": "1.4.5",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.5/NINA_W102.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.5/NINA.bin",
         "checksum": "SHA-256:7c2814c8f879e62d234d7ac3a9c28f9a2d1e1dbc3569bd740761ca796247a4c9",
         "size": "1127424",
         "module": "NINA"
-      }
-    ],
-    "loader_sketch": {
-      "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/loader/arduino.samd.nano_33_iot/loader.bin",
-      "checksum": "SHA-256:f643fd763ba6aec835bb708669a6a5f5709357990d9eab6f4e6d5223ea3ca2a3",
-      "size": "14348"
-    },
-    "module": "NINA",
-    "name": "Arduino NANO 33 IoT",
-    "uploader": "arduino:bossac@1.7.0-arduino3",
-    "upload.use_1200bps_touch": true,
-    "upload.wait_for_upload_port": true,
-    "uploader.command": {
-      "linux": "\"{tool_dir}/bossac\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R",
-      "windows": "\"{tool_dir}\\bossac.exe\" -i -d --port={serial.port.file} -U true -i -e -w -v \"{loader.sketch}.bin\" -R"
-    }
-  },
-  {
-    "fqbn": "arduino:samd:mkrvidor4000",
-    "firmware": [
-      {
-        "version": "1.0.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.0.0/NINA_W102.bin",
-        "checksum": "SHA-256:3fe2cd90a0774e271624d42ab1b238d92c7495648e9918ad49dea3b20379905e",
-        "size": "736256",
-        "module": "NINA"
-      },
-      {
-        "version": "1.1.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.1.0/NINA_W102.bin",
-        "checksum": "SHA-256:3b38f44a2e2e2d28995973f432bc2795f7c58a14e8638f55e3f024ffa499bcf8",
-        "size": "814080",
-        "module": "NINA"
-      },
-      {
-        "version": "1.2.1",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.1/NINA_W102.bin",
-        "checksum": "SHA-256:3121bf4074fce0248946810c4d03f5d3fb1296cd4667aeb801b5d066e1b07ff3",
-        "size": "880640",
-        "module": "NINA"
-      },
-      {
-        "version": "1.2.2",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.2/NINA_W102.bin",
-        "checksum": "SHA-256:71d0a49a4d79aa46dff6f434383133b4365581407846d709fbd961e2b770eb3c",
-        "size": "893952",
-        "module": "NINA"
-      },
-      {
-        "version": "1.2.3",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.3/NINA_W102.bin",
-        "checksum": "SHA-256:9c908f33cc05831972833a274f65baf84da35c61fc081856959211ae3504c899",
-        "size": "893952",
-        "module": "NINA"
-      },
-      {
-        "version": "1.2.4",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.4/NINA_W102.bin",
-        "checksum": "SHA-256:8b9c07abdaa5647c47466aa3c575e743495a295fd8db2fe91b7e28fe4135ffad",
-        "size": "917504",
-        "module": "NINA"
-      },
-      {
-        "version": "1.3.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.3.0/NINA_W102.bin",
-        "checksum": "SHA-256:aa37c920df18aabc6544df93c64bea6b3b97841b68ff4a6a53d2b800b265d2b5",
-        "size": "986112",
-        "module": "NINA"
-      },
-      {
-        "version": "1.4.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.0/NINA_W102.bin",
-        "checksum": "SHA-256:ca5ed0b5efd727dd3c507f39a744e171ce690ef17b116c0571f18d1fea17aa85",
-        "size": "1035264",
-        "module": "NINA"
-      },
-      {
-        "version": "1.4.1",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.1/NINA_W102.bin",
-        "checksum": "SHA-256:b20f213bc886a95556fc5cec5003c7ebc617da83581ba20fb9f96db003063bbd",
-        "size": "1208320",
-        "module": "NINA"
       },
       {
-        "version": "1.4.2",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.2/NINA_W102.bin",
-        "checksum": "SHA-256:61d0acbd3d2eeb45b6971448d9537f7c4fa27f264e20970ad5dfdd4cbfdd8ee0",
-        "size": "1125376",
+        "version": "1.4.6",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.6/NINA.bin",
+        "checksum": "SHA-256:9f3df8446bb5038437bfd25b4fe06cb84b32bff29c5ba8eea852b49d059837f7",
+        "size": "1127424",
         "module": "NINA"
       },
       {
-        "version": "1.4.3",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.3/NINA_W102.bin",
-        "checksum": "SHA-256:8c10c3ee3b8fb2ade3a650b41a3081566fc160e89b32e5d0ee040e63647692b8",
-        "size": "1125376",
+        "version": "1.4.7",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.7/NINA.bin",
+        "checksum": "SHA-256:22cfa44b41bf4219a025b93a33752528735ba82cb638999ff4015c5579a46cef",
+        "size": "1127424",
         "module": "NINA"
       },
       {
-        "version": "1.4.4",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.4/NINA_W102.bin",
-        "checksum": "SHA-256:c8678e00ab9b2dc99cdc45ef577b77498dac802c3f5b99961da190374fddcef8",
-        "size": "1125376",
+        "version": "1.4.8",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.8/NINA.bin",
+        "checksum": "SHA-256:6b75e118fedc8d1f45ac5667d59effe227d651f38e77ed2dac45f9a7593c07f6",
+        "size": "1127424",
         "module": "NINA"
       },
       {
-        "version": "1.4.5",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.5/NINA_W102.bin",
-        "checksum": "SHA-256:7c2814c8f879e62d234d7ac3a9c28f9a2d1e1dbc3569bd740761ca796247a4c9",
-        "size": "1127424",
+        "version": "1.5.0",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.5.0/NINA.bin",
+        "checksum": "SHA-256:12e915d44f3acfc26f2b9d266228afd11ad795fe37b7a4ba98a1eddc91a0eed1",
+        "size": "1129472",
         "module": "NINA"
       }
     ],
+    "uploader_plugin": "arduino:nina-fwuploader-plugin@1.0.0",
+    "additional_tools": [
+      "arduino:bossac@1.7.0-arduino3"
+    ],
     "module": "NINA",
-    "name": "Arduino MKR Vidor 4000",
-    "uploader": "arduino:bossac@1.7.0-arduino3",
-    "upload.use_1200bps_touch": true,
-    "upload.wait_for_upload_port": true,
-    "uploader.command": {
-      "linux": "\"{tool_dir}/bossac\" -i -d --port={serial.port.file} -I -U true -i -e -w \"{loader.sketch}.bin\" -R",
-      "windows": "\"{tool_dir}\\bossac.exe\" -i -d --port={serial.port.file} -I -U true -i -e -w \"{loader.sketch}.bin\" -R"
-    }
+    "name": "Arduino NANO 33 IoT"
   },
   {
     "fqbn": "arduino:megaavr:uno2018",
     "firmware": [
       {
         "version": "1.2.1",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.1/NINA_W102-Uno_WiFi_Rev2.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.1/NINA-arduino.megaavr.uno2018.bin",
         "checksum": "SHA-256:bac23326dd4c3b6358ee88ff322da8c16e24e9917b8b0bbd18f663aacfb758cf",
         "size": "880640",
         "module": "NINA"
       },
       {
         "version": "1.2.2",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.2/NINA_W102-Uno_WiFi_Rev2.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.2/NINA-arduino.megaavr.uno2018.bin",
         "checksum": "SHA-256:d1f496b185eff6b2ab2f839f6673afc80e1b3e3b2056fc8d9290a74895baf0e5",
         "size": "893952",
         "module": "NINA"
       },
       {
         "version": "1.2.3",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.3/NINA_W102-Uno_WiFi_Rev2.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.3/NINA-arduino.megaavr.uno2018.bin",
         "checksum": "SHA-256:53668eb76be80fffdd67ced7cbb8ab231638b9ee428ae83568dfe48359008bb4",
         "size": "893952",
         "module": "NINA"
       },
       {
         "version": "1.2.4",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.4/NINA_W102-Uno_WiFi_Rev2.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.2.4/NINA-arduino.megaavr.uno2018.bin",
         "checksum": "SHA-256:37b042cf759b52a96304c35af6a066038184533cc6256f795e92ed1b4fbda3d5",
         "size": "917504",
         "module": "NINA"
       },
       {
         "version": "1.3.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.3.0/NINA_W102-Uno_WiFi_Rev2.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.3.0/NINA-arduino.megaavr.uno2018.bin",
         "checksum": "SHA-256:c538028f428b3fc219d2f7c0d9debacd07bababf43dbc28680ed452225ff4629",
         "size": "986112",
         "module": "NINA"
       },
       {
         "version": "1.4.0",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.0/NINA_W102-Uno_WiFi_Rev2.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.0/NINA-arduino.megaavr.uno2018.bin",
         "checksum": "SHA-256:fe852e28eb0547a324069194dcce524b5a9f18adce2983bbe11a818a7ae8200a",
         "size": "1041408",
         "module": "NINA"
       },
       {
         "version": "1.4.1",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.1/NINA_W102-Uno_WiFi_Rev2.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.1/NINA-arduino.megaavr.uno2018.bin",
         "checksum": "SHA-256:f11deb8ce5abe908353eebca7253c18359eb8ea2a601908d5cdb56bf035b4158",
         "size": "1044480",
         "module": "NINA"
       },
       {
         "version": "1.4.2",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.2/NINA_W102-Uno_WiFi_Rev2.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.2/NINA-arduino.megaavr.uno2018.bin",
         "checksum": "SHA-256:7adff887267297dccc6c3ce77f41a986a23a1f7dfce9e8f3b70b3aa038371d47",
         "size": "1132544",
         "module": "NINA"
       },
       {
         "version": "1.4.3",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.3/NINA_W102-Uno_WiFi_Rev2.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.3/NINA-arduino.megaavr.uno2018.bin",
         "checksum": "SHA-256:c026f967bd3add27716a1afaf729d669a5e093771098329bab2477980d6879b5",
         "size": "1132544",
         "module": "NINA"
       },
       {
         "version": "1.4.4",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.4/NINA_W102-Uno_WiFi_Rev2.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.4/NINA-arduino.megaavr.uno2018.bin",
         "checksum": "SHA-256:6b7809357a57946638b271dd1b0b43a84cbcbea9b854d3ff093752fa0fe7b818",
         "size": "1132544",
         "module": "NINA"
       },
       {
         "version": "1.4.5",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.5/NINA_W102-Uno_WiFi_Rev2.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.5/NINA-arduino.megaavr.uno2018.bin",
         "checksum": "SHA-256:b641c4f6f76ab4c7a529848da54f15b9b9857a9627920129a0a6f65edc465c67",
         "size": "1133568",
         "module": "NINA"
+      },
+      {
+        "version": "1.4.6",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.6/NINA-arduino.megaavr.uno2018.bin",
+        "checksum": "SHA-256:9a0c9e5f4b63dbc468f1458dd01d4d33be272e0436055efeea033dd7e2b11880",
+        "size": "1133568",
+        "module": "NINA"
+      },
+      {
+        "version": "1.4.7",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.7/NINA-arduino.megaavr.uno2018.bin",
+        "checksum": "SHA-256:b560dd7bfef78513b3c468999da1f83b6185aa319a9da544260bc6a74aa8b89b",
+        "size": "1133568",
+        "module": "NINA"
+      },
+      {
+        "version": "1.4.8",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.8/NINA-arduino.megaavr.uno2018.bin",
+        "checksum": "SHA-256:89cbfbeb776437c15691c29da269cde63a13f8994a7ba2f3bba8e9fb1ef6efcb",
+        "size": "1133568",
+        "module": "NINA"
+      },
+      {
+        "version": "1.5.0",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.5.0/NINA-arduino.megaavr.uno2018.bin",
+        "checksum": "SHA-256:9687f9491d4f804487055dd1db3b8932567050c18552e4be109f096dea4201ca",
+        "size": "1135616",
+        "module": "NINA"
       }
     ],
-    "loader_sketch": {
-      "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/loader/arduino.megaavr.uno2018/loader.hex",
-      "checksum": "SHA-256:0d4c2bf93da575245e92595b1d0f55db1fa79583f1c3361646da051dab020afe",
-      "size": "18954"
-    },
+    "uploader_plugin": "arduino:nina-fwuploader-plugin@1.0.0",
+    "additional_tools": [
+      "arduino:avrdude@6.3.0-arduino17"
+    ],
     "module": "NINA",
-    "name": "Arduino Uno WiFi Rev2",
-    "uploader": "arduino:avrdude@6.3.0-arduino17",
-    "uploader.command": {
-      "linux": "\"{tool_dir}/bin/avrdude\" \"-C{tool_dir}/etc/avrdude.conf\" -v  -patmega4809 -cxplainedmini_updi -Pusb  -b115200 -e -D \"-Uflash:w:{loader.sketch}.hex:i\" \"-Ufuse2:w:0x01:m\" \"-Ufuse5:w:0xC9:m\" \"-Ufuse8:w:0x02:m\" "
-    }
+    "name": "Arduino Uno WiFi Rev2"
   },
   {
     "fqbn": "arduino:mbed_nano:nanorp2040connect",
     "firmware": [
       {
         "version": "1.4.5",
-        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.5/NINA_W102-Nano_RP2040_Connect.bin",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.5/NINA-arduino.mbed_nano.nanorp2040connect.bin",
         "checksum": "SHA-256:5cc391414abd2233001923221a0103dd5ca37222cf885dace065962c962ccd2b",
         "size": "1127424",
         "module": "NINA"
+      },
+      {
+        "version": "1.4.6",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.6/NINA-arduino.mbed_nano.nanorp2040connect.bin",
+        "checksum": "SHA-256:6b46f3cd771d6a322819855690b2703c51f15fa00894e94c77bad3f8c216be58",
+        "size": "1127424",
+        "module": "NINA"
+      },
+      {
+        "version": "1.4.7",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.7/NINA-arduino.mbed_nano.nanorp2040connect.bin",
+        "checksum": "SHA-256:d3fb2da91f46803e3dfed552d328e7d4d495be8b2773504bc695aefff3d114cb",
+        "size": "1127424",
+        "module": "NINA"
+      },
+      {
+        "version": "1.4.8",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.4.8/NINA-arduino.mbed_nano.nanorp2040connect.bin",
+        "checksum": "SHA-256:922b3c156498c4493272e15548fdf587ee957a1f400bd44d444e68890ad12eba",
+        "size": "1127424",
+        "module": "NINA"
+      },
+      {
+        "version": "1.5.0",
+        "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/NINA/1.5.0/NINA-arduino.mbed_nano.nanorp2040connect.bin",
+        "checksum": "SHA-256:f456ff99fc3d697ffd4c715a75172d793abd3d98c16b76589c4de92b6f787cf0",
+        "size": "1129472",
+        "module": "NINA"
       }
     ],
-    "loader_sketch": {
-      "url": "https://downloads.arduino.cc/arduino-fwuploader/firmwares/loader/arduino.mbed_nano.nanorp2040connect/loader.elf",
-      "checksum": "SHA-256:4b67381122df67a210c29d01f01153f34cdeea77593f7e5e12259e3c85b472f0",
-      "size": "1639020"
-    },
+    "uploader_plugin": "arduino:nina-fwuploader-plugin@1.0.0",
+    "additional_tools": [
+      "arduino:rp2040tools@1.0.6"
+    ],
     "module": "NINA",
-    "name": "Arduino Nano RP2040 Connect",
-    "uploader": "arduino:rp2040tools@1.0.2",
-    "upload.use_1200bps_touch": true,
-    "upload.wait_for_upload_port": true,
-    "uploader.command": {
-      "linux": "\"{tool_dir}/rp2040load\" -v -D \"{loader.sketch}.elf\""
-    }
+    "name": "Arduino Nano RP2040 Connect"
   }
 ]
\ No newline at end of file
diff --git a/indexes/firmwareindex/testdata/plugin_firmware_index.json.sig b/indexes/firmwareindex/testdata/plugin_firmware_index.json.sig
new file mode 100644
index 00000000..9218e3c7
Binary files /dev/null and b/indexes/firmwareindex/testdata/plugin_firmware_index.json.sig differ
diff --git a/indexes/indexes_test.go b/indexes/indexes_test.go
index e3f2d8a0..cbc9ff1d 100644
--- a/indexes/indexes_test.go
+++ b/indexes/indexes_test.go
@@ -33,7 +33,7 @@ func TestGetPackageIndex(t *testing.T) {
 }
 
 func TestGetFirmwareIndex(t *testing.T) {
-	index, err := GetFirmwareIndex(globals.ModuleFirmwareIndexGZURL, true)
+	index, err := GetFirmwareIndex(globals.PluginFirmwareIndexGZURL, true)
 	require.NoError(t, err)
 	require.NotNil(t, index)
 }
diff --git a/mkdocs.yml b/mkdocs.yml
index eabd7259..d4a34be4 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -60,3 +60,4 @@ nav:
       - firmware list: commands/arduino-fwuploader_firmware_list.md
       - version: commands/arduino-fwuploader_version.md
   - Plugins: plugins.md
+  - Deprecated boards: deprecated.md
diff --git a/programmers/programmer.go b/programmers/programmer.go
deleted file mode 100644
index 4b8c1e95..00000000
--- a/programmers/programmer.go
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
-	arduino-fwuploader
-	Copyright (c) 2021 Arduino LLC.  All right reserved.
-
-	This program is free software: you can redistribute it and/or modify
-	it under the terms of the GNU Affero General Public License as published
-	by the Free Software Foundation, either version 3 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU Affero General Public License for more details.
-
-	You should have received a copy of the GNU Affero General Public License
-	along with this program.  If not, see <https://www.gnu.org/licenses/>.
-*/
-
-package programmer
-
-import (
-	"io"
-
-	"github.com/arduino/arduino-cli/executils"
-)
-
-// Flash runs the upload command and outputs to outStream and errStream
-func Flash(command []string, outStream, errStream io.Writer) error {
-	cmd, err := executils.NewProcess(nil, command...)
-	if err != nil {
-		return err
-	}
-	cmd.RedirectStdoutTo(outStream)
-	cmd.RedirectStderrTo(errStream)
-	return cmd.Run()
-}