Cookie CSS

Monday, November 10, 2014

Programming the BlyncLight USB Led Lync Presence Indicator Device

A while back I came across the BlyncLight, a USB device that can illuminate a colored block to mirror your Lync presence. http://www.blynclight.com/. It looked like it may be a cheap solution to a problem I was trying to solve. I work in a separate facility on my property, which provides me the seclusion and peace and quiet I need to write software. It keeps co-workers from barging in and interrupting me while I am "wired in". The one fatal flaw in this is my 3 children. Nothing in the world it seems can stop them from running from the house to my office and bursting through the door, no matter if I am on the phone or presenting a webinar. I thought initially about purchasing another Lync Phone Edition device to face toward the door and training them to look at the icon on the phone to determine if I was in a state where I should not be disturbed or not. With a little research I came across the Blync instead, and at $40 instead of $150 it seemed like it was worth a try.




The device arrived in nice packaging and was simple enough to install, plug it in, and install the software. Here is were I ran into some issues, the software seemed to work fine, for 90 minutes or so, then die with a Write Failed error, and consume 25% of the cpu while ceasing to function after that. I tried a few different machines, all with the same result, so I gave up for a week or so. When I came up for air a week later I found they had an SDK so I figured I'd give that a whirl rather than the declaring the unit "bad" and returning it. Sure enough with 15 minutes a programming I had written a simple replacement program that works flawlessly for what I needed.

Here is the jist;

Step 1. Get the SDK from Blync, it's a little weird, as the old Zip file contains the new dll, for which the docs included don't apply, but honestly the SDK is so simple if you need docs, you may want to stop reading now.

Step 2. I defined a simple XAML C# app with a 75x75 screen, I thought about using a 3rd party lib to get access to toolbar icon, but wanted to do it quick and dirty.

<Window x:Class="BlyncTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="BLync" Height="75" Width="75" Loaded="Window_Loaded" WindowStyle="ToolWindow" Background="Green" Closing="Window_Closing">
<Grid>

</Grid>
</Window>


As you can see it's VERY simple, not even a control, i'll just change the window back color to match the light color, that's all.


Step 3. Add the Lync 2013 (in my case) client SDK libs as references.


Step 4. Write the code.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
//using Microsoft.Lync.Controls;
using Microsoft.Lync.Internal;
using Microsoft.Lync.Controls.Internal;
using Microsoft.Lync.Model;
using Microsoft.Lync.Model.Conversation;
using Microsoft.Lync.Model.Conversation.AudioVideo;
using Microsoft.Lync.Model.Extensibility;
using Microsoft.Lync.Model.Device;
using Microsoft.Lync.Model.Group;
using BlyncLightSDK;
using System.Windows.Threading;
using System.Threading;
namespace BlyncTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
LyncClient lc;
BlyncLightController oBlC = new BlyncLightController();
int numberOfBlync = 0;
int errors = 0;
System.Timers.Timer mt = new System.Timers.Timer();
BlyncLightController.Color currentColor = BlyncLightController.Color.Cyan;
Brush bkBrush = Brushes.Cyan;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
try
{
var desktopWorkingArea = System.Windows.SystemParameters.WorkArea;
this.Left = desktopWorkingArea.Right - this.Width;
this.Top = desktopWorkingArea.Bottom - this.Height;
}
catch { }
try
{
lc = LyncClient.GetClient();
mt.Interval = 1000;
mt.Elapsed += mt_Elapsed;
mt.Start();
lc.ConversationManager.ConversationAdded += new EventHandler<ConversationManagerEventArgs>(ConversationManager_ConversationAdded);
}
catch
{
MessageBox.Show("You should be running Lync First.");
this.Close();
}
try
{
loadBlyc();
}
catch { }
}
void ConversationManager_ConversationAdded(object sender, ConversationManagerEventArgs e)
{
try
{
if (ContainsAVCall(e.Conversation))
{
Task.Factory.StartNew(() =>
{
blinkB(BlyncLightController.Color.Blue, BlyncLightController.Speed.Fast);
Thread.Sleep(2000);
colorB(BlyncLightController.Color.Green);
});
}
}
catch { }
}
void mt_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
try
{
//reload the driver if errors have happend
if (errors > 0)
{
try
{
oBlC.CloseDevices(numberOfBlync);
}
catch { }
loadBlyc();
}

}
catch { }

try
{
//check the presence
ContactAvailability c = (ContactAvailability)lc.Self.Contact.GetContactInformation(ContactInformationType.Availability);
switch (c)
{
case ContactAvailability.Away:
colorB(BlyncLightController.Color.Yellow);
bkBrush = Brushes.Yellow;
break;
case ContactAvailability.Busy:
colorB(BlyncLightController.Color.Red);
bkBrush = Brushes.Red;
break;
case ContactAvailability.BusyIdle:
colorB(BlyncLightController.Color.Yellow);
bkBrush = Brushes.Yellow;
break;
case ContactAvailability.DoNotDisturb:
colorB(BlyncLightController.Color.Magenta);
bkBrush = Brushes.Magenta;
break;
case ContactAvailability.Free:
colorB(BlyncLightController.Color.Green);
bkBrush = Brushes.Green;
break;
case ContactAvailability.FreeIdle:
colorB(BlyncLightController.Color.Yellow);
bkBrush = Brushes.Yellow;
break;
case ContactAvailability.Invalid:
colorB(BlyncLightController.Color.Off);
bkBrush = Brushes.DimGray;
break;
case ContactAvailability.None:
colorB(BlyncLightController.Color.Green);
bkBrush = Brushes.Green;
break;
case ContactAvailability.Offline:
colorB(BlyncLightController.Color.White);
bkBrush = Brushes.White;
break;
case ContactAvailability.TemporarilyAway:
colorB(BlyncLightController.Color.Yellow);
bkBrush = Brushes.Yellow;
break;
}


this.Dispatcher.BeginInvoke((Action)delegate()
{
this.Background = bkBrush;
}, DispatcherPriority.ApplicationIdle);
}
catch { }
}
private void loadBlyc()
{
try
{
oBlC = new BlyncLightController();
numberOfBlync = oBlC.InitBlyncDevices();
errors = 0;
}
catch { }
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
try
{
mt.Stop();
mt.Dispose();
}
catch { }
try
{
oBlC.CloseDevices(numberOfBlync);
}
catch { }
}
private void blinkB(BlyncLightController.Color c, BlyncLightController.Speed s)
{
try
{
oBlC.Blink(c, s, 0);
}
catch
{
errors++;
}
}
private void colorB(BlyncLightController.Color c)
{
try
{
if (c != currentColor)
{
oBlC.Display(c, 0);
currentColor = c;
}
}
catch
{
errors++;
}
}
private bool ContainsAVCall(Conversation c)
{
try
{
//Console.WriteLine(c.Modalities[ModalityTypes.AudioVideo].State.ToString());
return c.Modalities.ContainsKey(ModalityTypes.AudioVideo) && c.Modalities[ModalityTypes.AudioVideo].State != ModalityState.Disconnected;
}
catch
{
return false;
}
}
}
}

Yep that's all folks, the program does the following;


Registers to connect to your local Lync client, so you need that running first.
Registers to connect to your blync device, so you need that connected.
Runs a timer every minute to examine your status, and change the light to the appropriate color if it's not already.
Creates an event so when a new conversion starts, it it contains audio, the light blinks blue for a second, then returns to your status color.






In conclusion, I really love the Blync device, it's a beacon even my kids can't miss. The price was fine to solve the issue I had, and with a little programming the short comings of the included software are easily overcome.


If you'd like an MSI install of this, just leave me a comment on the blog and i'll hook you up.


Doug Routledge, C# Lync, SQL, Exchange, UC Developer


10 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. I'm working on a similar item.. but with arduino and some RGB leds. I have come to the Point where i have a status, but i would like the Notification for new messages to blink like your.
    I can Catch the conversationadded and conversationremoved.. but once the conversation is idle in the background, i would like a Notification for every missed message. Like the sound that marks a new message and the Icon in the taskbar is blinking...
    Could you give a newbee some hints how to fix that?
    Found your other post, but can't figure out how to use your class https://reseller.bridgeoc.com/blog/post/popup-notification-of-new-lync-message

    ReplyDelete
  3. If you want to get notified on each new message in a conversation try something like this.

    var conversationHandler = new ConversationHandler(conversation);
    conversationHandler.MessageError += new MessageError(conversationService_MessageError);
    conversationHandler.MessageRecived += new MessageReceived(conversationService_MessageRecived);
    conversations.Add(conversationHandler);
    //starts listening to Lync events
    conversationHandler.Start();

    ReplyDelete
    Replies
    1. Yes.. i figured that out. but i don't know where to put the code?
      Inside the fired event from the
      lyncClient.ConversationManager.ConversationAdded += ConversationManager_ConversationAdded;
      or should they be anywhere.

      I get the red underline of the conversation, and conversationservice_messageerror and the other parameter. Where do they come from.. The rest i have actualy figured out :) But not this esential part.

      Delete
  4. yes add it in the ConversationAdded code.

    private void conversationService_MessageRecived(string message, string participantName,string uriname)
    {
    //blink your lights
    }

    ReplyDelete
    Replies
    1. private void ConversationManager_ConversationAdded(object sender, ConversationManagerEventArgs e)
      {
      var conversationHandler = new ConversationHandler(e.Conversation);
      conversationHandler.MessageError += new MessageError(conversationService_MessageError);
      conversationHandler.MessageRecived += new MessageReceived(conversationService_MessageRecived);
      conversations.Add(conversationHandler);
      //starts listening to Lync events
      conversationHandler.Start();
      }

      This is the routine for the new conversation. Now i understand the add conversation.. but where is the conversation service? Is that a routine that i need to create?
      New to this visaul stuff.. but not stupid :)

      Delete
    2. Sweet. Some tinkering and i got the hang of it. I now understand that i needed to create the extra subroutines to handle the messages received.

      Now i have a new question, that you might know of the back of your hand.

      When the chatwindows is in focus, like when you are in a conversation, the sound does not play. It is like the window is aware that you are looking at it.. but when the window is hidden, the sound at the computer plays.

      Is that a state that can be monitored, or can do i have to trigger the new message all the time?

      Delete
  5. I wrote a program I give away for free that can pop up on top of everything when you get a new message, and even use TTS to read the message to you. https://gallery.technet.microsoft.com/Lync-Message-Notifier-2b737ded

    ReplyDelete
  6. Well, that is basicly what i try to achive.. but in a litle more geeky style :) My colleage have a BlyncLight, so i want one custom made from scratch with arduino.
    I have managed to connect and use the serial Communication to the arduino, and i have status and message blink from your code.
    Very thankfull for the help. Now i just would like the blink to happend when i'm not in focus of the chattwindow.
    Like this event.. https://msdn.microsoft.com/EN-US/library/office/microsoft.lync.model.extensibility.conversationwindow.needsattention_di_3_uc_ocs14mreflyncwpf.aspx but as far as i can read me to it.. i need to create my own chatt window to get the Control of this window.

    As i wrote earlier.. I'm not an experienced developer.. so i don't understand the most inner parts of how the SDK connects to the client and the chat window and the event that throws the "need attantion" event..

    ReplyDelete
  7. Have you thought of adding a feature to the operator console to turn it on when on a call?

    ReplyDelete

Any spam comments will be deleted and your user account will be disabled.