Particle-api-js using flashDevice with Blob


#1

Trying to flash a device from the Particle JS API from the browser using Blob in the browser, the documentation makes me believe this will work, but I am missing something. I get “Device flashing started successfully” and it flashes (maroon) and restarts with the firmware it had.

Thanks for any help!

The flashDevice documentation: Compile and flash application firmware to a device. Pass a pre-compiled binary to flash it directly to the device.
I read this as two statements, you can compile and flash or flash a pre-compiled binary.

Documentation example:

particle.flashDevice({ deviceId: 'DEVICE_ID', files: { file1: './path/file1' }, auth: token }).then(function(data) {
  // success
}, function(err) {
  // fail
});

Currently

var blob = new Blob([document.getElementById('deviceCode').value], {
  type: 'application/octet-stream'
 });

particle.flashDevice({ deviceId: targetDevice, files: { file1: blob }, auth: token }).then(function(data) {
  // success
}, function(err) {
  // fail
});

I tried variations of the file object and type of Blob.
I am using the CDN API

A minimal test case below, just copy the html and host it locally or on your server.

<!DOCTYPE html>
<meta charset="UTF-8">
<html>
    <head>
        <script src="https://cdn.jsdelivr.net/particle-api-js/5/particle.min.js"></script>
    </head>
    <style>
    td { padding: 8px; }
    td:first-child { color: grey; }
    td:last-child { border: 1px solid grey; }
</style>
<body>

    <h3>Login</h3>
    <input id="particleEmail" type="email" placeholder="Email">
    <input id="particlePassword" type="password" placeholder="Password">
    <button onclick="particleLogin()">Login</button>

    <h3>Program Photon</h3>
    <code>
<textarea id="deviceCode" rows="20" cols="40">
void setup() {
    
    pinMode(D7, OUTPUT);

}

void loop() {
    
    digitalWrite(D7, HIGH);
    
    delay(3000);
    
    digitalWrite(D7, LOW);
    
    delay(1000);

}
</textarea>
    </code>
    </br>
    
    <table id="deviceList"></table>
    <p id="flashSelection"></p>
    <button onclick="particleFlash()">Flash</button>

<script>

var particle = new Particle();
var token;
var targetDevice;

function particleLogin() { particle.login({username: document.getElementById('particleEmail').value, password: document.getElementById('particlePassword').value}).then(
        function(data){
            console.log('API call completed on promise resolve: ', data.body.access_token);
            token = data.body.access_token;
            particleList();
        },
        function(err) {
            console.log('API call completed on promise fail: ', err);
        }
    );
}

function particleList() {
    var devicesPr = particle.listDevices({ auth: token });
    var deviceTable = "";

    devicesPr.then(
        function(devices){
            console.log('Devices: ', devices);
            for( var i = 0; i < devices.body.length; i++ ){
                deviceTable += "<tr><td>" + devices.body[i].name + '</td><td>' + devices.body[i].id + "</td></tr>";
            }
            document.getElementById('deviceList').innerHTML = deviceTable;
            document.getElementById('flashSelection').innerHTML = "Select device ID above";
        },
        function(err) {
            console.log('List devices call failed: ', err);
        }
    );
}

document.getElementById('deviceList').addEventListener("click",function(e) {
    targetDevice = e.target.innerHTML;
    document.getElementById('flashSelection').innerHTML = "Targeting " + e.target.innerHTML;
});

function particleFlash() {
    var blob = new Blob([document.getElementById('deviceCode').value], {
        type: 'application/octet-stream'
    });
    console.log(blob);
    particle.flashDevice({ 
        deviceId: targetDevice, 
        files: { file1: blob }, 
        auth: token })
    .then(function(data) {
        console.log('Device flashing started successfully:', data);
    }, function(err) {
        console.log('An error occurred while flashing the device:', err);
    });
}

</script>

</body>
</html>

#2

Hmmm, more documentation examples would be helpful, for sure.

I’m just throwing out a couple of guesses here, but maybe try:

    var blob = new Blob([document.getElementById('deviceCode').value], {
        type: 'text/plain'
    });
    console.log(blob);
    particle.flashDevice({ 
        deviceId: targetDevice, 
        files: { "./myfilename.ino": blob }, 
        auth: token })

This changes the key of the files property to a more standard relative filename, and sets the MIME type to text/plain. You might also try text/x-c++src?

Again, don’t know if that will make it work or not, but give it a try.


#3

Awesome! I tried a few the MIME types but didn’t change the files to "./myfilename.ino" worked with 'text/plain' or 'application/octet-stream'

There wasn’t much documentation working with the Blob type in the usual MDN, I should read up more on FileReader it probably is the same.

But for now, this was a key piece in making a project happen. Thanks so much.