Connectivity

Open the Box Workshop

Device management

Table of contents

1 ZigBee
2 EnOcean
3 Philips Hue
4 SimpleBee
5 Develop a new Base Driver

This document presents the wireless technologies handled by the Open the Box infrastructure. A base driver is dedicated for each of them. This page gives details about:

  • The required Maven dependencies.
  • Declarative Service references to require OSGi services representing devices.
  • Some piece of Java code showing how to send commands and retrieve data from the devices.

The ZigBee section proposes a tutorial describing a fully operational Open The Box application using ZigBee devices.

1 ZigBee

The ZigBee tutorial is available here.

2 EnOcean

EnOcean is a wireless protocol used in smart home and building markets. This is a very low power technology, some devices are powered without any battery. The EnOcean base driver is open source. Code and documentation are available on the Eclipse smarthome’s github.

2.1 Enocean devices described in this tutorial

Eltako smoke detector Temperature sensor plug on/off
smoke detector Temperature sensor plug on/off

the smoke detector and the temperature sensor will be automatically detected as they send data periodically whereas the plug need to be paired, as no data are sent and use on/off command

2.2 Paring

the plug on/off needs to be paired as all EnOcean devices with commands need to.
To enter in the pairing mod, press the button during 5 seconds. The plug should switch between on and off every second during 30 seconds. Be aware that there are many ways to enter in the pairing mod according to the Enocean device.
Now the base driver should send a paraing frame, it’s not automatic tough. That means you have to code this action in your application (ie coding a command sending) and then send the pairing frame manually via your application.

2.3 Maven

Let’s talk about the code now.
The following Maven dependency must be added into the POM of your Open the Box application:

<dependency>
   <groupId>org.osgi</groupId>
   <artifactId>org.osgi.service.enocean</artifactId>
   <scope>system</scope>
   <version>6.0.0</version>
   <systemPath>${basedir}/lib/org.osgi.service.enocean-1.0.0.jar</systemPath>
</dependency>

2.4 Declarative Services

Declarative Services are used to declare the EnOcean reference. In the application code, the file can be found at : “src/main/resources/OSGI-INF/component-devices.xml”

<reference name="enoceanDevice" cardinality="0..n" policy="dynamic"
   interface="org.osgi.service.enocean.EnOceanDevice"
   bind="setEnoceanDevice" unbind="unsetEnoceanDevice" />
// target="”(DEVICE_FRIENDLY_NAME=an EnOcean device)"

2.5 Java Code

   private List<EnOceanDevice> enOceanDevices;
   public void setEnoceanDevice(EnOceanDevice device) {
      if (! enOceanDevices.contains(device)) {
         enOceanDevices.add(device);
      }
   }

The following piece of code shows how to print out properties when a EnOcean binding occurs:

   public void setEnoceanDevice(EnOceanDevice device,Map properties) {
      if (! enOceanDevices.contains(device)) {
         enOceanDevices.add(device);
      }
	    Set set = properties.entrySet();
        Iterator it =  set.iterator();
        while (it.hasNext()) {
            Entry entry = (Entry) it.next();
            Object key = entry.getKey();
			Object value = entry.getValue();
             System.out.println(TAG, key + ", property (" + key 
               + "): " + value);
            System.out.println(TAG, "(" + value + ").getClass().getName()"
               + value.getClass().getName());           
        }
   }

2.6 Eventing

EnOcean payloads (sent by devices) are read through the eventing mechanism (OSGi EventAdmin), therefore they can be retrieved by registering an org.osgi.service.event.EventHandler OSGi service. EventHandler.handleEvent(Event event) is called by the EnOcean base driver when a new payload is received.

2.6.1 Enocean Equipment Profiles (EEP)

An Enocean Equipment Profile defines the type of a device and therefore how to communicate with it.
The EEP specification document can be found here.

2.6.2 Temperature Sensor

Here is a code example to handle a EnOcean temperature sensor:

public void handleEvent(Event event) {   
   System.out.println(TAG, "> handleEvent(event: " + event);
   String[] pns = event.getPropertyNames();
   for (int i = 0; i < pns.length; i++) {
      System.out.println(TAG, "pns[" + i + "]: " + pns[i] + ", event.getProperty(" + pns[i] + "): "          
         + event.getProperty(pns[i]));
// pns[0]: enocean.device.profile.func, event.getProperty(enocean.device.profile.func): 2 
// pns[1]: enocean.device.profile.rorg, event.getProperty(enocean.device.profile.rorg): 165 
// pns[2]: enocean.device.chip_id, event.getProperty(enocean.device.chip_id): 8969457 
// pns[3]: enocean.device.profile.type, event.getProperty(enocean.device.profile.type): 5 
// pns[4]: enocean.message, event.getProperty(enocean.message): a5000035080088dcf100 
// pns[5]: event.topics, event.getProperty(event.topics): org/osgi/service/enocean/EnOceanEvent/MESSAGE_RECEIVED    
   }    
   String topic = event.getTopic();    
   if (topic.equals(EnOceanEvent.TOPIC_MSG_RECEIVED)) {
      String chipId = (String) event.getProperty(EnOceanDevice.CHIP_ID);       
      String rorg = (String) event.getProperty(EnOceanDevice.RORG);       
      String func = (String) event.getProperty(EnOceanDevice.FUNC);       
      String type = (String) event.getProperty(EnOceanDevice.TYPE);       
      EnOceanMessage data = (EnOceanMessage) event.getProperty(EnOceanEvent.PROPERTY_MESSAGE);       
      String displayId = Utils.printUid(Integer.parseInt(chipId));       
      String profile = rorg + "/" + func + "/" + type;       
      System.out.println(TAG, "> MSG_RECEIVED event : sender=" + displayId + ", profile = '" + profile + "'");
      System.out.println(TAG, "Try to identify the device that has sent the just received event (e.g. is it an A5-02-05 device - a temperature sensor range 0°C to +40°C ?).");
      if ("165".equals(rorg)) {
         // hex 0xa5 == int 165.
         if ("2".equals(func)) {
            if ("5".equals(type)) {
               System.out.println(TAG, "This event has been sent by an A5-02-05 device.");
               System.out.println( TAG, "The end of page 12, and the beginning of page 13 of EnOcean_Equipment_Profiles_EEP_V2.61_public.pdf specifies how to get the temp°C value starting from an EnOcean telegram.");
               // propertyNames[4]: enocean.message, event.getProperty(propertyNames[4]): a5000035080088dcf100
               byte[] payload = data.getPayloadBytes();
               System.out.println(TAG, "payload: " + payload + ", payload.length: " + payload.length);
               for (int j = 0; j < payload.length; j++) {
                  System.out.println(TAG, "payload[" + j + "]: " + payload[j]);
               }
               byte rawTemperatureDB1InHexAsAByte = payload[2];
               float rawTemperatureDB1InNumberAsADouble = rawTemperatureDB1InHexAsAByte;
               System.out.println(TAG, "rawTemperatureDB1InNumberAsADouble: " + rawTemperatureDB1InNumberAsADouble);
               if (rawTemperatureDB1InNumberAsADouble < 0) {
                  System.out.println(TAG, "rawTemperatureDB1InNumberAsADouble is negative, so let's convert rawTemperatureDB1InNumberAsADouble to unsigned 0..255 value instead of -127..128 one.");
                  rawTemperatureDB1InNumberAsADouble = rawTemperatureDB1InNumberAsADouble * -1
                     + 2 * (128 + rawTemperatureDB1InNumberAsADouble);
                  System.out.println(TAG, "rawTemperatureDB1InNumberAsADouble: "
                     + rawTemperatureDB1InNumberAsADouble);
               } else {
                  System.out.println(TAG, "rawTemperatureDB1InNumberAsADouble is positive, everything is ok.");
               }
               // Now let's apply the formula: (rawTemperatureDB1InNumberAsADouble-255)*-40/255+0 = temp in celsius.
               double tempInCelsius = (rawTemperatureDB1InNumberAsADouble - 255) * -40 / 255 + 0;
               System.out.println(TAG, "tempInCelsius: " + tempInCelsius);
            } else {
               System.out.println(TAG, "This event has NOT been sent by an A5-02-05 device. TYPE is NOT equal to 5.");
            }
         } else {
            System.out.println(TAG, "This event has NOT been sent by an A5-02-05 device. FUNC is NOT equal to 2.");
         }
      }
   }
}

2.6.3 Smoke Detector

Example with an Eltako detector:

   if ("246".equals(rorg)) {
	  // the rorg in the Enocean terminology defines the type of the device.
	  // the Enocean profile specification lists all the existing rorgs in hexadecimal
      // suppose Eltako Detector
	
      byte[] payload = data.getBytes();
      if (payload[1] == 0x10) {
         System.out.println("fire");
         handleFire(chipId);
      } else if (payload[1] == 0x00) {
         System.out.println("normal situation");
         handleNormalSituation(chipId);
      }
   }

2.7 Command Invoking

It is also possible to send payloads to EnOcean devices through the base driver, like sending an ON command to a plug.

Invoking a command is simply sending a frame hardcoded in the base driver.
For that you need to get the device on which you want to send the frame, create an RPC and just use the method invoke. The RPC object contains the type of frame you want to send. You can create hardcoded RPC class for each frame or create a custom RPC class as follows:

public class CustomEnoceanRPC implements EnOceanRPC {
	
   //let's define here all the frames supported by the base driver. from now they are hardcoded as is:
   
   public static String APPAIR_FRAME="HARDCODED_UTE_APPAIR";
   // 55 00 0D 07 01 FD D4 D2 01 08 00 3E FF 91 00 00 00 00 00 03 01 85 64 14 FF 00 E9
	
   public static String ON_FRAME="HARDCODED_VLD_TURN_ON";
   // 55 00 09 07 01 56 D2 01 00 01 00 00 00 00 00 03 01 85 64 14 FF 00 64
	
   public static String OFF_FRAME="HARDCODED_VLD_TURN_OFF";
   // 55 00 09 07 01 56 D2 01 00 00 00 00 00 00 00 03 01 85 64 14 FF 00 F0
	
   public static String PTM210_APPAIR_FRAME="HARDCODED_APPAIR_TURN_ON";
   // 55 00 07 07 01 7A F6 50 00 29 21 9F 30 01 FF FF FF FF 31 00 37
   //PTM210 represents a classical Enocean switch, the frame on is also considered as a pairing one.
	
   public static String PTM210_ON_FRAME="HARDCODED_APPAIR_TURN_ON";
   // same frame as above.
	
   public static String PTM210_OFF_FRAME="HARDCODED_TURN_OFF";
   // 55 00 07 07 01 7A F6 70 00 29 21 9F 30 01 FF FF FF FF 2D 00 62
   //the switch frame off
	
   private String frame;
   private int senderId = 0x00000000;
	
   public CustomEnoceanRPC(String frame) {
      this.frame = frame;
   }

   public void setSenderId(int chipId) {
      this.senderId = chipId;
   }

   public int getSenderId() {
      return senderId;
   }

   public byte[] getPayload() {
      return null;
   }

   public int getManufacturerId() {
      return -1;
   }

   public int getFunctionId() {
      return -1;
   }

   public String getName() {
      // TODO Auto-generated method stub
      return frame;
   }
}

Method to invoke a command:

   public void invokeFrame(EnOceanDevice eod, String FrameName) {

      // Let's create an enoceanrpc in order to pair with the plug.
      EnOceanRPC appairRPC = new CustomEnoceanRPC(FrameName);
      EnOceanHandler handlerTurnOnRpc = new EnOceanHandler() {
         public void notifyResponse(EnOceanRPC enOceanRPC, byte[] payload) {
            System.out.println( "enOceanRPC: " + enOceanRPC + ", payload: " + payload);
         }
      };

      if (eod == null) {
         System.out.println("There is no EnOceanDevice --> So no invocation is possible.");
      } else {
         System.out.println("There is an EnOceanDevice --> So invocation is possible.");

         eod.invoke(appairRPC, handlerTurnOnRpc);

      }

   }

Method to invoke a OFF command:

invokeFrame(device, CustomEnoceanRPC.PTM210_OFF_FRAME);

3 Philips Hue

Hue Lights can be remotely set (intensity, color, blinking mode). They are accessible through the Hue Bridge (ZigBee Light Link). The Hue Base Driver is packaged as a bundle and reify as an OSGi service the Hue Bridge as well as the Hue Lights.

3.1 Maven

Maven dependency to be added to the pom file:

<dependency>
   <groupId>com.orange.openthebox.hab</groupId>
   <artifactId>hue.basedriver</artifactId>
   <version>1.0.3-SNAPSHOT</version>
   <scope>compile</scope>
</dependency>

The Hue Base Driver depends on the hue.controller bundle which handles the communication with the bridge (through its REST interface).

3.2 Declarative Services

<reference name="hueBridge" cardinality="1..1" policy="dynamic"
   interface="com.orange.openthebox.hab.HueBridgeDevice"
   bind="setHueBridge" unbind="unsetHueBridge" />

<reference name="hueLight" cardinality="0..n" policy="dynamic"
   interface="com.orange.openthebox.hab.HueLightDevice"
   // target=”(DEVICE_FRIENDLY_NAME=Hue Lamp *)”
   bind="setHueLight" unbind="unsetHueLight" />

The HueBridge service is used to set a group of Hue Lights. Once created, it is possible to set a common configuration to all Hue Lights belonging to the group.

3.3 Java code

   private List<HueLightDevice> lights;
   public void setHueLight(HueLightDevice light) {
      if (!lights.contains(light)) {
         lights.add(light);
      }
   }

   HueLightDevice light = lights.get(0);
   light.setState(true, 255, 0, 46920, 0, 1);

The HueLightDevice.setState(boolean on, int brightness, int saturation, int hue, int effect, int alert) configured the following properties of the Hue Light:

  • on/off switching
  • luminosity/intensity (value between 0 and 255; or -1 : no changes)
  • saturation (value between 0 (white) and 255, or -1: no changes)
  • color in hexadecimal (value between 0 to 65535, or -1: no changes). For instance, yellow : 12750, light green : 25500, dark green : 36210, blue : 46920, purple : 56100, red : 65280
  • the Hue effect (0: no effect, 1 : color loop)
  • the alert mode (0: no effect, 1 : one breathe cycle, 2 : a breathe cycle each single 30s)

The HueBridgeDevice class handles group of Hue lights and provides the following effects:

  • setWakeUp : turns on the lights, white color, medium brightness
  • setMeal : turns on the lights, light orange color, medium brightness
  • setNight : turns off the lights
  • setHomeCinema : turns on the lights, red color, low brightness
  • setParty : turns on the lights, color loop effect, low brightness

4 SimpleBee

Here is the SimpleBee tutorial.

5 Develop a new Base Driver

See the page Develop a new Base Driver.