How to get usable state from IoT events? #25daysofserverless
Tags: 25daysofserverless, serverless, azure, iot
Published: 2019-12-21 07:50:39

---
title: How to get usable state from IoT events? #25daysofserverless
published: true
cover_image: https://thepracticaldev.s3.amazonaws.com/i/6z5dct67wfpfbxnmivht.jpg
description: Let's help Julie inflate balloons for her patients with Azure IoT Hub and Durable entities.
tags: 25daysofserverless, serverless, azure, IoT
---

This article is part of [#25DaysOfServerless](https://25daysofserverless.com). New challenges will be published every day from Microsoft Cloud Advocates throughout the month of December. Find out more about how Microsoft Azure enables your [Serverless functions](https://docs.microsoft.com/azure/azure-functions/?WT.mc_id=25days_devto-blog-cxa).

Have an idea or a solution? <a class="twitter-share-button" href="https://twitter.com/intent/tweet?text=I'm joining the @azureadvocates %2325DaysOfServerless challenge!! Learn more at https://aka.ms/25daysofserverless or see solutions at https://dev.to/search?q=25DaysOfServerless! Join me!" data-url="https://aka.ms/25daysofserverless' " data-hashtags="25DaysOfServerless"> Share your thoughts on Twitter! 
</a><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<hr/>
Let's head over to South of France where Julie and her colleagues have decided to prepare a special gift for all patients
where she is working: custom-shaped inflated balloons! To make them, she'll need to inflate a LOT of balloons
with the help of an air compressor and one 12 liters air tank. Will they have enough air to do it?

We have put some IoT devices that tell us when the air compressor is starting and stopping to fill the tanks.
With the help of Azure IoT Hub and some serverless magic, your mission is to compute the amount of air available and
make this information available.

## Create our Project

After having created a new Azure Functions project, we will need to install the Azure Functions Durable extension, by adding the corresponding NuGet package.

```
func extensions install -p Microsoft.Azure.WebJobs.Extensions.DurableTask -v 2.0.0
```

You'll also need to create several Azure Resources, including: 
- A Storage Account. Your entity state will be serialized into it,
- An Event Hub, to reroute messages from the IoT Hub to the Azure Function
- An IoT Hub and a device that sending some messages :) (you can [fake it](https://docs.microsoft.com/en-us/azure/iot-hub/tutorial-connectivity?wt.mc_id=25serverless19-devto-chmaneu) if needed.

## Coding our Durable Entity

That's probably the easiest part. You simply have to write a class, with some assumptions and todos : 

- Any property will be only read-only. If you need to change the state of an object, you will need to create a method for it. Methods will be called, but not directly,
- We will only serialize what's needed. So you need to put some attributes for this,
- Any public method can be called by other functions
- You'll need a special `Run` method that will dispatch the actual work to the appropriate method. Remember, methods are not called directly on your object.

Here is a simple example of a class representing a Tank, with different properties.

```csharp
[JsonObject(MemberSerialization.OptIn)]
public class Tank
{
    [JsonProperty("pressure")]
    public int CurrentPressure {get; private set;} = 0;

    [JsonProperty("isFilling")]
    public bool IsFilling {get;private set;}

    [JsonProperty("fillingStartTime")]
    public DateTime FillingStartTime {get; private set;}

    [FunctionName(nameof(Tank))]
    public static Task Run([EntityTrigger] IDurableEntityContext ctx)
        => ctx.DispatchAsync<Tank>();

    public int GetActualPressure() => this.CurrentPressure;

    public void StartFilling()
    {
        IsFilling = true;
        FillingStartTime = DateTime.Now;
    }

    public void Stop()
    {
        IsFilling = false;
        var fillingStopTime = DateTime.Now;
        CurrentPressure += ComputeFillingPressure(FillingStartTime, fillingStopTime);
    }
}
```

## Calling a method on our durable entity from _regular_ functions

At the previous step, we've created some methods like `StartFilling` and `Stop`. We now need to call it when we receive an event from our IoT device. 

If you try to instantiate an entity directly, you'll have the feeling that's everything is working. However, nothing will work :). You'll need to use an `IDurableEntityClient` to communicate with a durable entity. This client will handle all the work behind the scenes to scale, serialize and restore your entities. You get this client via method parameters injection.

In a case of just calling a method in an entity without expecting any return value, you'll be simply **signaling** it. That means that your Azure function will almost always return _before_ any code within the entity gets executed. You just create an `EntityId` and call the method `SignalEntityAsync()` to send a request to execute a specific method.


```csharp
[FunctionName("processCompressorEvent")]
public static async Task<IActionResult> Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req,
    ILogger log,
    [DurableClient]IDurableEntityClient client)
{
    log.LogInformation("New event from IoT device.");

    string compressorId = req.Query["id"];
    string queryType = req.Query["eventType"];
    
    var entityId = new EntityId(nameof(Tank), compressorId);

    switch (queryType)
    {
        case "start": 
            await client.SignalEntityAsync(entityId, "StartFilling");
            break;
        case "stop": 
            await client.SignalEntityAsync(entityId, "Stop");
            break;
    }

    return (ActionResult)new OkObjectResult($"Event processed.");
}
```

## Accessing values of our durable entity from _regular_ functions

If you need to access the value of an entity, it's almost the same than calling a function: 

- Use an `IDurableEntityClient`,
- Create an `EntityId` object to _locate _ your entity,
- Call `durableEntityClient.ReadEntityStateAsync()`

**There is only one thing you need to know**: if you try to get an entity state for an entity that does not exists yet - because nobody called a method on it for example - You'll get a "value that is null". That's why the return value of `ReadEntityStateAsync` is not your object, but a wrapper object that exposes an `EntityExists` property.

```csharp
[FunctionName("GetCompressorState")]
public static async Task<IActionResult> Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
    ILogger log,
    [DurableClient]IDurableEntityClient client)
{
    log.LogInformation("New request to get compressor state.");

    string compressorId = req.Query["id"];

    var entityId = new EntityId(nameof(Tank), compressorId);
    var currentValue = await client.ReadEntityStateAsync<Tank>(entityId);
    
    if (currentValue.EntityExists)
        return (ActionResult)new OkObjectResult( new { value = currentValue.EntityState.CurrentPressure});
    else
        return (ActionResult)new OkObjectResult( new { value = 0, state = "no-data"});
}
```


Voilà ! With very few lines of code, you're now able to store a concrete state of an IoT object just from events data, and you're ready to scale it to millions of balloons :).

<hr/>
Want to submit your solution to this challenge? Build a solution locally and then [submit an issue](https://github.com/microsoft/25-days-of-serverless/issues/new?assignees=&labels=challenge-submission&template=challenge-solution-submission.md&title=%5BCHALLENGE+SUBMISSION%5D+). If your solution doesn't involve code you can record a short video and submit it as a link in the issue description. Make sure to tell us which challenge the solution is for. We're excited to see what you build! Do you have comments or questions? Add them to the comments area below.

<hr/>
Watch for surprises all during December as we celebrate 25 Days of Serverless. Stay tuned here on dev.to as we feature challenges and solutions! Sign up for a [free account on Azure](https://azure.microsoft.com/free/?WT.mc_id=25days_devto-blog-cxa) to get ready for the challenges!

Enjoying this initiative by Azure Advocates? Stay in touch via our [newsletter](aka.ms/usdevconnect).