esptool-js icon indicating copy to clipboard operation
esptool-js copied to clipboard

Compatibiity With Electron

Open conalllaverty opened this issue 1 year ago • 4 comments

Hi, Does anyone have an example project of being able to flash an ESP32 using esptool-js from an Electron app?

I'm currently getting this error.

Error: TypeError: Cannot read properties of undefined (reading 'get_info')
    at new ESPLoader (esploader.js:124:1)
    at HTMLButtonElement.<anonymous> (renderer.js:73:27)
// renderer.js

const { SerialPort } = require('serialport');
const requireESM = require('esm')(module);
const esptool = requireESM('esptool-js');
const fs = require('fs');
const axios = require('axios');

const dropdown = document.getElementById('serial-dropdown');
const status = document.getElementById('status');

let selectedPort;

function updateStatus(text) {
    status.innerHTML = text;
}

// Consts
const REMOTE_FIRMWARE_URL = "";
const REMOTE_BOOTLOADER_URL = "";
const REMOTE_PARTITIONS_URL = "";

async function listSerialPorts() {
    try {
        const ports = await SerialPort.list();
        
        // Clear the dropdown
        dropdown.innerHTML = '';

        if (ports.length > 0) {
            selectedPort = ports[0].path;
        }
        ports.forEach(port => {
            const option = document.createElement('option');
            option.value = port.path;
            option.text = port.path + (port.manufacturer ? ` (${port.manufacturer})` : '');
            dropdown.appendChild(option);
        });
    } catch (error) {
        console.error('Error listing serial ports:', error);
    }
}

listSerialPorts();

dropdown.addEventListener('change', (e) => {
    console.log(`Selected serial port: ${e.target.value}`);
    selectedPort = e.target.value;
});

document.getElementById('refreshButton').addEventListener('click', async () => {
    listSerialPorts();
});

// Flashing
async function downloadFile(url, outputPath) {
    const response = await axios({
        method: 'get',
        url: url,
        responseType: 'arraybuffer'
    });
    fs.writeFileSync(outputPath, new Uint8Array(response.data));
}

document.getElementById('flashButton').addEventListener('click', async () => {
    updateStatus('Flashing...');
    try {
        const espLoader = new esptool.ESPLoader({
            port: selectedPort,
            chip: 'esp32',
            logLevel: 'debug'
        });
        
        updateStatus('Erasing flash...');

        // Erase the flash first.
        await espLoader.eraseFlash();

        updateStatus('Downloading files...');

        // Download the necessary files
        await downloadFile(REMOTE_FIRMWARE_URL, './tempFirmware.bin');
        await downloadFile(REMOTE_BOOTLOADER_URL, './tempBootloader.bin');
        await downloadFile(REMOTE_PARTITIONS_URL, './tempPartitions.bin');

        updateStatus('Flashing bootloader...');

        // Flash the bootloader.
        const bootloader = await espLoader.readFirmware('./tempBootloader.bin');
        await espLoader.flashFirmware(bootloader, 0x10000);

        updateStatus('Flashing firmware...');

        // Flash the firmware.
        const firmware = await espLoader.readFirmware('./tempFirmware.bin');
        await espLoader.flashFirmware(firmware, 0x1000);

        updateStatus('Flashing partition...');

        // Flash the partitions.
        const partitions = await espLoader.readPartitions('./tempPartitions.bin');
        await espLoader.flashPartitions(partitions, 0x8000);

        await espLoader.close();

        updateStatus('Cleanup...');

        // Clean up the temporary files
        fs.unlinkSync('./tempFirmware.bin');
        fs.unlinkSync('./tempBootloader.bin');
        fs.unlinkSync('./tempPartitions.bin');

        console.log('Flashing complete');
        updateStatus('Flashing completed successfully!');
    } catch (error) {
        console.error('Error:', error);
        updateStatus(error.toString());
    }
});

conalllaverty avatar Oct 08 '23 10:10 conalllaverty

esptool-js will not work on electron because it requires the window.navigator.serial API which is not supported on whatever browser electron uses. Since you're already using Electron you could package your app with the python version of esptool which is more supported and works better.

ruigouveiamaciel avatar Oct 25 '23 13:10 ruigouveiamaciel

esptool-js will not work on electron because it requires the window.navigator.serial API which is not supported on whatever browser electron uses. Since you're already using Electron you could package your app with the python version of esptool which is more supported and works better.

esptool-js uses the Web Serial API which is supported in electron. Electron uses chromium browser which supports both Web Serial and Web Bluetooth APIs. Documentation for the same can be found here - https://www.electronjs.org/docs/latest/tutorial/devices#web-serial-api

sahilrastogi94 avatar Oct 31 '23 07:10 sahilrastogi94

I'm sorry, I completely missed that page. It seems electron has a couple extra steps to work with web serial so that might be why esptool-js doesn't work out of the box.

ruigouveiamaciel avatar Oct 31 '23 11:10 ruigouveiamaciel

I don't have an example code but esptool-js should work with electron. Just try using the Web Serial API instead of the serialport package.

sahilrastogi94 avatar Oct 31 '23 11:10 sahilrastogi94