Register device The Things Stack v3 API

Trying to register a new device in my The Things Stack v3 community application. Created an API key with all the grants for the application.

When adding the device in the web console I see in network inspect adding a new device generates 4 POST. Creating the device looks like it is working but it does not add the AppKey, however I keep getting a “Forbidden path” for errors for the subsequent POSTs.

I have tried generating personal and applications API keys, but same result.

Am I going about this all wrong?

import requests
import json

app_name = "my_app_name"
app_key = "my_app_key"

dev_eui = "my_dev_eui"
join_eui = "my_join_eui"
device_id = "my_device_id"

auth_token = "NNSXS.XXXXXXXXXXX......."

headers = {
    "Authorization" : f"Bearer {auth_token}",
    "Accept" : "application/json",
    }

en = {
        "end_device":{
            "ids":{
                "dev_eui" : f"{dev_eui}",
                "join_eui": f"{join_eui}",
                "device_id": f"{device_id}"
            },
            "network_server_address":"eu1.cloud.thethings.network",
            "application_server_address":"eu1.cloud.thethings.network",
            "join_server_address":"eu1.cloud.thethings.network"
        },
        "field_mask":{
            "paths":[
                "network_server_address",
                "application_server_address",
                "join_server_address"
            ]
        }
    }

to = {
        "end_device":{
            "frequency_plan_id":"EU_863_870_TTN",
            "lorawan_phy_version":"PHY_V1_0_3_REV_A",
            "multicast":False,
            "supports_join":True,
            "lorawan_version":"MAC_V1_0_3",
            "ids":{
                "dev_eui" : f"{dev_eui}",
                "join_eui": f"{join_eui}",
                "device_id": f"{device_id}"
            },
            "supports_class_c":False,
            "supports_class_b":False,
            "mac_settings":{
                "rx2_data_rate_index":0,
                "rx2_frequency":869525000
            }
        },
        "field_mask":{
            "paths":[
                "frequency_plan_id",
                "lorawan_phy_version",
                "multicast",
                "supports_join",
                "lorawan_version",
                "ids.dev_eui",
                "ids.join_eui",
                "ids.device_id",
                "supports_class_c",
                "supports_class_b",
                "mac_settings.rx2_data_rate_index",
                "mac_settings.rx2_frequency"
            ]
        }
}

tre = {
        "end_device":{
            "ids":{
                "dev_eui" : f"{dev_eui}",
                "join_eui": f"{join_eui}",
                "device_id": f"{device_id}"
            }
        },
        "field_mask":{
            "paths":[
                "ids.dev_eui",
                "ids.join_eui",
                "ids.device_id"
            ]
        }
}

fire = {
        "end_device":{
            "ids":{
                "dev_eui" : f"{dev_eui}",
                "join_eui": f"{join_eui}",
                "device_id": f"{device_id}"
            },
            "network_server_address":"eu1.cloud.thethings.network",
            "application_server_address":"eu1.cloud.thethings.network",
            "root_keys":{
                "app_key":{
                    "key" : f"{app_key}"
                }
            }
        },
        "field_mask":{
            "paths":[
                "network_server_address",
                "application_server_address",
                "ids.dev_eui",
                "ids.join_eui",
                "ids.device_id",
                "root_keys.app_key.key"
            ]
        }
    }

response = requests.post(f"https://eu1.cloud.thethings.network/api/v3/applications/{app_name}/devices", data=json.dumps(en), headers=headers)
print(response.text)
response = requests.put(f"https://eu1.cloud.thethings.network/api/v3/applications/{app_name}/devices/a84041000181d595", data=json.dumps(to), headers=headers)
print(response.text)
response = requests.put(f"https://eu1.cloud.thethings.network/api/v3/applications/{app_name}/devices/a84041000181d595", data=json.dumps(tre), headers=headers)
print(response.text)
response = requests.put(f"https://eu1.cloud.thethings.network/api/v3/applications/{app_name}/devices/a84041000181d595", data=json.dumps(fire), headers=headers)
print(response.text)

Yes, at two very fundamental levels :pleading_face:

  1. Call variables by what they are holding - 1, 2, 3, 4 just makes debugging stupidly hard and now you have to debug it, you have your hands full.
  2. Search the forum - this has been solved (by me & others) in Python & PHP already.

On the plus side, :+1: for looking at the console output to figure it out. You don’t need much in the way of a field_mask, that’s just a list of fields to be included in the response, much of which you already know.

Turns out endpoints where wrong, so remember to use the ["/ns/", “/as/”, “/js/”] in the url when registering the device with the different servers. Not using these gives you a "getting a “Forbidden path” for error in the responses.

import requests
import json

app_name = "my_app_name"
app_key = "my_app_key"

dev_eui = "my_dev_eui"
join_eui = "my_join_eui"
device_id = "my_device_id"

auth_token = "NNSXS.XXXXXXXX......"

headers = {
    "Accept" : "application/json",
    "Authorization" : f"Bearer {auth_token}",
    "Accept" : "application/json"
    }

create_device = {
   "end_device":{
      "name":"bbb_device_name",
      "description":"device-description",
      "ids":{
         "device_id":f"{device_id}",
         "dev_eui":f"{dev_eui}",
         "join_eui":f"{join_eui}",
         "application_ids":{
            "application_id":"{app_name}"
         }
      },
      "join_server_address":"eu1.cloud.thethings.network",
      "network_server_address":"eu1.cloud.thethings.network",
      "application_server_address":"eu1.cloud.thethings.network",
      "version_ids":{
         "brand_id":"dragino",
         "model_id":"lht65",
         "hardware_version":"_unknown_hw_version_",
         "firmware_version":"1.8",
         "band_id":"EU_863_870"
      }
   },
   "field_mask":{
      "paths":[
         "join_server_address",
         "network_server_address",
         "application_server_address",
         "version_ids.brand_id",
         "version_ids.model_id",
         "version_ids.hardware_version",
         "version_ids.firmware_version",
         "version_ids.band_id"
      ]
   }
}

register_name_server = {
   "end_device":{
      "supports_join":True,
      "lorawan_version":"MAC_V1_0_3",
      "ids":{
         "device_id":f"{device_id}",
         "dev_eui":f"{dev_eui}",
         "join_eui": f"{join_eui}",
         "application_ids":{
            "application_id": f"{app_name}"
         }
      },
      "frequency_plan_id":"EU_863_870_TTN",
      "version_ids":{
         "brand_id":"dragino",
         "model_id":"lht65",
         "hardware_version":"_unknown_hw_version_",
         "firmware_version":"1.8",
         "band_id":"EU_863_870"
      },
      "lorawan_phy_version":"PHY_V1_0_3_REV_A",
      "mac_settings":{
         "class_c_timeout":"60s",
         "supports_32_bit_f_cnt":True
      }
   },
   "field_mask":{
      "paths":[
         "supports_join",
         "lorawan_version",
         "ids.device_id",
         "ids.dev_eui",
         "ids.join_eui",
         "ids.application_ids.application_id",
         "frequency_plan_id",
         "version_ids.brand_id",
         "version_ids.model_id",
         "version_ids.hardware_version",
         "version_ids.firmware_version",
         "version_ids.band_id",
         "lorawan_phy_version",
         "mac_settings.class_c_timeout",
         "mac_settings.supports_32_bit_f_cnt"
      ]
   }
}

register_application_server = {
   "end_device":{
      "ids":{
         "device_id": f"{device_id}",
         "dev_eui": f"{dev_eui}",
         "join_eui": f"{join_eui}",
         "application_ids":{
            "application_id": f"{app_name}"
         }
      },
      "version_ids":{
         "brand_id":"dragino",
         "model_id":"lht65",
         "hardware_version":"_unknown_hw_version_",
         "firmware_version":"1.8",
         "band_id":"EU_863_870"
      },
      "formatters":{
         "up_formatter":"FORMATTER_REPOSITORY",
         "down_formatter":"FORMATTER_REPOSITORY"
      }
   },
   "field_mask":{
      "paths":[
         "ids.device_id",
         "ids.dev_eui",
         "ids.join_eui",
         "ids.application_ids.application_id",
         "version_ids.brand_id",
         "version_ids.model_id",
         "version_ids.hardware_version",
         "version_ids.firmware_version",
         "version_ids.band_id",
         "formatters.up_formatter",
         "formatters.down_formatter"
      ]
   }
}

register_join_server = {
   "end_device":{
      "ids":{
         "device_id": f"{device_id}",
         "dev_eui": f"{dev_eui}",
         "join_eui": f"{join_eui}",
         "application_ids":{
            "application_id": f"{app_name}"
         }
      },
      "network_server_address":"eu1.cloud.thethings.network",
      "application_server_address":"eu1.cloud.thethings.network",
      "root_keys":{
         "app_key":{
            "key": f"{app_key}"
         }
      }
   },
   "field_mask":{
      "paths":[
         "network_server_address",
         "application_server_address",
         "root_keys.app_key.key",
         "ids.device_id",
         "ids.dev_eui",
         "ids.join_eui",
         "ids.application_ids.application_id"
      ]
   }
}

response = requests.post(f"https://eu1.cloud.thethings.network/api/v3/applications/{app_name}/devices", data=json.dumps(create_device), headers=headers)
print("RESPONSE DEVICE CREATE")
print(response.text)

response = requests.put(f"https://eu1.cloud.thethings.network/api/v3/ns/applications/{app_name}/devices/{device_id}", data=json.dumps(register_name_server), headers=headers)
print("REGISTER NAME SERVER")
print(response.text)

response = requests.put(f"https://eu1.cloud.thethings.network/api/v3/as/applications/{app_name}/devices/{device_id}", data=json.dumps(register_application_server), headers=headers)
print("REGISTER APPLICATION SERVER")
print(response.text)

response = requests.put(f"https://eu1.cloud.thethings.network/api/v3/js/applications/{app_name}/devices/{device_id}", data=json.dumps(register_join_server), headers=headers)
print("REGISTER JOIN SERVER")
print(response.text)

1 Like