Team Foundation Server controlled …ehhm… amBX lights?

Enige tijd geleden heeft mijn collega Stephan Smetsers een fraai artikel gepubliceerd om gloeilampen als stoplichten te schakelen. Maar gloeilampen zijn zo 2008, in 2010 willen we LED verlichting!

Natuurlijk kunnen we in de kerst-uitverkoopjes van een online gadget winkel enkele USB kerstboompjes uitzoeken welke met een programmaatje op het
scherm geschakeld worden, maar we willen de lat hoger leggen. Tegenwoordig heb je fraaie Ambilight flatscreens, dus waarom zouden we minder willen?

ambx lights

Toevallig heeft een Philips spin-off Ambilight naar de PC gebracht  http://www.ambx.com/ . Hierdoor is het mogelijk om het spelen van een PC spel te vervolmaken met geluid, licht, wind en trillingen. Leuk voor de kerstdagen maar als developer denken we verder!

Want toevallig is er ook een SDK beschikbaar http://developer.ambx.com/ zodat we toch niet tijdens de feestdagen uit het raam hoeven te staren. Dus wat moeten we nog snel inkopen en/of downloaden voordat de winkels dicht zijn:

Philips amBX starter kitofPhilips amBX 2.1 premium kit 25 euro bij Computerland http://www.computerland.nl/66 euro bij Paradigit http://www.paradigit.nl/
Visual Studio 2008 Express Gratis te downloaden op http://www.microsoft.com/exPress/
Een amBX Developer account Aan te maken op http://developer.ambx.com/
De amBX SDK 1.1.0 Latest release – 26th February 2009 https://developer.ambx.com/component/attachments/download/6
Een C# wrapper rond de ambxrt.dll http://grazz.com/projects/ambxlib/(of https://developer.ambx.com/forum/viewtopic.php?f=5&t=80 )

Vervolgens bouwen we drie hoofdcomponenten:

TFS Custom MsBuild Task Deze task roept de webservice methodes aan om de status van een build aan te geven. Via parameters is door te geven of een build start of stopt. Tevens is de status door te geven (niet of wel gebuild)
Webservice De webservice krijgt commando’s om de status van de build bij te
houden
WindowsService De windows service controleert regelmatig de status op de webservice en stuurt echt de lampen aan via een proxy klasse.

De webservice moet dus verschillende methodes ondersteunen:

Build X is gestart Flikkerend ambi light effecten
Build X is geslaagd Groene glow, langzaam aan en uit
Build X is niet geslaagd:  build faalde Rode glow, snel aan en uit
Wat is de status vande huidige build? Gelezen door windows service

De opstelling wordt dan als volgt:

ambx architectuur

  • De TFS server heeft de mogelijkheid om de amBX server aan te roepen via de custom MSBuild tasks.
  • De webservice op de amBX Server ontvangt de opdrachten en houdt de status (semafoor) vast.
  • Een Windows Service controleert regematig (met een timer) de build status en stuurt de lampen aan.
  • Een ontwikkelaar is verbaasd omdat zijn briljante code wel heel veel
    briljante kleuren oplevert. Zijn baas maakt een aantekening…

Maak dus eerst een build aan op de TFS Server:

TFS Build

Op de TFS kan dan de bijbehorende TFSBuild.proj aangepast worden:

<?xml version="1.0" encoding="utf-8"?>
<Project>
  <UsingTask TaskName="AmbxLighterTask.AmbxTask"
             AssemblyFile="C:\BuildOutput\AmbxLighterTaskLibrary.dll"/>
  <Target Name="BeforeEndToEndIteration">
    <AmbxLighterTask.AmbxTask
      Status="1"
      TfsAmbxWebService="htt p://AmbxServer/TfsAmbxLighter/Service.svc"
      ContinueOnError="true"/>
  </Target>
  <Target Name="AfterEndToEndIteration">
    <AmbxLighterTask.AmbxTask
      Status="2"
      TfsAmbxWebService="htt p://AmbxServer/TfsAmbxLighter/Service.svc"
      ContinueOnError="true"/>
  </Target>
  <Target Name="BeforeOnBuildBreak">
    <AmbxLighterTask.AmbxTask
      Status="3"
      TfsAmbxWebService="htt p://AmbxServer/TfsAmbxLighter/Service.svc"
      ContinueOnError="true"/>
  </Target>
</Project>

Check deze weer in als deze aangepast is.

Plaat vervolgende op de opgegeven lokatie op de TFS server de dll met
de custom MSBuild task (AmbxLighterTaskLibrary.dll)

public class AmbxTask : Task
{
  [Required]
  public string Status { get; set; }
  [Required]
  public string TfsAmbxWebService { get; set; }
  public override bool Execute()
  {
    try
    {
      SemaphoreType semaphore =
        (SemaphoreType)Convert.ToInt32(Status);
      BasicHttpBinding basicHttpBinding = new BasicHttpBinding();
      EndpointAddress endpointAddress = new
        EndpointAddress(TfsAmbxWebService);
      ChannelFactory<IService> channelFactory =
        new ChannelFactory<IService>(basicHttpBinding,
          endpointAddress);
      IService service = channelFactory.CreateChannel();
      switch (semaphore)
      {
        case SemaphoreType.BuildIsStarted:
          service.BuildHasStarted();
        break;

        case SemaphoreType.BuildIsSucceeded:
          service.BuildHasSucceeded();
        break;

        case SemaphoreType.BuildIsFailed:
          service.BuildHasFailed();
        break;
      }

      channelFactory.Close();
      return true;
    }
    catch (Exception ex)
    {
      Log.LogMessage("*** AmbxTask " + Status
          + " exception: " + ex.Message);
      return false;
    }
  }
}

In de task word een aanroep naar de AmbxServer uitgevoerd (geen extra config
nodig met WCF settings voor de connectie in dit geval).

De WCF service heeft het volgende contract:

[ServiceContract]
public interface IService
{
  [OperationContract]
  void BuildHasStarted();
  [OperationContract]
  void BuildHasSucceeded();
  [OperationContract]
  void BuildHasFailed();
  [OperationContract]
  int ShowStatus();
}

De service draait dus op de Ambx server en is stateless met uitzondering van
één STATUS waarde. Deze wordt met een WindowsService timer uitgelezen:

void _Timer_Elapsed(object sender, ElapsedEventArgs e)
{
  TfsAmbxLighterServiceReference.ServiceClient
    client =
      new TfsAmbxLighterServiceReference.ServiceClient();
  SemaphoreType semaphore = (SemaphoreType) client.ShowStatus();
  switch (semaphore)
  {
    case SemaphoreType.BuildIsStarted:
      ResetTeller();
      AmbxProxy.ShowBuilding();
    break;

    case SemaphoreType.BuildIsSucceeded:
      _Teller++;
      if (_Teller >= _IdleInterval)
      {
        if (_Teller % _IdleInterval == 0)
        {
          AmbxProxy.ShowBuildSucceed();
          break;
        }
        break;
      }
      AmbxProxy.ShowBuildSucceed();
    break;

    case SemaphoreType.BuildIsFailed:
      _Teller++;
      if (_Teller >= _IdleInterval)
      {
        if (_Teller % _IdleInterval == 0)
        {
          AmbxProxy.ShowBuildFailed();
          break;
        }
        break;
      }
      AmbxProxy.ShowBuildFailed();
    break;
  }
  client.Close();
}

En de windowsService roept du s een Proxy klasse rond de amBX api aan (met
gebruik van amBXLib van http://grazz.com/projects/ambxlib/

public class AmbxProxy
{
  public static void ShowBuildSucceed()
  {
    using (amBX engine = new amBX(1, 0, "AmbxProxy", "v1.0"))
    {
      amBXLight everyLight =
        engine.CreateLight(
          CompassDirection.Everywhere,
          RelativeHeight.AnyHeight);
      everyLight.FadeTime = 1800;
      everyLight.Color = new amBXColor(){Red=0f,Green=1f,Blue=0f};
      Thread.Sleep(1800);
      everyLight.Color = new amBXColor(){Red=1f,Green=1f,Blue=1f};
      Thread.Sleep(1800);
      everyLight.Color = new amBXColor(){Red=0f,Green=0f,Blue=0f};
      Thread.Sleep(1800);
    }
  }
}

De amBXLight instantie wordt dus steeds van een andere kleur voorzien
en de opgegeven fade krijgt de kans door de blocked call (de sleep implementatie). Het is prettig voor de gebruiker als je weer terug fade naar zwart.

Het resultaat is hier te bekijken op YouTube waarbij ik de  werking demonstreer met een laptop en een  server.

Conclusie

Voor een paar centen  heb je een hoop lol en leer je terloops ook nog iets over TFS uitrollen en  inrichten. Ook WCF Webservice, Windows Services en MSBuild komt langs. Dus je hoeft je niet te vervelen. Mocht het toch niks worden met TFS dan kun je altijd nog de kerstperiode vullen met het bijgeleverde racespel.

Prettige kerstdagen!

Update: Met TFS 2010 stapt MS over op Workflow Foundation (WF4) als build script. Hoewel bestaande MSBuild oplossingen ook nog ondersteund worden zou bij WF4 gekozen kunnen worden voor het simpel toevoegen van een SendActivity. Deze al bestaande Activity kan WCF services aanroepen. De AmbxTask verandert in een geconfigureerde activity. Dus kan gewoon de juiste methode op de http://AmbxServer/TfsAmbxLighter/Service.svc aangeroepen
worden.

Advertenties