All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.relayr.java.model.Device Maven / Gradle / Ivy

The newest version!
package io.relayr.java.model;

import com.google.gson.annotations.SerializedName;

import java.io.Serializable;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import io.relayr.java.RelayrJavaSdk;
import io.relayr.java.api.helpers.AggregatedDataHelper;
import io.relayr.java.api.helpers.RawDataHelper;
import io.relayr.java.model.action.Command;
import io.relayr.java.model.action.Configuration;
import io.relayr.java.model.action.Reading;
import io.relayr.java.model.models.DeviceFirmware;
import io.relayr.java.model.models.DeviceModel;
import io.relayr.java.model.models.error.DeviceModelsException;
import io.relayr.java.model.models.schema.ValueSchema;
import io.relayr.java.model.models.transport.DeviceReading;
import io.relayr.java.model.models.transport.Transport;
import io.relayr.java.model.state.State;
import io.relayr.java.model.state.StateCommands;
import io.relayr.java.model.state.StateConfigurations;
import io.relayr.java.model.state.StateMetadata;
import io.relayr.java.model.state.StateReadings;
import rx.Observable;
import rx.Observer;
import rx.Subscriber;

import static io.relayr.java.RelayrJavaSdk.getDeviceModelsCache;

/**
 * The Device class is a representation of the device entity.
 * A device entity is any external entity capable of gathering measurements
 * or one which is capable of receiving information from the relayr platform.
 * Examples would be a thermometer, a gyroscope or an infrared sensor.
 */
public class Device implements Serializable {

    private static final long serialVersionUID = 1L;

    private final String id;
    private final String model;
    private final String modelId;
    private String created;
    private String description;
    private String name;
    private final String owner;
    private final String firmwareVersion;
    private String secret;
    private final String externalId;
    private boolean shared;
    private String integrationType;
    @SerializedName("public") private boolean isPublic;

    private transient DeviceModel deviceModel;
    private transient AggregatedDataHelper aggDataHelper;
    private transient RawDataHelper rawDataHelper;

    public Device(String id, String owner, String modelId, String name) {
        this(id, owner, modelId, name, "");
    }

    public Device(String id, String owner, String modelId, String name, String description) {
        this.id = id;
        this.name = name;
        this.description = description;
        this.owner = owner;
        this.modelId = modelId;
        this.model = modelId;
        this.firmwareVersion = null;
        this.externalId = null;
        this.secret = null;
    }

    public Device(String id, String modelId, String name, String description, String owner,
                  String firmwareVersion, String externalId, boolean isPublic, String accountType) {
        this.id = id;
        this.name = name;
        this.description = description;
        this.owner = owner;
        this.modelId = modelId;
        this.model = modelId;
        this.firmwareVersion = firmwareVersion;
        this.externalId = externalId;
        this.isPublic = isPublic;
        this.integrationType = accountType;
    }

    public String getName() {
        return name;
    }

    public String getDescription() {
        return description;
    }

    /** @return unique device UUID */
    public String getId() {
        return id;
    }

    /** @return null if created timestamp doesn't exist or if there is a ParseException */
    public Date getCreated() {
        if (created == null) return null;
        try {
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
            return df.parse(created);
        } catch (ParseException e) {
            System.err.println("io.relayr.java.model.Device - created timestamp parsing failed");
            return null;
        }
    }

    /** @return return device's firmware version unless device is a prototype and it doesn't have a model and firmwareVersion yet */
    public String getFirmwareVersion() {
        return firmwareVersion;
    }

    public String getSecret() {
        return secret;
    }

    /** @return return device's id if device is originaly owned by another platform */
    public String getExternalId() {
        return externalId;
    }

    public boolean isShared() {
        return shared;
    }

    public String getOwner() {
        return owner;
    }

    public String getIntegrationType() {
        return integrationType;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    /**
     * Subscribes an app to a device channel. Enables the app to receive data from the device.
     * @return {@link Reading}
     */
    public Observable subscribeToCloudReadings() {
        return RelayrJavaSdk.getWebSocketClient().subscribe(id);
    }

    /** Unsubscribes an app from a device channel, stopping and cleaning up the connection. */
    public void unSubscribeToCloudReadings() {
        RelayrJavaSdk.getWebSocketClient().unSubscribe(id);
    }

    /**
     * Returns whole state with all latest readings, configurations, commands and metadata for device.
     * Readings, commands and configurations are persisted automatically when received on the server.
     * @return {@link State}
     */
    public Observable getState() {
        return RelayrJavaSdk.getDeviceApi().getState(id);
    }

    /**
     * Returns all latest readings saved in the device state.
     * For filtering readings use {@link #getReadings(String, String)}
     * @return {@link StateReadings}
     */
    public Observable getReadings() {
        return getReadings(null, null);
    }

    /**
     * Returns latest readings saved in device state optionally filtered with path and meaning
     * @param path    see {@link io.relayr.java.model.models.transport.DeviceReading#path} in {@link DeviceModel} for more details
     * @param meaning see {@link io.relayr.java.model.models.transport.DeviceReading#meaning} in  {@link DeviceModel} for more details
     * @return {@link StateReadings}
     * @throws NullPointerException if meaning is NULL
     */
    public Observable getReadings(String path, String meaning) {
        return RelayrJavaSdk.getDeviceApi().getReadings(id, path, meaning);
    }

    /**
     * Sends a configuration to device.
     * Configuration will be automatically saved in device state and can be fetched with {@link #getStateConfigurations()}
     * @param configuration - check possible configuration in {@link DeviceModel}
     * @return empty {@link Observable}
     * @throws NullPointerException if configuration is NULL
     */
    public Observable sendConfiguration(Configuration configuration) {
        if (configuration == null) throw new NullPointerException("Configuration can't be null");
        return RelayrJavaSdk.getDeviceApi().sendConfiguration(id, configuration);
    }

    /**
     * Returns all latest configurations saved in device state.
     * For filtering configurations use {@link #getStateConfigurations(String, String)}
     * @return {@link StateConfigurations}
     */
    public Observable getStateConfigurations() {
        return getStateConfigurations(null, null);
    }

    /**
     * Returns latest configurations saved in device state optionally filtered with path and meaning
     * @param path see {@link io.relayr.java.model.models.transport.DeviceConfiguration#path} in {@link DeviceModel} for more details
     * @param name see {@link io.relayr.java.model.models.transport.DeviceConfiguration#name} in  {@link DeviceModel} for more details
     * @return {@link StateConfigurations}
     */
    public Observable getStateConfigurations(String path, String name) {
        return RelayrJavaSdk.getDeviceApi().getConfigurations(id, path, name);
    }

    /**
     * Sends a command to the this device.
     * Command will be automatically saved in device state and  can be fetched with {@link #getStateCommands()}
     * @param command - check possible commands in {@link DeviceModel}
     * @return empty {@link Observable}
     * @throws NullPointerException if command is NULL
     */
    public Observable sendCommand(Command command) {
        if (command == null) throw new NullPointerException("Command can't be null");
        return RelayrJavaSdk.getDeviceApi().sendCommand(id, command);
    }

    /**
     * Returns all latest commands saved in device state.
     * For filtering readings use {@link #getStateCommands(String, String)}
     * @return {@link StateCommands}
     */
    public Observable getStateCommands() {
        return getStateCommands(null, null);
    }

    /**
     * Returns latest commands saved in device state optionally filtered with path and meaning
     * @param path see {@link io.relayr.java.model.models.transport.DeviceCommand#path} in {@link DeviceModel} for more details
     * @param name see {@link io.relayr.java.model.models.transport.DeviceCommand#name} in  {@link DeviceModel} for more details
     * @return {@link StateCommands}
     */
    public Observable getStateCommands(String path, String name) {
        return RelayrJavaSdk.getDeviceApi().getCommands(id, path, name);
    }

    /**
     * Returns metadata saved in device state.
     * @param key if null whole metadata is returned, otherwise object with specified key is returned (if one exists)
     * @return {@link StateMetadata}
     */
    public Observable getStateMetadata(String key) {
        return RelayrJavaSdk.getDeviceApi().getMetadata(id, key);
    }

    /**
     * @param key if null nothing is deleted, otherwise object with specified key is deleted (if one exists)
     * @return in onNext if data is deleted
     */
    public Observable deleteStateMetadata(String key) {
        return RelayrJavaSdk.getDeviceApi().deleteMetadata(id, key);
    }

    /**
     * Saves object with corresponding key into device metadata.
     * @param key    separated with dots '.' to create nicer dictionary structure for easier navigation.
     * @param object object to save under specified key
     * @return empty {@link Observable}
     */
    public Observable saveStateMetadata(String key, Object object) {
        return RelayrJavaSdk.getDeviceApi().setMetadata(id, key, object);
    }

    /** Returns device specific {@link AggregatedDataHelper} object. Use to get device history data. */
    public AggregatedDataHelper getAggregatedDataHelper() {
        if (aggDataHelper == null) aggDataHelper = AggregatedDataHelper.init(getId());
        return aggDataHelper;
    }

    /** Returns device specific {@link AggregatedDataHelper} object. Use to get device history data. */
    public RawDataHelper getRawDataHelper() {
        if (rawDataHelper == null) rawDataHelper = RawDataHelper.init(getId());
        return rawDataHelper;
    }

    /**
     * Returns ID of {@link DeviceModel} that defines readings, commands and configurations
     * @return modelId
     */
    public String getModelId() {
        if (modelId != null) return modelId;
        if (model != null) return model;
        return null;
    }

    /**
     * Returns {@link DeviceModel} that defines readings, commands and configurations for
     * specific device depending on device firmware version.
     * Use if {@link RelayrJavaSdk#getDeviceModelsCache()} is initialized.
     * @return {@link DeviceModel}
     */
    public Observable getDeviceModel() {
        if (getModelId() == null)
            return Observable.error(DeviceModelsException.deviceModelNotFound());
        if (deviceModel != null) return Observable.just(deviceModel);

        return Observable.create(new Observable.OnSubscribe() {
            @Override public void call(final Subscriber subscriber) {
                if (!getDeviceModelsCache().available())
                    RelayrJavaSdk.getDeviceModelsApi().getDeviceModelById(getModelId())
                            .subscribe(new Observer() {
                                @Override public void onCompleted() {}

                                @Override public void onError(Throwable e) {
                                    subscriber.onError(e);
                                }

                                @Override public void onNext(DeviceModel model) {
                                    if (deviceModel == null) deviceModel = model;
                                    subscriber.onNext(model);
                                }
                            });
                else {
                    try {
                        if (deviceModel == null)
                            deviceModel = getDeviceModelsCache().getModelById(getModelId());
                        subscriber.onNext(deviceModel);
                    } catch (DeviceModelsException e) {
                        e.printStackTrace();
                        subscriber.onError(e);
                    }
                }
            }
        });
    }

    /**
     * Returns {@link ValueSchema} for specified meaning and path from received {@link io.relayr.java.model.action.Reading} object.
     * {@link ValueSchema} defines received data and a way to parse it.
     * @param path    defined by {@link DeviceReading#getPath()} in {@link io.relayr.java.model.models.DeviceModel}
     * @param meaning defined by {@link DeviceReading#getMeaning()} in {@link io.relayr.java.model.models.DeviceModel}
     * @return {@link ValueSchema}
     */
    public Observable getValueSchema(final String meaning, final String path) {
        if (getModelId() == null) return Observable.error(new Exception("ModelId doesn't exist"));
        if (deviceModel != null) return Observable.just(getValueSchema(deviceModel, meaning, path));

        return Observable.create(new Observable.OnSubscribe() {
            @Override public void call(final Subscriber subscriber) {
                if (!getDeviceModelsCache().available())
                    RelayrJavaSdk.getDeviceModelsApi().getDeviceModelById(getModelId())
                            .subscribe(new Observer() {
                                @Override public void onCompleted() {}

                                @Override public void onError(Throwable e) {
                                    subscriber.onError(e);
                                }

                                @Override public void onNext(DeviceModel model) {
                                    if (deviceModel == null) deviceModel = model;
                                    try {
                                        subscriber.onNext(getValueSchema(getDeviceModelsCache().getModelById(getModelId()), meaning, path));
                                    } catch (DeviceModelsException e) {
                                        e.printStackTrace();
                                        subscriber.onError(e);
                                    }
                                }
                            });
                else {
                    try {
                        subscriber.onNext(getValueSchema(getDeviceModelsCache().getModelById(getModelId()), meaning, path));
                    } catch (DeviceModelsException e) {
                        e.printStackTrace();
                        subscriber.onError(e);
                    }
                }
            }
        });
    }

    /**
     * Used only for Wunderbar devices.
     * @return {@link TransmitterDevice}
     */
    public TransmitterDevice toTransmitterDevice() {
        return new TransmitterDevice(id, secret, owner, name, modelId);
    }

    /** Clears device's helper objects */
    public void recycle() {
        deviceModel = null;
        aggDataHelper = null;
    }

    @Override
    public boolean equals(Object o) {
        return o instanceof TransmitterDevice && ((TransmitterDevice) o).getId().equals(id) ||
                o instanceof Device && ((Device) o).id.equals(id);
    }

    @Override public int hashCode() {
        int result = id.hashCode();
        result = 31 * result + name.hashCode();
        return result;
    }

    @Override public String toString() {
        return "Device{" +
                "id='" + id + '\'' +
                ", model='" + model + '\'' +
                ", modelId='" + modelId + '\'' +
                ", name='" + name + '\'' +
                ", description='" + description + '\'' +
                ", owner='" + owner + '\'' +
                ", firmwareVersion='" + firmwareVersion + '\'' +
                ", externalId='" + externalId + '\'' +
                ", isPublic=" + isPublic +
                ", integrationType='" + integrationType + '\'' +
                ", deviceModel=" + deviceModel +
                ", aggDataHelper=" + aggDataHelper +
                '}';
    }

    private ValueSchema getValueSchema(DeviceModel model, String meaning, String path) {
        try {
            if (model == null) throw DeviceModelsException.deviceModelNotFound();

            DeviceFirmware firmware = model.getFirmwareByVersion(firmwareVersion);
            if (firmware == null) throw DeviceModelsException.firmwareNotFound();

            Transport defaultTransport = firmware.getDefaultTransport();
            if (defaultTransport == null) throw DeviceModelsException.transportNotFound();

            return defaultTransport.getReadingByMeaning(meaning, path).getValueSchema();
        } catch (DeviceModelsException e) {
            e.printStackTrace();
            return null;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy