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