When the COVID-19 lockdown became a reality, I found some spare time to fulfill the long desired wish of tinkering with Arduino boards. I had been ordering components from AliExpress for about a year, but never got around to actually doing anything with it.

I always have this unhelpful idea I should not start with the simple stuff like driving a single LED or make a buzzer beep, but for my first project, I wanted to drive 1740 (58×30) RGB ws2812b LEDs using them as a pixel art design piece without ever having even installed an Arduino IDE.

Naturally, I screwed up a couple of times, but fortunately without burning the house down. As a C# developer, I love I can just debug my programs in Visual Studio and fix my bugs on the fly. With the Arduino IDE, it is a whole different story. While there is the serial monitor I can usually write some output to, the serial monitor port was in use driving the massive amounts of LEDs because I had split the data signal into 8 chunks to avoid latency in driving the LEDs.

Without the feedback from the serial monitor, I was flying blind on where my C program blew up. Of course, I could have restricted the number of ports to drive my LEDs on, but I figured I could easily log the messages to an Azure Table Storage account.

I have created a logging function method in an Azure Function App and I use the table storage output binding from the Microsoft.Azure.Cosmos.Table package to write to the Table Storage.

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Azure.Cosmos.Table;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace LoggingArduino
{
    public static class LogMessage
    {
        [FunctionName("LogMessage")]
        [return: Table("ArduinoLog")] // ArduinoLog is the name of the table to log to using the output binding
        public async static Task<LogItem> TableOutput([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, ILogger log)
        {
            // Log this for debugging purposes
            log.LogInformation("Logging function processed a request.");

            // Get the JSON string from the querystring as a fallback
            string message = req.Query["message"];

            // Read the message body 
            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();

            // Deserialize the JSON object from the body
            dynamic data = JsonConvert.DeserializeObject(requestBody);

            // Get the message from either the querystring or the JSON message body
            message = message ?? data?.message;

            // Output the message to the Table Storage output binding
            return new LogItem { PartitionKey = "Http", RowKey = Guid.NewGuid().ToString(), Text = message };
        }
    }

    // Extend the TableEntity item with extra fields
    public class LogItem: TableEntity
    {
        public string Text { get; set; }
    }
}

This function example can be invoked anonymously which is usually not the best idea since everyone can invoke it from the internet. You should always consider using HTTPS and some form of authentication like using a secret key or a form of user authentication. You can find more information on Azure Function security here.

Invoking the logging method from your ESP8266 Arduino board is as easy as making a GET or POST request:

#include <ESP8266HTTPClient.h>

void setup() {
  logMessage("Initializing setup");
}

void loop() {
}

void logMessage(String message) {
  HTTPClient http;
  http.begin("http://yourfunctionappname.azurewebsites.net/api/LogMessage?message="+message); 
  http.GET();
  http.end();
}

Now you can use the Azure Storage Explorer to find your storage account that contains the logging table and browse your logging messages from your Arduino ESP8266 projects.