AdaFruit IO meets my basic criteria as it has support for HTTP/S clients (it also has an MQTT interface which I will look at in a future post) and the API is well documented.
My first Proof of Concept (PoC) was to build a desktop client which used the HttpWebRequest (for ease of porting to NetMF) classes to upload data.
The program uploaded one of three simulated values to AdaFruit.IO every 10 seconds.
I found the username, group, and feed keys to be case sensitive so pay close attention to the values displayed in the webby UI or copy n paste.
program.cs
class Program
{
static void Main(string[] args)
{
string adaFruitIOApiBaseUrl = "https://IO.adafruit.com/api/v2/";
string adaFruitIOUserName = "YourUserName"; // This is mixed case & case sensitive
string adaFruitIOApiKey = "YourAPIKey";
// The feed group and feed key are forced to lower case by UI
const string feedGroup = "";
//const string feedGroup = "devduinov2-dot-2";
const string temperatureKey = "t";
const double temperatureBase = 20.0;
const double temperatureRange = 10.0;
const string humidityKey = "h";
const double humidityBase = 70.0;
const double humidityRange = 20.0;
const string batteryVoltageKey = "v";
const double batteryVoltageBase = 3.00;
const double batteryVoltageRange = -1.00;
TimeSpan dataUpdateDelay = new TimeSpan(0, 0, 10);
Random random = new Random();
while (true)
{
double temperature = temperatureBase + random.NextDouble() * temperatureRange;
Console.WriteLine("Temperature {0}°C", temperature.ToString("F1"));
AdaFruitIoFeedUpdate(adaFruitIOApiBaseUrl, adaFruitIOUserName, adaFruitIOApiKey, feedGroup, temperatureKey, temperature.ToString("F1"));
Thread.Sleep(dataUpdateDelay);
double humidity = humidityBase + random.NextDouble() * humidityRange;
Console.WriteLine("Humidity {0}%", humidity.ToString("F0"));
AdaFruitIoFeedUpdate(adaFruitIOApiBaseUrl, adaFruitIOUserName, adaFruitIOApiKey, feedGroup, humidityKey, humidity.ToString("F0"));
Thread.Sleep(dataUpdateDelay);
double batteryVoltage = batteryVoltageBase + random.NextDouble() * batteryVoltageRange;
Console.WriteLine("Battery voltage {0}V", batteryVoltage.ToString("F2"));
AdaFruitIoFeedUpdate(adaFruitIOApiBaseUrl, adaFruitIOUserName, adaFruitIOApiKey, feedGroup, batteryVoltageKey, batteryVoltage.ToString("F2"));
Thread.Sleep(dataUpdateDelay);
}
}
client.cs
public void AdaFruitIoFeedUpdate(string apiBaseUrl, string userName, string apiKey, string group, string feedKey, string value, int httpRequestTimeoutmSec = 2500, int httpRequestReadWriteTimeoutmSec = 5000)
{
string feedUrl;
if (group.Trim() == string.Empty)
{
feedUrl = apiBaseUrl + userName + @"/feeds/" + feedKey + @"/data";
}
else
{
feedUrl = apiBaseUrl + userName + @"/feeds/" + group.Trim() + "." + feedKey + @"/data";
}
Console.WriteLine(" Feed URL :{0}", feedUrl);
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(feedUrl);
{
string payload = @"{""value"": """ + value + @"""}";
byte[] buffer = Encoding.UTF8.GetBytes(payload);
DateTime httpRequestedStartedAtUtc = DateTime.UtcNow;
request.Method = "POST";
request.ContentLength = buffer.Length;
request.ContentType = @"application/json";
request.Headers.Add("X-AIO-Key", apiKey);
request.KeepAlive = false;
request.Timeout = httpRequestTimeoutmSec;
request.ReadWriteTimeout = httpRequestReadWriteTimeoutmSec;
using (Stream stream = request.GetRequestStream())
{
stream.Write(buffer, 0, buffer.Length);
}
using (var response = (HttpWebResponse)request.GetResponse())
{
Console.WriteLine(" Status: " + response.StatusCode + " : " + response.StatusDescription);
}
TimeSpan duration = DateTime.UtcNow - httpRequestedStartedAtUtc;
Console.WriteLine(" Duration: " + duration.ToString());
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
}
}
This approach seemed to work pretty reliably






