Monitoring Local Presence Changes in Lync Client SDK
Thursday, February 18, 2016Overview
I’m giving a talk remotely today to the DFW Unified Communications Users Group on Skype for Business development and will be showing some of the code related to my simple Raspberry Pi LED Status tool. The code behind the project was thrown together in under an hour and really isn’t a great example of best practices, however, it’s a good place to get an idea about how to do some basic development with the Skype for Business Client.
In this post, I’ll go through some of the code used for that project. This post is based on the initial commit, so make sure you’re referencing that in case I’ve got the bug and decided to update it.
The Lync Client SDK
Yes, Lync. Unfortunately, it wasn’t updated for the Skype for Business release, however, it works fine with the latest client. You’ll need to be running the latest Lync 2013 client or Skype for Business client in order to use solutions developed with Lync Client SDK, however, you require no other components to actually run the program—it’s all included with the client.
References
Download the Lync Client SDK (search, I won’t provide a link due to Link Rot regularly wiping them out) and install it.
You’ll need to reference Microsoft.Lync.Model.dll and Microsoft.Lync.Utilities.dll. They’ll be located in the Office15 folder…somewhere.
A Note about Multi-threaded Code
The Lync Client SDK provides a set of APIs for interacting with the client using multi-threaded code. This means that you’re going to have to be cautious with certain operations. Many things you’ll want to work with are fired on events in a background thread and all of the perils of multi-threaded programming will apply. You’ll see a few things I’ve done to combat this, but the code in the initial commit is by no means fully audited to ensure thread-safety and a lot can go wrong in this area!
Interacting With the Lync Client
In the constructor for the Monitor class, you’ll see everything you need in order to connect to and interact with the Lync client.
// Connect to the current Lync Client m_client = LyncClient.GetClient(); var contact = m_client.Self.Contact; if (contact == null) // There's better ways to do this, but this works in a dirty implementation { SimpleLogger.Log("Client is not logged in - Setting Offline", m_gpioController.AllOff()); throw new InvalidOperationException("Client must be logged in before starting the monitor"); } // Create a subscription and subscribe to our own contact object contact.ContactInformationChanged += ContactOnContactInformationChanged; var contactSubscription = m_client.ContactManager.CreateSubscription(); contactSubscription.Contacts.Add(contact);
The connection occurs at LyncClient.GetClient(). This method will throw if the client is not launched. I chose not to catch that exception since it effectively renders the application dead.
From there, I subscribe to the ContactInformationChanged event and add a subscription to my local contact (m_client.Self.Contact). This ensures that when any property of my contact changes, the method “ContactOnContactInformationChanged” will fire (on a background thread).
When Contact Information Changes
I have a pretty simple event handler defined for that:
private void ContactOnContactInformationChanged(object sender, ContactInformationChangedEventArgs e) { if (e.ChangedContactInformation.Contains(ContactInformationType.Availability)) SetLedState(); }The "e" property lets us know what specific modification caused the event to fire. It's common for more than one thing to change at a time, but since I only care about the Availability component, I check for it and fire off "SetLedState". The changed information is not included, just the component that changed, so we have to look that up. This is done via the following in SetLedState();
var contact = m_client.Self.Contact; if (contact == null) return; object availabilityId = contact.GetContactInformation(ContactInformationType.Availability); var availability = (ContactAvailability) availabilityId;In this application, I'm only subscribing to the local contact's presence so I simply grab that contact's Contact object. Availability is an int boxed in an object, not a ContactAvailability enum as one might expect, however it's simple to just cast that to ContactAvailability for easier decoding. From there, I "switch" on the ContactAvailability and set the LEDs using the GpioController class.
What’s up With All The Interlocked Stuff in GpioController
Remember all of that multi-threaded nonsense I mentioned earlier? I implemented Blinking using a Timer, which is a class that lets you fire off a method on a background thread at a given interval. Because of this, and because our status changes come on an event handler that fires on a background thread, there’s a few members of our GpioController that could be modified by more than one thread.
Normally I’d use a lock, and that would be fine here, as well, but the requirements for this application were simply to ensure that the variable being read is the latest copy in memory. Lighter weight patterns work fine in this scenario and I use them enough that I simply go there when the kind of variable fits well.
In addition, the GpioController is disposable because that timer needs to be cleaned up. The Dispose pattern that’s commonly used is not thread-safe. I’ve included a class in the Patterns class that handles it in a thread-safe manner. There’s not going to be a case in the application, as it’s currently written, where the GpioController will be disposed on anything but the main UI thread, however, I anticipate that future changes will introduce this and I’d rather not fix that later. For the most part, you can ignore that class. If you’ve not done a lot with the Interlocked static methods, you’ll find it to be confusing.
The GpioController keeps a “current LED state” in a flags enum. Enums are effectively syntactical sugar over ints with constant fields. I developed a NuGet package that contains a number of helpers for flags enums and includes a wrapper to provide “safe” access to an enum from multiple threads, providing guarantees that when the “Value” member is set, any getters on another thread will always receive the latest value instead of what happens to be in the cache for the core your code is executing on.
The only other place that needed protection was around the blinking feature. To protect that, I used an int variable in place of a bool and Interlocked to ensure it’s updated and read properly. Let’s look at that more closely:
// Check that the light is actually blinking and set it to NOT blinking in a threadsafe manner if (Interlocked.CompareExchange(ref m_isBlinking, 0, 1) == 1) { m_timer.Change(Timeout.Infinite, -1); Thread.Sleep(m_currentBlinkInterval.Milliseconds * 2); }
The Interlocked bit serves two purposes. First, it ensures that the value of m_isBlinking is both read and written to in a manner that guarantees the latest value will be retrieved. It also ensures that if two threads hit this code at nearly exactly the same time, only one will execute the statements in the if block, modifying our timer and incurring the penalty from sleep.
What the code is actually doing is saying "read what is actually stored in m_isBlinking" and if it's set to "1", set it to "0". Then, check the value that was previously stored in m_isBlinking and continue into the body of the "if" only if the previous value of m_isBlinking was "1".
Summary
The code is pretty thoroughly commented, so I’d encourage you to look at each of the methods in each of the classes for more information. You’ll see I’ve put an event handler in for detecting power events, which is a good idea when your application is going to run on a laptop/tablet. It’ll catch the “Suspend” event and let you do anything you need to do to clean up before suspending. Beware that this code should be simple, since the machine can hit suspend before your code is finished executing. I use it to turn the LEDs off and catch the Resume to ensure the application doesn’t crash when coming back up (the Lync Client API will fire events before you can actually get at the data contained within the Contact class, but it’s easy to detect and prevent while resuming).
Making a Network Connected Raspberry Pi Display Your Presence State on LEDs
Overview
I work from home full time and at Modality, we use Skype for Business for all of our conference calls and other communications needs.
Being a work from home employee with children, particularly one who doesn’t like to lock himself in his office, I wanted a way to let my family know when I cannot be interrupted. And being a geek with geek kids, what better way to solve the problem than with legos and a Raspberry Pi?
Items Required
A Raspberry Pi – I used a Model B (non-Plus). Any Raspberry Pi model should work provided you can get it on the network somehow. These cost about USD $35.00. This would likely work with a Banana Pro, as well (about $45.00) and using that would give you wireless out-of-the-box.
A Network Connection – I purchased a RealTek WiFi+Bluetooth Adapter. Personally, I wouldn’t recommend this product since it required compiling a driver since the kernel didn’t have native support for it. Refer to the compatibility list for the least effort in getting WiFi working. If you’re using the Banana Pro, you won’t need to worry about this.
3 LEDs – Green, Yellow, Red if you want to keep with the colors that Skype for Business uses.
3 270-330 ohm resistors – one for each LED.
Wires and a Breadboard – or some other way to connect them to the GPIO pins.
Legos to build an ugly case (optional).
An SD card that works with the platform you’re using (I recommend sticking with 16GB to give you space to play around).
Setting up the Software
I won’t go into the full setup instructions for a Raspberry Pi, but you’ll want to get it up and running. I used the DietPi operating system, but this will work with Raspbian and I’d recommend using the NOOBS tool to install if you’ve not done an RPi install before.
You’ll need WebIOPi in order to interact with the GPIO via the web. This came preinstalled with DietPi.
Update the Raspberry Pi OS
I did the installation with the latest bits as of the writing of this post and it’s always a good idea to be up-to-date. You’ll want to either connect via Secure Shell (PuTTY works well for this on Windows) or plug your RPi into a display and keyboard to get a shell. Once you’ve gotten a shell up, run these commands (and grab yourself a cup of coffee).
$ sudo apt-get update $ sudo apt-get upgrade $ sudo rpi-update
Configure WebIOPi
The GPIO pins aren’t configured the way we need them to be, yet, so we’ll edit the WebIOPi configuration to get that going.
$ sudo nano /etc/webiopi/config
Nano is a simple console text editor. Locate the heading labeled [GPIO] (hint: CTRL+W can be used to find text in Nano, however, GPIO should be at the top). Anything with a “#” in front of it is ignored (a comment). The configuration under GPIO is “PIN = DIRECTION STATE”. If you have 17, 18 and 27 already setup in some way, you’ll want to modify those lines. If they are not configured at all, you can simply add the following lines.
17 = OUT 0 18 = OUT 0 27 = OUT 0
Locate the [HTTP] heading and make sure it is setup as follows
[HTTP] # HTTP Server configuration enabled = true port = 8000 # File containing sha256(base64("user:password")) # Use webiopi-passwd command to generate it passwd-file = /etc/webiopi/passwd # Change login prompt message prompt = "WebIOPi"
Locate the [REST] heading and make sure it is setup as follows
[REST] # By default, REST API allows to GET/POST on all GPIOs # Use gpio-export to limit GPIO available through REST API gpio-export = 17, 18, 27 # Uncomment to forbid changing GPIO values #gpio-post-value = false # Uncomment to forbid changing GPIO functions #gpio-post-function = false # Uncomment to disable automatic device mapping #device-mapping = false
The rest should be fine as is. Hit CTRL+X and choose “Yes” to save the file. Finally, we’ll setup a user/password that will let us authenticate.
sudo webiopi-passwdSet up an ID and password of your choosing.
Wiring it up
The wiring for the project is pretty simple. Here’s a diagram that explains how to set everything up. Make sure your resistors are wired correctly! I’m not an EE guy, but in my reading the warnings indicated that failing to install resistors or using the wrong resistors will result in damaging the Raspberry Pi.
It’s also important to note that LEDs are one-way devices. If you install them backward you won’t break anything, but they won’t light up (which is the first thing to check if your tests don’t work).
That’s the GPIO arrangement of a B (non plus version).
That’s it, you’re ready for the code.
On Your Windows Box
The code is client-side, so it won’t work if your PC is turned off or asleep, but it’s the easiest way to do it and doesn’t require administrator privileges on the Skype for Business server as would be if we’d done this with the Unified Communications Managed API (though it can be done with a bit more work that way).
You can get the source code from the GitHub Repo. I’ll provide a compiled version, but because the software is very hastily designed, you’ll need to build it yourself. You can download Visual Studio 2015 Community Edition to compile the project.
Running the Application
Hit Win+R and type CMD. Go to the folder that the application compiled to (usually ProjectName\bin\Debug) and run:
Cs-WebIoPi <IPADDRESS> <PORT> <USERID> <PASSWORD> --test
If you’ve configured it following this gude, you’ll put “8000” for the port. When started in “Test” mode, it’ll blink all of the LEDs and cycle through each one so that you can verify your wiring. Fix any wiring issues and when you’re all set, run it with the same command above but without the “test”.
HOWTO: Build the RTL8723BU for Raspbian (Raspberry Pi Model B)
Saturday, February 6, 2016UPDATE: The HubPiWi Blue includes this chipset and the instructions for that also work with the USB dongle. I've provided an updated set of instructions here that are a bit simpler and are targetted at Raspbian Jessie. You should use those, instead.
I recently started getting my second RPi setup, only on this one I wanted to use a dual WiFi/Bluetooth USB dongle. I picked a device based on the Realtek RTL8723BU after reading a few posts indicating success. Unfortunately, it doesn’t work “out-of-the-box” with Raspbian Wheezy on Kernel 4.1.13.
Before we Proceed
I’ve been tinkering with RPi’s for a little bit, but I’m by no means an expert. If there are obvious problems with the steps I’m doing here, kick me a comment and I’ll correct them. This worked for me. It might not work for you. I’m assuming you’re on 4.1.13+ installed via NOOBS and you haven’t added/changed much up to this point. If you have, some of the steps (like removing the build/src folder) might already have things in them that you don’t want to lose, so exercise some discretion before running each command. And, of course, this comes with NO WARRANTY expressed or implied – use at your own risk, my friend.
What You’ll Need
Besides the hardware, you’ll need a wired or working wireless connection (using a device other than the one we’re building a module for).
If you’ve done the Raspbian install from NOOBS, you should have all of the necessary packages required to build the driver. If you haven’t, you might need to apt-get build-essential and others that I’m not entirely sure of.
Overview
We’ll update the system, clone the git repo for the driver, download the kernel source, set up the build environment, and build the driver.
I’ll also provide the steps I took to get the miserable thing to actually work!
Let’s Get To It
To get this going, you’ll need the kernel source and it’s probably a good idea to make sure you’re all up to date.
apt-get update apt-get upgrade dist-upgrade reboot
You can go run some errands during the dist-upgrade, it took over an hour for me.
To start, get the latest drivers
cd ~/ git clone https://github.com/lwfinger/rtl8723bu.git
If you’ve installed from NOOBS (as I did), at this point, you’re not going to be able to make the driver. You need the kernel headers for the kernel you’re running. Normally, apt-get install linux-headers or something along those lines would do the trick. Not this time.
Unfortunately, when I wrote this, the linux headers for the version of the kernel used by Raspbian, 4.1.13+, were not available from aptitude. After some searching, I found a downloadable debian package that works.
wget https://www.niksula.hut.fi/~mhiienka/Rpi/linux-headers-rpi/linux-headers-4.1.13%2B_4.1.13%2B-2_armhf.deb sudo dpkg –i ./linux-headers-4.1.13+-2_armhf.deb
If you lack one or more of the dependencies, install them with apt-get install <dependency>, then apt-get –f install which will finish up the installation of the headers.
Modifying the Makefile for Raspbian
We’ll need to tweak the Makefile for the driver to build properly. I’m not sure that all of this needs to be added – I grabbed it from several google searches. But, hey, it worked, so here’s what I changed.
nano Makefile
Hit CTRL+W and type “CONFIG_PLATFORM_I386_PC =” and hit Enter. Set it to “n”. Add a line below it and type “CONFIG_RASPBIAN = y”.
Hit CTRL+W and type “ifeq ($(CONFIG_BT_COEXIST)” and hit Enter. Insert the following text above that line.
ifeq ($(CONFIG_RASPBIAN), y) EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 EXTRA_CFLAGS += -DRTW_USE_CFG80211_STA_EVENT # only enable when kernel >= 3.2 EXTRA_CFLAGS += -DCONFIG_P2P_IPS ARCH := arm CROSS_COMPILE := arm-linux-gnueabihf- KVER := $(shell uname -r) KSRC ?= /lib/modules/$(KVER)/build MODULE_NAME := 8723bu MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ endif
Hit CTRL+X then “Y” to save the file.
Build It
sudo –i cd /home/pi/rtl8723bu make && make install
That part took almost an hour on my RPi Model B.
Making It Work
Well, at this point, you can just reboot. But if you want to test prior to rebooting, run the following:
insmod 8723bu.ko ifconfig
You should now see “wlan0” among the network adapters!
HowTo: Keep the factory image from booting after you’ve upgraded to DD-WRT
Thursday, February 4, 2016So you’ve upgraded your WRT1900AC router (or other similarly designed router) to DD-WRT and it’s humming along fine, or maybe you’ve done the upgrade and then followed it up with a 30-30-30 reset and suddenly you’re back to the original Linksys Firmware! Gah, lousy downgrading $#!+!
What’s happening
Linksys routers used to be a popular choice for running DD-WRT back in the days when the vendors were far less happy with you replacing their buggy, insecure firmware with something open and customizable. Rather than taking the approach of keeping you from replacing their firmware, lately they’ve gone the route of keeping you from breaking your device should you choose to hack around with DD-WRT.
They used to do this by providing a “failsafe” mode that provided an extremely limited, but “possible to fix” mode that would leave you carefully timing a TFTP upload during the first two seconds of boot (this still exists, I believe). Many-a-panicked afternoons were spent in this home praying my $150 router didn’t just turn into a doorstop because of this. They’ve gotten way better since. Your flash memory is split into two partitions, only one of which has the currently running firmare. The other has the last version of the firmware that you successfully installed. When you upgrade, it replaces the unused partition and changes an NVRAM value to tell the bootloader to use the other partition for subsequent boots.
Hopefully no more TFTP adventures, but it comes at a small cost. Should something bad enough happen, or should you do a “factory reset”, you’re likely going to end up booting the other partition – the one you were trying to get away from.
Making the install a little more Undo Proof
If you’ve followed the installation guides to the letter, you probably did what I did. Upgraded, reboted and then did a 30-30-30 factory reset. I’m not sure if it’s the timing of *when* you do the 30-30-30 or just doing the 30-30-30 that causes it, but the boot partition ends up flipping right back to the original firmware.
I think I ended up doing the 30-30-30 during the boot-up process into the new firmware which, I’m guessing, caused the boot to fail and reverted me back to the last version. I’m honestly not sure, but after that happened, I simply skipped the 30-30-30 until I finished the next step.
Install DD-WRT … Twice
Yup. Simply installing one SVN version out of date, then the latest SVN version (you might even be able to install the latest on both, but I didn’t try it), ensured that I had both partitions on DD-WRT. After that, I did a factory reset through the web interface (which didn’t take me to the backup partition, incidentally) and I was ready to go with a fresh router that can’t fallback to the factory image.
This doesn’t solve everything, unfortunately, because there are aparently other reasons it may decide to toss you into the backup partition. In my case, it looks like a failed boot might have caused it to revert the second and third times. But once you have DD-WRT installed, you can drop to SSH and run nvram get bootpartition, and simply set it to the other one via nvram set bootpartition. That’s a heck of a lot easier than redoing the upgrade during the rare times this might happen.