In the RM Rule Engine the script service events are used in the event-based triggers when defining a rule. In Dynamic Properties and Methods section, where we created a rule, we used the Device Manager script service event – OSGiDeviceStatusChanged.

For sending a script service event in the RM framework the service com.prosyst.mprm.backend.event.EventService has to be used, which is a registered OSGi service in the RM framework.

Now we are going to define events for our service – Camera Manager. We want to know if a camera setting is changed on the camera itself. We will receive a message from the camera device that a setting has been changed and an event will be sent to the appropriate event listeners.

We will add the event sending to the CameraManager implementation, because it is the message handler:

public class CameraManagerImpl implements CameraManager {
  ...
  public static final String CAMERA_RESPONSE_MSG = "set.camera.feature.response";
 
  public static final String CAMERA_SETTING_CHANHED_MSG = "camera.setting.changed";
  ...
  public void processMessage(Connection connection, Message message, Packet response) {
    GatewayConnectionContext context = (GatewayConnectionContext)connection.getConnectionContext();
    String gatewayId = context.getGatewayId();
    DataInputStream in = message.getInput();
 
    if (CAMERA_RESPONSE_MSG.equals(message.getType())) {
     ...
    } else {// CAMERA_SETTING_CHANHED_MSG
      try {
        String featureName = in.readUTF();
        double featureValue = in.readDouble();
        ((CameraImpl)getCamera(gatewayId)).saveFeatureValue(featureName, featureValue);
        sendEvent(CameraSettingsChanged.class.getSimpleName(), new CameraSettingsChanged(gatewayId, featureName, featureValue));
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
 
  private void sendEvent(String eventType, Object eventData) throws EventListenerException, ManagementException {
    Activator.getEventService().event(eventType, eventData);
  }
  ...
}


In order to have script service events listed in RM console when choosing an event-based trigger, we have to register the events metadata as an OSGi service from type com.prosyst.mprm.rule.metadata.EventsMetadata.

Let's say the event data looks like this:

CameraSettingChanged{
  String cameraId;
  String changedFeature;
  Object changedFetureValue;
  double brightness;
  double stauration;
  double zoom;
  ...
}


The CameraSettingChanged implementation:

package com.prosyst.mprm.demos.rules;
 
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
 
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsonschema.JsonSchema;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.prosyst.mprm.backend.rules.spi.PropertyMissing;
import com.prosyst.mprm.rule.metadata.EventsMetadata;
import com.prosyst.mprm.rule.metadata.EventsMetadataGroup;
import com.prosyst.mprm.rule.metadata.EventsMetadataLeaf;
 
public class CameraSettingsChanged implements PropertyMissing, Serializable {
 
  private static final long serialVersionUID = -4395865241620298185L;
 
  private static final String ROOT_GROUP_NAME = "Camera Manager";
  private static final ObjectMapper MAPPER = new ObjectMapper();
 
  private String cameraId;
 
  private String changedFeature;
 
  private double changedFeatureValue;
 
  public CameraSettingsChanged() {
 
  }
 
  public CameraSettingsChanged(String gatewayId, String featureName, double featureValue) {
    this.cameraId = gatewayId;
    this.changedFeature = featureName;
    this.changedFeatureValue = featureValue;
  }
 
  public String getCameraId() {
    return cameraId;
  }
 
  public String getChangedFeature() {
    return changedFeature;
  }
 
  public double getChangedFeatureValue() {
    return changedFeatureValue;
  }
 
  public Object propertyMissing(String propertyName) throws Exception {
    return CameraManagerImpl.getCameraFeatureValue(cameraId, propertyName);
  }
 
  public static EventsMetadata generateEventsMetadata() {
    List<EventsMetadata> subNodes = new ArrayList<EventsMetadata>();
    addEventMetadata(subNodes, CameraSettingsChanged.class.getSimpleName(), CameraSettingsChanged.class);
    EventsMetadata rootEventsMetadata = new EventsMetadataGroup(ROOT_GROUP_NAME, subNodes.toArray(new EventsMetadata[subNodes.size()]));
    return rootEventsMetadata;
  }
 
  private static void addEventMetadata(List<EventsMetadata> subNodes, String eventType, Class<?> clazz) {
    try {
      JsonSchema eventSchema = MAPPER.generateJsonSchema(clazz);
      if (clazz.equals(CameraSettingsChanged.class)) {
        ObjectNode propsNode = (ObjectNode)eventSchema.getSchemaNode().get("properties");
        for (String featureName : CameraImpl.FEATURES) {
          ObjectNode newValueNode = propsNode.putObject(featureName);
          newValueNode.put("type", "number");
        }
      }
      String eventSchemaStr = MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(eventSchema);
      EventsMetadataLeaf eventsMetadata = new EventsMetadataLeaf(eventType, eventSchemaStr);
      subNodes.add(eventsMetadata);
    } catch (JsonMappingException e) {
      Logger.error("Failed to generate Json schema for class \'" + clazz + "\'!" + e.getMessage());
    } catch (JsonProcessingException e) {
      Logger.error("Failed to get generate Json schema as string for class \'" + clazz + "\'!" + e.getMessage());
    }
  }
}


Note that the event class:

  • is serializable (implements java.io.Serializable).

  • has a default constructor.

  • is placed in the exported package.


In order to have the CameraSettingChanged event listed when choosing an event based trigger, we have to register its event metadata as well.

public class Activator implements BundleActivator {
 
  private ServiceRegistration eventsMetadataReg;
  ...
 
  public void start(BundleContext bc) throws Exception {
    ...
    registerEventsMetadata();
  }
 
  public void stop(BundleContext context) throws Exception {
    ...
    eventsMetadataReg = unregisterService(eventsMetadataReg);
  }
 
  private void registerEventsMetadata() {
    EventsMetadata eventsMetadata = CameraSettingsChanged.generateEventsMetadata();
    eventsMetadataReg = bc.registerService(EventsMetadata.class.getName(), eventsMetadata, null);
  }
}



The event object is bound under 'event' alias in the trigger condition.

Lets create a rule that will not allow the saturation go under 6.0%.

The action script will be:

cm.getCamera('camera1').setSaturation(6.0d);

and the trigger condition

event.saturation < 6



Saturation Rule Trigger Condition:



If the saturation feature on the camera is changed to less than 6.0% (the command "cameraSettings.change saturation 5.0d" is executed on the device with ID 'camera1') the saturation is changed to 6.0%.