Interfacing our devices using XMPP

XMPP is already implemented and supported through the Clayster.Metering.Xmpp module that we mentioned earlier. This module models each entity in XMPP as a separate node in the Topology data source. Connections with provisioning servers and thing registries are handled automatically through separate nodes dedicated to this task. Friendships are handled through simple child creation and removal operations. It can be done automatically through requests made by others or recommendations from the provisioning server, or manually by adding friends in the CMT. All we need to do is provide specialized classes that override base class functionality, and add specific features that are needed.

Creating a class for our sensor

In our project, we will create a class for managing our sensor. We will derive it from the XmppSensor class defined in Clayster.Metering.Xmpp and provide the required default constructor through the following code:

public class Sensor : XmppSensor
{
  public Sensor()
  {
  }

Each class managed by Clayster.Library.Abstract, such as those used by the Topology data source, must define a TagName and a Namespace property. These are used during import and export to identify the class in question as follows:

public override string TagName
{
  get { return "IoTSensor"; }
}

public override string Namespace
{
  get { return "http://www.clayster.com/learningiot/"; }
}

We must also provide a human readable name to the class. Whenever objects of this class are displayed, for instance in the CMT, it is this human readable name that will be displayed, as shown in the following code:

public override string GetDisplayableTypeName (Language UserLanguage)
{
  return "Learning IoT - Sensor";
}

Finding the best class

When the system finds a new device, it needs to know which class best represents that device. This is done by forcing each XMPP device class to implement a Supports method that returns to which degree the class handles said device, based on features and interoperability interfaces reported by the device. The class with the highest support grade is then picked to handle the newly found device.

By using the following code, we will override this method to provide a perfect match when our sensor is found:

public override SupportGrade Supports (
  XmppDeviceInformation DeviceInformation)
{
  if (Array.IndexOf<string> (
    DeviceInformation.InteroperabilityInterfaces,
    "Clayster.LearningIoT.Sensor.Light") >= 0 &&
    Array.IndexOf<string> (
    DeviceInformation.InteroperabilityInterfaces,
    "Clayster.LearningIoT.Sensor.Motion") >= 0) 
    {
    return SupportGrade.Perfect;
    }
  else
    return SupportGrade.NotAtAll;
}

Subscribing to sensor data

Manual readout of the sensor is already supported by the XmppSensor class. This means you can already read data from the sensor from the CMT, for instance, as it is. However, this is not sufficient for our application. We want to subscribe to the data from the sensor. This subscription is application-specific, and therefore must be done by us in our application. We will send a new subscription every time the sensor reports an online or chat presence. The XmppSensor class will then make sure that the subscription is sent again if the data is not received accordingly. The subscription call is similar to the one we did in the previous chapter. The subscription call is sent using the following code:

protected override void OnPresenceChanged (XmppPresence Presence)
{
  if (Presence.Status == PresenceStatus.Online ||
  Presence.Status == PresenceStatus.Chat) 
  {
    this.SubscribeData (-1, ReadoutType.MomentaryValues,
      new FieldCondition[] {
        FieldCondition.IfChanged ("Temperature", 0.5),
        FieldCondition.IfChanged ("Light", 1),
        FieldCondition.IfChanged ("Motion", 1)
      }, null, null, new Duration (0, 0, 0, 0, 1, 0), true, 
    this.NewSensorData, null);
  }
}

Interpreting incoming sensor data

Interpreting incoming sensor data is done using the Clayster platform in a way that is similar to what we did using the Clayster.Library.IoT library in the previous chapters. We will start by looping through incoming fields:

private void NewSensorData (object Sender, SensorDataEventArgs e)
{
  FieldNumeric Num;
  FieldBoolean Bool;
  double? LightPercent = null;
  bool? Motion = null;

  if(e.HasRecentFields)
  {
    foreach(Field Field in e.RecentFields)
    {
      switch(Field.FieldName)
      {

There is one added advantage of handling field values when we run them on the Clayster platform: we can do unit conversions very easily. We will illustrate this with the help of an example, where we handle the incoming field value - temperature. First, we will try to convert it to Celsius. If successful, we will report it to our controller application (that will soon be created):

case "Temperature":
  if ((Num = Field as FieldNumeric) != null)
  {
    Num = Num.Convert ("C");
    if (Num.Unit == "C")
    Controller.SetTemperature (Num.Value);
  }
  break;

Tip

There is a data source dedicated to unit conversion. You can create your own unit categories and units and determine how these relate to a reference unit plane, which is defined for each unit category. Unit conversions must be linear transformations from this reference unit plane.

We will handle the Light and Motion values in a similar way. Finally, after all the fields have been processed, we will call the Controller application and ask it to check its control rules:

    if (LightPercent.HasValue && Motion.HasValue)
      Controller.CheckControlRules (
      LightPercent.Value, Motion.Value);
  }
}

Our Sensor class will then be complete.

Creating a class for our actuator

If implementing support for our Sensor class was simple, implementing a class for our actuator is even simpler. Most of the actuator is already configured by the XmppActuator class. So, we will first create an Actuator class that is derived from this XmppActuator class. We will provide it with a TagName that will return "IoTActuator" and the same namespace that the Sensor class returns. We will use Learning IoT – Actuator as a displayable type name. We will also override the Supports method to return a perfect response when the corresponding interoperability interfaces are found.

Customizing control operations

Our Actuator class is basically complete. The XmppActuator class already has support for reading out the control form and publishing the available control parameters. This can be tested in the CMT, for instance, where the administrator configures control parameters accordingly.

To make control of the actuator a bit simpler, we will add customized control methods to our class. We already know that the parameters exist (or should exist) since the corresponding interoperability interfaces (contracts) are supported.

We will begin by adding a method to update the LEDs on the actuator:

public void UpdateLeds(int LedMask)
{
  this.RequestConfiguration ((NodeConfigurationMethod)null, "R_Digital Outputs", LedMask, this.Id);
}

The RequestConfiguration method is called to perform a configuration. This method is defined by Clayster.Library.Meters namespace, and can be called for all configurable nodes in the system. Configuration is then performed from a context that is defined by the node. The XmppActuator class translates this configuration into the corresponding set operation, based on the data type of the parameter value.

The first parameter contains an optional callback method that is called after the parameter has been successfully (or unsuccessfully) configured. We don't require a callback, so we will only send a null parameter value. The second parameter contains the name of the parameter that needs to be configured. Local configurable parameters of the XmppActuator class differ from its remote configurable parameters, which are prefixed by R_. The third parameter value is the value that needs to be configured. The type of value to send here depends on the parameter used. The fourth and last parameter is a subject string that will be used when the corresponding configuration event is logged in the event log.

Tip

You can find out which configurable parameters are available on a node by using the CMT.

In a similar fashion, we will add a method for controlling the alarm state of the actuator and then our Actuator class will be complete.

Creating a class for our camera

In essence, our Camera class does not differ much from our Sensor class. It will only have different property values as well as a somewhat different sensor data subscription and field-parsing method. Interested readers can refer to the source code for this chapter.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.99.71