IoT Hub and Azure Functions using Python and Visual Studio Code

ChrisU 231 Reputation points
2022-05-03T14:42:50.71+00:00

To set the scene: I am new to coding and in my first coding/software support role having completed a diploma last year to bring about a career change. I am also new to IoT but have been tasked with delivering a IoT proof of concept to my employer. So far, I have managed to setup a couple of gateways and devices on a LoRaWAN network server, output to an Azure IoT Hub and store the data in an Azure SQL DB using a Stream analytics job.

However, the sensor environment data arrives encoded in hexadecimal format and so needs decoding. I have already set up a WebSocket output and a simple app that consumes and decodes the data to variables that you can then use/store. This is within Visual Studio Code and run from the console/terminal; I have not yet been able to create an Azure Function for this. I want to now use this decoding script I have written within an Azure function which will take the uplink data, decode the environment data, and then output these along with other data to an Azure database. The trigger being the receiving of uplink data within the IoT-Hub:

198546-image.png

In this, the decode function would replace the Stream analytics job. Would this work or would I require additional functionality?

From reading the documentation here, I think I am right in that an IoT-Hub is an Event hub? I am using Visual Studio Code and Python and I have found very little documentation on setting up Azure Functions for IoT Hub/Event Hub and those that I have found focus on C# and Visual studio. Is there any other resource that I can be pointed to that may help?

Thanks in advance

Azure Functions
Azure Functions
An Azure service that provides an event-driven serverless compute platform.
4,283 questions
Azure IoT Hub
Azure IoT Hub
An Azure service that enables bidirectional communication between internet of things (IoT) devices and applications.
1,123 questions
Azure Event Hubs
Azure Event Hubs
An Azure real-time data ingestion service.
558 questions
{count} votes

Accepted answer
  1. Bruno Lucas 4,411 Reputation points MVP
    2022-05-11T10:14:13.273+00:00

    Hi @ChrisU ,

    I cloned your code and it seems correct. I managed to debug it and deploy it.

    First. the debugging locally problem could be 2 things:

    1 - Firewall. the trigger function defaults to AMQP, so, it is trying to reach tpc ports 5671 and 5672. usually I fix this by creating a firewall rule but I see couple months ago Microsoft has finally provided the option to change it to amqpwebsocket. First try adjusting the firewall. if doesn't work, try to change your host.json to this:

    {  
      "version": "2.0",  
      "extensions": {  
        "eventHubs": {  
          "transportType" : "amqpWebSockets"  
        }  
      },  
      "logging": {  
        "applicationInsights": {  
          "samplingSettings": {  
            "isEnabled": true,  
            "excludedTypes": "Request"  
          }  
        }  
      },  
      "extensionBundle": {  
        "id": "Microsoft.Azure.Functions.ExtensionBundle",  
        "version": "[2.*, 3.0.0)"  
      }  
    }  
    

    2 - Did your VS Code generated the python environment? if so, you should have a folder called ".venv"
    200961-image.png

    Regarding deployment, did you use the vs code deploy?
    200972-image.png

    I think part of it is an add-on bug. you can try to deploy without an ide: https://learn.microsoft.com/en-us/azure/azure-functions/deployment-zip-push if you prefer, but back to vs code, for now, after deployment, just make sure the azure function settings (in the cloud) match the ones on the app.seetings.json. the hub connection string must be the same name in Azure. did you grab that here?:

    201023-image.png

    The storage is not mapped in the bindings but seems to be picked as long the name is "AzureWebJobsStorage". just need to make sure the value is correct.

    200914-image.png

    Before moving into testing (and after deploying) remember you need to stop the azure function in azure when testing locally, otherwise the cloud will always grab the messages.

    200992-image.png

    To send messages for testing, I use the iot hub add-on for vs code:

    https://marketplace.visualstudio.com/items?itemName=vsciot-vscode.azure-iot-tools
    https://marketplace.visualstudio.com/items?itemName=vsciot-vscode.azure-iot-toolkit

    200910-image.png
    200936-image.png

    Did you add any devices? the vs code message sending add-on will expect at least one device. If you don't, just add on under the iot hub in azure before using the add-on

    The right place to check if that is running in azure is here:

    Functions > [the function you want to check] > Monitor:

    200968-image.png

    ----------

    200987-image.png

    ----------

    the logs are good for initial troubleshoot. this line writes to that log:
    logging.info('Python EventHub trigger processed an event: %s',
    event.get_body().decode('utf-8'))

    200963-image.png

    to debug locally, make sure the azure function is stopped. hit f5 or click here :

    200930-image.png

    Remember to install this if you want to use the iot hub add-on: https://marketplace.visualstudio.com/items?itemName=vsciot-vscode.azure-iot-tools . It helps testing/debugging

    The confusion in VS Code is where to go to use add-ons. if you were in the devug section, to find the "send message" you need to click in the explorer:

    200944-image.png

    you should see this:

    200966-image.png
    200985-image.png
    201002-image.png

    If everything is good, you should see this:
    200918-image.png

    Would be good to first debug locally to confirm you have the correct connection strings.

    Let me know if that helps.


6 additional answers

Sort by: Most helpful
  1. ChrisU 231 Reputation points
    2022-05-12T14:44:21.89+00:00

    Thanks again for your comprehensive response. I have worked through you last response and have had good success today. See below:

    • I opened the firewall ports as you suggested. I did not update the host.json as you suggested. Opening the ports seemed to work.

    • Yes, I did use the VS code deploy button as your screen shot indicated and it did generate a .venv file:
    201455-image.png

    • I have double checked, and the The azure function configuration settings in the cloud match those in local.settings.json. Below shows where I got these values form.
    201488-image.png

    • Once I added the azure iot tools and toolkit my iot hub and devices were displayed within VSC without me doing anything:
    201465-image.png

    • I did notice that I had eventHubName configured incorrectly within the function.json file. I had it set to an event hub I have created, not the IoT Hub:
    201500-image.png
    I changed this to my IoT Hub and then redeployed the function App to Azure:
    201542-image.png
    This was likely the cause of the issues I was seeing (possibly not the firewall settings. I will test further to see)

    • I deployed these updates to Azure and also managed to get the ‘function’ option to show my trigger when clicking on Functions, by clicking ‘Refresh’
    201509-image.png
    This allowed me to check that the code has been deployed correctly – see below the json file with the change shown above to prove this.
    201489-image.png

    TESTING.
    So I ensured that the function was not running on the Azure platform at the time that this was tested locally. Good news! I did not get the error I had last time. This was with the new firewall settings and also the correct hub name detailed within the function.json file.

    However when I ran the test you detailed I got 10 failed messages:
    201533-image.png
    However, as you can see above, at the same time I started receiving uplink data from the device.

    I have now adjusted my code to read the data and assign specific values to variables. I have also added the decoder function to convert the environment data from hexadecimal to display the temperature and humidity data. See below and I have updated the repo here.
    201519-image.png
    I deployed the updated code to Azure and confirmed that this worked as below:
    201525-image.png
    I started the function with Azure and it is posting to the logs:
    201543-image.png
    201490-image.png

    So this is good!

    To surmise.

    1. It is now working in that I am able to read the uplink data, sort through it and assign to variables.
    2. I can now edit and test within the dev environment and then deploy successfully on the Azure platform.
    3. Testing by sending D2C message to IoT Hub does not work. It would be good to have your feedback on this as to why you think this would be the case.

    Next steps:
    I now need to hook this up to my Azure SQL database and deposit the variable values within it. I do not quite understand defining the AzureWebJobStorage within the local.settings.json, as when I check the assigned storage with Azure nothing seems to have taken place there; if any activity has taken place here, where would you check?

    Can you advise me and on any best practices in connecting to an Azure SQL DB, how to do it, or point me at resources that you think will help?

    Finally. A massive thanks to you for getting me this far. I had almost given up numerous times!

    0 comments No comments

  2. Bruno Lucas 4,411 Reputation points MVP
    2022-05-13T01:44:32.727+00:00

    Hi @ChrisU ,

    Glad to hear you've got it running.

    Once you run it first time and see the messages flowing, you should also see this under the storage> blob>container

    201585-image.png

    It needs that to track the messages. Take another look and let me know. be careful also if you need to delete that or move resources around , the message will stay in the hub for the time you specify (I think default/minimum is one day). if you delete the storage that contains the message that was already sent and drop the storage data that tracks that, the hub my thrown an error)

    Regarding querying Azure Sql Server, you will need something like this:
    https://learn.microsoft.com/en-us/azure/azure-sql/database/connect-query-python?view=azuresql#create-code-to-query-your-database

    You may also make sure your Sql Server allows for the connection:
    https://learn.microsoft.com/en-us/azure/azure-sql/database/firewall-configure?view=azuresql#connections-from-inside-azure

    if you start to have many azure resources you may also consider a vnet:
    https://learn.microsoft.com/en-us/azure/virtual-network/virtual-networks-overview

    hope that helps

    0 comments No comments