Argon CLI Setup Tool

I’m building a product based on the Argon (and eventually the P2 when they become available), and I’m interested in a way to mass-setup the devices before physically integrating them into the product. The current setup process of claiming a device, copying and pasting its ID into the product add popover, and flashing it with firmware feels to complex to scale. What I would like is to combine a series of CLI commands that can be executed by a Python script sequentially, so all that’s required to setup an Argon is to plug it into a computer and run one terminal command. I assumed this could be done by ‘particle serial wifi, particle device add, particle product device add’ or something similar, but whenever I try this, I’m told that there are ‘no devices available via serial’, and I’m not sure what the deal is. Does the CLI only work with devices that have already been claimed and set up, and/or is there a much simpler way to do this without a custom script?

Hey @pbass450

I’ve developed similar scripts in Python and bash for automating the provisioning process.

You could use neopo as a starting point for developing a script to meet your needs since it takes care of installing and using the Particle toolchains and is available on the CLI or as a Python module:

If you have any requests for new features I will gladly add them.

Also, regarding that no devices available via serial message it’s likely because the Argon is not in listening mode (blinking blue). You can put a device into listening mode with the CLI using:

particle usb listen

I’ll give that a look; thanks.

Right now I’m using new Argons right out of the box, so I assume they are in listening mode (they do blink blue), and even when I try particle usb listen I still get the ‘no devices found’ message. I’m not sure what the deal is.

Hi, there was this topic that discussed some scripting here.

Jeff @jgskarda were you able to create something in the area by any chance?
Thanks and cheers,
Gustavo.

2 Likes

@gusgonnet - Yeah, I’ve done a few things using a single Python Script to provision a Boron out of the box. I’d assume the Python Script could be modified for Argon provisioning as well. I personally think the fastest/easiest way to provision is via Using SWD/JTAG | Reference | Particle

This is basically how I do it. It’s a bit piecemealed but has really sped up the provisioning process for me. Here are the rough steps I currently do. Happy to share the pythons script itself if others would find it useful.

One time Pre-Work:

  • Bulk add all devices to the product. I personally use a 2D Barcode reader to scan a batch of them into a .txt file and then use the console to add devices in bulk to an existing product (i.e. 1, 10, or even 50 at a time). A USB 2D barcode reader as outlined here is very handy. Lookup Tools | Tools | Particle By the way… I personally wish I got a wireless USB 2D barcode scanner.
  • Create a .HEX file of your application and DeviceOS Particle Hex File Generator

Physical steps per device:

  1. Remove from package and install antenna
  2. Plug in the JTAG/SWD programmer to device
  3. Apply power (Plug in a battery, plug in USB, add to carrier board that has power, etc.)
  4. Run the script outlined below
  5. Scan in the Particle Device ID using a barcode scanner
  6. Scan in my specific hexadecimal ID using barcode scanner

When I execute the python script it automates the following steps:

  1. Ask the user to input the 2D barcode on the particle device. I click in the input field and use the USB scanner to scan it in from the Boron.
  2. Given the device serial number as scanned in from the barcode, make a call to the particle cloud API to obtain the device’s device_id
  3. Ask the user to scan in the 2D barcode/serial number unique to my product. This is a 2D barcode I physically print and located on the exterior of the product. I need to match this to the device_id in my backend. (10 digit hexadecimal). I use my own 10 digit hexadecimal as not all devices in my database are Particle.IO devices. This allows an end customer to use the same process to associate a device to a particular customer weather it’s a particle.io device or not.
  4. Using SQL Alchemy - call a stored procedure within my SQL database that adds the device to my SQL database given parameters of device_id, device type, and 10 digit hexadecimal. This adds the device to all necessary SQL tables in my “backend” data storage, device settings, device management, database as used by other aspects of the application.
  5. Make a call to the Particle Cloud API to claim the device to an “admin” account. I currently claim all devices to a single admin account.
  6. Make a call to the Particle cloud API to update the device notes and device name for that device. I use device name and device notes to add a little context to the particle console of what customer purchased each device and what type of device it is. In this case, I just set notes to “status”:“unclaimed” and the device name to the 10 digit hexadecimal value I reference earlier.
  7. Finally, flash the hex file to the device. My application code also clears the setup done flag if it is not set. Setup Done Flag in Setup - OK to leave in with production Firmware? - #5 by rickkas7 This takes 1-2 seconds to flash everything.

Flashing is this line of code and it flashes it all in just 2-3 seconds:

#Now Flash the Device OS
os.chdir(r"C:\Users\Particle\hex")
os.system("nrfjprog -f NRF52 --program Boron_V27.hex --chiperase --reset")

I never timed myself, but with this process I think I can commission a device in 1-2 minutes each. It becomes… plug in a device, hit run on the script, scan in the particle barcode, scan in the 10 digit hexadecimal barcode and in 10 second or less the script is done. I spend more time taking a device out of the box and attaching the antenna and plugging it in then the actual script running.

Happy to share the entire script if others think it’ll help. It’s a blend between custom for my own application and SQL backend and particle specific stuff. With spaces and comments it’s only 120 lines long so not much to it. Just let me know and I could probably post it to github for others to use as a reference.

Now that I think about it a bit… a few other changes I could make could be:

  1. Add the device to the product automatically as part of the script vs having to do that in advance manually. Not sure why I did it separately as I assume the particle cloud API could do it as well.
  2. Create a basic of basic flask app user interface around the python script. This could provide a better “user interface” rather than just the command line of a python environment. Or put some sort of interface around it all and use an easy button ICON to kick the process off instead of just the python command prompt.
    image

Are there any other ideas how to make it even easier faster? I know there is some node.JS application note or something out there on this right? I went down this path just because I am the most familiar with Python but I’m sure could be done other ways as well.

2 Likes

Thank you Jeff for taking the time!
That was amazing.

Yes please, I invite you to either post it here or in a repo so people can benefit from it.

2 Likes

I’ll create the GitHub repo once I include the “adding the device to the product” and also migrate to a Flask App interface. If/when I do that, I’ll share it back here or maybe just create a new post sharing all the details.

In the meantime… here is the 3/4 baked Python script I use today and just use the Command Line as the interface. I’d appreciate any feedback/ideas on how to make this even easier. If I end up doing hundreds of devices, I may try and setup a raspberry PI with cheap touch screen that I could do it all easily from my “workbench” area instead of “office” area. All in time…

import os
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
import json, requests

#Enter Particle Product IDs (These are not my actual IDs)
sandbox = '12345'
growth = '12345'

#Read sensative configuration parameters, tokens, etc. via OS Environment Variables. 
SQLALCHEMY_DATABASE_URI = os.environ.get('SQLALCHEMY_DATABASE_URI')
PARTICLE_TOKEN = os.environ.get('PARTICLE_TOKEN')

#Update this line based on where to add the device (either to SandBox or Growth Plan)
PARTICLE_PRODUCTID = sandbox

#Connect to the database...
engine = create_engine(SQLALCHEMY_DATABASE_URI, echo=False)
Base = declarative_base()
Session = sessionmaker(bind=engine)
session = Session()

###############################################################
#  Various functions used elsewhere are defined Here
###############################################################

#  This function calls a stored procedure that exists on the SQL database. 
#  This specific stored procedure is used to add a device to the DB and initialize all tables for that device. 
def exec_procedure(session, proc_name, params):
    sql_params = ",".join(["@{0}={1}".format(name, value) for name, value in params.items()])
    sql_string = """
        DECLARE @return_value int;
        EXEC    @return_value = [dbo].[{proc_name}] {params};
        SELECT 'Return Value' = @return_value;
    """.format(proc_name=proc_name, params=sql_params)
    session.execute(sql_string)
    return "true"


###############################################################
# STEP 1: Scan the Particle Device QR
###############################################################
print('Scan Particle Device QR Code:')
ParticleQR_Full = input()
ParticleSerial = ParticleQR_Full[0:15]

#Look up the device_id from Particle.
#Device ID is needed as it is the primary key to the DB and all device settings and data storage. 
#The barcode just has the device serial number. 
data = {
    'access_token': PARTICLE_TOKEN
}

response = requests. get('https://api.particle.io/v1/serial_numbers/'+ParticleSerial+'?access_token='+PARTICLE_TOKEN)
dictFromServer = response.json()
device_id = dictFromServer['device_id']
print("The Device ID is: "+ device_id)


###############################################################
#Step 2: Scan the device claim code (10 digit hexadecimal unique to my product)
###############################################################
print('Now Scan the devices claim code: ')
ClaimCode_Full = input()
if (len(ClaimCode_Full) > 12):
  ClaimCode = ClaimCode_Full[-10:]
else:
  ClaimCode = ClaimCode_Full

print("The Claim Code is: "+ ClaimCode)

#Uncomment or Comment out the type of device this is (used in the SQL Database). 
#This allows the same firmware to be used for different devices with different sensors attatched, 
#This is sent to the device via function call so the device knows what it is AND used in the front end to hide/show 
#differnet settings/screens based on what type of sesnors/actuators is wired to it. 
deviceFeatures = 1   #Cellular, Sesnor1, Sensor2, Relay1
# deviceFeatures = 2   #Cellular, Sensor1
# deviceFeatures = 3   #Cellular, Relay1
# deviceFeatures = 4   #Cellular, widget10
#...
print("The Selected Feature of this device is: " + str(deviceFeatures))


###############################################################
#Step 3: Execute the stored procedure to add the device to my SQL database
###############################################################
params = {
    'NewDeviceID': '"'+device_id+'"',
    'NewDeviceSerialNum': '"'+ClaimCode+'"',
    'NewDevice_features_id' : deviceFeatures 
}
print(params)
exec_procedure(session, 'AddNewDevice', params)
session.commit()


###############################################################
#Step 4: Claim the device to a single Admin account within the product
###############################################################
data = {
    'access_token': PARTICLE_TOKEN,
    'id':device_id
}

response = requests.post('https://api.particle.io/v1/devices', data=data)
dictFromServer = response.json()
print(dictFromServer)


###############################################################
#Step 5: update the device notes and device name to provide more context to the devices in the console
#Note: when a customer associates a device with their account through the web app, this updates again to include that user in the notes and device name is updated
###############################################################
notes = {"status":"unclaimed"}
name = ClaimCode + '_unclaimed'

data = {
    'notes': json.dumps(notes),
    'name': name,
    'access_token': PARTICLE_TOKEN
}

response = requests.put('https://api.particle.io/v1/products/'+PARTICLE_PRODUCTID+'/devices/'+ device_id, data=data)
dictFromServer = response.json()
print(dictFromServer)
 

###############################################################
#Step 6: Flash the latest and greatest Hex File to the device
# ###############################################################
os.chdir(r"C:\Users\Particle\hex")
os.system("nrfjprog -f NRF52 --program Boron_V27.hex --chiperase --reset")



#General Enhancements needed to this process:
#1) Why not just add the device to the product using this script too. That way I don't need to do that in advance. 
#2) Create a basic Python Flask Web app around this to provide a better user interface
1 Like

Thank you Jeff.

@pbass450 you have some info here. Hope that helps!
Gustavo.

1 Like