Skip to content
This repository has been archived by the owner on Oct 12, 2023. It is now read-only.

Commit

Permalink
Merge pull request #14 from Azure-Samples/dt-register-change
Browse files Browse the repository at this point in the history
refactor: separated digital twin client register API and renamed interface instance to component
  • Loading branch information
davilu authored Jan 30, 2020
2 parents 3785a69 + 9ec5972 commit 6f7f0b6
Show file tree
Hide file tree
Showing 14 changed files with 138 additions and 196 deletions.
2 changes: 1 addition & 1 deletion digital-twin/Samples/device/AndroidSample/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ dependencies {
implementation 'com.google.android.material:material:1.0.0'
implementation 'com.github.tony19:logback-android:2.0.0'
implementation 'commons-io:commons-io:2.6'
implementation 'com.microsoft.azure.sdk.iot:digital-twin-device-client-preview:1.0.+'
implementation 'com.microsoft.azure.sdk.iot:digital-twin-device-client-preview:1.+'
compileOnly 'org.projectlombok:lombok:1.18.10'
annotationProcessor 'org.projectlombok:lombok:1.18.10'
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import com.fasterxml.jackson.databind.node.DoubleNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.fasterxml.jackson.databind.node.ValueNode;
import com.microsoft.azure.sdk.iot.digitaltwin.device.AbstractDigitalTwinInterfaceClient;
import com.microsoft.azure.sdk.iot.digitaltwin.device.AbstractDigitalTwinComponent;
import com.microsoft.azure.sdk.iot.digitaltwin.device.DigitalTwinClientResult;
import com.microsoft.azure.sdk.iot.digitaltwin.device.model.DigitalTwinReportProperty;

Expand All @@ -24,9 +24,9 @@
import static com.microsoft.azure.sdk.iot.digitaltwin.device.serializer.JsonSerializer.isNotEmpty;

@Slf4j
public class DeviceInformation extends AbstractDigitalTwinInterfaceClient {
public class DeviceInformation extends AbstractDigitalTwinComponent {
private static final String DEVICE_INFORMATION_INTERFACE_ID = "urn:azureiot:DeviceManagement:DeviceInformation:1";
private static final String DEVICE_INFORMATION_INTERFACE_INSTANCE = "deviceInformation";
private static final String DEVICE_INFORMATION_COMPONENT_NAME = "deviceInformation";
private static final String PROPERTY_MANUFACTURER = "manufacturer";
private static final String PROPERTY_MODEL = "model";
private static final String PROPERTY_SOFTWARE_VERSION = "swVersion";
Expand All @@ -46,7 +46,7 @@ private DeviceInformation(String manufacturer,
String processorManufacturer,
Double totalStorage,
Double totalMemory) {
super(DEVICE_INFORMATION_INTERFACE_INSTANCE, DEVICE_INFORMATION_INTERFACE_ID);
super(DEVICE_INFORMATION_COMPONENT_NAME, DEVICE_INFORMATION_INTERFACE_ID);
this.properties = new HashMap<>();
if (isNotEmpty(manufacturer)) {
properties.put(PROPERTY_MANUFACTURER, TextNode.valueOf(manufacturer));
Expand Down Expand Up @@ -75,8 +75,8 @@ private DeviceInformation(String manufacturer,
}

@Override
protected void onRegistered() {
super.onRegistered();
protected void ready() {
super.ready();
if (!properties.isEmpty()) {
log.debug("Reporting device information...");
List<DigitalTwinReportProperty> reportProperties = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

package com.microsoft.azure.sdk.iot.digitaltwin.sample;

import com.microsoft.azure.sdk.iot.digitaltwin.device.AbstractDigitalTwinInterfaceClient;
import com.microsoft.azure.sdk.iot.digitaltwin.device.AbstractDigitalTwinComponent;
import com.microsoft.azure.sdk.iot.digitaltwin.device.DigitalTwinClientResult;
import com.microsoft.azure.sdk.iot.digitaltwin.device.model.DigitalTwinAsyncCommandUpdate;
import com.microsoft.azure.sdk.iot.digitaltwin.device.model.DigitalTwinCommandRequest;
Expand Down Expand Up @@ -32,12 +32,13 @@
import static com.microsoft.azure.sdk.iot.digitaltwin.device.serializer.JsonSerializer.deserialize;
import static com.microsoft.azure.sdk.iot.digitaltwin.device.serializer.JsonSerializer.serialize;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static java.util.concurrent.TimeUnit.SECONDS;

@Slf4j
public class EnvironmentalSensor extends AbstractDigitalTwinInterfaceClient {
static final String ENVIRONMENTAL_SENSOR_INTERFACE_ID = "urn:java_sdk_sample:EnvironmentalSensor:1";
private static final String COMMAND_NOT_HANDLED_MESSAGE_PATTERN = "\"Command[%s] is not handled for interface[%s].\"";
public class EnvironmentalSensor extends AbstractDigitalTwinComponent {
public static final String ENVIRONMENTAL_SENSOR_INTERFACE_ID = "urn:java_sdk_sample:EnvironmentalSensor:1";
private static final String COMMAND_NOT_HANDLED_MESSAGE_PATTERN = "\"Command[%s] is not handled for component[%s].\"";
private static final String TELEMETRY_NAME_TEMPERATURE = "temp";
private static final String TELEMETRY_NAME_HUMIDITY = "humid";
private static final String COMMAND_TURN_ON = "turnon";
Expand All @@ -49,21 +50,18 @@ public class EnvironmentalSensor extends AbstractDigitalTwinInterfaceClient {
private static final String PROPERTY_BRIGHTNESS = "brightness";
private final UiHandler uiHandler;

protected EnvironmentalSensor(@NonNull String digitalTwinInterfaceInstanceName, @NonNull UiHandler uiHandler) {
super(digitalTwinInterfaceInstanceName, ENVIRONMENTAL_SENSOR_INTERFACE_ID);
protected EnvironmentalSensor(@NonNull String digitalTwinComponentName, @NonNull UiHandler uiHandler) {
super(digitalTwinComponentName, ENVIRONMENTAL_SENSOR_INTERFACE_ID);
this.uiHandler = uiHandler;
}

public Single<DigitalTwinClientResult> updateTemperatureAsync(double temperature) throws IOException {
log.debug("Temperature changed to {}.", temperature);
uiHandler.updateTemperature(temperature);
return sendTelemetryAsync(TELEMETRY_NAME_TEMPERATURE, serialize(temperature));
}

public Single<DigitalTwinClientResult> updateHumidityAsync(double humidity) throws IOException {
log.debug("Humidity changed to {}.", humidity);
uiHandler.updateHumidity(humidity);
return sendTelemetryAsync(TELEMETRY_NAME_HUMIDITY, serialize(humidity));
public Single<DigitalTwinClientResult> updateTemperatureAndHumidityAsync(double temperature, double humidity) throws IOException {
log.info("Temperature changed to {}, Humidity changed to {}.", temperature, humidity);
uiHandler.updateTemperatureAndHumidity(temperature, humidity);
Map<String, Double> properties = new HashMap<>();
properties.put(TELEMETRY_NAME_TEMPERATURE, temperature);
properties.put(TELEMETRY_NAME_HUMIDITY, humidity);
return sendTelemetryAsync(serialize(properties));
}

public Single<DigitalTwinClientResult> updateStatusAsync(final boolean state) {
Expand All @@ -77,58 +75,31 @@ public Single<DigitalTwinClientResult> updateStatusAsync(final boolean state) {
}

@Override
public void onRegistered() {
super.onRegistered();
public void ready() {
super.ready();
final Random random = new Random();
Disposable temperatureReportProcess= Single.just(random)
Disposable reportProcess = Single.just(random)
.delay(10, SECONDS)
.map(new Function<Random, Double>() {
.flatMap(new Function<Random, Single<DigitalTwinClientResult>>() {
@Override
public Double apply(Random random) {
return random.nextDouble() * 100;
public Single<DigitalTwinClientResult> apply(Random random) throws IOException {
double temperature = random.nextDouble() * 100, humidity = random.nextDouble() * 100;
return updateTemperatureAndHumidityAsync(temperature, humidity);
}
}).flatMap(new Function<Double, Single<DigitalTwinClientResult>>() {
@Override
public Single<DigitalTwinClientResult> apply(Double temperature) throws IOException {
return updateTemperatureAsync(temperature);
}
}).repeat()
})
.repeat()
.subscribe(new Consumer<DigitalTwinClientResult>() {
@Override
public void accept(DigitalTwinClientResult result) {
log.debug("Update temperature was {}", result);
log.info("Update temperature was {}", result);
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) {
log.debug("Update temperature failed.", throwable);
}
});
Disposable humidityReportProcess = Single.just(random)
.delay(10, SECONDS)
.map(new Function<Random, Double>() {
@Override
public Double apply(Random random) {
return random.nextDouble() * 100;
}
}).flatMap(new Function<Double, Single<DigitalTwinClientResult>>() {
@Override
public Single<DigitalTwinClientResult> apply(Double humidity) throws IOException {
return updateHumidityAsync(humidity);
}
}).repeat()
.subscribe(new Consumer<DigitalTwinClientResult>() {
@Override
public void accept(DigitalTwinClientResult result) {
log.debug("Update humidity was {}", result);
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) {
log.debug("Update humidity failed.", throwable);
}
});
log.debug("Once application quit, should dispose {} and {}.", temperatureReportProcess, humidityReportProcess);
log.debug("Once application quit, should dispose {}.", reportProcess);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.microsoft.azure.sdk.iot.device.transport.IotHubConnectionStatus;
import com.microsoft.azure.sdk.iot.digitaltwin.device.DigitalTwinClientResult;
import com.microsoft.azure.sdk.iot.digitaltwin.device.DigitalTwinDeviceClient;
import com.microsoft.azure.sdk.iot.digitaltwin.device.SdkInformationComponent;

import org.apache.commons.io.IOUtils;

Expand All @@ -40,7 +41,6 @@ public class MainActivity extends AppCompatActivity implements UiHandler {
private TextView brightnessView;
private TextView temperatureView;
private TextView humidityView;
private TextView connectivityView;
private TextView registrationView;
private TextView onoffView;
private ObjectAnimator anim;
Expand All @@ -54,21 +54,14 @@ protected void onCreate(Bundle savedInstanceState) {
brightnessView = (TextView) findViewById(R.id.brightness);
temperatureView = (TextView) findViewById(R.id.temperature);
humidityView = (TextView) findViewById(R.id.humidity);
connectivityView = (TextView) findViewById(R.id.connectivity);
registrationView = (TextView) findViewById(R.id.registration);
onoffView = (TextView) findViewById(R.id.onoff);
anim = ObjectAnimator.ofInt(findViewById(R.id.blink), "backgroundColor", Color.WHITE, Color.RED, Color.WHITE);

try {
DeviceClient deviceClient = new DeviceClient(DIGITAL_TWIN_CONNECTION_STRING, MQTT);
deviceClient.registerConnectionStatusChangeCallback(new IotHubConnectionStatusChangeCallback() {
@Override
public void execute(IotHubConnectionStatus status, IotHubConnectionStatusChangeReason statusChangeReason, Throwable throwable, Object callbackContext) {
log.debug("Device client status changed to: {}, reason: {}, cause: {}", status, statusChangeReason, throwable);
updateConnectivity(status);
}
}, deviceClient);
DigitalTwinDeviceClient digitalTwinDeviceClient = new DigitalTwinDeviceClient(deviceClient);

DigitalTwinDeviceClient digitalTwinDeviceClient = new DigitalTwinDeviceClient(deviceClient, DCM_ID);
final EnvironmentalSensor environmentalSensor = new EnvironmentalSensor(ENVIRONMENTAL_SENSOR_INTERFACE_INSTANCE_NAME, this);
final DeviceInformation deviceInformation = DeviceInformation.builder()
.manufacturer("Microsoft")
Expand All @@ -82,11 +75,18 @@ public void execute(IotHubConnectionStatus status, IotHubConnectionStatusChangeR
.build();
InputStream environmentalSensorModelDefinition = getAssets().open("EnvironmentalSensor.interface.json");
final ModelDefinition modelDefinition = ModelDefinition.builder()
.digitalTwinInterfaceInstanceName(MODEL_DEFINITION_INTERFACE_NAME)
.digitalTwinComponentName(MODEL_DEFINITION_INTERFACE_NAME)
.environmentalSensorModelDefinition(IOUtils.toString(environmentalSensorModelDefinition, UTF_8))
.build();

// step 1: bindComponents
DigitalTwinClientResult bindComponentsResult = digitalTwinDeviceClient.bindComponents(asList(deviceInformation, environmentalSensor, modelDefinition, SdkInformationComponent.getInstance()));
log.info("Bind components result: {}.", bindComponentsResult);

// step 2: send registration message, optional
// TODO It's now required for IoTExplorer
registrationView.setText("Registering...");
digitalTwinDeviceClient.registerInterfacesAsync(DCM_ID, asList(deviceInformation, environmentalSensor, modelDefinition)).subscribe(new Consumer<DigitalTwinClientResult>() {
digitalTwinDeviceClient.registerComponentsAsync().subscribe(new Consumer<DigitalTwinClientResult>() {
@Override
public void accept(DigitalTwinClientResult digitalTwinClientResult) {
log.debug("Register interfaces {}.", digitalTwinClientResult);
Expand All @@ -103,11 +103,29 @@ public void accept(Throwable throwable) {
updateRegistrationStatus("Register Failed");
}
});

// step 3: subscribe for commands and properties, optional, to enable command and properties
DigitalTwinClientResult subscribeForCommandsResult = digitalTwinDeviceClient.subscribeForCommands();
log.info("Subscribe for commands result: {}.", subscribeForCommandsResult);
DigitalTwinClientResult subscribeForPropertiesResult = digitalTwinDeviceClient.subscribeForProperties();
log.info("Subscribe for properties result: {}.", subscribeForPropertiesResult);

// step 4: ready to use
DigitalTwinClientResult readyResult = digitalTwinDeviceClient.ready();
log.info("Notify ready result: {}.", readyResult);

// step 5: sync up properties, optional
DigitalTwinClientResult syncupPropertiesResult = digitalTwinDeviceClient.syncupProperties();
log.info("Sync up properties result: {}.", syncupPropertiesResult);

DigitalTwinClientResult updateStatusResult = environmentalSensor.updateStatusAsync(true).blockingGet();
log.info("Update state of environmental sensor to true, result: {}", updateStatusResult);
} catch (Exception e) {
log.error("Create device client failed", e);
}
}

@Override
public void updateName(final String name) {
runOnUiThread(new Runnable() {
@Override
Expand All @@ -117,6 +135,7 @@ public void run() {
});
}

@Override
public void updateBrightness(final double brightness) {
runOnUiThread(new Runnable() {
@Override
Expand All @@ -126,33 +145,17 @@ public void run() {
});
}

public void updateTemperature(final double temperature) {
@Override
public void updateTemperatureAndHumidity(final double temperature, final double humidity) {
runOnUiThread(new Runnable() {
@Override
public void run() {
temperatureView.setText(String.valueOf(temperature));
}
});
}

public void updateHumidity(final double humidity) {
runOnUiThread(new Runnable() {
@Override
public void run() {
humidityView.setText(String.valueOf(humidity));
}
});
}

private void updateConnectivity(final IotHubConnectionStatus connectionStatus) {
runOnUiThread(new Runnable() {
@Override
public void run() {
connectivityView.setText(connectionStatus.toString());
}
});
}

private void updateRegistrationStatus(final String registrationStatus) {
runOnUiThread(new Runnable() {
@Override
Expand All @@ -162,6 +165,7 @@ public void run() {
});
}

@Override
public void updateOnoff(final boolean on) {
runOnUiThread(new Runnable() {
@Override
Expand All @@ -171,6 +175,7 @@ public void run() {
});
}

@Override
public void startBlink(final long interval) {
runOnUiThread(new Runnable() {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,24 @@

package com.microsoft.azure.sdk.iot.digitaltwin.sample;

import com.microsoft.azure.sdk.iot.digitaltwin.device.AbstractDigitalTwinInterfaceClient;
import com.microsoft.azure.sdk.iot.digitaltwin.device.AbstractDigitalTwinComponent;
import com.microsoft.azure.sdk.iot.digitaltwin.device.model.DigitalTwinCommandRequest;
import com.microsoft.azure.sdk.iot.digitaltwin.device.model.DigitalTwinCommandResponse;
import lombok.Builder;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class ModelDefinition extends AbstractDigitalTwinInterfaceClient {
public class ModelDefinition extends AbstractDigitalTwinComponent {
private static final String modelDefinitionInterfaceId = "urn:azureiot:ModelDiscovery:ModelDefinition:1";

private final String environmentalSensorModelDefinition;

private static final String getModelDefinitionCommandName = "getModelDefinition";

@Builder
private ModelDefinition(@NonNull String digitalTwinInterfaceInstanceName, @NonNull String environmentalSensorModelDefinition) {
super(digitalTwinInterfaceInstanceName, modelDefinitionInterfaceId);
private ModelDefinition(@NonNull String digitalTwinComponentName, @NonNull String environmentalSensorModelDefinition) {
super(digitalTwinComponentName, modelDefinitionInterfaceId);
this.environmentalSensorModelDefinition = environmentalSensorModelDefinition;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
interface UiHandler {
void updateName(String name);
void updateBrightness(double brightness);
void updateTemperature(double temperature);
void updateHumidity(double humidity);
void updateTemperatureAndHumidity(double temperature, double humidity);
void updateOnoff(boolean on);
void startBlink(long interval);
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,26 +87,6 @@
android:layout_height="wrap_content" />
</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">

<TextView
android:layout_width="100sp"
android:layout_height="wrap_content"
android:gravity="start"
android:paddingStart="2sp"
android:paddingEnd="2sp"
android:text="@string/status_connectivity"
android:textStyle="bold" />

<TextView
android:id="@+id/connectivity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/status_disconnected" />
</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
Expand Down
Loading

0 comments on commit 6f7f0b6

Please sign in to comment.