How to use the Azure IoT Hub File Upload API with Python

I’m hacking with a customer today who is using Python and needs to upload images to Azure IoT Hub using the File Upload API. It took us a while to figure it out and ran into a bunch of issues.

Here’s how we got it working.

Create Azure IoT Hub and Register a Device

1. Create an Azure IoT Hub
2. Register an Azure IoT Hub Device.
3. Copy the Device’s connection string, you’ll need it later.

Enable Azure IoT Hub File Upoads

After you created your IoT Hub, you need to enable file uploads on the Azure Portal. I’m sure you can do via cli as well, but I don’t have time to research that right now.

1. Go to the IoT Hub on Azure Portal
2. Click Messaging -> File Upload

3. Create a new or select an existing Standard storage account and create a container.

Make sure you create or use a Standard storage account. For some reason, file upload doesn’t work with Premium storage accounts. I’m following up with the team on that.

4. Turn on “Receive notifications for uploaded files”

5. Click Save

Get Python IDE

You’ll need an IDE if you want to debug and step-through the code. I use VS Code and this Python extension.

Install Azure IoT Python SDK

Follow the instructions here for getting the Python SDK on your machine. If you are using Linux, then you will have to compile it yourself. If you are using Windows you can use pip.

Get Python Sample

You can either just copy this file locally or clone the entire SDK repo.

Run Python Sample

You don’t have to open the sample to run it, but if you want to look at the code it is in the azure-iot-sdk-python repo device/samples/iothub_client_sample_class.py.

Navigate to the folder devices/samples/ and run the following.

Replace [device connection string] with the device’s connection string that you copied in step 1 above.

python iothub_client_sample_class.py -p mqtt -c [device connection string]

If everything is setup correctly, you will see the following message:

Blob upload confirmation[1001] received for message with result = OK
Total calls confirmed: 1

Here’s the meat of the code for this sample.

def upload_to_blob(self, destinationfilename, source, size, usercontext):
self.client.upload_blob_async(
destinationfilename, source, size,
self._blob_upload_confirmation_callback, usercontext)

And here’s the code that calls that method:

filename= "hello_python_blob.txt"
content = "Hello World from Python Blob APi"
hub_manager.upload_to_blob(filename, content, len(content), 1001)

If you want to upload files, you need to read them into memory first like this:

filename = "myimage.png"
f = open("C:\Temp\myimage.png", "rb")
content = f.read()
print("IoTHubClient is uploading blob to storage")
iotHubClient.upload_blob_async(filename, content, len(content), blob_upload_confirmation_callback, 1001)

If you see the following error…you will need to open up the sample file in your IDE and add a comma after ‘size’ like this:

File "iothub_client_sample_class.py", line 158
self._send_reported_state_callback, user_context)
^
SyntaxError: invalid syntax

If you see the following error…it could mean one of two things:
1. You don’t have a storage account associated with your IoT Hub.
2. You are using a “Premium Storage” Account. Solution: Change your storage account to Standard Storage.
3. You aren’t using the correct container access type. It must be a container with “container” access type, like this:

Note: File upload appears to now work with any container access type.

Error: Time:Thu Jan 26 12:23:05 2017 File:E:\GitRepos\azure-iot-sdk-python\c\iothub_client\src\iothub_client_ll_uploadtoblob.c Func:IoTHubClient_LL_UploadToBlob_step3 Line:649 HTTP code was 400
Error: Time:Thu Jan 26 12:23:05 2017 File:E:\GitRepos\azure-iot-sdk-python\c\iothub_client\src\iothub_client_ll_uploadtoblob.c Func:IoTHubClient_LL_UploadToBlob_Impl Line:843 IoTHubClient_LL_UploadToBlob_step3 failed
Error: Time:Thu Jan 26 12:23:05 2017 File:E:\GitRepos\azure-iot-sdk-python\c\iothub_client\src\iothub_client.c Func:uploadingThread Line:1500 unable to IoTHubClient_LL_UploadToBlob
Blob upload confirmation[1001] received for message with result = ERROR
Total calls confirmed: 1

The error is apparently due to the Premium Storage account not allowing ACLs. See the “warn” statement below.

azure storage container create --container jongcontainer1 -p Container -a jongiothubstorage -k
info: Executing command storage container create
+ Creating storage container jongcontainer1
warn: Current storage account doesn't support setting ACL
+ Getting storage container information
data: {
data: name: 'jongcontainer1',
data: metadata: {},
data: etag: '"0x8D445A036A4FC64"',
data: lastModified: 'Thu, 26 Jan 2017 04:02:57 GMT',
data: lease: { status: 'unlocked', state: 'available' },
data: requestId: 'de4a3094-001c-0000-2989-7792b7000000',
data: publicAccessLevel: 'Off'
data: }
info: storage container create command OK

View The File

You can use Azure Storage Explorer to view the uploaded file.

If you go to the storage account that you associated with IoT Hub in Azure Portal, you’ll see an Open in Storage Explorer button.

Drill down to your container and you’ll see your file.

Access The File

If you want a direct URL to the file it will look like this:
https://jongiothubstandard.blob.core.windows.net/blobcontainer/foo/hello_python_blob.txt

You’ll need to replace your storage name, container name and then build the rest of the path based on the parameters you passed to the upload method when you uploaded the file.

Jon

Share