appicals unter Java

appicals-kompatible Geräte können in verschiedenen Programmiersprachen erstellt werden. Wir stellen eine Implementierung für Java inklusive Quellcode unter Downloads zur Verfügung. Auf dieser Seite wird gezeigt, wie man eigene Geräteklassen oder Dienste definiert, wobei letzteres nur in Ausnahmefällen gebraucht wird.

Für das Nachstellen benötigt man Eclipse in der aktuellsten Version und ein Java Development Kit, vorzugsweise in Version 7 oder 8. Dieses kann man bei Oracle herunterladen.

Eigene Dienste definieren

Basis aller appicals-Geräte sind Services bzw. Dienste. Der vordefinierte DigitalInput-Service sieht im Java-Framework z.B. folgendermassen aus:

public class SCFServiceDigitalInput extends SCFDeviceService
{
  public SCFServiceDigitalInput(SCFDevice device)
  {
    super(device, SCFConstants.ServiceTypeDigitalInput, SCFConstants.ValueTypeBoolean, true);
    setVersion(0x10);
    value.setBooleanValue(false);
  }
}

Die Definition des SensorInput-Dienstes sieht in Java so aus (gekürzt)

public class SCFServiceSensorInput extends SCFDeviceServiceComposite
{

  private long minLimit        = 0;

  private long maxLimit        = 0;

  private long currentValue    = 0;

  private int  sensorValueType = SCFConstants.ValueTypeUINT8;
 
...

  /**
   * Creates a sensor input service that represents a used or available storage space, e.g., on a
   * database or hard disk.
   * 
   * 
   * @param device
   * @param name
   * @return
   */
  public static SCFServiceSensorInput createStorageService(SCFDevice device,
    int serviceTag)
  {
    SCFServiceSensorInput result =
      new SCFServiceSensorInput(device, serviceTag);

    result.getValue()
      .setCompositePartedValueList(SCFCompositeServiceDefinitions.SensorInputCompositePartListStorage);
    result.setSensorValueType(SCFConstants.ValueTypeUINT32);

    result.getValue().setNumericValue(0);
    result.setMinLimit(0);
    result.setMaxLimit(1000000);

    result.getValue().setCompositeRawValue(result.getCompositeServiceValue());

    return result;
  }

  /**
   * Creates a new instance of SCFSensorInputService.
   * 
   * @param device
   * @param name
   * @param serviceTag
   * @param valueType
   */
  public SCFServiceSensorInput(SCFDevice device, int serviceTag)
  {
    // use type also as ID
    super(device, SCFConstants.ServiceTypeSensorInput, true);
    this.serviceTag = serviceTag;

    setVersion(0x10);

    value.setCompositeRawValue(getCompositeServiceValue());
  }

  /* (non-Jsdoc)
   * @see de.alexanderkoenig.scf.core.device.SCFDeviceService#getCompositeServiceValue()
   */
  public byte[] getCompositeServiceValue()
  {
    ByteArrayOutputStream resultStream = new ByteArrayOutputStream();
    try
    {
      if (sensorValueType == SCFConstants.ValueTypeINT16)
      {
        resultStream.write(ByteArrayHelper.int16ToByteArray((short)currentValue));
        resultStream.write(ByteArrayHelper.int16ToByteArray((short)minLimit));
        resultStream.write(ByteArrayHelper.int16ToByteArray((short)maxLimit));
      }
      if (sensorValueType == SCFConstants.ValueTypeUINT16)
      {
        resultStream.write(ByteArrayHelper.uint16ToByteArray((short)currentValue));
        resultStream.write(ByteArrayHelper.uint16ToByteArray((short)minLimit));
        resultStream.write(ByteArrayHelper.uint16ToByteArray((short)maxLimit));
      }
      if (sensorValueType == SCFConstants.ValueTypeUINT32)
      {
        resultStream.write(ByteArrayHelper.uint32ToByteArray(currentValue));
        resultStream.write(ByteArrayHelper.uint32ToByteArray(minLimit));
        resultStream.write(ByteArrayHelper.uint32ToByteArray(maxLimit));
      }
    } catch (Exception e)
    {

    }
    return resultStream.toByteArray();
  }

 ... 
 
}
Eigene Geräte definieren

Dienste werden in Geräten zusammengefasst. Ein Gerät stellt eine physikalische oder logische Einheit dar. Ein Lichtschalter hätte z.B. einen DigitalInput-Dienst, dazu können optionale Dienste kommen wie ServiceManagement, Identification, usw.. Die Gerätedefinition sähe im Java-Framework folgendermassen aus:

	
public class SCFDiskUsageDevice extends SCFManageableDevice
{
  private List diskUsageServiceList;

  private List diskLetterList;

  private long lastCheck = 0;

  /**
   * Creates a new instance of SCFDiskUsageDevice.
   */
  public SCFDiskUsageDevice(SCFTemplateEntity entity, long deviceID, String name, int locationID)
  {
    super(entity, deviceID, name, SCFConstants.DeviceTagPC, locationID);

  }

  /* (non-Javadoc)
   * @see de.alexanderkoenig.scf.core.device.SCFManageableDevice#initDeviceContent()
   */
  public void initDeviceContent()
  {
    super.initDeviceContent();

    diskUsageServiceList = new ArrayList();
    diskLetterList = new ArrayList();

    // add services
    String disks = getEntity().getStartupConfiguration().getProperty("Drives", "C;D");

    StringTokenizer tokenizer = new StringTokenizer(disks, ",; ");
    while (tokenizer.hasMoreTokens())
    {
      String disk = tokenizer.nextToken();
      diskLetterList.add(disk + ":\\");
      SCFServiceSensorInput diskService =
        SCFServiceSensorInput.createStorageService(this,
          SCFConstants.ServiceTagSensorAvailableDiskSpace);

      diskService.setServiceName("Free on disk " + disk.toUpperCase() + ":");

      diskUsageServiceList.add(diskService);
      registerService(diskService);
    }

  }

  /**
   * Called regularly to handle tasks.
   * 
   */
  public void handleEvent()
  {
    super.handleEvent();
    if ((Portable.currentTimeMillis() - lastCheck) > 5000)
    {
      lastCheck = Portable.currentTimeMillis();
      for (int i = 0; i < diskUsageServiceList.size(); i++)
      {
        SCFServiceSensorInput diskService = (SCFServiceSensorInput)diskUsageServiceList.get(i);

        File file = new File(diskLetterList.get(i).toString());
        long freeSpaceMegabyte = file.getFreeSpace() / 1000000;

        diskService.setCurrentValue(freeSpaceMegabyte);
      }
    }
  }
}

Durch die Ableitung von der Basisklasse SCFManageableDevice enthält das Gerät neben dem DigitalInput-Dienst zusätzlich die Dienste ServiceManagement, Persistence und Identification.

Eine ausführbare Klasse definieren

Die Hauptklasse mit der main()-Funktion wird für Konsolenprogramme von SCFTemplateEntity abgeleitet. Sie legt die genutzten Kommunikationsschnittstellen fest und fasst Geräte sowie einen optionalen Klienten zusammen.

	
public class SCFDigitalInputEntity extends SCFTemplateEntity
{

  // entity should use IP interfaces
  private CommTransceiverManagementIP ipTransceiverManagement;

  private SCFDigitalInputDevice       digitalInputDevice;

  /**
   * Creates a new instance of EventInputEntity.
   * 
   * @param startupConfiguration
   */
  public SCFDigitalInputEntity(CommStartupConfiguration startupConfiguration)
  {
    super(startupConfiguration);
  }
 
  public void initEntityContent()
  {
    super.initEntityContent();
    if ((getStartupConfiguration() != null) && getStartupConfiguration().isValid())
    {
      ipTransceiverManagement = new CommTransceiverManagementIP(getStartupConfiguration());

      setPersistenceImplementor(new FilePersistenceImplementor());
      // optional: add control point for connected output
      // setControlPoint(new SCFControlPoint(this));

      digitalInputDevice =
        new SCFDigitalInputDevice(this,
          getStartupConfiguration().getNumericProperty("ID", SCFDeviceIDConstants.DeviceIDBasePCDigitalInput),
          "VirtualSwitch",
          SCFConstants.LocationIDFloor);
      ipTransceiverManagement.enable();
      registerDevice(digitalInputDevice);
    }
  }

  /**
   * Retrieves the value of digitalInputDevice.
   * 
   * @return The value of digitalInputDevice
   */
  public SCFDigitalInputDevice getDigitalInputDevice()
  {
    return digitalInputDevice;
  }

}