你可以依据 MQTT API参考文档 来开发设备固件中用于执行配置请求的功能。
如前所述,设备可以在注册过程中由服务器生成访问凭据或提供其自己的访问凭据。请参阅下面每个请求/响应和示例代码:
由服务端创建访问凭据
Parameter | Example value | 描述 |
---|---|---|
deviceName | DEVICE_NAME | ThingsBoard中的设备名称。 |
provisionDeviceKey | PUT_PROVISION_KEY_HERE | 设备批量化的键, 从已配置的设备配置文件中获取。 |
provisionDeviceSecret | PUT_PROVISION_SECRET_HERE | 设备批量化的密钥的值,从已配置的设备配置文件中获取。 |
请求参数示例:
{
"deviceName": "DEVICE_NAME",
"provisionDeviceKey": "PUT_PROVISION_KEY_HERE",
"provisionDeviceSecret": "PUT_PROVISION_SECRET_HERE"
}
响应示例:
{
"status":"SUCCESS",
"credentialsType":"ACCESS_TOKEN",
"credentialsValue":"sLzc0gDAZPkGMzFVTyUY"
}
示例脚本
为了与 ThingsBoard 通信,我们将使用 Paho MQTT 模块,因此我们应该安装它:
pip3 install paho-mqtt --user
下面提供了脚本源代码。您可以将其复制粘贴到文件中,例如:
device-provision-example.py
现在,按照以下步骤运行脚本。
您可以使用 python 3 启动脚本:
python3 device-provision-example.py
脚本源代码:
from paho.mqtt.client import Client
from json import dumps, loads
RESULT_CODES = {
1: "incorrect protocol version",
2: "invalid client identifier",
3: "server unavailable",
4: "bad username or password",
5: "not authorised",
}
def collect_required_data():
config = {}
print("\n\n", "="*80, sep="")
print(" "*10, "\033[1m\033[94mThingsBoard device provisioning with basic authorization example script.\033[0m", sep="")
print("="*80, "\n\n", sep="")
host = input("Please write your ThingsBoard \033[93mhost\033[0m or leave it blank to use default (cloud.thingsboard.io): ")
config["host"] = host if host else "cloud.thingsboard.io"
port = input("Please write your ThingsBoard \033[93mport\033[0m or leave it blank to use default (1883): ")
config["port"] = int(port) if port else 1883
config["provision_device_key"] = input("Please write \033[93mprovision device key\033[0m: ")
config["provision_device_secret"] = input("Please write \033[93mprovision device secret\033[0m: ")
device_name = input("Please write \033[93mdevice name\033[0m or leave it blank to generate: ")
if device_name:
config["device_name"] = device_name
print("\n", "="*80, "\n", sep="")
return config
class ProvisionClient(Client):
PROVISION_REQUEST_TOPIC = "/provision/request"
PROVISION_RESPONSE_TOPIC = "/provision/response"
def __init__(self, host, port, provision_request):
super().__init__()
self._host = host
self._port = port
self._username = "provision"
self.on_connect = self.__on_connect
self.on_message = self.__on_message
self.__provision_request = provision_request
def __on_connect(self, client, userdata, flags, rc): # Callback for connect
if rc == 0:
print("[Provisioning client] Connected to ThingsBoard ")
client.subscribe(self.PROVISION_RESPONSE_TOPIC) # Subscribe to provisioning response topic
provision_request = dumps(self.__provision_request)
print("[Provisioning client] Sending provisioning request %s" % provision_request)
client.publish(self.PROVISION_REQUEST_TOPIC, provision_request) # Publishing provisioning request topic
else:
print("[Provisioning client] Cannot connect to ThingsBoard!, result: %s" % RESULT_CODES[rc])
def __on_message(self, client, userdata, msg):
decoded_payload = msg.payload.decode("UTF-8")
print("[Provisioning client] Received data from ThingsBoard: %s" % decoded_payload)
decoded_message = loads(decoded_payload)
provision_device_status = decoded_message.get("status")
if provision_device_status == "SUCCESS":
self.__save_credentials(decoded_message["credentialsValue"])
else:
print("[Provisioning client] Provisioning was unsuccessful with status %s and message: %s" % (provision_device_status, decoded_message["errorMsg"]))
self.disconnect()
def provision(self):
print("[Provisioning client] Connecting to ThingsBoard (provisioning client)")
self.__clean_credentials()
self.connect(self._host, self._port, 60)
self.loop_forever()
def get_new_client(self):
client_credentials = self.__get_credentials()
new_client = None
if client_credentials:
new_client = Client()
new_client.username_pw_set(client_credentials)
print("[Provisioning client] Read credentials from file.")
else:
print("[Provisioning client] Cannot read credentials from file!")
return new_client
@staticmethod
def __get_credentials():
new_credentials = None
try:
with open("credentials", "r") as credentials_file:
new_credentials = credentials_file.read()
except Exception as e:
print(e)
return new_credentials
@staticmethod
def __save_credentials(credentials):
with open("credentials", "w") as credentials_file:
credentials_file.write(credentials)
@staticmethod
def __clean_credentials():
open("credentials", "w").close()
def on_tb_connected(client, userdata, flags, rc): # Callback for connect with received credentials
if rc == 0:
print("[ThingsBoard client] Connected to ThingsBoard with credentials: %s" % client._username.decode())
else:
print("[ThingsBoard client] Cannot connect to ThingsBoard!, result: %s" % RESULT_CODES[rc])
if __name__ == '__main__':
config = collect_required_data()
THINGSBOARD_HOST = config["host"] # ThingsBoard instance host
THINGSBOARD_PORT = config["port"] # ThingsBoard instance MQTT port
PROVISION_REQUEST = {"provisionDeviceKey": config["provision_device_key"], # Provision device key, replace this value with your value from device profile.
"provisionDeviceSecret": config["provision_device_secret"], # Provision device secret, replace this value with your value from device profile.
}
if config.get("device_name") is not None:
PROVISION_REQUEST["deviceName"] = config["device_name"]
provision_client = ProvisionClient(THINGSBOARD_HOST, THINGSBOARD_PORT, PROVISION_REQUEST)
provision_client.provision() # Request provisioned data
tb_client = provision_client.get_new_client() # Getting client with provisioned data
if tb_client:
tb_client.on_connect = on_tb_connected # Setting callback for connect
tb_client.connect(THINGSBOARD_HOST, THINGSBOARD_PORT, 60)
tb_client.loop_forever() # Starting infinity loop
else:
print("Client was not created!")
由设备提供访问令牌
Parameter | Example value | Description |
---|---|---|
deviceName | DEVICE_NAME | Thingsboard中的设备名称。 |
provisionDeviceKey | PUT_PROVISION_KEY_HERE | 设备批量化的键, 从已配置的设备配置文件中获取。 |
provisionDeviceSecret | PUT_PROVISION_SECRET_HERE | 设备批量化的密钥,从已配置的设备配置文件中获取。 |
credentialsType | ACCESS_TOKEN | 凭证类型参数。 |
token | DEVICE_ACCESS_TOKEN | 设备访问 Thingsboard 的令牌 |
请求参数示例:
{
"deviceName": "DEVICE_NAME",
"provisionDeviceKey": "PUT_PROVISION_KEY_HERE",
"provisionDeviceSecret": "PUT_PROVISION_SECRET_HERE",
"credentialsType": "ACCESS_TOKEN",
"token": "DEVICE_ACCESS_TOKEN"
}
响应示例:
{
"credentialsType":"ACCESS_TOKEN",
"credentialsValue":"DEVICE_ACCESS_TOKEN",
"status":"SUCCESS"
}
示例脚本
为了与 ThingsBoard 通信,我们将使用 Paho MQTT 模块,因此我们应该安装它:
pip3 install paho-mqtt --user
下面提供了脚本源代码。您可以将其复制粘贴到文件中,例如:
device-provision-example.py
现在,按照以下步骤运行脚本。
您可以使用 python 3 启动脚本:
python3 device-provision-example.py
脚本源代码:
from paho.mqtt.client import Client
from json import dumps, loads
RESULT_CODES = {
1: "incorrect protocol version",
2: "invalid client identifier",
3: "server unavailable",
4: "bad username or password",
5: "not authorised",
}
def collect_required_data():
config = {}
print("\n\n", "="*80, sep="")
print(" "*10, "\033[1m\033[94mThingsBoard device provisioning with access token authorization example script. MQTT API\033[0m", sep="")
print("="*80, "\n\n", sep="")
host = input("Please write your ThingsBoard \033[93mhost\033[0m or leave it blank to use default (cloud.thingsboard.io): ")
config["host"] = host if host else "cloud.thingsboard.io"
port = input("Please write your ThingsBoard \033[93mport\033[0m or leave it blank to use default (1883): ")
config["port"] = int(port) if port else 1883
config["provision_device_key"] = input("Please write \033[93mprovision device key\033[0m: ")
config["provision_device_secret"] = input("Please write \033[93mprovision device secret\033[0m: ")
config["token"] = input("Please write \033[93mdevice access token\033[0m: ")
device_name = input("Please write \033[93mdevice name\033[0m or leave it blank to generate: ")
if device_name:
config["device_name"] = device_name
print("\n", "="*80, "\n", sep="")
return config
class ProvisionClient(Client):
PROVISION_REQUEST_TOPIC = "/provision/request"
PROVISION_RESPONSE_TOPIC = "/provision/response"
def __init__(self, host, port, provision_request):
super().__init__()
self._host = host
self._port = port
self._username = "provision"
self.on_connect = self.__on_connect
self.on_message = self.__on_message
self.__provision_request = provision_request
def __on_connect(self, client, userdata, flags, rc): # Callback for connect
if rc == 0:
print("[Provisioning client] Connected to ThingsBoard ")
client.subscribe(self.PROVISION_RESPONSE_TOPIC) # Subscribe to provisioning response topic
provision_request = dumps(self.__provision_request)
print("[Provisioning client] Sending provisioning request %s" % provision_request)
client.publish(self.PROVISION_REQUEST_TOPIC, provision_request) # Publishing provisioning request topic
else:
print("[Provisioning client] Cannot connect to ThingsBoard!, result: %s" % RESULT_CODES[rc])
def __on_message(self, client, userdata, msg):
decoded_payload = msg.payload.decode("UTF-8")
print("[Provisioning client] Received data from ThingsBoard: %s" % decoded_payload)
decoded_message = loads(decoded_payload)
provision_device_status = decoded_message.get("status")
if provision_device_status == "SUCCESS":
self.__save_credentials(decoded_message["credentialsValue"])
else:
print("[Provisioning client] Provisioning was unsuccessful with status %s and message: %s" % (provision_device_status, decoded_message["errorMsg"]))
self.disconnect()
def provision(self):
print("[Provisioning client] Connecting to ThingsBoard (provisioning client)")
self.__clean_credentials()
self.connect(self._host, self._port, 60)
self.loop_forever()
def get_new_client(self):
client_credentials = self.__get_credentials()
new_client = None
if client_credentials:
new_client = Client()
new_client.username_pw_set(client_credentials)
print("[Provisioning client] Read credentials from file.")
else:
print("[Provisioning client] Cannot read credentials from file!")
return new_client
@staticmethod
def __get_credentials():
new_credentials = None
try:
with open("credentials", "r") as credentials_file:
new_credentials = credentials_file.read()
except Exception as e:
print(e)
return new_credentials
@staticmethod
def __save_credentials(credentials):
with open("credentials", "w") as credentials_file:
credentials_file.write(credentials)
@staticmethod
def __clean_credentials():
open("credentials", "w").close()
def on_tb_connected(client, userdata, flags, rc): # Callback for connect with received credentials
if rc == 0:
print("[ThingsBoard client] Connected to ThingsBoard with credentials: %s" % client._username.decode())
else:
print("[ThingsBoard client] Cannot connect to ThingsBoard!, result: %s" % RESULT_CODES[rc])
if __name__ == '__main__':
config = collect_required_data()
THINGSBOARD_HOST = config["host"] # ThingsBoard instance host
THINGSBOARD_PORT = config["port"] # ThingsBoard instance MQTT port
PROVISION_REQUEST = {"provisionDeviceKey": config["provision_device_key"], # Provision device key, replace this value with your value from device profile.
"provisionDeviceSecret": config["provision_device_secret"], # Provision device secret, replace this value with your value from device profile.
"credentialsType": "ACCESS_TOKEN",
"token": config["token"],
}
if config.get("device_name") is not None:
PROVISION_REQUEST["deviceName"] = config["device_name"]
provision_client = ProvisionClient(THINGSBOARD_HOST, THINGSBOARD_PORT, PROVISION_REQUEST)
provision_client.provision() # Request provisioned data
tb_client = provision_client.get_new_client() # Getting client with provisioned data
if tb_client:
tb_client.on_connect = on_tb_connected # Setting callback for connect
tb_client.connect(THINGSBOARD_HOST, THINGSBOARD_PORT, 60)
tb_client.loop_forever() # Starting infinity loop
else:
print("Client was not created!")
设备提供基本的 MQTT 凭证
Parameter | Example value | Description |
---|---|---|
deviceName | DEVICE_NAME | Thingsboard中的设备名称 |
provisionDeviceKey | PUT_PROVISION_KEY_HERE | 设备批量化的键, 从已配置的设备配置文件中获取。 |
provisionDeviceSecret | PUT_PROVISION_SECRET_HERE | 设备批量化的密钥,从已配置的设备配置文件中获取。 |
credentialsType | MQTT_BASIC | 凭证类型参数。 |
username | DEVICE_USERNAME_HERE | Thingsboard中设备的用户名。 |
password | DEVICE_PASSWORD_HERE | Thingsboard中设备的密码。 |
clientId | DEVICE_CLIENT_ID_HERE | Client id for device in ThingsBoard.设备在 Thingsboard 中的客户端 ID |
请求参数示例:
{
"deviceName": "DEVICE_NAME",
"provisionDeviceKey": "PUT_PROVISION_KEY_HERE",
"provisionDeviceSecret": "PUT_PROVISION_SECRET_HERE",
"credentialsType": "MQTT_BASIC",
"username": "DEVICE_USERNAME_HERE",
"password": "DEVICE_PASSWORD_HERE",
"clientId": "DEVICE_CLIENT_ID_HERE"
}
响应示例:
{
"credentialsType":"MQTT_BASIC",
"credentialsValue": {
"clientId":"DEVICE_CLIENT_ID_HERE",
"userName":"DEVICE_USERNAME_HERE",
"password":"DEVICE_PASSWORD_HERE"
},
"status":"SUCCESS"
}
示例脚本
为了与 ThingsBoard 通信,我们将使用 Paho MQTT 模块,因此我们应该安装它:
pip3 install paho-mqtt --user
下面提供了脚本源代码。您可以将其复制粘贴到文件中,例如:
device-provision-example.py
现在,按照以下步骤运行脚本。
您可以使用python 3启动脚本:
python3 device-provision-example.py
脚本源代码:
from paho.mqtt.client import Client
from json import dumps, loads
RESULT_CODES = {
1: "incorrect protocol version",
2: "invalid client identifier",
3: "server unavailable",
4: "bad username or password",
5: "not authorised",
}
def collect_required_data():
config = {}
print("\n\n", "="*80, sep="")
print(" "*10, "\033[1m\033[94mThingsBoard device provisioning with basic authorization example script.\033[0m", sep="")
print("="*80, "\n\n", sep="")
host = input("Please write your ThingsBoard \033[93mhost\033[0m or leave it blank to use default (cloud.thingsboard.io): ")
config["host"] = host if host else "cloud.thingsboard.io"
port = input("Please write your ThingsBoard \033[93mport\033[0m or leave it blank to use default (1883): ")
config["port"] = int(port) if port else 1883
config["provision_device_key"] = input("Please write \033[93mprovision device key\033[0m: ")
config["provision_device_secret"] = input("Please write \033[93mprovision device secret\033[0m: ")
device_name = input("Please write \033[93mdevice name\033[0m or leave it blank to generate: ")
if device_name:
config["device_name"] = device_name
config["clientId"] = input("Please write \033[93mclient Id\033[0m: ")
config["username"] = input("Please write \033[93musername\033[0m: ")
config["password"] = input("Please write \033[93mpassword\033[0m: ")
print("\n", "="*80, "\n", sep="")
return config
class ProvisionClient(Client):
PROVISION_REQUEST_TOPIC = "/provision/request"
PROVISION_RESPONSE_TOPIC = "/provision/response"
def __init__(self, host, port, provision_request):
super().__init__()
self._host = host
self._port = port
self._username = "provision"
self.on_connect = self.__on_connect
self.on_message = self.__on_message
self.__provision_request = provision_request
def __on_connect(self, client, userdata, flags, rc): # Callback for connect
if rc == 0:
print("[Provisioning client] Connected to ThingsBoard ")
client.subscribe(self.PROVISION_RESPONSE_TOPIC) # Subscribe to provisioning response topic
provision_request = dumps(self.__provision_request)
print("[Provisioning client] Sending provisioning request %s" % provision_request)
client.publish(self.PROVISION_REQUEST_TOPIC, provision_request) # Publishing provisioning request topic
else:
print("[Provisioning client] Cannot connect to ThingsBoard!, result: %s" % RESULT_CODES[rc])
def __on_message(self, client, userdata, msg):
decoded_payload = msg.payload.decode("UTF-8")
print("[Provisioning client] Received data from ThingsBoard: %s" % decoded_payload)
decoded_message = loads(decoded_payload)
provision_device_status = decoded_message.get("status")
if provision_device_status == "SUCCESS":
self.__save_credentials(decoded_message["credentialsValue"])
else:
print("[Provisioning client] Provisioning was unsuccessful with status %s and message: %s" % (provision_device_status, decoded_message["errorMsg"]))
self.disconnect()
def provision(self):
print("[Provisioning client] Connecting to ThingsBoard (provisioning client)")
self.__clean_credentials()
self.connect(self._host, self._port, 60)
self.loop_forever()
def get_new_client(self):
client_credentials = loads(self.__get_credentials())
new_client = None
if client_credentials:
new_client = Client(client_id=client_credentials["clientId"]) # Setting client id
new_client.username_pw_set(client_credentials["userName"], client_credentials["password"]) # Setting username and password for ThingsBoard client
print("[Provisioning client] Read credentials from file.")
else:
print("[Provisioning client] Cannot read credentials from file!")
return new_client
@staticmethod
def __get_credentials():
new_credentials = None
try:
with open("credentials", "r") as credentials_file:
new_credentials = credentials_file.read()
except Exception as e:
print(e)
return new_credentials
@staticmethod
def __save_credentials(credentials):
with open("credentials", "w") as credentials_file:
credentials_file.write(dumps(credentials))
@staticmethod
def __clean_credentials():
open("credentials", "w").close()
def on_tb_connected(client, userdata, flags, rc): # Callback for connect with received credentials
if rc == 0:
print("[ThingsBoard client] Connected to ThingsBoard with credentials: username: %s, password: %s, client id: %s" % (client._username.decode(), client._password.decode(), client._client_id.decode()))
else:
print("[ThingsBoard client] Cannot connect to ThingsBoard!, result: %s" % RESULT_CODES[rc])
if __name__ == '__main__':
config = collect_required_data()
THINGSBOARD_HOST = config["host"] # ThingsBoard instance host
THINGSBOARD_PORT = config["port"] # ThingsBoard instance MQTT port
PROVISION_REQUEST = {"provisionDeviceKey": config["provision_device_key"],
# Provision device key, replace this value with your value from device profile.
"provisionDeviceSecret": config["provision_device_secret"],
# Provision device secret, replace this value with your value from device profile.
"credentialsType": "MQTT_BASIC",
"username": config["username"],
"password": config["password"],
"clientId": config["clientId"],
}
if config.get("device_name") is not None:
PROVISION_REQUEST["deviceName"] = config["device_name"]
provision_client = ProvisionClient(THINGSBOARD_HOST, THINGSBOARD_PORT, PROVISION_REQUEST)
provision_client.provision() # Request provisioned data
tb_client = provision_client.get_new_client() # Getting client with provisioned data
if tb_client:
tb_client.on_connect = on_tb_connected # Setting callback for connect
tb_client.connect(THINGSBOARD_HOST, THINGSBOARD_PORT, 60)
tb_client.loop_forever() # Starting infinity loop
else:
print("Client was not created!")
设备提供X.509证书
:::info INFO: To use this feature, you should configure MQTT over SSL in ThingsBoard :::
Parameter | Example value | Description |
---|---|---|
deviceName | DEVICE_NAME | 设备在Thingsboard中的名称。 |
provisionDeviceKey | PUT_PROVISION_KEY_HERE | 设备批量化的键, 从已配置的设备配置文件中获取。 |
provisionDeviceSecret | PUT_PROVISION_SECRET_HERE | 设备批量化的密钥,从已配置的设备配置文件中获取。 |
credentialsType | X509_CERTIFICATE | 凭证类型参数。 |
hash | MIIB……..AQAB | 设备提供X.509证书 |
预配请求数据示例:
{
"deviceName": "DEVICE_NAME",
"provisionDeviceKey": "PUT_PROVISION_KEY_HERE",
"provisionDeviceSecret": "PUT_PROVISION_SECRET_HERE",
"credentialsType": "X509_CERTIFICATE",
"hash": "MIIB........AQAB"
}
预配响应示例:
{
"deviceId":"3b829220-232f-11eb-9d5c-e9ed3235dff8",
"credentialsType":"X509_CERTIFICATE",
"credentialsId":"f307a1f717a12b32c27203cf77728d305d29f64694a8311be921070dd1259b3a",
"credentialsValue":"MIIB........AQAB",
"provisionDeviceStatus":"SUCCESS"
}
MQTT示例脚本
要使用此脚本,请将 mqttserver.pub.pem
(服务器的公钥) 放入带有脚本的文件夹中。
import ssl
from datetime import datetime, timedelta
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from paho.mqtt.client import Client
from json import dumps, loads
RESULT_CODES = {
1: "incorrect protocol version",
2: "invalid client identifier",
3: "server unavailable",
4: "bad username or password",
5: "not authorised",
}
def collect_required_data():
config = {}
print("\n\n", "="*80, sep="")
print(" "*10, "\033[1m\033[94mThingsBoard device provisioning with X509 certificate authorization example script. MQTT API\033[0m", sep="")
print("="*80, "\n\n", sep="")
host = input("Please write your ThingsBoard \033[93mhost\033[0m or leave it blank to use default (cloud.thingsboard.io): ")
config["host"] = host if host else "cloud.thingsboard.io"
port = input("Please write your ThingsBoard \033[93mSSL port\033[0m or leave it blank to use default (8883): ")
config["port"] = int(port) if port else 8883
config["provision_device_key"] = input("Please write \033[93mprovision device key\033[0m: ")
config["provision_device_secret"] = input("Please write \033[93mprovision device secret\033[0m: ")
device_name = input("Please write \033[93mdevice name\033[0m or leave it blank to generate: ")
if device_name:
config["device_name"] = device_name
print("\n", "="*80, "\n", sep="")
return config
def generate_certs(ca_certfile="mqttserver.pub.pem"):
root_cert = None
try:
with open(ca_certfile, "r") as ca_file:
root_cert = x509.load_pem_x509_certificate(str.encode(ca_file.read()), default_backend())
except Exception as e:
print("Failed to load CA certificate: %r" % e)
if root_cert is not None:
private_key = rsa.generate_private_key(
public_exponent=65537, key_size=2048, backend=default_backend()
)
new_subject = x509.Name([
x509.NameAttribute(NameOID.COMMON_NAME, "localhost")
])
certificate = (
x509.CertificateBuilder()
.subject_name(new_subject)
.issuer_name(new_subject)
.public_key(private_key.public_key())
.serial_number(x509.random_serial_number())
.not_valid_before(datetime.utcnow())
.not_valid_after(datetime.utcnow() + timedelta(days=365*10))
.add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True)
.sign(private_key=private_key, algorithm=hashes.SHA256(), backend=default_backend())
)
with open("cert.pem", "wb") as cert_file:
cert_file.write(certificate.public_bytes(encoding=serialization.Encoding.PEM))
with open("key.pem", "wb") as key_file:
key_file.write(private_key.private_bytes(encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption(),
))
def read_cert():
cert = None
key = None
try:
with open("cert.pem", "r") as cert_file:
cert = cert_file.read()
with open("key.pem", "r") as key_file:
key = key_file.read()
except Exception as e:
print("Cannot read certificate with error: %r" % e)
return cert, key
class ProvisionClient(Client):
PROVISION_REQUEST_TOPIC = "/provision/request"
PROVISION_RESPONSE_TOPIC = "/provision/response"
def __init__(self, host, port, provision_request):
super().__init__()
self._host = host
self._port = port
self._username = "provision"
self.tls_set(ca_certs="mqttserver.pub.pem", tls_version=ssl.PROTOCOL_TLSv1_2)
self.on_connect = self.__on_connect
self.on_message = self.__on_message
self.__provision_request = provision_request
def __on_connect(self, client, userdata, flags, rc): # Callback for connect
if rc == 0:
print("[Provisioning client] Connected to ThingsBoard ")
client.subscribe(self.PROVISION_RESPONSE_TOPIC) # Subscribe to provisioning response topic
provision_request = dumps(self.__provision_request)
print("[Provisioning client] Sending provisioning request %s" % provision_request)
client.publish(self.PROVISION_REQUEST_TOPIC, provision_request) # Publishing provisioning request topic
else:
print("[Provisioning client] Cannot connect to ThingsBoard!, result: %s" % RESULT_CODES[rc])
def __on_message(self, client, userdata, msg):
decoded_payload = msg.payload.decode("UTF-8")
print("[Provisioning client] Received data from ThingsBoard: %s" % decoded_payload)
decoded_message = loads(decoded_payload)
provision_device_status = decoded_message.get("status")
if provision_device_status == "SUCCESS":
if decoded_message["credentialsValue"] == cert.replace("-----BEGIN CERTIFICATE-----\n", "")\
.replace("-----END CERTIFICATE-----\n", "")\
.replace("\n", ""):
print("[Provisioning client] Provisioning success! Certificates are saved.")
self.__save_credentials(cert)
else:
print("[Provisioning client] Returned certificate is not equal to sent one.")
else:
print("[Provisioning client] Provisioning was unsuccessful with status %s and message: %s" % (provision_device_status, decoded_message["errorMsg"]))
self.disconnect()
def provision(self):
print("[Provisioning client] Connecting to ThingsBoard (provisioning client)")
self.__clean_credentials()
self.connect(self._host, self._port, 60)
self.loop_forever()
def get_new_client(self):
client_credentials = self.__get_credentials()
new_client = None
if client_credentials:
new_client = Client()
new_client.tls_set(ca_certs="mqttserver.pub.pem", certfile="cert.pem", keyfile="key.pem", cert_reqs=ssl.CERT_REQUIRED,
tls_version=ssl.PROTOCOL_TLSv1_2, ciphers=None)
new_client.tls_insecure_set(False)
print("[Provisioning client] Read credentials from file.")
else:
print("[Provisioning client] Cannot read credentials from file!")
return new_client
@staticmethod
def __get_credentials():
new_credentials = None
try:
with open("credentials", "r") as credentials_file:
new_credentials = credentials_file.read()
except Exception as e:
print(e)
return new_credentials
@staticmethod
def __save_credentials(credentials):
with open("credentials", "w") as credentials_file:
credentials_file.write(credentials)
@staticmethod
def __clean_credentials():
open("credentials", "w").close()
def on_tb_connected(client, userdata, flags, rc): # Callback for connect with received credentials
if rc == 0:
print("[ThingsBoard client] Connected to ThingsBoard with credentials: username: %s, password: %s, client id: %s" % (client._username, client._password, client._client_id))
else:
print("[ThingsBoard client] Cannot connect to ThingsBoard!, result: %s" % RESULT_CODES[rc])
if __name__ == '__main__':
config = collect_required_data()
THINGSBOARD_HOST = config["host"] # ThingsBoard instance host
THINGSBOARD_PORT = config["port"] # ThingsBoard instance MQTT port
PROVISION_REQUEST = {"provisionDeviceKey": config["provision_device_key"], # Provision device key, replace this value with your value from device profile.
"provisionDeviceSecret": config["provision_device_secret"], # Provision device secret, replace this value with your value from device profile.
"credentialsType": "X509_CERTIFICATE",
}
if config.get("device_name") is not None:
PROVISION_REQUEST["deviceName"] = config["device_name"]
generate_certs() # Generate certificate and key
cert, key = read_cert() # Read certificate and key
PROVISION_REQUEST["hash"] = cert
if PROVISION_REQUEST.get("hash") is not None:
provision_client = ProvisionClient(THINGSBOARD_HOST, THINGSBOARD_PORT, PROVISION_REQUEST)
provision_client.provision() # Request provisioned data
tb_client = provision_client.get_new_client() # Getting client with provisioned data
if tb_client:
tb_client.on_connect = on_tb_connected # Setting callback for connect
tb_client.connect(THINGSBOARD_HOST, THINGSBOARD_PORT, 60)
tb_client.loop_forever() # Starting infinity loop
else:
print("Client was not created!")
else:
print("Cannot read certificate.")