.NET nanoFramework RAK11200 – Azure IoT Hub HTTP Power conservation

My test setup was a RAK11200 WisBlock WiFi Module, RAK19007 WisBlock Base Board, RAK1901 WisBlock Temperature and Humidity Sensor and Keweisi KWS-MX19 USB Tester DC 4V-30V 0-5A Current Voltage Detector to measure the power consumption of my test setup.

RAK11200 + RAK19007 +RAK1901+Keweisi KWS-MX19 test setup

The baseline version of the RAK11200 WisBlock WiFi Module software had no power conservation functionality.

public static void Main()
{
    DateTime sasTokenValidUntilUtc = DateTime.UtcNow;

    Debug.WriteLine($"{DateTime.UtcNow:HH:mm:ss} devMobile.IoT.RAK.Wisblock.AzureIoTHub.RAK11200.PowerConservation starting");

    Configuration.SetPinFunction(Gpio.IO04, DeviceFunction.I2C1_DATA);
    Configuration.SetPinFunction(Gpio.IO05, DeviceFunction.I2C1_CLOCK);

    if (!WifiNetworkHelper.ConnectDhcp(Config.Ssid, Config.Password, requiresDateTime: true))
    {
        if (NetworkHelper.HelperException != null)
        {
             Debug.WriteLine($"{DateTime.UtcNow:HH:mm:ss} WifiNetworkHelper.ConnectDhcp failed {NetworkHelper.HelperException}");
        }

        Thread.Sleep(Timeout.Infinite);
    }

    string uri = $"{Config.AzureIoTHubHostName}.azure-devices.net/devices/{Config.DeviceID}";

    // not setting Authorization here as it will change as SAS Token refreshed
    HttpClient httpClient = new HttpClient
    {
        SslProtocols = System.Net.Security.SslProtocols.Tls12,
        HttpsAuthentCert = new X509Certificate(Config.DigiCertBaltimoreCyberTrustRoot),
        BaseAddress = new Uri($"https://{uri}/messages/events?api-version=2020-03-13"),
    };

    I2cConnectionSettings settings = new(I2cDeviceBusID, Shtc3.DefaultI2cAddress);
    I2cDevice device = I2cDevice.Create(settings);
    Shtc3 shtc3 = new(device);

    AdcController adcController = new AdcController();
    AdcChannel batteryChargeAdcChannel = adcController.OpenChannel(AdcControllerChannel);

    string sasToken = "";

    while (true)
    {
        DateTime standardisedUtcNow = DateTime.UtcNow;

        Debug.WriteLine($"{DateTime.UtcNow:HH:mm:ss} Azure IoT Hub device {Config.DeviceID} telemetry update start");

        if (sasTokenValidUntilUtc <= standardisedUtcNow)
        {
            sasTokenValidUntilUtc = standardisedUtcNow.Add(Config.SasTokenRenewEvery);

            sasToken = SasTokenGenerate(uri, Config.Key, sasTokenValidUntilUtc);

            Debug.WriteLine($" Renewing SAS token for {Config.SasTokenRenewFor} valid until {sasTokenValidUntilUtc:HH:mm:ss dd-MM-yy}");
        }

        if (!shtc3.TryGetTemperatureAndHumidity(out var temperature, out var relativeHumidity))
        {
            Debug.WriteLine($" Temperature and Humidity read failed");

            continue;
        }

        double batteryCharge = batteryChargeAdcChannel.ReadRatio() * 100.0;

        Debug.WriteLine($" Temperature {temperature.DegreesCelsius:F1}°C Humidity {relativeHumidity.Value:F0}% BatteryCharge {batteryCharge:F1}%");

        string payload = $"{{\"RelativeHumidity\":{relativeHumidity.Value:F0},\"Temperature\":{temperature.DegreesCelsius.ToString("F1")}, \"BatteryCharge\":{batteryCharge:F1}}}";

        try
        {
            using (HttpContent content = new StringContent(payload))
            {
                content.Headers.Add("Authorization", sasToken);

                using (HttpResponseMessage response = httpClient.Post("", content))
                {
                    Console.WriteLine($"{DateTime.UtcNow:HH:mm:ss} Response code:{response.StatusCode}");

                    response.EnsureSuccessStatusCode();
                 }
            }
        }
        catch (Exception ex)
        {
            Debug.WriteLine($"{DateTime.UtcNow:HH:mm:ss} Azure IoT Hub POST failed:{ex.Message} {ex?.InnerException?.Message}");
        }

        Debug.WriteLine($"{DateTime.UtcNow:HH:mm:ss} Azure IoT Hub telemetry update done");

        Thread.Sleep(Config.TelemetryUploadInterval);
    }
}

When the program was “idle” the current varied between 0.067A to 0.074A with “spikes” when transmitting.

The second version of the application could be configured to “sleep” the RAK11200 WisBlock WiFi Module and RAK1901 WisBlock Temperature and Humidity Sensor. The RAK11200 WisBlock WiFi Module can be put into a LightSleep or DeepSleep.

public static void Main()
{
    Debug.WriteLine($"{DateTime.UtcNow:HH:mm:ss} devMobile.IoT.RAK.Wisblock.AzureIoTHub.RAK11200.PowerSleep starting");

    Thread.Sleep(5000);

    try
    {
        Configuration.SetPinFunction(Gpio.IO04, DeviceFunction.I2C1_DATA);
        Configuration.SetPinFunction(Gpio.IO05, DeviceFunction.I2C1_CLOCK);

        Debug.WriteLine($"{DateTime.UtcNow:HH:mm:ss} Wifi connecting");

        if (!WifiNetworkHelper.ConnectDhcp(Config.Ssid, Config.Password, requiresDateTime: true))
       {
            if (NetworkHelper.HelperException != null)
            {
                 Debug.WriteLine($"{DateTime.UtcNow:HH:mm:ss} WifiNetworkHelper.ConnectDhcp failed {NetworkHelper.HelperException}");
            }

            Sleep.EnableWakeupByTimer(Config.FailureRetryInterval);
            Sleep.StartDeepSleep();
        }

        Debug.WriteLine($"{DateTime.UtcNow:HH:mm:ss} Wifi connected");

        // Configure the SHTC3 
        I2cConnectionSettings settings = new(I2cDeviceBusID, Shtc3.DefaultI2cAddress);
        I2cDevice device = I2cDevice.Create(settings);
        Shtc3 shtc3 = new(device);

        // Assuming that if TryGetTemperatureAndHumidity fails accessing temperature or relativeHumidity will cause an exception
        shtc3.TryGetTemperatureAndHumidity(out var temperature, out var relativeHumidity);

#if SLEEP_SHT3C
        shtc3.Sleep();
#endif

        // Configure Analog input (AIN0) port then read the "battery charge"
        AdcController adcController = new AdcController();
        AdcChannel batteryChargeAdcChannel = adcController.OpenChannel(AdcControllerChannel);

        double batteryCharge = batteryChargeAdcChannel.ReadRatio() * 100.0;

        Debug.WriteLine($" Temperature {temperature.DegreesCelsius:F1}°C Humidity {relativeHumidity.Value:F0}% BatteryCharge {batteryCharge:F1}");

        // Assemble the JSON payload, should use nanoFramework.Json
        string payload = $"{{\"RelativeHumidity\":{relativeHumidity.Value:F0},\"Temperature\":{temperature.DegreesCelsius.ToString("F1")}, \"BatteryCharge\":{batteryCharge:F1}}}";

        // Configure the HttpClient uri, certificate, and authorization
        string uri = $"{Config.AzureIoTHubHostName}.azure-devices.net/devices/{Config.DeviceID}";

        HttpClient httpClient = new HttpClient()
        {
            SslProtocols = System.Net.Security.SslProtocols.Tls12,
            HttpsAuthentCert = new X509Certificate(Config.DigiCertBaltimoreCyberTrustRoot),
            BaseAddress = new Uri($"https://{uri}/messages/events?api-version=2020-03-13"),
        };
        httpClient.DefaultRequestHeaders.Add("Authorization", SasTokenGenerate(uri, Config.Key, DateTime.UtcNow.Add(Config.SasTokenRenewFor)));

        Debug.WriteLine($"{DateTime.UtcNow:HH:mm:ss} Azure IoT Hub device {Config.DeviceID} telemetry update start");

        HttpResponseMessage response = httpClient.Post("", new StringContent(payload));

        Debug.WriteLine($"{DateTime.UtcNow:HH:mm:ss} Response code:{response.StatusCode}");

        response.EnsureSuccessStatusCode();
    }
    catch (Exception ex)
    {
        Debug.WriteLine($"{DateTime.UtcNow:HH:mm:ss} Azure IoT Hub telemetry update failed:{ex.Message} {ex?.InnerException?.Message}");

        Sleep.EnableWakeupByTimer(Config.FailureRetryInterval);
        Sleep.StartDeepSleep();
    }

    Sleep.EnableWakeupByTimer(Config.TelemetryUploadInterval);
#if SLEEP_LIGHT
    Sleep.StartLightSleep();
#endif
#if SLEEP_DEEP
    Sleep.StartDeepSleep();
#endif
 }

The LightSleep or DeepSleep based code is significantly less complex because the allocation and deallocation of resources does not have to be managed because the application is restarted when the WakeUp Timer triggers.

Both LightSleep and DeepSleep reduced the idle current to 0.000A. The Keweisi KWS-MX19 USB Tester DC 4V-30V 0-5A Current Voltage Detector is not a precision laboratory instrument. I couldn’t detect if sleeping the RAK1901 WisBlock Temperature and Humidity Sensor or LightSleep vs. DeepSleep made any difference. But it did show the power consumption of my setup could be significantly reduced by using the ESP32 LightSleep and DeepSleep functionality.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.