Create device using gRPC

Hello,

I have a problem with chirpstack v4: I am trying to create a device using gRPC to an existing application that I created manually and it has an ID “application id: 47024c85-9559-46a0-ad0d-dbf1b16bde45”.

My python file is :

import os
import sys

import grpc
from chirpstack_api.as_pb.external import api

# Configuration.

# This must point to the API interface.
server = "localhost:8081"

# The API token (retrieved using the web-interface).
api_token = "...."

if __name__ == "__main__":
  # Connect without using TLS.
  channel = grpc.insecure_channel(server)

  client = api.DeviceServiceStub(channel)

  # Define the API key meta-data.
  auth_token = [("authorization", "Bearer %s" % api_token)]

  # Construct request.
  try:
  	req = api.CreateDeviceRequest()
  	req.device.dev_eui = 'f4fbcdb6545e5e3b'
  	req.device.name = 'device2'
  	req.device.description = 'A new device via grpc'
  	req.device.application_id = int('525548505299565345575353574552549748459710048100451009810249984954981001015253')
  	req.device.device_profile_id = 'Prof A'
  	req.device.skip_f_cnt_check = False
  	req.device.is_disabled = True
  	#req.device.variables = 'ras'
  	#req.device.variables.value = 'ras'
  	#req.device.tags = 'ras'
  	#req.device.tags.value = 'ras'
  	resp = client.Create(req, metadata=auth_token)
  except Exception as e:
  	print('<><><> Exception <><><> ' + str(e))

I have an error with the variable “req.device.application_id” that must be an integer.

Thank you in advance.

1 Like

App id in v4 should be uuid instead?

Yes but I didn’t understand how I can get the UUID of an application that I created manually.

The UUID of any device, application, device profile, etc. are created automatically by ChirpStack. They will be included in the response when you create them, but you can also pull them via the API (list endpoint) or the web UI.

  1. So the UUID of this application is “4e07ce27-1d3e-4f51-8eb4-862e08dddfd5” ?

  1. If yes, when I’m trying to use it in my code :
import os
import sys

import grpc
from chirpstack_api.as_pb.external import api

# Configuration.

# This must point to the API interface.
server = "localhost:8081"

# The API token (retrieved using the web-interface).
api_token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJjaGlycHN0YWNrIiwiaXNzIjoiY2hpcnBzdGFjayIsInN1YiI6IjY1OTViODVjLWQ1ZTYtNGZhMi04YzQ2LWY0MWQ1Y2E2NjZhZSIsInR5cCI6ImtleSJ9.fyP9Pxm0zSEdjmRwn4x1_lnB97Bq2wcvibSEQLGQ__M"

if __name__ == "__main__":
  # Connect without using TLS.
  channel = grpc.insecure_channel(server)

  # Device-queue API client.
  client = api.DeviceServiceStub(channel)

  # Define the API key meta-data.
  auth_token = [("authorization", "Bearer %s" % api_token)]

  # Construct request.
  try:
  	req = api.CreateDeviceRequest()
  	req.device.dev_eui = 'f4fbcdb6545e5e3b'
  	req.device.name = 'device2'
  	req.device.description = 'A new device via grpc'
  	req.device.application_id = "4e07ce27-1d3e-4f51-8eb4-862e08dddfd5"
  	req.device.device_profile_id = 'Prof A'
  	req.device.skip_f_cnt_check = False
  	req.device.is_disabled = True
  	resp = client.Create(req, metadata=auth_token)
  except Exception as e:
  	print('<><><> Exception <><><> ' + str(e))

  
  # Print the downlink frame-counter value.
    #print(resp.device)
  print('------- End OF TEST')
  1. I’m getting this error :

Cannot set api.Device.application_id to ‘4e07ce27-1d3e-4f51-8eb4-862e08dddfd5’: ‘4e07ce27-1d3e-4f51-8eb4-862e08dddfd5’ has type <type ‘str’>, but expected one of: (<type ‘int’>, <type ‘long’>)

Your Chirpstack instance is v4, but the Python API you’re trying to use is v3 (which previously used integer application IDs). Take a look here:

https://www.chirpstack.io/docs/chirpstack/api/python-examples.html

I used the same example as https://www.chirpstack.io/docs/chirpstack/api/python-examples.html with a function for device creation.

Do you have an example for the function that I am looking for (create a device using Python API v4) ?

@Reine_ABOU_SLEIMAN Reine did you get this to work?

Here is my Python script to import form Excel .xlsx file
Updated to add Tags which need to be in JSON format {“foo”:“Bar”}

################################################################################################################################
#  V0.1 - Added support for tags which need to be JSON strin
#  Python script to import Devices to an CS v4 Application from Excel .xlsx file
#  requires uuid of application/device profile you can get from UI/Console
#  E.g. application id: FFFFFF-b8bf-47c3-bcb1-686bc2fcAAA & device profile id:   
#  
#  I can't find away to test if device entery exsists via get grpc.StatusCode.ALREADY_EXISTS: 
#  but grpc.StatusCode.INTERNAL: fires if Device exsists so that will have to surfice
#  Applogies to any Pro Devloper this was put together by a scrippter!!
#
#  Excel cols:
#  dev_eui | application_id | device_profile_id | name | description | network_key | application_key | is_disabled | tags
#  tag example: {"loc":"ii@St_Albans@GF@Study","device_details":"manf_Elsys,model_EMS,sn_174747,hw:_v1.1,fw:_v3","notes":" ..."}
################################################################################################################################
import openpyxl
import json
from   chirpstack_api import api
import grpc

class DeviceImportRecord:
    def __init__(self, dev_eui, application_id, device_profile_id, name, description, network_key, application_key,is_disabled,tags):
        self.DevEUI          = dev_eui
        self.ApplicationID   = application_id
        self.DeviceProfileID = device_profile_id
        self.Name            = name
        self.Description     = description
        self.NetworkKey      = network_key
        self.ApplicationKey  = application_key
        self.is_disabled     = is_disabled
        self.tags            = tags

def get_device_import_list(file: str) -> list[DeviceImportRecord]:
    out = []
    try:
        wb = openpyxl.load_workbook(file)
    except Exception as e:
        print("open excel file error",e)
        return []

    sheet = wb.active
    rw_no = 0   
    rows = sheet.iter_rows(min_row=1,max_row=sheet.max_row)
    for a,b,c,d,e,f,g,h,i in rows:
        if rw_no > 0:
            print('importing rw:',rw_no,':',a.value,b.value,c.value,d.value,e.value,f.value,g.value,h.value,i.value)
            out.append(DeviceImportRecord(a.value,b.value,c.value,d.value,e.value,f.value,g.value,h.value,i.value))
        rw_no += 1
    
    return out

def import_devices(devices):
    server  = "localhost:8080"
    api_token = "your API token"

    channel = grpc.insecure_channel(server)
    client  = api.DeviceServiceStub(channel)
    auth_token = [("authorization", "Bearer %s" % api_token)]
    
    try:
        req = api.CreateDeviceRequest()
        for dev in devices:
            print('creating Device with DevEUI:',dev.DevEUI)
            req.device.dev_eui           = str(dev.DevEUI)
            req.device.name              = str(dev.Name)
            req.device.description       = str(dev.Description)
            req.device.application_id    = str(dev.ApplicationID)
            req.device.device_profile_id = str(dev.DeviceProfileID)
            req.device.is_disabled       = dev.is_disabled                     
            req.device.tags.update(json.loads(dev.tags))
            resp = client.Create(req, metadata=auth_token)
    except grpc.RpcError as e:
        #print('error:',type(e))
        if e.code() == grpc.StatusCode.INTERNAL:
            print('import error device',dev.DevEUI,' import aborted! Check Device my already exsist.')
    try:
        req = api.CreateDeviceKeysRequest()
        for dev in devices:
            print('creating keys for device DevEUI:',dev.DevEUI)
            req.device_keys.dev_eui = str(dev.DevEUI)
            req.device_keys.nwk_key = str(dev.NetworkKey)
            req.device_keys.app_key = str(dev.ApplicationKey)
            resp = client.CreateKeys(req, metadata=auth_token)
    except  grpc.RpcError as e:
        print('error:',type(e))

    return None

if __name__ == "__main__":
    dev_list = get_device_import_list('/your path to/device_import.xlsx')
    import_devices(dev_list)

Excel file

1 Like

@iiLaw - Thank you for providing the example. I have a question - where are you getting the network_key that is populated in the import spreadsheet? The application_id and device_profile_id you can get from the chirpstack UI once they are created. The devices I am using come with devUI, appEUI and appKey. I don’t see where I can get the network_key to add to the spreadsheet to create a set of devices.

Thank you

Follow-up: I have checked the vendor documentation and I do not see a network key provided. I will contact the vendor for that. Is the nwk_key the same as the session network key? Does that value differ for each device?

I have tried the call without the network_key and receive the following:

error: <class 'grpc._channel._InactiveRpcError'>
<_InactiveRpcError of RPC that terminated with:
        status = StatusCode.INTERNAL
        details = "Invalid string length"
        debug_error_string = "UNKNOWN:Error received from peer  {grpc_message:"Invalid string length", grpc_status:13, created_time:"2023-08-21T12:56:09.069398-04:00"}"
>

I’m looking to add devices with javascript but do not find how to configure tags while creating the device.

Do you know how to do that?

Sorry no but you could try and take my script and use chatGPT to translate to JS.
I started that way by taking a GO example and used chatGPT to convert to python

BTW The issue bosavage was having is sorted by repeating application_key
in the network_key in Excel file if device isn’t LoRaWAN v1.1

This is how it is done in the ChirpStack UI (which is using the gRPC-web interface to make gRPC work in the browser, I expect this will be very similar to what you need):

nwk_key the same as the app session key,

the MAC version of profile must be 1.0.x