We have our annual, internal Technical Summit coming up in a couple of weeks. I’ll be heading across to Montreal with 700+ other Autodesk employees to learn more about the cool stuff going on within the company. As I’ve done in previous years, I’ll do my best to report information that I think will be interesting to this blog’s readers (and that is ready to be discussed publicly, of course).
One of the event’s activities is being hosted by my team: the IoT Hackday. We’ll have 30+ participants spread across 8 different teams. Each team will get provided some sensors, some LEDs, a Raspberry Pi 3 and the access credentials to connect to the back-end IoT data service Autodesk Research is building. They’ll use these ingredients to cook up interesting IoT-related projects that use our back-end data service.
As part of this effort, I was asked to put together a custom Dynamo node that allows you to query the service for the latest reading from a particular sensor.
I’m happy to say it’s working well. At some point – as the API gets closer to being publicly consumable – I’ll share the complete code, here. The project really is basically a “zero touch” plugin – a .NET Class Library (.DLL) which can be imported into Dynamo Studio – that calls into our back-end service via its REST API. In our case we want our sensor readings to be read periodically, so we need to mark that particular method with [CanUpdatePeriodicallyAttribute(true)]. This tells Dynamo Studio to enable the otherwise greyed-out “Periodic” execution option (in addition to “Manual” and “Automatic”) so that the values will be read regularly and have their values propagated through the graph.
As the API we’re using for this isn’t yet live, I decided to consider other REST APIs that return sensor-like data that changes frequently. I settled on retrieving stock quotes from Yahoo Finance, and using this data to adjust geometry in Dynamo Studio. (I first looked at Google Finance, but it seems this API is long-deprecated… neither API can be used for commercial applications, in case you’re considering it.)
And so it was that DynaQuote was born. :-)
So yes, the title of this post should probably be “Connecting Dynamo to Realtime Stock Data”, but that’s not really the point: this is about the approach you can take to have generative geometry connect to REST APIs, which could well be based on IoT sensor data (as we’ll be exploring at the Hackday).
Here’s the C# code. To get it working you’ll need to NuGet in the ZeroTouchLibrary and Json.NET. I also added a project reference to System.Net.Http. Otherwise you should be able to get it working by copy & pasting it into a simple Class Library project.
using Autodesk.DesignScript.Runtime;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
namespace DynaQuote
{
internal static class Extensions
{
// Extension to simplify adding key-value pairs to a list
internal static void AddPair(
this List<KeyValuePair<string, string>> list, string key, string val
)
{
list.Add(new KeyValuePair<string, string>(key, val));
}
}
public class Stock
{
private const string quoteUrl =
"http://finance.yahoo.com/webservice/v1/symbols/{0}/quote?format=json";
// Another alternative is...
//"http://www.google.com/finance/info?q={0}";
// Which requires different unpacking, of course
private string _ticker;
// The constructor is internal as Dynamo users will construct it via a
// static method
internal Stock(string ticker)
{
_ticker = ticker;
}
/// <summary>
/// Creates a stock node based on a ticker.
/// </summary>
/// <param name="ticker">The stock ticker</param>
/// <returns>A node representing the specified stock</returns>
public static Stock ByTicker(string ticker)
{
return new Stock(ticker);
}
/// <summary>
/// Gets the most recent stock quote
/// </summary>
/// <returns>The most recent stock quote</returns>
[CanUpdatePeriodicallyAttribute(true)]
public double Quote()
{
try
{
// Format the URL to return the quote for a particular stock
var url = String.Format(quoteUrl, _ticker);
var res = Invoke(url).Result;
// If we still haven't succeeded, return an invalid value
if (String.IsNullOrEmpty(res))
{
return Double.NaN;
}
// Parse and sort the results
var json = JObject.Parse(res);
return
json["list"]["resources"][0]["resource"]["fields"]["price"].Value<double>();
}
catch { return Double.NaN; }
}
static private async Task<string> Invoke(string uri)
{
using (var hc = new HttpClient())
{
// Get the response: if it's valid return the JSON string else null
var res = await hc.GetAsync(uri);
return
(res.IsSuccessStatusCode ? await res.Content.ReadAsStringAsync() : null);
}
}
}
}
Here’s the code in action, adjusting the size of a sphere based on Autodesk’s stock price.
I used a couple of tricks to make it all more visible: firstly I took away the integer component of the stock price (as 2 cent fluctuations on a base of $58 aren’t very visible), before using that for the sphere’s radius. I also edited out big chunks of the video, as stock-watching is boring business. I tried having the colour of the sphere keyed off the stock price, too – which would make this very much like a virtual version of Ambient Devices’ Stock Orb, a ground-breaking device that’s incredibly been around for 14 or so years – but as I’m running Dynamo Studio in a virtual machine, and the Display.ByGeometryColor node apparently uses hardware rendering, this didn’t actually do anything beyond adding unwanted complexity to the graph.
I hope you have fun with this technique: I actually think it has really interesting potential, given the broad availability of realtime data APIs (and not just in the domains of IoT and finance). It’ll be interesting to see how people end up using it at the Hackday!