Skip to content

Commit 247bf2d

Browse files
authored
Merge pull request #109417 from JimacoMS3/python-upload-files-howto-v2-update
File upload how-to update for Python SDK V2
2 parents 1b0a18d + 91698f3 commit 247bf2d

File tree

6 files changed

+126
-56
lines changed

6 files changed

+126
-56
lines changed

articles/iot-hub/iot-hub-python-python-file-upload.md

Lines changed: 108 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ ms.service: iot-hub
66
services: iot-hub
77
ms.devlang: python
88
ms.topic: conceptual
9-
ms.date: 07/30/2019
9+
ms.date: 03/31/2020
1010
ms.author: robinsh
1111
---
1212

@@ -22,21 +22,15 @@ This article shows how to use the [file upload capabilities of IoT Hub](iot-hub-
2222

2323
The [Send telemetry from a device to an IoT hub](quickstart-send-telemetry-python.md) quickstart demonstrates the basic device-to-cloud messaging functionality of IoT Hub. However, in some scenarios you cannot easily map the data your devices send into the relatively small device-to-cloud messages that IoT Hub accepts. When you need to upland files from a device, you can still use the security and reliability of IoT Hub.
2424

25-
> [!NOTE]
26-
> IoT Hub Python SDK currently only supports uploading character-based files such as **.txt** files.
27-
28-
At the end of this tutorial you run the Python console app:
25+
At the end of this tutorial, you run the Python console app:
2926

3027
* **FileUpload.py**, which uploads a file to storage using the Python Device SDK.
3128

3229
[!INCLUDE [iot-hub-include-python-sdk-note](../../includes/iot-hub-include-python-sdk-note.md)]
3330

34-
> [!NOTE]
35-
> This guide uses the deprecated V1 Python SDK, as the File Upload feature has not yet been implemented in the new V2 SDK.
36-
3731
## Prerequisites
3832

39-
[!INCLUDE [iot-hub-include-python-installation-notes](../../includes/iot-hub-include-python-installation-notes.md)]
33+
[!INCLUDE [iot-hub-include-python-v2-async-installation-notes](../../includes/iot-hub-include-python-v2-async-installation-notes.md)]
4034

4135
* Make sure that port 8883 is open in your firewall. The device sample in this article uses MQTT protocol, which communicates over port 8883. This port may be blocked in some corporate and educational network environments. For more information and ways to work around this issue, see [Connecting to IoT Hub (MQTT)](iot-hub-mqtt-support.md#connecting-to-iot-hub).
4236

@@ -46,88 +40,140 @@ At the end of this tutorial you run the Python console app:
4640

4741
In this section, you create the device app to upload a file to IoT hub.
4842

49-
1. At your command prompt, run the following command to install the **azure-iothub-device-client** package:
43+
1. At your command prompt, run the following command to install the **azure-iot-device** package. You use this package to coordinate the file upload with your IoT hub.
5044

5145
```cmd/sh
52-
pip install azure-iothub-device-client
46+
pip install azure-iot-device
5347
```
5448
55-
2. Using a text editor, create a test file that you will upload to blob storage.
49+
1. At your command prompt, run the following command to install the [**azure.storage.blob**](https://pypi.org/project/azure-storage-blob/) package. You use this package to perform the file upload.
50+
51+
```cmd/sh
52+
pip install azure.storage.blob
53+
```
5654
57-
> [!NOTE]
58-
> IoT Hub Python SDK currently only supports uploading character-based files such as **.txt** files.
55+
1. Create a test file that you'll upload to blob storage.
5956
60-
3. Using a text editor, create a **FileUpload.py** file in your working folder.
57+
1. Using a text editor, create a **FileUpload.py** file in your working folder.
6158
62-
4. Add the following `import` statements and variables at the start of the **FileUpload.py** file.
59+
1. Add the following `import` statements and variables at the start of the **FileUpload.py** file.
6360
6461
```python
65-
import time
66-
import sys
67-
import iothub_client
6862
import os
69-
from iothub_client import IoTHubClient, IoTHubClientError, IoTHubTransportProvider, IoTHubClientResult, IoTHubError
63+
import asyncio
64+
from azure.iot.device.aio import IoTHubDeviceClient
65+
from azure.core.exceptions import AzureError
66+
from azure.storage.blob import BlobClient
7067
7168
CONNECTION_STRING = "[Device Connection String]"
72-
PROTOCOL = IoTHubTransportProvider.HTTP
73-
74-
PATHTOFILE = "[Full path to file]"
75-
FILENAME = "[File name for storage]"
69+
PATH_TO_FILE = r"[Full path to local file]"
7670
```
7771
78-
5. In your file, replace `[Device Connection String]` with the connection string of your IoT hub device. Replace `[Full path to file]` with the path to the test file that you created, or any file on your device that you want to upload. Replace `[File name for storage]` with the name that you want to give to your file after it's uploaded to blob storage.
72+
1. In your file, replace `[Device Connection String]` with the connection string of your IoT hub device. Replace `[Full path to local file]` with the path to the test file that you created or any file on your device that you want to upload.
7973
80-
6. Create a callback for the **upload_blob** function:
74+
1. Create a function to upload the file to blob storage:
8175
8276
```python
83-
def blob_upload_conf_callback(result, user_context):
84-
if str(result) == 'OK':
85-
print ( "...file uploaded successfully." )
86-
else:
87-
print ( "...file upload callback returned: " + str(result) )
77+
async def store_blob(blob_info, file_name):
78+
try:
79+
sas_url = "https://{}/{}/{}{}".format(
80+
blob_info["hostName"],
81+
blob_info["containerName"],
82+
blob_info["blobName"],
83+
blob_info["sasToken"]
84+
)
85+
86+
print("\nUploading file: {} to Azure Storage as blob: {} in container {}\n".format(file_name, blob_info["blobName"], blob_info["containerName"]))
87+
88+
# Upload the specified file
89+
with BlobClient.from_blob_url(sas_url) as blob_client:
90+
with open(file_name, "rb") as f:
91+
result = blob_client.upload_blob(f, overwrite=True)
92+
return (True, result)
93+
94+
except FileNotFoundError as ex:
95+
# catch file not found and add an HTTP status code to return in notification to IoT Hub
96+
ex.status_code = 404
97+
return (False, ex)
98+
99+
except AzureError as ex:
100+
# catch Azure errors that might result from the upload operation
101+
return (False, ex)
88102
```
89103
90-
7. Add the following code to connect the client and upload the file. Also include the `main` routine:
104+
This function parses the *blob_info* structure passed into it to create a URL that it uses to initialize an [azure.storage.blob.BlobClient](https://docs.microsoft.com/python/api/azure-storage-blob/azure.storage.blob.blobclient?view=azure-python). Then it uploads your file to Azure blob storage using this client.
105+
106+
1. Add the following code to connect the client and upload the file:
91107
92108
```python
93-
def iothub_file_upload_sample_run():
109+
async def main():
94110
try:
95111
print ( "IoT Hub file upload sample, press Ctrl-C to exit" )
96112
97-
client = IoTHubClient(CONNECTION_STRING, PROTOCOL)
113+
conn_str = CONNECTION_STRING
114+
file_name = PATH_TO_FILE
115+
blob_name = os.path.basename(file_name)
116+
117+
device_client = IoTHubDeviceClient.create_from_connection_string(conn_str)
118+
119+
# Connect the client
120+
await device_client.connect()
98121
99-
f = open(PATHTOFILE, "r")
100-
content = f.read()
122+
# Get the storage info for the blob
123+
storage_info = await device_client.get_storage_info_for_blob(blob_name)
101124
102-
client.upload_blob_async(FILENAME, content, len(content), blob_upload_conf_callback, 0)
125+
# Upload to blob
126+
success, result = await store_blob(storage_info, file_name)
103127
104-
print ( "" )
105-
print ( "File upload initiated..." )
128+
if success == True:
129+
print("Upload succeeded. Result is: \n")
130+
print(result)
131+
print()
106132
107-
while True:
108-
time.sleep(30)
133+
await device_client.notify_blob_upload_status(
134+
storage_info["correlationId"], True, 200, "OK: {}".format(file_name)
135+
)
136+
137+
else :
138+
# If the upload was not successful, the result is the exception object
139+
print("Upload failed. Exception is: \n")
140+
print(result)
141+
print()
142+
143+
await device_client.notify_blob_upload_status(
144+
storage_info["correlationId"], False, result.status_code, str(result)
145+
)
146+
147+
except Exception as ex:
148+
print("\nException:")
149+
print(ex)
109150
110-
except IoTHubError as iothub_error:
111-
print ( "Unexpected error %s from IoTHub" % iothub_error )
112-
return
113151
except KeyboardInterrupt:
114-
print ( "IoTHubClient sample stopped" )
115-
except:
116-
print ( "generic error" )
152+
print ( "\nIoTHubDeviceClient sample stopped" )
117153
118-
if __name__ == '__main__':
119-
print ( "Simulating a file upload using the Azure IoT Hub Device SDK for Python" )
120-
print ( " Protocol %s" % PROTOCOL )
121-
print ( " Connection string=%s" % CONNECTION_STRING )
154+
finally:
155+
# Finally, disconnect the client
156+
await device_client.disconnect()
122157
123-
iothub_file_upload_sample_run()
158+
159+
if __name__ == "__main__":
160+
asyncio.run(main())
161+
#loop = asyncio.get_event_loop()
162+
#loop.run_until_complete(main())
163+
#loop.close()
124164
```
125165
126-
8. Save and close the **UploadFile.py** file.
166+
This code creates an asynchronous **IoTHubDeviceClient** and uses the following APIs to manage the file upload with your IoT hub:
167+
168+
* **get_storage_info_for_blob** gets information from your IoT hub about the linked Storage Account you created previously. This information includes the hostname, container name, blob name, and a SAS token. The storage info is passed to the **store_blob** function (created in the previous step), so the **BlobClient** in that function can authenticate with Azure storage. The **get_storage_info_for_blob** method also returns a correlation_id, which is used in the **notify_blob_upload_status** method. The correlation_id is IoT Hub's way of marking which blob you're working on.
169+
170+
* **notify_blob_upload_status** notifies IoT Hub of the status of your blob storage operation. You pass it the correlation_id obtained by the **get_storage_info_for_blob** method. It's used by IoT Hub to notify any service that might be listening for a notification on the status of the file upload task.
171+
172+
1. Save and close the **UploadFile.py** file.
127173
128174
## Run the application
129175
130-
Now you are ready to run the application.
176+
Now you're ready to run the application.
131177
132178
1. At a command prompt in your working folder, run the following command:
133179
@@ -137,11 +183,11 @@ Now you are ready to run the application.
137183
138184
2. The following screenshot shows the output from the **FileUpload** app:
139185
140-
![Output from simulated-device app](./media/iot-hub-python-python-file-upload/1.png)
186+
![Output from simulated-device app](./media/iot-hub-python-python-file-upload/run-device-app.png)
141187
142188
3. You can use the portal to view the uploaded file in the storage container you configured:
143189
144-
![Uploaded file](./media/iot-hub-python-python-file-upload/2.png)
190+
![Uploaded file](./media/iot-hub-python-python-file-upload/view-blob.png)
145191
146192
## Next steps
147193
@@ -152,3 +198,9 @@ In this tutorial, you learned how to use the file upload capabilities of IoT Hub
152198
* [Introduction to C SDK](iot-hub-device-sdk-c-intro.md)
153199
154200
* [Azure IoT SDKs](iot-hub-devguide-sdks.md)
201+
202+
Learn more about Azure Blob Storage with the following links:
203+
204+
* [Azure Blob Storage documentation](https://docs.microsoft.com/azure/storage/blobs/)
205+
206+
* [Azure Blob Storage for Python API documentation](https://docs.microsoft.com/python/api/overview/azure/storage-blob-readme?view=azure-python)
Binary file not shown.
Binary file not shown.
34.8 KB
Loading
32 KB
Loading
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
title: include file
3+
description: include file
4+
services: iot-hub
5+
author: robinsh
6+
ms.service: iot-hub
7+
ms.topic: include
8+
ms.date: 03/30/2020
9+
ms.author: robinsh
10+
ms.custom: include file
11+
---
12+
13+
* An active Azure account. (If you don't have an account, you can create a [free account](https://azure.microsoft.com/pricing/free-trial/) in just a couple of minutes.)
14+
15+
* [Python version 3.7 or later](https://www.python.org/downloads/) is recommended. Make sure to use the 32-bit or 64-bit installation as required by your setup. When prompted during the installation, make sure to add Python to your platform-specific environment variable. For other versions of Python supported, see [Azure IoT Device Features](https://github.com/Azure/azure-iot-sdk-python/tree/master/azure-iot-device#azure-iot-device-features) in the SDK documentation.
16+
17+
> [!IMPORTANT]
18+
> Because the device code in this article uses the asynchronous API, you cannot use Python 2.7.

0 commit comments

Comments
 (0)