A hands on workshop for an agrotech hackathon 🌽
In the previous step, you exported IoT telemetry to Azure Blob Storage. In this step you will create an Azure Function triggered by Azure Stream Analytics to check soil moisture.
Azure Functions is an event driven serverless compute platform, essentially a way to define small blocks of code that are triggered by events such as a web request, data changes in storage or events being put onto an Azure Event Hub. They can be written in a multitude of different languages including C#, F#, Java, JavaScript and Python.
Azure Stream Analytics can call Azure Functions in response to streaming data, either individual messages or an aggregation across a time window.
To monitor soil moisture, the moisture measurement needs to be checked against a defined level, and if it is too low then the plant needs watering. Events are coming in every 60 seconds, and the moisture level doesn’t need to be checked that often, instead an average over 5 minutes can be checked.
The Azure Function to be created will be triggered by a web request, called from Azure Stream Analytics.
To build, test and deploy Azure Functions in Python using Visual Studio Code, you will need to install a couple of extensions.
Launch Visual Studio Code. You will be developing locally, so close any remote development sessions to the Raspberry Pi that you have open.
Select the Extensions tab from the left hand menu, or select View -> Extensions
Search for Python
and install the Python extension from Microsoft by selecting Install.
There are a number of Python extensions available, so ensure you install the one from Microsoft
Search for Azure Functions
and install the Azure Functions extension from Microsoft by selecting Install.
Azure Functions can be created inside Visual Studio Code, or via the Azure CLI.
Create a new folder for the Azure Functions project called MoistureTrigger
Launch Visual Studio Code and open the new folder using either the Open Folder button in the Explorer, or by selecting File -> Open..
From Visual Studio Code, launch the command palette
Search for Azure Functions: Create New Project
and select it
Select the folder to create the project in. The currently open folder will be one of the options, so select it.
Select Python for the function project language
The function will be created using a Python Virtual environment, so select the Python version to use. Select the latest version of Python 3 that you have installed.
The function project will be created with a single trigger. Select the Http Trigger option to have this function triggered by a web request.
Name the function SoilMoistureCheck
Set the function authorization level to Function
. This means it can only be called using a key either as a header or a query string. Without the key the function cannot be called.
The project and virtual environment will be created. This will take a few seconds.
From the terminal, create a new functions project called MoistureTrigger
using the following command
func init MoistureTrigger
The tool will ask what worker runtime you want, so enter the number for Python
Select a number for worker runtime:
1. dotnet
2. node
3. python
4. powershell
Choose option: 3
Once the function has been created, change to the functions folder with the following command
cd MoistureTrigger
Create a new Python3 Virtual Environment inside the function folder with the following command
python3 -m venv .venv
Create an Http trigger called SoilMoistureCheck with the following command. This trigger will be triggered by a web request. By default, the function authorization level will be set to Function
. This means it can only be called using a key either as a header or a query string. Without the key the function cannot be called.
func new --name SoilMoistureCheck --template "HttpTrigger"
Open the folder in Visual Studio Code to edit the function code using the following command
code .
In this step, the function just needs to exist so that it can be called by Azure Stream Analytics, along with some logging. In a later step more code will be added to it to check weather and execute an Azure IoT Central command.
You can find all the code for this step in the Code/Functions folder.
Open the __init__.py
file from the SoilMoistureCheck
folder if it’s not already open
Change the main
function to the following:
def main(req: func.HttpRequest) -> func.HttpResponse:
# Log the function was called
logging.info('Python HTTP trigger function processed a request.')
# Return a 200 status
return func.HttpResponse(f"OK")
Save the file. If you don’t want to have to remember to save files, you can turn on Auto Save by selecting File -> Auto Save.
The function can be tested from inside Visual Studio Code, or from the Azure CLI.
Select the debugger from the left-hand menu, or select View -> Debug
Select the Start Debugging button from the top of the debug pane. It is a green play triangle ▶️.
The Azure Functions runtime will launch and host the function. When it is running you will see the list of functions inside the app in the terminal containing the single Http trigger.
Test the trigger by opening http://localhost:7071/api/SoilMoistureCheck in your web browser. In the terminal in Visual Studio Code you will see the call being made, and the browser will show the output of OK
.
When you have finished testing the function, detach from the functions host debugger by selecting the Disconnect button from the debug toolbar
From the terminal activate the Python Virtual Environment
On Windows use the following command
.venv\Scripts\activate.bat
On macOS use the following command
source ./.venv/bin/activate
Install the require pip packages with the following command
pip install -r requirements.txt
Launch the function with the following command
func start
The Azure Functions runtime will launch and host the function. When it is running you will see the list of functions inside the app in the terminal containing the single Http trigger.
Test the trigger by opening http://localhost:7071/api/SoilMoistureCheck in your web browser. In the terminal in Visual Studio Code you will see the call being made, and the browser will show the output of OK
.
When you have finished testing the function, detach from the functions host debugger by pressing ctrl+c.
Azure Stream Analytics needs to be able to access the URL for the function to be able to run it. This means it cannot call functions running locally, so the function will need to be published to Azure to make it publicly available and therefore callable from Azure Stream Analytics.
The function can be deployed from Visual Studio code, or the Azure CLI.
From Visual Studio Code, launch the command palette
Search for Azure Functions: Deploy to Function App
and select it
If you have multiple Azure subscriptions a list of them will be shown, so select the correct one
Select + Create new Function App in Azure... (Advanced)
. There are two options with this name, one marked as Advanced
. Select the one that is marked as Advanced
. The Advanced option gives more control including adding the Function App to the existing Resource Group.
Give the Function App a name that is globally unique, so include things such as the date or your name, for example agrohackjim2020
. To make it easier, name it the same as your Azure IoT Central app and storage account.
Select Linux
for the OS
Select Consumption
for the app service plan. This plan means you only pay based off the function app usage, with a generous free tier.
Select the latest Python 3 runtime that is available
Select the AgroHack
Resource Group
Select the storage account that was created earlier for the data export. This storage account is used to save the files needed for the function app.
Select Create new Application Insights Resource. Application Insights allows you to monitor the Function App.
Accept the default Application Insights name
The Function App will be created and your code deployed. This will take a few seconds and a notification will pop up when complete.
Select the Azure tab from the left-hand menu
In the Functions section, expand your subscription to see all your Function Apps. Expand the newly created function app to see all functions.
Right-click on the SoilMoistureCheck (HTTP) function and select Copy Function Url
Paste this URL into a browser and test the function is working
Create a new Azure Function App to host the function using the following command
az functionapp create \
--resource-group AgroHack \
--runtime python \
--os-type linux \
--consumption-plan-location <location> \
--name <function_app_name> \
--storage-account <storage_account>
This will create a Function App in the AgroHack
Resource Group, running on linux
with the Python run time.
For <location>
use be the same location you created the other resources in.
For <function_app_name>
, pick a name that is globally unique, so include things such as the date or your name, for example agrohackjim2020
. To make it easier, name it the same as your Azure IoT Central app and storage account.
For <storage_account>
use the name of the storage account you created when exporting data. This storage account is used to save the files needed for the function app.
Deploy your function to this app with the following command
func azure functionapp publish <function_app_name> --build remote
For <function_app_name>
use the name you used when creating the Function App
Once the function is deployed, the Http trigger URL will be listed in the terminal with a query string of code=<key>
, the key
being your Function App key. Copy this entire URL and test it out in a browser.
SoilMoistureChecking
.From the Stream Analytics Job, select Job topology -> Outputs from the left-hand menu
Select + Add, then select Azure function
Fill in the output details
Set the alias to be soil-moisture-check
Select Select azure function from your subscriptions
Select your subscription
Select the function app you just deployed to
Select the SoilMoistureCheck
function
Leave the rest of the values as the defaults
Select Save
From the Stream Analytics Job, select Job topology -> Query from the left-hand menu
Change the query to be the following
SELECT
AVG(humidity) as humidity,
AVG(pressure) as pressure,
AVG(temperature) as temperature,
AVG(soil_moisture) as soil_moisture
INTO
[soil-moisture-check]
FROM
[telemetry]
GROUP BY
TumblingWindow(minute,5)
This will select data as it comes into the telemetry
event hub, grouping data using a 5 minute tumbling window. This groups data into 5 minute blocks and calls the query for each block. The query will get the average value of 4 telemetry values.
Select Test Query to test the query and see a sample output using real data from the event hub
Select Save Query
From the Stream Analytics Job, select Overview from the left-hand menu
Select Start
For the Job output start time select Now
Select Start
The easiest way to ensure the query is running correctly is by verifying that the Azure Function gets called.
Open the Azure Portal
Log in with your Microsoft account if required
In the search bar, search for you Function Apps name
Select the Function app. It will be marked as an App Service and have a lightning bolt icon.
Expand the app and Functions nodes, and select Monitor
When the Azure Function is called an entry will appear in the table with a green tick
It will take a few minutes for rows to appear as each window is 5 minutes, so nothing will appear until the 5 minute window is complete. Refresh the window using the Refresh button after a few minutes to see rows appear.
In this step you created an Azure Function triggered by Azure Stream Analytics to check soil moisture. In the next step you will add to this function to trigger an Azure IoT Central command if the soil moisture is too low.