components support
This commit is contained in:
Родитель
e6d8b8c87d
Коммит
78909f2945
|
@ -13,4 +13,10 @@ exp.py
|
|||
# publish
|
||||
*.egg-info
|
||||
build
|
||||
dist
|
||||
dist
|
||||
|
||||
# virtualenv
|
||||
Include/
|
||||
Lib/
|
||||
Scripts/
|
||||
pyvenv.cfg
|
|
@ -0,0 +1 @@
|
|||
azure-iot-device
|
|
@ -6,41 +6,42 @@ import sys
|
|||
from random import randint
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
config.read(os.path.join(os.path.dirname(__file__),'samples.ini'))
|
||||
config.read(os.path.join(os.path.dirname(__file__), "samples.ini"))
|
||||
|
||||
if config['DEFAULT'].getboolean('Local'):
|
||||
sys.path.insert(0, 'src')
|
||||
if config["DEFAULT"].getboolean("Local"):
|
||||
sys.path.insert(0, "src")
|
||||
|
||||
from iotc import IOTCConnectType, IOTCLogLevel, IOTCEvents
|
||||
from iotc.aio import IoTCClient
|
||||
|
||||
device_id = config['DEVICE_M3']['DeviceId']
|
||||
scope_id = config['DEVICE_M3']['ScopeId']
|
||||
key = config['DEVICE_M3']['DeviceKey']
|
||||
device_id = config["DEVICE_M3"]["DeviceId"]
|
||||
scope_id = config["DEVICE_M3"]["ScopeId"]
|
||||
key = config["DEVICE_M3"]["DeviceKey"]
|
||||
|
||||
# optional model Id for auto-provisioning
|
||||
try:
|
||||
model_id = config['DEVICE_M3']['ModelId']
|
||||
model_id = config["DEVICE_M3"]["ModelId"]
|
||||
except:
|
||||
model_id = None
|
||||
|
||||
|
||||
async def on_props(propName, propValue):
|
||||
print(propValue)
|
||||
async def on_props(property_name, property_value, component_name):
|
||||
print("Received {}:{}".format(property_name, property_value))
|
||||
return True
|
||||
|
||||
|
||||
async def on_commands(command, ack):
|
||||
print(command.name)
|
||||
await ack(command.name, 'Command received', command.request_id)
|
||||
await ack(command.name, "Command received", command.request_id)
|
||||
|
||||
async def on_enqueued_commands(command_name,command_data):
|
||||
|
||||
async def on_enqueued_commands(command_name, command_data):
|
||||
print(command_name)
|
||||
print(command_data)
|
||||
|
||||
|
||||
# change connect type to reflect the used key (device or group)
|
||||
client = IoTCClient(device_id, scope_id,
|
||||
IOTCConnectType.IOTC_CONNECT_SYMM_KEY, key)
|
||||
client = IoTCClient(device_id, scope_id, IOTCConnectType.IOTC_CONNECT_DEVICE_KEY, key)
|
||||
if model_id != None:
|
||||
client.set_model_id(model_id)
|
||||
|
||||
|
@ -54,13 +55,18 @@ client.on(IOTCEvents.IOTC_ENQUEUED_COMMAND, on_enqueued_commands)
|
|||
|
||||
async def main():
|
||||
await client.connect()
|
||||
await client.send_property({"writeableProp": 50})
|
||||
while client.is_connected():
|
||||
await client.send_telemetry({
|
||||
'accelerometerX': str(randint(20, 45)),
|
||||
'accelerometerY': str(randint(20, 45)),
|
||||
"accelerometerZ": str(randint(20, 45))
|
||||
})
|
||||
await client.send_telemetry(
|
||||
{
|
||||
"acceleration": {
|
||||
"x": str(randint(20, 45)),
|
||||
"y": str(randint(20, 45)),
|
||||
"z": str(randint(20, 45)),
|
||||
}
|
||||
}
|
||||
)
|
||||
await asyncio.sleep(3)
|
||||
|
||||
|
||||
|
||||
asyncio.run(main())
|
||||
|
|
2
setup.py
2
setup.py
|
@ -5,7 +5,7 @@ import sys
|
|||
with open("README.md", "r") as fh:
|
||||
long_description = fh.read()
|
||||
|
||||
version = "1.0.4"
|
||||
version = "1.0.5"
|
||||
|
||||
setuptools.setup(
|
||||
name='iotc',
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
|
@ -12,9 +11,11 @@ from datetime import datetime
|
|||
__version__ = pkg_resources.get_distribution("iotc").version
|
||||
if sys.version_info[0] < 3:
|
||||
import urllib
|
||||
|
||||
quote = urllib.quote_plus
|
||||
else:
|
||||
import urllib.parse
|
||||
|
||||
quote = urllib.parse.quote_plus
|
||||
|
||||
try:
|
||||
|
@ -48,7 +49,6 @@ except ImportError:
|
|||
sys.exit()
|
||||
|
||||
|
||||
|
||||
class IOTCConnectType:
|
||||
IOTC_CONNECT_SYMM_KEY = 1
|
||||
IOTC_CONNECT_X509_CERT = 2
|
||||
|
@ -78,8 +78,8 @@ class IOTCMessageStatus:
|
|||
|
||||
|
||||
class IOTCEvents:
|
||||
IOTC_COMMAND = 2,
|
||||
IOTC_PROPERTIES = 4,
|
||||
IOTC_COMMAND = (2,)
|
||||
IOTC_PROPERTIES = (4,)
|
||||
IOTC_ENQUEUED_COMMAND = 8
|
||||
|
||||
|
||||
|
@ -113,8 +113,8 @@ class AbstractClient:
|
|||
self._prop_thread = None
|
||||
self._cmd_thread = None
|
||||
self._enqueued_cmd_thread = None
|
||||
self._content_type='application%2Fjson'
|
||||
self._content_encoding='utf-8'
|
||||
self._content_type = "application%2Fjson"
|
||||
self._content_encoding = "utf-8"
|
||||
self._global_endpoint = "global.azure-devices-provisioning.net"
|
||||
|
||||
def is_connected(self):
|
||||
|
@ -124,7 +124,9 @@ class AbstractClient:
|
|||
:rtype: bool
|
||||
"""
|
||||
if not self._device_client:
|
||||
print("ERROR: A connection was never attempted. You need to first call connect() before querying the connection state")
|
||||
print(
|
||||
"ERROR: A connection was never attempted. You need to first call connect() before querying the connection state"
|
||||
)
|
||||
else:
|
||||
return self._device_client.connected
|
||||
|
||||
|
@ -149,14 +151,14 @@ class AbstractClient:
|
|||
"""
|
||||
self._logger.set_log_level(log_level)
|
||||
|
||||
def set_content_type(self,content_type):
|
||||
def set_content_type(self, content_type):
|
||||
self._content_type = quote(content_type)
|
||||
|
||||
def set_content_encoding(self,content_encoding):
|
||||
def set_content_encoding(self, content_encoding):
|
||||
self._content_encoding = content_encoding
|
||||
|
||||
def _prepare_message(self,payload,properties):
|
||||
msg = Message(payload,uuid.uuid4(),self._content_encoding,self._content_type)
|
||||
def _prepare_message(self, payload, properties):
|
||||
msg = Message(payload, uuid.uuid4(), self._content_encoding, self._content_type)
|
||||
if bool(properties):
|
||||
for prop in properties:
|
||||
msg.custom_properties[prop] = properties[prop]
|
||||
|
@ -171,99 +173,152 @@ class AbstractClient:
|
|||
self._events[eventname] = callback
|
||||
return 0
|
||||
|
||||
class IoTCClient(AbstractClient):
|
||||
|
||||
|
||||
class IoTCClient(AbstractClient):
|
||||
def __init__(self, device_id, scope_id, cred_type, key_or_cert, logger=None):
|
||||
AbstractClient.__init__(self,device_id, scope_id, cred_type, key_or_cert)
|
||||
AbstractClient.__init__(self, device_id, scope_id, cred_type, key_or_cert)
|
||||
if logger is None:
|
||||
self._logger = ConsoleLogger(IOTCLogLevel.IOTC_LOGGING_API_ONLY)
|
||||
else:
|
||||
if hasattr(logger, "info") and hasattr(logger, "debug") and hasattr(logger, "set_log_level"):
|
||||
if (
|
||||
hasattr(logger, "info")
|
||||
and hasattr(logger, "debug")
|
||||
and hasattr(logger, "set_log_level")
|
||||
):
|
||||
self._logger = logger
|
||||
else:
|
||||
print("ERROR: Logger object has unsupported format. It must implement the following functions\n\
|
||||
info(message);\ndebug(message);\nset_log_level(message);")
|
||||
print(
|
||||
"ERROR: Logger object has unsupported format. It must implement the following functions\n\
|
||||
info(message);\ndebug(message);\nset_log_level(message);"
|
||||
)
|
||||
sys.exit()
|
||||
|
||||
|
||||
def _handle_property_ack(
|
||||
self,
|
||||
callback,
|
||||
property_name,
|
||||
property_value,
|
||||
property_version,
|
||||
component_name=None,
|
||||
):
|
||||
ret = callback(property_name, property_value, component_name)
|
||||
if ret:
|
||||
if component_name is not None:
|
||||
self._logger.debug("Acknowledging {}".format(property_name))
|
||||
self.send_property(
|
||||
{
|
||||
"{}".format(component_name): {
|
||||
"{}".format(property_name): {
|
||||
"ac": 200,
|
||||
"ad": "Property received",
|
||||
"av": property_version,
|
||||
"value": property_value,
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
else:
|
||||
self._logger.debug("Acknowledging {}".format(property_name))
|
||||
self.send_property(
|
||||
{
|
||||
"{}".format(property_name): {
|
||||
"ac": 200,
|
||||
"ad": "Property received",
|
||||
"av": property_version,
|
||||
"value": property_value,
|
||||
}
|
||||
}
|
||||
)
|
||||
else:
|
||||
self._logger.debug('Property "{}" unsuccessfully processed'.format(property_name))
|
||||
|
||||
def _on_properties(self):
|
||||
self._logger.debug('Setup properties listener')
|
||||
self._logger.debug("Setup properties listener")
|
||||
while True:
|
||||
try:
|
||||
prop_cb = self._events[IOTCEvents.IOTC_PROPERTIES]
|
||||
except KeyError:
|
||||
self._logger.debug('Properties callback not found')
|
||||
self._logger.debug("Properties callback not found")
|
||||
time.sleep(10)
|
||||
continue
|
||||
|
||||
patch = self._device_client.receive_twin_desired_properties_patch()
|
||||
self._logger.debug(
|
||||
'\nReceived desired properties. {}\n'.format(patch))
|
||||
self._logger.debug("\nReceived desired properties. {}\n".format(patch))
|
||||
|
||||
for prop in patch:
|
||||
if prop == '$version':
|
||||
is_component = False
|
||||
if prop == "$version":
|
||||
continue
|
||||
|
||||
ret = prop_cb(prop, patch[prop]['value'])
|
||||
if ret:
|
||||
self._logger.debug('Acknowledging {}'.format(prop))
|
||||
self.send_property({
|
||||
'{}'.format(prop): {
|
||||
"ac": 200,
|
||||
"ad": 'Property received',
|
||||
"av": patch['$version'],
|
||||
"value": patch[prop]["value"]
|
||||
}
|
||||
})
|
||||
# check if component
|
||||
try:
|
||||
is_component = patch[prop]["__t"]
|
||||
del patch[prop]["__t"]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if is_component:
|
||||
for component_prop in patch[prop]:
|
||||
self._logger.debug(
|
||||
'In component "{}" for property "{}"'.format(
|
||||
prop, component_prop
|
||||
)
|
||||
)
|
||||
self._handle_property_ack(
|
||||
prop_cb,
|
||||
component_prop,
|
||||
patch[prop][component_prop]["value"],
|
||||
patch["$version"],
|
||||
prop,
|
||||
)
|
||||
else:
|
||||
self._logger.debug(
|
||||
'Property "{}" unsuccessfully processed'.format(prop))
|
||||
self._handle_property_ack(
|
||||
prop_cb, prop, patch[prop]["value"], patch["$version"]
|
||||
)
|
||||
|
||||
def _cmd_ack(self, name, value, request_id):
|
||||
self.send_property({
|
||||
'{}'.format(name): {
|
||||
'value': value,
|
||||
'requestId': request_id
|
||||
}
|
||||
})
|
||||
self.send_property(
|
||||
{"{}".format(name): {"value": value, "requestId": request_id}}
|
||||
)
|
||||
|
||||
def _on_commands(self):
|
||||
self._logger.debug('Setup commands listener')
|
||||
self._logger.debug("Setup commands listener")
|
||||
while True:
|
||||
try:
|
||||
cmd_cb = self._events[IOTCEvents.IOTC_COMMAND]
|
||||
except KeyError:
|
||||
self._logger.debug('Commands callback not found')
|
||||
self._logger.debug("Commands callback not found")
|
||||
time.sleep(10)
|
||||
continue
|
||||
# Wait for unknown method calls
|
||||
method_request = self._device_client.receive_method_request()
|
||||
self._logger.debug(
|
||||
'Received command {}'.format(method_request.name))
|
||||
self._device_client.send_method_response(MethodResponse.create_from_method_request(
|
||||
method_request, 200, {
|
||||
'result': True, 'data': 'Command received'}
|
||||
))
|
||||
self._logger.debug("Received command {}".format(method_request.name))
|
||||
self._device_client.send_method_response(
|
||||
MethodResponse.create_from_method_request(
|
||||
method_request, 200, {"result": True, "data": "Command received"}
|
||||
)
|
||||
)
|
||||
cmd_cb(method_request, self._cmd_ack)
|
||||
|
||||
def _on_enqueued_commands(self):
|
||||
self._logger.debug('Setup enqueued commands listener')
|
||||
self._logger.debug("Setup enqueued commands listener")
|
||||
while True:
|
||||
try:
|
||||
enqueued_cmd_cb = self._events[IOTCEvents.IOTC_ENQUEUED_COMMAND]
|
||||
except KeyError:
|
||||
self._logger.debug('Enqueued commands callback not found')
|
||||
self._logger.debug("Enqueued commands callback not found")
|
||||
time.sleep(10)
|
||||
continue
|
||||
# Wait for unknown method calls
|
||||
c2d = self._device_client.receive_message()
|
||||
c2d_name=c2d.custom_properties['method-name'].split(':')[1]
|
||||
self._logger.debug(
|
||||
'Received enqueued command {}'.format(c2d_name))
|
||||
enqueued_cmd_cb(c2d_name,c2d.data)
|
||||
c2d_name = c2d.custom_properties["method-name"].split(":")[1]
|
||||
self._logger.debug("Received enqueued command {}".format(c2d_name))
|
||||
enqueued_cmd_cb(c2d_name, c2d.data)
|
||||
|
||||
def _send_message(self, payload, properties):
|
||||
msg = self._prepare_message(payload,properties)
|
||||
msg = self._prepare_message(payload, properties)
|
||||
self._device_client.send_message(msg)
|
||||
|
||||
def send_property(self, payload):
|
||||
|
@ -271,7 +326,7 @@ class IoTCClient(AbstractClient):
|
|||
Send a property message
|
||||
:param dict payload: The properties payload. Can contain multiple properties in the form {'<propName>':{'value':'<propValue>'}}
|
||||
"""
|
||||
self._logger.debug('Sending property {}'.format(json.dumps(payload)))
|
||||
self._logger.debug("Sending property {}".format(json.dumps(payload)))
|
||||
self._device_client.patch_twin_reported_properties(payload)
|
||||
|
||||
def send_telemetry(self, payload, properties=None):
|
||||
|
@ -280,7 +335,7 @@ class IoTCClient(AbstractClient):
|
|||
:param dict payload: The telemetry payload. Can contain multiple telemetry fields in the form {'<fieldName1>':<fieldValue1>,...,'<fieldNameN>':<fieldValueN>}
|
||||
:param dict optional properties: An object with custom properties to add to the message.
|
||||
"""
|
||||
self._logger.info('Sending telemetry message: {}'.format(payload))
|
||||
self._logger.info("Sending telemetry message: {}".format(payload))
|
||||
self._send_message(json.dumps(payload), properties)
|
||||
|
||||
def connect(self):
|
||||
|
@ -288,58 +343,84 @@ class IoTCClient(AbstractClient):
|
|||
Connects the device.
|
||||
:raises exception: If connection fails
|
||||
"""
|
||||
if self._cred_type in (IOTCConnectType.IOTC_CONNECT_DEVICE_KEY, IOTCConnectType.IOTC_CONNECT_SYMM_KEY):
|
||||
if self._cred_type in (
|
||||
IOTCConnectType.IOTC_CONNECT_DEVICE_KEY,
|
||||
IOTCConnectType.IOTC_CONNECT_SYMM_KEY,
|
||||
):
|
||||
if self._cred_type == IOTCConnectType.IOTC_CONNECT_SYMM_KEY:
|
||||
self._key_or_cert = self._compute_derived_symmetric_key(
|
||||
self._key_or_cert, self._device_id)
|
||||
self._logger.debug('Device key: {}'.format(self._key_or_cert))
|
||||
self._key_or_cert, self._device_id
|
||||
)
|
||||
self._logger.debug("Device key: {}".format(self._key_or_cert))
|
||||
|
||||
self._provisioning_client = ProvisioningDeviceClient.create_from_symmetric_key(
|
||||
self._global_endpoint, self._device_id, self._scope_id, self._key_or_cert)
|
||||
self._provisioning_client = (
|
||||
ProvisioningDeviceClient.create_from_symmetric_key(
|
||||
self._global_endpoint,
|
||||
self._device_id,
|
||||
self._scope_id,
|
||||
self._key_or_cert,
|
||||
)
|
||||
)
|
||||
else:
|
||||
self._key_file = self._key_or_cert['key_file']
|
||||
self._cert_file = self._key_or_cert['cert_file']
|
||||
self._key_file = self._key_or_cert["key_file"]
|
||||
self._cert_file = self._key_or_cert["cert_file"]
|
||||
try:
|
||||
self._cert_phrase = self._key_or_cert['cert_phrase']
|
||||
self._cert_phrase = self._key_or_cert["cert_phrase"]
|
||||
x509 = X509(self._cert_file, self._key_file, self._cert_phrase)
|
||||
except:
|
||||
self._logger.debug(
|
||||
'No passphrase available for certificate. Trying without it')
|
||||
"No passphrase available for certificate. Trying without it"
|
||||
)
|
||||
x509 = X509(self._cert_file, self._key_file)
|
||||
# Certificate provisioning
|
||||
self._provisioning_client = ProvisioningDeviceClient.create_from_x509_certificate(
|
||||
provisioning_host=self._global_endpoint, registration_id=self._device_id, id_scope=self._scope_id, x509=x509)
|
||||
self._provisioning_client = (
|
||||
ProvisioningDeviceClient.create_from_x509_certificate(
|
||||
provisioning_host=self._global_endpoint,
|
||||
registration_id=self._device_id,
|
||||
id_scope=self._scope_id,
|
||||
x509=x509,
|
||||
)
|
||||
)
|
||||
|
||||
if self._model_id:
|
||||
self._provisioning_client.provisioning_payload = {
|
||||
'iotcModelId': self._model_id}
|
||||
"iotcModelId": self._model_id
|
||||
}
|
||||
try:
|
||||
registration_result = self._provisioning_client.register()
|
||||
assigned_hub = registration_result.registration_state.assigned_hub
|
||||
self._logger.debug(assigned_hub)
|
||||
self._hub_conn_string = 'HostName={};DeviceId={};SharedAccessKey={}'.format(
|
||||
assigned_hub, self._device_id, self._key_or_cert)
|
||||
self._hub_conn_string = "HostName={};DeviceId={};SharedAccessKey={}".format(
|
||||
assigned_hub, self._device_id, self._key_or_cert
|
||||
)
|
||||
self._logger.debug(
|
||||
'IoTHub Connection string: {}'.format(self._hub_conn_string))
|
||||
"IoTHub Connection string: {}".format(self._hub_conn_string)
|
||||
)
|
||||
|
||||
if self._cred_type in (IOTCConnectType.IOTC_CONNECT_DEVICE_KEY, IOTCConnectType.IOTC_CONNECT_SYMM_KEY):
|
||||
if self._cred_type in (
|
||||
IOTCConnectType.IOTC_CONNECT_DEVICE_KEY,
|
||||
IOTCConnectType.IOTC_CONNECT_SYMM_KEY,
|
||||
):
|
||||
self._device_client = IoTHubDeviceClient.create_from_connection_string(
|
||||
self._hub_conn_string)
|
||||
self._hub_conn_string
|
||||
)
|
||||
else:
|
||||
self._device_client = IoTHubDeviceClient.create_from_x509_certificate(
|
||||
x509=x509, hostname=assigned_hub, device_id=registration_result.registration_state.device_id)
|
||||
x509=x509,
|
||||
hostname=assigned_hub,
|
||||
device_id=registration_result.registration_state.device_id,
|
||||
)
|
||||
except:
|
||||
t, v, tb = sys.exc_info()
|
||||
self._logger.info(
|
||||
'ERROR: Failed to get device provisioning information')
|
||||
self._logger.info("ERROR: Failed to get device provisioning information")
|
||||
raise t(v)
|
||||
# Connect to iothub
|
||||
try:
|
||||
self._device_client.connect()
|
||||
self._logger.debug('Device connected')
|
||||
self._logger.debug("Device connected")
|
||||
except:
|
||||
t, v, tb = sys.exc_info()
|
||||
self._logger.info('ERROR: Failed to connect to Hub')
|
||||
self._logger.info("ERROR: Failed to connect to Hub")
|
||||
raise t(v)
|
||||
|
||||
# setup listeners
|
||||
|
@ -361,8 +442,11 @@ class IoTCClient(AbstractClient):
|
|||
try:
|
||||
secret = base64.b64decode(secret)
|
||||
except:
|
||||
self._logger.debug(
|
||||
"ERROR: broken base64 secret => `" + secret + "`")
|
||||
self._logger.debug("ERROR: broken base64 secret => `" + secret + "`")
|
||||
sys.exit()
|
||||
|
||||
return base64.b64encode(hmac.new(secret, msg=reg_id.encode('utf8'), digestmod=hashlib.sha256).digest()).decode('utf-8')
|
||||
return base64.b64encode(
|
||||
hmac.new(
|
||||
secret, msg=reg_id.encode("utf8"), digestmod=hashlib.sha256
|
||||
).digest()
|
||||
).decode("utf-8")
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import sys
|
||||
import asyncio
|
||||
import pkg_resources
|
||||
from .. import AbstractClient,IOTCLogLevel, IOTCEvents, IOTCConnectType
|
||||
from .. import AbstractClient, IOTCLogLevel, IOTCEvents, IOTCConnectType
|
||||
from azure.iot.device import X509, MethodResponse, Message
|
||||
from azure.iot.device.aio import IoTHubDeviceClient, ProvisioningDeviceClient
|
||||
|
||||
|
@ -58,98 +58,151 @@ class ConsoleLogger:
|
|||
|
||||
|
||||
class IoTCClient(AbstractClient):
|
||||
|
||||
def __init__(self, device_id, scope_id, cred_type, key_or_cert, logger=None):
|
||||
AbstractClient.__init__(self,device_id, scope_id, cred_type, key_or_cert)
|
||||
AbstractClient.__init__(self, device_id, scope_id, cred_type, key_or_cert)
|
||||
if logger is None:
|
||||
self._logger = ConsoleLogger(IOTCLogLevel.IOTC_LOGGING_API_ONLY)
|
||||
else:
|
||||
if hasattr(logger, "info") and hasattr(logger, "debug") and hasattr(logger, "set_log_level"):
|
||||
if (
|
||||
hasattr(logger, "info")
|
||||
and hasattr(logger, "debug")
|
||||
and hasattr(logger, "set_log_level")
|
||||
):
|
||||
self._logger = logger
|
||||
else:
|
||||
print("ERROR: Logger object has unsupported format. It must implement the following functions\n\
|
||||
info(message);\ndebug(message);\nset_log_level(message);")
|
||||
print(
|
||||
"ERROR: Logger object has unsupported format. It must implement the following functions\n\
|
||||
info(message);\ndebug(message);\nset_log_level(message);"
|
||||
)
|
||||
sys.exit()
|
||||
|
||||
async def _handle_property_ack(
|
||||
self,
|
||||
callback,
|
||||
property_name,
|
||||
property_value,
|
||||
property_version,
|
||||
component_name=None,
|
||||
):
|
||||
ret = await callback(property_name, property_value, component_name)
|
||||
if ret:
|
||||
if component_name is not None:
|
||||
await self._logger.debug("Acknowledging {}".format(property_name))
|
||||
await self.send_property(
|
||||
{
|
||||
"{}".format(component_name): {
|
||||
"{}".format(property_name): {
|
||||
"ac": 200,
|
||||
"ad": "Property received",
|
||||
"av": property_version,
|
||||
"value": property_value,
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
else:
|
||||
await self._logger.debug("Acknowledging {}".format(property_name))
|
||||
await self.send_property(
|
||||
{
|
||||
"{}".format(property_name): {
|
||||
"ac": 200,
|
||||
"ad": "Property received",
|
||||
"av": property_version,
|
||||
"value": property_value,
|
||||
}
|
||||
}
|
||||
)
|
||||
else:
|
||||
await self._logger.debug(
|
||||
'Property "{}" unsuccessfully processed'.format(property_name)
|
||||
)
|
||||
|
||||
async def _on_properties(self):
|
||||
await self._logger.debug('Setup properties listener')
|
||||
await self._logger.debug("Setup properties listener")
|
||||
while True:
|
||||
try:
|
||||
prop_cb = self._events[IOTCEvents.IOTC_PROPERTIES]
|
||||
except KeyError:
|
||||
await self._logger.debug('Properties callback not found')
|
||||
await self._logger.debug("Properties callback not found")
|
||||
await asyncio.sleep(10)
|
||||
continue
|
||||
patch = await self._device_client.receive_twin_desired_properties_patch()
|
||||
await self._logger.debug('Received desired properties. {}'.format(patch))
|
||||
await self._logger.debug("Received desired properties. {}".format(patch))
|
||||
|
||||
for prop in patch:
|
||||
if prop == '$version':
|
||||
is_component = False
|
||||
if prop == "$version":
|
||||
continue
|
||||
|
||||
ret = await prop_cb(prop, patch[prop]['value'])
|
||||
if ret:
|
||||
await self._logger.debug('Acknowledging {}'.format(prop))
|
||||
await self.send_property({
|
||||
'{}'.format(prop): {
|
||||
"ac": 200,
|
||||
"ad": 'Property received',
|
||||
"av": patch['$version'],
|
||||
"value": patch[prop]["value"]}
|
||||
})
|
||||
# check if component
|
||||
try:
|
||||
is_component = patch[prop]["__t"]
|
||||
del patch[prop]["__t"]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if is_component:
|
||||
for component_prop in patch[prop]:
|
||||
await self._logger.debug(
|
||||
'In component "{}" for property "{}"'.format(
|
||||
prop, component_prop
|
||||
)
|
||||
)
|
||||
await self._handle_property_ack(
|
||||
prop_cb,
|
||||
component_prop,
|
||||
patch[prop][component_prop]["value"],
|
||||
patch["$version"],
|
||||
prop,
|
||||
)
|
||||
else:
|
||||
await self._logger.debug(
|
||||
'Property "{}" unsuccessfully processed'.format(prop))
|
||||
await self._handle_property_ack(
|
||||
prop_cb, prop, patch[prop]["value"], patch["$version"]
|
||||
)
|
||||
|
||||
async def _cmd_ack(self, name, value, requestId):
|
||||
await self.send_property({
|
||||
'{}'.format(name): {
|
||||
'value': value,
|
||||
'requestId': requestId
|
||||
}
|
||||
})
|
||||
await self.send_property(
|
||||
{"{}".format(name): {"value": value, "requestId": requestId}}
|
||||
)
|
||||
|
||||
async def _on_commands(self):
|
||||
await self._logger.debug('Setup commands listener')
|
||||
await self._logger.debug("Setup commands listener")
|
||||
|
||||
while True:
|
||||
try:
|
||||
cmd_cb = self._events[IOTCEvents.IOTC_COMMAND]
|
||||
except KeyError:
|
||||
await self._logger.debug('Commands callback not found')
|
||||
await self._logger.debug("Commands callback not found")
|
||||
await asyncio.sleep(10)
|
||||
continue
|
||||
# Wait for unknown method calls
|
||||
method_request = (
|
||||
await self._device_client.receive_method_request()
|
||||
method_request = await self._device_client.receive_method_request()
|
||||
await self._logger.debug("Received command {}".format(method_request.name))
|
||||
await self._device_client.send_method_response(
|
||||
MethodResponse.create_from_method_request(
|
||||
method_request, 200, {"result": True, "data": "Command received"}
|
||||
)
|
||||
)
|
||||
await self._logger.debug(
|
||||
'Received command {}'.format(method_request.name))
|
||||
await self._device_client.send_method_response(MethodResponse.create_from_method_request(
|
||||
method_request, 200, {
|
||||
'result': True, 'data': 'Command received'}
|
||||
))
|
||||
await cmd_cb(method_request, self._cmd_ack)
|
||||
|
||||
async def _on_enqueued_commands(self):
|
||||
await self._logger.debug('Setup enqueued commands listener')
|
||||
await self._logger.debug("Setup enqueued commands listener")
|
||||
|
||||
while True:
|
||||
try:
|
||||
enqueued_cmd_cb = self._events[IOTCEvents.IOTC_ENQUEUED_COMMAND]
|
||||
except KeyError:
|
||||
await self._logger.debug('Enqueued commands callback not found')
|
||||
await self._logger.debug("Enqueued commands callback not found")
|
||||
await asyncio.sleep(10)
|
||||
continue
|
||||
# Wait for unknown method calls
|
||||
c2d = await self._device_client.receive_message()
|
||||
c2d_name=c2d.custom_properties['method-name'].split(':')[1]
|
||||
await self._logger.debug(
|
||||
'Received enqueued command {}'.format(c2d_name))
|
||||
await enqueued_cmd_cb(c2d_name,c2d.data)
|
||||
c2d_name = c2d.custom_properties["method-name"].split(":")[1]
|
||||
await self._logger.debug("Received enqueued command {}".format(c2d_name))
|
||||
await enqueued_cmd_cb(c2d_name, c2d.data)
|
||||
|
||||
async def _send_message(self, payload, properties):
|
||||
msg = self._prepare_message(payload,properties)
|
||||
msg = self._prepare_message(payload, properties)
|
||||
await self._device_client.send_message(msg)
|
||||
|
||||
async def send_property(self, payload):
|
||||
|
@ -157,7 +210,7 @@ class IoTCClient(AbstractClient):
|
|||
Send a property message
|
||||
:param dict payload: The properties payload. Can contain multiple properties in the form {'<propName>':{'value':'<propValue>'}}
|
||||
"""
|
||||
await self._logger.debug('Sending property {}'.format(json.dumps(payload)))
|
||||
await self._logger.debug("Sending property {}".format(json.dumps(payload)))
|
||||
await self._device_client.patch_twin_reported_properties(payload)
|
||||
|
||||
async def send_telemetry(self, payload, properties=None):
|
||||
|
@ -166,7 +219,7 @@ class IoTCClient(AbstractClient):
|
|||
:param dict payload: The telemetry payload. Can contain multiple telemetry fields in the form {'<fieldName1>':<fieldValue1>,...,'<fieldNameN>':<fieldValueN>}
|
||||
:param dict optional properties: An object with custom properties to add to the message.
|
||||
"""
|
||||
await self._logger.info('Sending telemetry message: {}'.format(payload))
|
||||
await self._logger.info("Sending telemetry message: {}".format(payload))
|
||||
await self._send_message(json.dumps(payload), properties)
|
||||
|
||||
async def connect(self):
|
||||
|
@ -174,58 +227,88 @@ class IoTCClient(AbstractClient):
|
|||
Connects the device.
|
||||
:raises exception: If connection fails
|
||||
"""
|
||||
if self._cred_type in (IOTCConnectType.IOTC_CONNECT_DEVICE_KEY, IOTCConnectType.IOTC_CONNECT_SYMM_KEY):
|
||||
if self._cred_type in (
|
||||
IOTCConnectType.IOTC_CONNECT_DEVICE_KEY,
|
||||
IOTCConnectType.IOTC_CONNECT_SYMM_KEY,
|
||||
):
|
||||
if self._cred_type == IOTCConnectType.IOTC_CONNECT_SYMM_KEY:
|
||||
self._key_or_cert = await self._compute_derived_symmetric_key(
|
||||
self._key_or_cert, self._device_id)
|
||||
self._key_or_cert, self._device_id
|
||||
)
|
||||
|
||||
await self._logger.debug('Device key: {}'.format(self._key_or_cert))
|
||||
await self._logger.debug("Device key: {}".format(self._key_or_cert))
|
||||
|
||||
self._provisioning_client = ProvisioningDeviceClient.create_from_symmetric_key(
|
||||
self._global_endpoint, self._device_id, self._scope_id, self._key_or_cert)
|
||||
self._provisioning_client = (
|
||||
ProvisioningDeviceClient.create_from_symmetric_key(
|
||||
self._global_endpoint,
|
||||
self._device_id,
|
||||
self._scope_id,
|
||||
self._key_or_cert,
|
||||
)
|
||||
)
|
||||
else:
|
||||
self._key_file = self._key_or_cert['key_file']
|
||||
self._cert_file = self._key_or_cert['cert_file']
|
||||
self._key_file = self._key_or_cert["key_file"]
|
||||
self._cert_file = self._key_or_cert["cert_file"]
|
||||
try:
|
||||
self._cert_phrase = self._key_or_cert['cert_phrase']
|
||||
self._cert_phrase = self._key_or_cert["cert_phrase"]
|
||||
x509 = X509(self._cert_file, self._key_file, self._cert_phrase)
|
||||
except:
|
||||
await self._logger.debug(
|
||||
'No passphrase available for certificate. Trying without it')
|
||||
"No passphrase available for certificate. Trying without it"
|
||||
)
|
||||
x509 = X509(self._cert_file, self._key_file)
|
||||
# Certificate provisioning
|
||||
self._provisioning_client = ProvisioningDeviceClient.create_from_x509_certificate(
|
||||
provisioning_host=self._global_endpoint, registration_id=self._device_id, id_scope=self._scope_id, x509=x509)
|
||||
self._provisioning_client = (
|
||||
ProvisioningDeviceClient.create_from_x509_certificate(
|
||||
provisioning_host=self._global_endpoint,
|
||||
registration_id=self._device_id,
|
||||
id_scope=self._scope_id,
|
||||
x509=x509,
|
||||
)
|
||||
)
|
||||
|
||||
if self._model_id:
|
||||
print("Provision model Id")
|
||||
self._provisioning_client.provisioning_payload = {
|
||||
'iotcModelId': self._model_id}
|
||||
"iotcModelId": self._model_id
|
||||
}
|
||||
try:
|
||||
registration_result = await self._provisioning_client.register()
|
||||
assigned_hub = registration_result.registration_state.assigned_hub
|
||||
await self._logger.debug(assigned_hub)
|
||||
self._hub_conn_string = 'HostName={};DeviceId={};SharedAccessKey={}'.format(
|
||||
assigned_hub, self._device_id, self._key_or_cert)
|
||||
self._hub_conn_string = "HostName={};DeviceId={};SharedAccessKey={}".format(
|
||||
assigned_hub, self._device_id, self._key_or_cert
|
||||
)
|
||||
await self._logger.debug(
|
||||
'IoTHub Connection string: {}'.format(self._hub_conn_string))
|
||||
"IoTHub Connection string: {}".format(self._hub_conn_string)
|
||||
)
|
||||
|
||||
if self._cred_type in (IOTCConnectType.IOTC_CONNECT_DEVICE_KEY, IOTCConnectType.IOTC_CONNECT_SYMM_KEY):
|
||||
if self._cred_type in (
|
||||
IOTCConnectType.IOTC_CONNECT_DEVICE_KEY,
|
||||
IOTCConnectType.IOTC_CONNECT_SYMM_KEY,
|
||||
):
|
||||
self._device_client = IoTHubDeviceClient.create_from_connection_string(
|
||||
self._hub_conn_string)
|
||||
self._hub_conn_string
|
||||
)
|
||||
else:
|
||||
self._device_client = IoTHubDeviceClient.create_from_x509_certificate(
|
||||
x509=x509, hostname=assigned_hub, device_id=registration_result.registration_state.device_id)
|
||||
x509=x509,
|
||||
hostname=assigned_hub,
|
||||
device_id=registration_result.registration_state.device_id,
|
||||
)
|
||||
except:
|
||||
await self._logger.info(
|
||||
'ERROR: Failed to get device provisioning information')
|
||||
"ERROR: Failed to get device provisioning information"
|
||||
)
|
||||
sys.exit()
|
||||
# Connect to iothub
|
||||
try:
|
||||
await self._device_client.connect()
|
||||
await self._logger.debug('Device connected')
|
||||
await self._logger.debug("Device connected")
|
||||
self._twin = await self._device_client.get_twin()
|
||||
await self._logger.debug("Current twin: {}".format(self._twin))
|
||||
except:
|
||||
await self._logger.info('ERROR: Failed to connect to Hub')
|
||||
await self._logger.info("ERROR: Failed to connect to Hub")
|
||||
sys.exit()
|
||||
|
||||
# setup listeners
|
||||
|
@ -243,8 +326,11 @@ class IoTCClient(AbstractClient):
|
|||
try:
|
||||
secret = base64.b64decode(secret)
|
||||
except:
|
||||
await self._logger.debug(
|
||||
"ERROR: broken base64 secret => `" + secret + "`")
|
||||
await self._logger.debug("ERROR: broken base64 secret => `" + secret + "`")
|
||||
sys.exit()
|
||||
|
||||
return base64.b64encode(hmac.new(secret, msg=reg_id.encode('utf8'), digestmod=hashlib.sha256).digest()).decode('utf-8')
|
||||
return base64.b64encode(
|
||||
hmac.new(
|
||||
secret, msg=reg_id.encode("utf8"), digestmod=hashlib.sha256
|
||||
).digest()
|
||||
).decode("utf-8")
|
||||
|
|
|
@ -103,6 +103,9 @@ class NewDeviceClient():
|
|||
def patch_twin_reported_properties(self, payload):
|
||||
return True
|
||||
|
||||
def get_twin(self):
|
||||
return 'Twin'
|
||||
|
||||
|
||||
def init(mocker):
|
||||
client = IoTCClient(device_id, scopeId,
|
||||
|
@ -139,7 +142,7 @@ def test_onproperties_before(mocker):
|
|||
mocker.patch.object(client, 'send_property', mock.Mock())
|
||||
client.on(IOTCEvents.IOTC_PROPERTIES, on_props)
|
||||
client.connect()
|
||||
on_props.assert_called_with('prop1', 40)
|
||||
on_props.assert_called_with('prop1', 40,None)
|
||||
|
||||
|
||||
def test_onproperties_after(mocker):
|
||||
|
@ -151,7 +154,7 @@ def test_onproperties_after(mocker):
|
|||
client.on(IOTCEvents.IOTC_PROPERTIES, on_props)
|
||||
# give at least 10 seconds for the new listener to be recognized. assign the listener after connection is discouraged
|
||||
time.sleep(11)
|
||||
on_props.assert_called_with('prop1', 40)
|
||||
on_props.assert_called_with('prop1', 40,None)
|
||||
|
||||
|
||||
def test_onCommands_before(mocker):
|
||||
|
|
|
@ -9,60 +9,61 @@ import sys
|
|||
from contextlib import suppress
|
||||
|
||||
from azure.iot.device.provisioning.models import RegistrationResult
|
||||
from azure.iot.device.iothub.models import MethodRequest,Message
|
||||
from azure.iot.device.iothub.models import MethodRequest, Message
|
||||
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
config.read(os.path.join(os.path.dirname(__file__), '../tests.ini'))
|
||||
config.read(os.path.join(os.path.dirname(__file__), "../tests.ini"))
|
||||
|
||||
if config['TESTS'].getboolean('Local'):
|
||||
sys.path.insert(0, 'src')
|
||||
if config["TESTS"].getboolean("Local"):
|
||||
sys.path.insert(0, "src")
|
||||
|
||||
from iotc import IOTCConnectType, IOTCLogLevel, IOTCEvents
|
||||
from iotc.aio import IoTCClient
|
||||
|
||||
try:
|
||||
groupKey = config['TESTS']['GroupKey']
|
||||
groupKey = config["TESTS"]["GroupKey"]
|
||||
except:
|
||||
groupKey='groupKey'
|
||||
groupKey = "groupKey"
|
||||
|
||||
try:
|
||||
deviceKey = config['TESTS']['DeviceKey']
|
||||
deviceKey = config["TESTS"]["DeviceKey"]
|
||||
except:
|
||||
deviceKey='kPufjjN/EMoyKcNiAXvlTz8H61mlhSnmvoF6dxhnysA='
|
||||
deviceKey = "kPufjjN/EMoyKcNiAXvlTz8H61mlhSnmvoF6dxhnysA="
|
||||
|
||||
try:
|
||||
device_id = config['TESTS']['DeviceId']
|
||||
device_id = config["TESTS"]["DeviceId"]
|
||||
except:
|
||||
device_id='device_id'
|
||||
device_id = "device_id"
|
||||
|
||||
try:
|
||||
scopeId = config['TESTS']['ScopeId']
|
||||
scopeId = config["TESTS"]["ScopeId"]
|
||||
except:
|
||||
scopeId='scopeId'
|
||||
scopeId = "scopeId"
|
||||
|
||||
try:
|
||||
assignedHub = config['TESTS']['AssignedHub']
|
||||
assignedHub = config["TESTS"]["AssignedHub"]
|
||||
except:
|
||||
assignedHub='assignedHub'
|
||||
assignedHub = "assignedHub"
|
||||
|
||||
try:
|
||||
expectedHub = config['TESTS']['ExpectedHub']
|
||||
expectedHub = config["TESTS"]["ExpectedHub"]
|
||||
except:
|
||||
expectedHub='HostName=assignedHub;DeviceId=device_id;SharedAccessKey=kPufjjN/EMoyKcNiAXvlTz8H61mlhSnmvoF6dxhnysA='
|
||||
expectedHub = "HostName=assignedHub;DeviceId=device_id;SharedAccessKey=kPufjjN/EMoyKcNiAXvlTz8H61mlhSnmvoF6dxhnysA="
|
||||
|
||||
propPayload = {'prop1': {'value': 40}, '$version': 5}
|
||||
propPayload = {"prop1": {"value": 40}, "$version": 5}
|
||||
|
||||
cmdRequestId = 'abcdef'
|
||||
cmdName = 'command1'
|
||||
cmdPayload = 'payload'
|
||||
cmdRequestId = "abcdef"
|
||||
cmdName = "command1"
|
||||
cmdPayload = "payload"
|
||||
methodRequest = MethodRequest(cmdRequestId, cmdName, cmdPayload)
|
||||
enqueued_method_name='test:enqueued'
|
||||
enqueued_method_name = "test:enqueued"
|
||||
|
||||
enqueued_message = Message('test_enqueued')
|
||||
enqueued_message.custom_properties['method-name']=enqueued_method_name
|
||||
enqueued_message = Message("test_enqueued")
|
||||
enqueued_message.custom_properties["method-name"] = enqueued_method_name
|
||||
|
||||
class NewRegState():
|
||||
|
||||
class NewRegState:
|
||||
def __init__(self):
|
||||
self.assigned_hub = assignedHub
|
||||
|
||||
|
@ -70,13 +71,13 @@ class NewRegState():
|
|||
return self.assigned_hub
|
||||
|
||||
|
||||
class NewProvClient():
|
||||
class NewProvClient:
|
||||
async def register(self):
|
||||
reg = RegistrationResult('3o375i827i852', 'assigned', NewRegState())
|
||||
reg = RegistrationResult("3o375i827i852", "assigned", NewRegState())
|
||||
return reg
|
||||
|
||||
|
||||
class NewDeviceClient():
|
||||
class NewDeviceClient:
|
||||
async def connect(self):
|
||||
return True
|
||||
|
||||
|
@ -98,6 +99,9 @@ class NewDeviceClient():
|
|||
async def patch_twin_reported_properties(self, payload):
|
||||
return True
|
||||
|
||||
async def get_twin(self):
|
||||
return "Twin"
|
||||
|
||||
|
||||
def async_return(result):
|
||||
f = asyncio.Future()
|
||||
|
@ -113,20 +117,24 @@ async def stop_threads(client):
|
|||
|
||||
@pytest.mark.asyncio
|
||||
def init(mocker):
|
||||
client = IoTCClient(device_id, scopeId,
|
||||
IOTCConnectType.IOTC_CONNECT_SYMM_KEY, groupKey)
|
||||
mocker.patch('iotc.aio.ProvisioningDeviceClient.create_from_symmetric_key',
|
||||
return_value=NewProvClient())
|
||||
mocker.patch('iotc.aio.IoTHubDeviceClient.create_from_connection_string',
|
||||
return_value=NewDeviceClient())
|
||||
client = IoTCClient(
|
||||
device_id, scopeId, IOTCConnectType.IOTC_CONNECT_SYMM_KEY, groupKey
|
||||
)
|
||||
mocker.patch(
|
||||
"iotc.aio.ProvisioningDeviceClient.create_from_symmetric_key",
|
||||
return_value=NewProvClient(),
|
||||
)
|
||||
mocker.patch(
|
||||
"iotc.aio.IoTHubDeviceClient.create_from_connection_string",
|
||||
return_value=NewDeviceClient(),
|
||||
)
|
||||
return client
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_computeKey(mocker):
|
||||
client = init(mocker)
|
||||
key = await client._compute_derived_symmetric_key(
|
||||
groupKey, device_id)
|
||||
key = await client._compute_derived_symmetric_key(groupKey, device_id)
|
||||
assert key == deviceKey
|
||||
|
||||
|
||||
|
@ -150,13 +158,14 @@ async def test_hubConnectionString(mocker):
|
|||
async def test_onproperties_before(mocker):
|
||||
client = init(mocker)
|
||||
|
||||
async def onProps(propname, propvalue):
|
||||
assert propname == 'prop1'
|
||||
async def on_props(propname, propvalue,component_name):
|
||||
assert propname == "prop1"
|
||||
assert propvalue == 40
|
||||
assert component_name == None
|
||||
await stop_threads(client)
|
||||
|
||||
mocker.patch.object(client, 'send_property', return_value=True)
|
||||
client.on(IOTCEvents.IOTC_PROPERTIES, onProps)
|
||||
mocker.patch.object(client, "send_property", return_value=True)
|
||||
client.on(IOTCEvents.IOTC_PROPERTIES, on_props)
|
||||
await client.connect()
|
||||
try:
|
||||
await client._prop_thread
|
||||
|
@ -169,15 +178,16 @@ async def test_onproperties_before(mocker):
|
|||
async def test_onproperties_after(mocker):
|
||||
client = init(mocker)
|
||||
|
||||
async def onProps(propname, propvalue):
|
||||
assert propname == 'prop1'
|
||||
async def on_props(propname, propvalue, component_name):
|
||||
assert propname == "prop1"
|
||||
assert propvalue == 40
|
||||
assert component_name == None
|
||||
await stop_threads(client)
|
||||
return True
|
||||
|
||||
mocker.patch.object(client, 'send_property', return_value=True)
|
||||
mocker.patch.object(client, "send_property", return_value=True)
|
||||
await client.connect()
|
||||
client.on(IOTCEvents.IOTC_PROPERTIES, onProps)
|
||||
client.on(IOTCEvents.IOTC_PROPERTIES, on_props)
|
||||
|
||||
try:
|
||||
await client._prop_thread
|
||||
|
@ -192,14 +202,14 @@ async def test_on_commands_before(mocker):
|
|||
|
||||
async def onCmds(command, ack):
|
||||
ret = ack()
|
||||
assert ret == 'mocked'
|
||||
assert ret == "mocked"
|
||||
await stop_threads(client)
|
||||
return True
|
||||
|
||||
def mockedAck():
|
||||
return 'mocked'
|
||||
return "mocked"
|
||||
|
||||
mocker.patch.object(client, '_cmd_ack', mockedAck)
|
||||
mocker.patch.object(client, "_cmd_ack", mockedAck)
|
||||
|
||||
client.on(IOTCEvents.IOTC_COMMAND, onCmds)
|
||||
await client.connect()
|
||||
|
@ -216,14 +226,14 @@ async def test_on_commands_after(mocker):
|
|||
|
||||
async def onCmds(command, ack):
|
||||
ret = ack()
|
||||
assert ret == 'mocked'
|
||||
assert ret == "mocked"
|
||||
await stop_threads(client)
|
||||
return True
|
||||
|
||||
def mockedAck():
|
||||
return 'mocked'
|
||||
return "mocked"
|
||||
|
||||
mocker.patch.object(client, '_cmd_ack', mockedAck)
|
||||
mocker.patch.object(client, "_cmd_ack", mockedAck)
|
||||
|
||||
await client.connect()
|
||||
client.on(IOTCEvents.IOTC_COMMAND, onCmds)
|
||||
|
@ -233,17 +243,17 @@ async def test_on_commands_after(mocker):
|
|||
except asyncio.CancelledError:
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_on_enqueued_commands_before(mocker):
|
||||
|
||||
client = init(mocker)
|
||||
|
||||
async def on_enqs(command_name,command_data):
|
||||
assert command_name == enqueued_method_name.split(':')[1]
|
||||
async def on_enqs(command_name, command_data):
|
||||
assert command_name == enqueued_method_name.split(":")[1]
|
||||
await stop_threads(client)
|
||||
return True
|
||||
|
||||
|
||||
client.on(IOTCEvents.IOTC_ENQUEUED_COMMAND, on_enqs)
|
||||
await client.connect()
|
||||
try:
|
||||
|
@ -257,12 +267,11 @@ async def test_on_enqueued_commands_after(mocker):
|
|||
|
||||
client = init(mocker)
|
||||
|
||||
async def on_enqs(command_name,command_data):
|
||||
assert command_name == enqueued_method_name.split(':')[1]
|
||||
async def on_enqs(command_name, command_data):
|
||||
assert command_name == enqueued_method_name.split(":")[1]
|
||||
await stop_threads(client)
|
||||
return True
|
||||
|
||||
|
||||
await client.connect()
|
||||
client.on(IOTCEvents.IOTC_ENQUEUED_COMMAND, on_enqs)
|
||||
try:
|
||||
|
|
Загрузка…
Ссылка в новой задаче