This commit is contained in:
ludruda 2020-04-29 13:17:04 +02:00
Родитель c6b9ce4582
Коммит acfbe660da
9 изменённых файлов: 126 добавлений и 89 удалений

2
.gitignore поставляемый
Просмотреть файл

@ -11,6 +11,6 @@ samples/
.vscode/
# publish
iotc.egg-info
azure_iotcentral_device_client.egg-info
build
dist

Просмотреть файл

@ -1 +1,2 @@
include src/iotc/baltimore.pem
include src/iotc/baltimore.pem
include assets/*

Просмотреть файл

@ -1,12 +1,15 @@
#!/bin/bash
shopt -s expand_aliases
source ~/.bashrc
rm -rf build/ dist/ src/azure/iotcentral/device/client/iotc_device.egg-info src/azure/iotcentral/device/client/_pycache_ src/azure/iotcentral/device/client/_init_.pyc
TEST=""
if [[ $1 == 'test' ]]; then
TEST="-r testpypi"
TEST="--repository testpypi"
fi
python2 setup.py sdist bdist_wheel
#python2 setup.py sdist bdist_wheel
python3 setup.py sdist bdist_wheel
twine upload dist/* $TEST
python3 -m twine upload $TEST dist/*

Просмотреть файл

@ -7,9 +7,12 @@ from azure.iotcentral.device.client import IoTCClient, IOTCConnectType, IOTCLogL
deviceId = "nuovodev"
scopeId = "0ne00052362"
key = '68p6zEjwVNB6L/Dz8Wkz4VhaTrYqkndPrB0uJbWr2Hc/AmB+Qxz/eJJ9MIhLZFJ6hC0RmHMgfaYBkNTq84OCNQ=='
deviceId = "<DEVICE_ID>"
scopeId = "<SCOPE_ID>"
key = '<DEVICE_OR_GROUP_KEY>'
# optional model Id for auto-provisioning
modelId= '<TEMPLATE_ID>'
def onProps(propName, propValue):
@ -25,12 +28,11 @@ def onCommands(command, ack):
# see iotc.Device documentation above for x509 argument sample
iotc = IoTCClient(deviceId, scopeId,
IOTCConnectType.IOTC_CONNECT_SYMM_KEY, key)
iotc.setModelId('c318d580-39fc-4aca-b995-843719821049/1.5.0')
iotc.setModelId(modelId)
iotc.setLogLevel(IOTCLogLevel.IOTC_LOGGING_ALL)
iotc.on(IOTCEvents.IOTC_PROPERTIES, onProps)
# iotc.on(IOTCEvents.IOTC_COMMAND, onCommands)
# iotc.setQosLevel(IOTQosLevel.IOTC_QOS_AT_MOST_ONCE)
def main():

Просмотреть файл

@ -1,16 +1,18 @@
import sys
sys.path.insert(0, 'src')
import time
import asyncio
from random import randint
from azure.iotcentral.device.client.aio import IoTCClient, IOTCConnectType, IOTCLogLevel, IOTCEvents
deviceId = "nuovodev"
scopeId = "0ne00052362"
key = '68p6zEjwVNB6L/Dz8Wkz4VhaTrYqkndPrB0uJbWr2Hc/AmB+Qxz/eJJ9MIhLZFJ6hC0RmHMgfaYBkNTq84OCNQ=='
deviceId = "<DEVICE_ID>"
scopeId = "<SCOPE_ID>"
key = '<DEVICE_OR_GROUP_KEY>'
# optional model Id for auto-provisioning
modelId= '<TEMPLATE_ID>'
async def onProps(propName, propValue):
@ -23,10 +25,10 @@ async def onCommands(command, ack):
await ack(command.name, 'Command received', command.request_id)
# see iotc.Device documentation above for x509 argument sample
# change connect type to reflect the used key (device or group)
iotc = IoTCClient(deviceId, scopeId,
IOTCConnectType.IOTC_CONNECT_SYMM_KEY, key)
iotc.setModelId('c318d580-39fc-4aca-b995-843719821049/1.5.0')
iotc.setModelId(modelId)
iotc.setLogLevel(IOTCLogLevel.IOTC_LOGGING_ALL)
iotc.on(IOTCEvents.IOTC_PROPERTIES, onProps)
iotc.on(IOTCEvents.IOTC_COMMAND, onCommands)
@ -42,7 +44,7 @@ async def main():
'accelerometerY': str(randint(20, 45)),
"accelerometerZ": str(randint(20, 45))
})
time.sleep(3)
await asyncio.sleep(3)
asyncio.run(main())

Просмотреть файл

@ -2,7 +2,7 @@ import setuptools
import sys
sys.path.insert(0, 'src')
from iotc import __version__, __name__
from azure.iotcentral.device.client import __version__, __name__
with open("README.md", "r") as fh:
long_description = fh.read()
@ -15,7 +15,7 @@ setuptools.setup(
description="Azure IoT Central device client for Python",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/lucadruda/azure-iotcentral-device-client",
url="https://github.com/lucadruda/iotc-python-device-client",
packages=setuptools.find_packages('src'),
package_dir={'': 'src'},
license="MIT",
@ -27,10 +27,8 @@ setuptools.setup(
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy'
'Programming Language :: Python :: 3.8',
],
include_package_data=True,
install_requires=["paho-mqtt", "httplib2"]
install_requires=["azure-iot-device"]
)

Просмотреть файл

@ -9,7 +9,7 @@ from azure.iot.device import ProvisioningDeviceClient
from azure.iot.device import Message, MethodResponse
from datetime import datetime
__version__ = "0.0.1-beta.2"
__version__ = "0.2.0-beta.3"
__name__ = "azure-iotcentral-device-client"
@ -57,11 +57,6 @@ class IOTCConnectType:
IOTC_CONNECT_DEVICE_KEY = 3
class IOTCProtocol:
IOTC_PROTOCOL_MQTT = 1
IOTC_PROTOCOL_AMQP = 2
IOTC_PROTOCOL_HTTP = 4
class IOTCLogLevel:
IOTC_LOGGING_DISABLED = 1
@ -116,7 +111,6 @@ class IoTCClient:
self._credType = credType
self._keyORCert = keyOrCert
self._modelId = None
self._protocol = IOTCProtocol.IOTC_PROTOCOL_MQTT
self._connected = False
self._events = {}
self._propThread = None
@ -138,12 +132,6 @@ class IoTCClient:
else:
return False
def setProtocol(self, protocol):
"""
Set the connection protocol to be used.
:param IOTCProtocol protocol: One protocol between MQTT, AMQP and HTTPS (default MQTT)
"""
self._protocol = protocol
def setGlobalEndpoint(self, endpoint):
"""

Просмотреть файл

@ -5,7 +5,7 @@ from azure.iot.device.aio import ProvisioningDeviceClient
from azure.iot.device import Message, MethodResponse
from datetime import datetime
__version__ = "0.0.1-beta.2"
__version__ = "0.2.0-beta.3"
__name__ = "azure-iotcentral-device-client"
@ -53,11 +53,6 @@ class IOTCConnectType:
IOTC_CONNECT_DEVICE_KEY = 3
class IOTCProtocol:
IOTC_PROTOCOL_MQTT = 1
IOTC_PROTOCOL_AMQP = 2
IOTC_PROTOCOL_HTTP = 4
class IOTCLogLevel:
IOTC_LOGGING_DISABLED = 1
@ -112,7 +107,6 @@ class IoTCClient:
self._credType = credType
self._keyORCert = keyOrCert
self._modelId = None
self._protocol = IOTCProtocol.IOTC_PROTOCOL_MQTT
self._connected = False
self._events = {}
# self._threads = None
@ -125,24 +119,44 @@ class IoTCClient:
self._logger = logger
def isConnected(self):
"""
Check if device is connected to IoTCentral
:returns: Connection state
:rtype: bool
"""
if self._connected:
return True
else:
return False
def setProtocol(self, protocol):
self._protocol = protocol
def setGlobalEndpoint(self, endpoint):
"""
Set the device provisioning endpoint.
:param str endpoint: Custom device provisioning endpoint. Default ('global.azure-devices-provisioning.net')
"""
self._globalEndpoint = endpoint
def setModelId(self, modelId):
"""
Set the model Id for the device to be associated
:param str modelId: Id for an existing model in the IoTCentral app
"""
self._modelId = modelId
def setLogLevel(self, logLevel):
"""
Set the logging level
:param IOTCLogLevel: Logging level. Available options are: ALL, API_ONLY, DISABLE
"""
self._logger.setLogLevel(logLevel)
def on(self, eventname, callback):
"""
Set a listener for a specific event
:param IOTCEvents eventname: Supported events: IOTC_PROPERTIES, IOTC_COMMANDS
:param function callback: Function executed when the specified event occurs
"""
self._events[eventname] = callback
return 0
@ -216,16 +230,31 @@ class IoTCClient:
callback()
async def sendProperty(self, payload, callback=None):
"""
Send a property message
:param dict payload: The properties payload. Can contain multiple properties in the form {'<propName>':{'value':'<propValue>'}}
:param function callback: Function executed after successfull dispatch
"""
self._logger.debug('Sending property {}'.format(json.dumps(payload)))
await self._deviceClient.patch_twin_reported_properties(payload)
if callback is not None:
callback()
async def sendTelemetry(self, payload, properties=None, callback=None):
"""
Send a telemetry message
: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.
:param function callback: Function executed after successfull dispatch
"""
self._logger.info('Sending telemetry message: {}'.format(payload))
await self._sendMessage(json.dumps(payload), properties, callback)
async def connect(self):
"""
Connects the device.
:raises exception: If connection fails
"""
if self._credType in (IOTCConnectType.IOTC_CONNECT_DEVICE_KEY, IOTCConnectType.IOTC_CONNECT_SYMM_KEY):
if self._credType == IOTCConnectType.IOTC_CONNECT_SYMM_KEY:
self._keyORCert = self._computeDerivedSymmetricKey(
@ -269,8 +298,7 @@ class IoTCClient:
# setup listeners
self._propThread = asyncio.create_task(self._onProperties())
await self._propThread
#self._cmdThread = asyncio.create_task(self._onCommands())
self._cmdThread = asyncio.create_task(self._onCommands())
# self._threads = await asyncio.gather(
# self._onProperties(),
# self._onCommands()

Просмотреть файл

@ -66,9 +66,7 @@ def async_return(result):
async def stopThreads(iotc):
iotc._propThread.cancel()
with suppress(asyncio.CancelledError):
return True
#iotc._cmdThread.cancel()
iotc._cmdThread.cancel()
@pytest.mark.asyncio
@ -91,7 +89,7 @@ async def test_deviceKeyGeneration(mocker):
iotc = init(mocker)
await iotc.connect()
assert iotc._keyORCert == deviceKey
stopThreads(iotc)
await stopThreads(iotc)
@pytest.mark.asyncio
@ -99,14 +97,33 @@ async def test_hubConnectionString(mocker):
iotc = init(mocker)
await iotc.connect()
assert iotc._hubCString == expectedHub
stopThreads(iotc)
await stopThreads(iotc)
@pytest.mark.asyncio
async def test_onproperties_before(mocker):
iotc = init(mocker)
async def onProps(propname,propvalue):
assert propname == 'prop1'
assert propvalue == 40
await stopThreads(iotc)
mocker.patch.object(iotc,'sendProperty',return_value=True)
iotc.on(IOTCEvents.IOTC_PROPERTIES,onProps)
await iotc.connect()
try:
await iotc._propThread
await iotc._cmdThread
except asyncio.CancelledError:
pass
@pytest.mark.asyncio
async def test_onproperties_after(mocker):
iotc = init(mocker)
async def onProps(propname,propvalue):
assert propname == 'prop1'
assert propvalue == 40
@ -114,64 +131,62 @@ async def test_onproperties_before(mocker):
return True
mocker.patch.object(iotc,'sendProperty',return_value=True)
iotc.on(IOTCEvents.IOTC_PROPERTIES,onProps)
await iotc.connect()
@pytest.mark.asyncio
async def test_onproperties_after(mocker):
mock_async=mock.Mock()
async def onProps(propname,propvalue):
return True
mock_async.return_value=await onProps('prop1',40)
iotc = init(mocker)
mocker.patch.object(iotc,'sendProperty',return_value=True)
asyncio.run(iotc.connect())
iotc.on(IOTCEvents.IOTC_PROPERTIES,onProps)
# give at least 10 seconds for the new listener to be recognized. assign the listener after connection is discouraged
time.sleep(11)
mock_async.assert_called_with('prop1',40)
stopThreads(iotc)
try:
await iotc._propThread
except asyncio.CancelledError:
pass
@pytest.mark.asyncio
async def test_onCommands_before(mocker):
onCmds=mock.Mock()
iotc = init(mocker)
def mockedAck():
print('Callback called')
async def onCmds(command,ack):
ret=ack()
assert ret=='mocked'
await stopThreads(iotc)
return True
iotc = init(mocker)
def mockedAck():
return 'mocked'
mocker.patch.object(iotc,'_cmdAck',mockedAck)
iotc.on(IOTCEvents.IOTC_COMMAND,onCmds)
asyncio.run(iotc.connect())
onCmds.assert_called_with(methodRequest,mockedAck)
stopThreads(iotc)
await iotc.connect()
try:
await iotc._cmdThread
except asyncio.CancelledError:
pass
@pytest.mark.asyncio
async def test_onCommands_after(mocker):
onCmds=mock.Mock()
iotc = init(mocker)
def mockedAck():
print('Callback called')
async def onCmds(command,ack):
ret=ack()
assert ret=='mocked'
await stopThreads(iotc)
return True
iotc = init(mocker)
def mockedAck():
return 'mocked'
mocker.patch.object(iotc,'_cmdAck',mockedAck)
asyncio.run(iotc.connect())
await iotc.connect()
iotc.on(IOTCEvents.IOTC_COMMAND,onCmds)
# give at least 10 seconds for the new listener to be recognized. assign the listener after connection is discouraged
time.sleep(11)
onCmds.assert_called_with(methodRequest,mockedAck)
stopThreads(iotc)
try:
await iotc._cmdThread
except asyncio.CancelledError:
pass