Take it further
After you Get started with Live Systems Data, use this section to learn more about the settings and components used in the sample project, which includes code snippets that you can use in future projects. By further investigating the sample project and its scripts, you learn how to do more with the Live Systems Data services.
Environment settings
You can find your EnvironmentSettings by going to the Services/Settings folder in your Samples directory.
The sample uses default values for its environment settings. To use other data sources in the environment settings, select the EnvironmentSettings ScriptableObject and modify the fields displayed in the Inspector window.
Services controller
The Services GameObject makes up the foundation on which other services are built. The ServicesController component exists inside the Services GameObject.
To open and edit the ServicesController script, right-click the ServicesController component and select Edit script. The script opens in the external script editor you have set in your Editor preferences.
You can also find and open your ServicesController script by going to the Assets/Samples/Digital Twins Live SDK/<package-version>/How To Use Services/Controllers folder.
For more details on the ServicesController script, see the Create a services controller page.
Login controller
The LoginController component authenticates and connects Live Systems Data services to one another.
To access the LoginController script, go to Services and select the Login GameObject. Alternatively, you can find and open your LoginController script by going to the Assets/Samples/Digital Twins Live SDK/<package-version>/How To Use Services/Controllers folder.
When you run a scene, the LoginController script confirms authentication and connection through console logs and a public Access Token field in the Inspector window when you select the GameObject.
Login controller initialization
The LoginController script implements the MonoBehaviour.Start() to initialize the login controller. The initialization script also does the following:
- Implements an
asyncmethod to wait for the result of calls to theAuthenticator. - References the
ServicesControllerto assign a listener to theAuthenticator.AuthenticationStateChangedevent. - Implements an
InitializeAsyncmethod to initialize theAuthenticator. - Confirms the
AuthenticationState. - Calls
LoginAsync()to continue the login flow.
async void Start()
{
m_ServicesController.Authenticator.AuthenticationStateChanged += OnAuthenticationStateChanged;
await m_ServicesController.Authenticator.InitializeAsync();
if (m_ServicesController.Authenticator.AuthenticationState == AuthenticationState.LoggedOut)
await m_ServicesController.Authenticator.LoginAsync();
}
Logged in state
After the Authenticator updates its AuthenticationState, the LoginController script calls the AuthenticationStateChanged event. The OnAuthenticationStateChanged listener receives this event.
All states are logged to the console, but only the LoggedIn state also launches the task FetchUserInfoAccessToken.
void OnAuthenticationStateChanged(AuthenticationState state)
{
switch (state)
{
case AuthenticationState.LoggedOut:
Debug.Log("User logged out.");
break;
case AuthenticationState.LoggedIn:
Debug.Log("User logged in.");
Task.Run(FetchUserInfoAndAccessToken);
break;
case AuthenticationState.AwaitingLogin:
Debug.Log("Awaiting login...");
break;
case AuthenticationState.AwaitingLogout:
Debug.Log("Awaiting logout...");
break;
}
Facility service connection
The LoginController script implements the MonoBehaviour.Start() to initialize the login controller. The initialization script also implements an async method to wait for the result of calls to the Authenticator.
After the Authenticator logs you in, you can get an access token and connect to the FacilityService. The facility service script does the following:
- Obtains valid
UserInfothroughUserInfoProvider.GetUserInfoAsync(). - Obtains a valid
stringrepresenting the Access Token throughAuthenticator.GetAccessTokenAsync(). - Uses the
stringto populate the public fieldm_AccessTokenfor visibility in the Inspector window. - Retrieves a list of available scenes through
SceneProvider.ListScenesAsync. ThisScenedefinition exists within theUnity.Cloud.Commonnamespace and is different from the Unity Editor definition of a scene. - Iterates the list of scenes to retrieve a scene that matches the
WorkspaceIdandFacilityIdfrom yourEnvironmentSettings. If there isn't a match, it logs a warning to your console. - Provides
scene,userInfo, andaccessTokenand establishes a connection through theFacilityService.ConnectAsync(scene, userInfo, accessToken).
async void FetchUserInfoAndAccessToken()
{
var userInfo = await m_ServicesController.UserInfoProvider.GetUserInfoAsync();
var accessToken = await m_ServicesController.Authenticator.GetAccessTokenAsync();
m_AccessToken = accessToken;
var sceneList = await m_ServicesController.SceneProvider.ListScenesAsync();
var scene = sceneList
.FirstOrDefault(scene =>
scene.WorkspaceId.ToString().Equals(m_ServicesController.EnvironmentSettings.WorkspaceId) &&
scene.Id.ToString().Equals(m_ServicesController.EnvironmentSettings.FacilityId));
if (scene is null)
{
Debug.LogWarning($"No {nameof(scene)} found in DT Portal for Facility: " +
$"{m_ServicesController.EnvironmentSettings.FacilityId} and Workspace: " +
$"{m_ServicesController.EnvironmentSettings.WorkspaceId}. If given Facility exists " +
$"in LSD, only LSD services will work.");
}
await m_ServicesController.FacilityService.ConnectAsync(scene, userInfo, accessToken);
}
Configuration controller
To access the ConfigurationController script, go to the Assets/Samples/Digital Twins Live SDK/<package-version>/How To Use Services/Controllers folder.
Configuration controller behavior
The ConfigurationController is made up of a single GetResultsAsync() method. To trigger this method, select Use Service in the Inspector window.
Note: The ConfigurationControllerEditor script (Assets/Samples/Digital Twins Live SDK/<package-version>/How To Use Services/Editor/ConfigurationControllerEditor) takes information from the Use Service button and links it to the GetResultsAsync() method.
The configuration controller script does the following:
- Verifies the reference to the
ServicesController. - Retrieves the
ConfigurationServiceand stores it in them_ConfigurationServicevariable. Any requests you make to theDeviceSummaryandTimeSeriesPlotConfigurationuse this service. - Calls
GetDeviceSummaryAsync(m_DeviceType)with a valid string form_DeviceType. - Uses the
DeviceSummaryto populateDeviceSummaryResults, if available. - Calls
GetTimeSeriesPlotAsync(m_TelemetryKey)with a valid string form_TelemetryKey. - Populates the
TimeSeriesPlotMessagewith a confirmation message if aTimeSeriesPlotConfigurationis returned.
public async Task GetResultsAsync()
{
if (m_ServicesController is null)
{
Debug.LogError($"{nameof(m_ServicesController)} is not set.");
return;
}
m_ConfigurationService ??= m_ServicesController.ConfigurationService;
var deviceSummary = await m_ConfigurationService.GetDeviceSummaryAsync(m_DeviceType);
if (deviceSummary is null)
{
Debug.Log($"No device summary for {m_DeviceType} was found.");
}
else
{
m_Result.DeviceSummaryResults.Add(new DeviceSummaryResult
{
PropertyNames = deviceSummary.PropertyNames?.ToList(),
TelemetryNames = deviceSummary.TelemetryNames?.ToList()
});
Debug.Log($"The device summary for {m_DeviceType} was added to {nameof(m_Result)}.");
}
var timeSeriesPlot = await m_ConfigurationService.GetTimeSeriesPlotAsync(m_TelemetryKey);
if (timeSeriesPlot is null)
{
Debug.Log($"No time series plot for {m_TelemetryKey} was found.");
}
else
{
m_Result.TimeSeriesPlotMessage.Add($"We found a time series plot for {m_TelemetryKey}!");
Debug.Log($"The time series plot for {m_TelemetryKey} was added to {nameof(m_Result)}.");
}
}
Device service
The DeviceService component is shown through the DeviceController script. It retrieves all instances of LiveDevice from the data source.
To access the DeviceController script, go to the Assets/Samples/Digital Twins Live SDK/<package-version>/How To Use Services/Controllers folder.
Device service initialization
The DeviceController script implements the MonoBehaviour.Start() to retrieve the DeviceService from the ServicesController.
void Start()
{
m_DeviceService = m_ServicesController.DeviceService;
}
Device service behavior
The GetResultsAsync() method shows the main behavior of the DeviceService component. To trigger this method, select Use Service in the Inspector window.
Note: The DeviceControllerEditor script (Assets/Samples/Digital Twins Live SDK/<package-version>/How To Use Services/Editor/DeviceControllerEditor) takes information from the Use Service button and links it to the GetResultsAsync() method.
The device controller script does the following:
- Uses
m_DeviceService.GetDevicesAsync()to retrieve the latest list of Live Devices from the data source. - Selects the first Live Device and associates it with the scene's DeviceGameObject through its
liveDevice.GameObjectassignment, and is selected through setting theliveDevice.IsSelectedboolean totrue. - Calls
m_DeviceService.GetCachedDevices()to prepare theLiveDeviceResultViewfor eachLiveDevice. This array populates the Results > Live Devices field in the Inspector window. - Uses
m_DeviceService.GetSelectedLiveDevicesto isolate eachLiveDevicethat has anIsSelectedboolean set totrue. This collection populates the Results > Selected Live Devices field in the Inspector window.
public async Task GetResultsAsync()
{
var liveDevices = await m_DeviceService.GetDevicesAsync();
var liveDevice = liveDevices.FirstOrDefault();
if (liveDevice != null)
{
liveDevice.GameObjects?.AddRange(m_DeviceGameObjects);
liveDevice.IsSelected = true;
}
m_Result.LiveDevices = m_DeviceService
.GetCachedDevices()
.Select(device => new LiveDeviceResultView(device))
.ToArray();
m_Result.SelectedLiveDevices = m_DeviceService
.GetSelectedLiveDevices()
.Select(device => new LiveDeviceResultView(device))
.ToArray();
}
Notification service
The NotificationService component is shown through the NotificationController script. It posts and receives a mock NotificationResource.
To access the NotificationController script, go to the Assets/Samples/Digital Twins Live SDK/<package-version>/How To Use Services/Controllers folder.
Notification service initialization
The NotificationController script implements the MonoBehaviour.Start() to retrieve the NotificationService and DeviceService from the ServicesController.
void Start()
{
m_NotificationService = m_ServicesController.NotificationService;
m_DeviceService = m_ServicesController.DeviceService;
}
Notification service behavior
The GetResultsAsync() method sends a mock NotificationResource with SendNotificationAsync(), and retrieves the result using m_NotificationService.GetNotifications(). To trigger this method, select Use Service in the Inspector window.
Note: The NotificationControllerEditor script (Assets/Samples/Digital Twins Live SDK/<package-version>/How To Use Services/Editor/NotificationControllerEditor) takes information from the Use Service button and links it to the GetResultsAsync() method.
The notification controller script does the following:
- Uses
m_DeviceService.GetDevicesAsync()to retrieve the latest list of Live Devices from the data source. - Selects the first Live Device and uses its
Device.Idstringto create a validNotificationRequestResource. - Adds the new
NotificationRequestResourceto aListto match the expected parameter form_NotificationService.CreateNotificationsAsync(IEnumerable<NotificationRequestResource> notificationResources). - Uses
m_NotificationServiceto create and post aNotificationResourceand logs the results to the console.
public async Task GetResultsAsync()
{
await SendNotificationAsync();
m_Result.LatestNotifications = m_NotificationService
.GetNotifications()
.Select(notification => $"{notification.Timestamp}: {notification.Title}")
.ToArray();
}
SendNotificationAsync() and AnyNotificationRequestResource(IEnumerable<string> deviceIdList) create and post a mock Notification.
async Task SendNotificationAsync()
{
var liveDevices = await m_DeviceService.GetDevicesAsync();
var liveDevice = liveDevices.FirstOrDefault();
if (liveDevice is null || string.IsNullOrEmpty(liveDevice.Device.Id))
{
Debug.LogError($"There must be a {nameof(liveDevice.Device)} with correct id to successfully send a Notification.");
return;
}
var notification = AnyNotificationRequestResource(new List<string>
{
liveDevice.Device.Id
});
var response = await m_NotificationService.CreateNotificationsAsync(new List<NotificationRequestResource> { notification });
if (response.IsPresent())
{
Debug.Log("Notification created");
}
else
{
var json = JsonConvert.SerializeObject(notification);
Debug.LogWarning($"Notification creation failed:\n{json}");
}
}
static NotificationRequestResource AnyNotificationRequestResource(IEnumerable<string> deviceIdList)
=> new()
{
Title = $"Samples Title: {Guid.NewGuid().ToString()}",
Message = $"Samples Message: {Guid.NewGuid().ToString()}",
DeviceIds = deviceIdList,
Timestamp = DateTimeOffset.UtcNow,
Severity = "LOW"
};
Facility service
The FacilityService component is shown through the FacilityController script. It retrieves available Facility information from the data source.
To access the FacilityController script, go to the Assets/Samples/Digital Twins Live SDK/<package-version>/How To Use Services/Controllers folder.
Facility service initialization
The FacilityController script implements the MonoBehaviour.Start() to retrieve the FacilityService from the ServicesController.
void Start()
{
m_FacilityService = m_ServicesController.FacilityService;
}
Facility service behavior
The GetResultsAsync() method receives the FacilityInfo fields from the FacilityService. The FacilityInfo fields are the following:
IsLoggedInIsConnectedToMessagingServiceWorkspaceIdFacilityId
public void GetResults()
{
var facilityInfo = m_FacilityService.GetFacilityInfo();
m_Result.IsLoggedIn = facilityInfo.IsLoggedIn;
m_Result.IsConnectedToMessagingService = facilityInfo.IsConnectedToMessagingService;
m_Result.WorkspaceId = facilityInfo.WorkspaceId;
m_Result.FacilityId = facilityInfo.FacilityId;
}
Telemetry history service
Important: The Telemetry history service isn't currently supported.
The TelemetryHistoryService component is shown through the TelemetryHistoryController script. It retrieves the telemetry history based on a specific set of parameters.
To access the TelemetryHistoryController script, go to the Assets/Samples/Digital Twins Live SDK/<package-version>/How To Use Services/Controllers folder.
Telemetry history service initialization
The TelemetryHistoryController script implements the MonoBehaviour.Start() to retrieve the TelemetryHistoryService and DeviceService from the ServicesController.
void Start()
{
m_TelemetryHistoryService = m_ServicesController.TelemetryHistoryService;
m_DeviceService = m_ServicesController.DeviceService;
}
Telemetry history service behavior
The GetResultsAsync() method uses TelemetryHistoryService to retrieve a list of TelemetryHistory based on a specific set of parameters. The parameters are the following:
IEnumerable<string> deviceIds: identifies any Live Devices to be returned inTelemetryHistory.string telemetryKey: the name of a singleTelemetryspecific to your data source. In this sample, that name is WindSpeed.DateTimeOffset startTime: the earliestTimestamponTelemetryincluded in the response.DateTimeOffset endTime: the latestTimestamponTelemetryincluded in the response.int stepResolutionInSeconds: the frequency of results included in the response.
The telemetry history controller script does the following:
- Uses
m_DeviceService.GetDevicesAsync()to retrieve the latest list of Live Devices from the data source. - Selects the first Live Device and uses its
Device.Idstringto create a request forTelemetryHistory. At least one validDevice.Idis required to request theTelemetryHistorysuccessfully. - Defines the remaining parameters required to request the
TelemetryHistory. - Calls the
m_TelemetryHistoryService.GetHistoryAsyncwith the defined parameters to retrieve theTelemetryHistorythat matches the request. - Formats the content of the response and displays it in the Result field in the Inspector window.
public async Task GetResultsAsync()
{
var liveDevices = await m_DeviceService.GetDevicesAsync();
var liveDevice = liveDevices.FirstOrDefault();
if (liveDevice is null)
{
Debug.LogError($"There must be a {nameof(liveDevice)} to successfully receive Telemetry.");
return;
}
m_Result.TelemetryHistoriesCount = 0;
var endTime = DateTimeOffset.UtcNow;
var startTime = endTime.AddMinutes(-10);
var stepResolutionInSeconds = 1;
var telemetryHistories = await m_TelemetryHistoryService.GetHistoryAsync(
new[] { liveDevice.Device.Id },
m_TelemetryKey,
startTime,
endTime,
stepResolutionInSeconds);
var telemetries = telemetryHistories
.First()
.Telemetries
.First(group => group.Key.Equals(m_TelemetryKey))
.ToList();
m_Result.DeviceId = liveDevice.Device.Id;
m_Result.TelemetryHistoriesCount = telemetries.Count;
}