Chat with us, powered by LiveChat

Interlude

What’s having a corporate event driven by developers and for developers without a little family time and great food?  Nothing – that’s what, NOTHING!!!

Thank goodness for the family and friends of those dang Kleinschnitz’s (or however one pluralizes that name)!  Check out the delicious addition to the party…

20160127_180601
Figure 8:Paella good enough to make you beg for more!

 

I’ve never seen a group of developers dig down on something so fast as I did this night… with one exception!

Alcohol!  [Say what] and cereal… somehow I think there is a correlation?!?

 

 

2016-01-27 21.57.522016-01-27 21.44.52

Before all that debauchery… we had a lot of fun competing in games and brain teasers testing the limits of everyone involved!

MaxVsChris

Ok, off to the meat of the Pi!

We had a very interactive session designing the UI for our project… Clayton used every tool at his disposal to design and articulate an interactive UX that will provide real-time data, and the tools we need to reset and calculate based on unit and measure.

IMG_2924
Figure 9: Clayton’s attempt outlining our User Interface

This was only upstaged by the graphic I was assigned to create for the UI… it ultimately didn’t make the cut into the design – I’m heartbroken.

Figure 10: Ugly Scale with status/warning states
Figure 10: Ugly Scale with status/warning states

UI aside, all the programming is going great!  Late nights, like until 3 or 4am and progress is being made.  Our final code for the Win 10 IoT has come out spectacularly and we are now ready to showcase the fruits of our development.  But first, proof of late night programming sessions:

Figure 11: A loooooong day programming - tired developers!
Figure 11: A loooooong day programming – tired developers!

On to the code!

The heartbeat of the scale is a custom action in the vNew Platform (there’s that top-secret code again). This allowed us to report the weight and respond with a status, which is ultimately what we need to work with!  169 lines of code later and we’ve got a working product!  Consumable Scale for the win!  We’ve laid down the code, made the integration to the middle-man (Arduino) and we have a full working solution.

 

namespace Cireson.Consumables.Actions

{

/// <summary>

/// Class supports an Action that is unbound to specific instances of entities.

/// </summary>

/// <example>

/// http://localhost/api/SendCurrentWeight

/// </example>

[AllowAnonymous]

[ODataAlias()]

public class SendCurrentWeight : UnboundAction<ScaleStatusReport>

{

private ConsumableItemService _consumableItemService;

public SendCurrentWeight(ConsumableItemService consumableItemService)

{

_consumableItemService = consumableItemService;

}


/// <summary>

/// Asynchronously executes an action.  This is akin to post operation.

/// </summary>

/// <returns>Returns the execution result.</returns>

public override async Task<ScaleStatusReport> ExecuteAsync()

{

return await _consumableItemService.ProcessReportAsync(new ScaleWeightReport { ScaleId = ScaleId, Weight = Weight });

}


public Guid ScaleId { get; set; }

public decimal Weight { get; set; }

}

}

 

Models like this in the vNew platform  automatically created methods and a database tables needed to store the data.

 

namespace Cireson.Consumables.Models

{

/// <summary>

/// Base Implementation of a Cireson Platform Entity model.

/// </summary>

[ODataAlias]

public partial class ConsumableScale : IPlatformEntity

{

public decimal MinimumWeightThreshold { get; set; }

public Consumable Consumable { get; set; }


[ForeignKey("Consumable")]

public long? ConsumableId { get; set; }

public decimal CurrentWeight { get; set; }

public DateTimeOffset LastReport { get; set; }

public ICollection<ConsumableNeedRequest> ConsumableNeedRequests { get; set; }

#region IPlatformEntity

/// <summary>

/// Gets or sets the identifier.

/// </summary>

/// <value>The identifier.</value>

[AlwaysAllowPropertyRead]

[Key]

[Column(Order = 1)]

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]

public long Id { get; set; }

/// <summary>

/// Gets or sets the modified date.

/// </summary>

/// <value>The modified date.</value>

[Column(Order = 2)]

[AlwaysAllowPropertyRead]

public virtual DateTimeOffset? ModifiedDate { get; set; }

/// <summary>

/// Gets or sets the modified by identifier.

/// </summary>

/// <value>The modified by identifier.</value>

[Column(Order = 3)]

public virtual long? ModifiedById { get; set; }

/// <summary>

/// Gets or sets the created date.

/// </summary>

/// <value>The created date.</value>

[Column(Order = 4)]

public virtual DateTimeOffset? CreatedDate { get; set; }

/// <summary>

/// Gets or sets the created by identifier.

/// </summary>

/// <value>The created by identifier.</value>

[Column(Order = 5)]

public virtual long? CreatedById { get; set; }

/// <summary>

/// Gets or sets the unique identifier.

/// </summary>

/// <value>The unique identifier.</value>

[Column(Order = 6)]

public virtual Guid? Guid { get; set; }

/// <summary>

/// Gets or sets a value indicating whether this instance is deleted.

/// </summary>

/// <value><c>true</c> if this instance is deleted; otherwise, <c>false</c>.</value>

[Column(Order = 7)]

public virtual bool IsDeleted { get; set; }

#endregion  // IPlatformEntity

}

}

 

 

The scale was fun to hookup to with some tricky settings.

private async void ConnectSerialPort()

{

await DisconnectSerialPort();

ConnectedSerialPort = await SerialDevice.FromIdAsync(SelectedSerialDevice.Id);

// Configure serial settings

ConnectedSerialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);

ConnectedSerialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000);

ConnectedSerialPort.BaudRate = 9600;

ConnectedSerialPort.Parity = SerialParity.None;

ConnectedSerialPort.StopBits = SerialStopBitCount.One;

ConnectedSerialPort.DataBits = 8;

ConnectedSerialPort.Handshake = SerialHandshake.None;

ListenToConnectedPort();

}

 

 

 

On a timer we sent the reported data back to the vNew platform using OData

private async void _timer_Tick(object sender, object e)

{

try

{

_timer.Stop();

Debug.WriteLine($"Sending Current Weight {ConsumablesWeight}");

var client = PlatformServiceResolver.GetODataClient();

var request = new Dictionary<string, object> {{"ScaleId", _scaleId}, {"Weight", ConsumablesWeight}};

await client.Unbound<ScaleWeightReport>()

.Action("SendCurrentWeight")

.Set(new {ScaleId=_scaleId, Weight=ConsumablesWeight})

.ExecuteAsync();

Debug.WriteLine($"Sent Current Weight {ConsumablesWeight}");

}

catch (Exception ex)

{

Debug.WriteLine(ex.Message);

}

finally

{

_timer.Start();

}

}

 

Onto the important parts…

Finishing touches:

Don used some maker tech to develop a sweet plate for our scale… respect to the Cireson Scales laser etched scale top.  Really adds the perfect touch to what is a beautiful solution!

Figure 12: Going the extra mile with laser etched logo
Figure 12: Going the extra mile with laser etched logo

Let’s see this in action!

Scenario recap:  We want to be able to accurately measure how much of a consumable we have on hand.  In our video (below) we are looking at pucks and paper… yes, we can scale (pun intended) it all the way down to a single page of paper – that’s how freaking accurate this is!  [#BallerStatusAcheived] This allows us to understand and identify any unit of measure for a single consumable (single quantity) reorder quantity and set a tare rate. We can understand how many units are on hand and automatically reorder when needed.  Powerful stuff for sure!

 

Cireson PiDay Consumable Scale from Team Cireson on Vimeo.