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
async
method to wait for the result of calls to theAuthenticator
. - References the
ServicesController
to assign a listener to theAuthenticator.AuthenticationStateChanged
event. - Implements an
InitializeAsync
method 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
UserInfo
throughUserInfoProvider.GetUserInfoAsync()
. - Obtains a valid
string
representing the Access Token throughAuthenticator.GetAccessTokenAsync()
. - Uses the
string
to populate the public fieldm_AccessToken
for visibility in the Inspector window. - Retrieves a list of available scenes through
SceneProvider.ListScenesAsync
. ThisScene
definition exists within theUnity.Cloud.Common
namespace and is different from the Unity Editor definition of a scene. - Iterates the list of scenes to retrieve a scene that matches the
WorkspaceId
andFacilityId
from yourEnvironmentSettings
. If there isn't a match, it logs a warning to your console. - Provides
scene
,userInfo
, andaccessToken
and 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
ConfigurationService
and stores it in them_ConfigurationService
variable. Any requests you make to theDeviceSummary
andTimeSeriesPlotConfiguration
use this service. - Calls
GetDeviceSummaryAsync(m_DeviceType)
with a valid string form_DeviceType
. - Uses the
DeviceSummary
to populateDeviceSummaryResults
, if available. - Calls
GetTimeSeriesPlotAsync(m_TelemetryKey)
with a valid string form_TelemetryKey
. - Populates the
TimeSeriesPlotMessage
with a confirmation message if aTimeSeriesPlotConfiguration
is 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.GameObject
assignment, and is selected through setting theliveDevice.IsSelected
boolean totrue
. - Calls
m_DeviceService.GetCachedDevices()
to prepare theLiveDeviceResultView
for eachLiveDevice
. This array populates the Results > Live Devices field in the Inspector window. - Uses
m_DeviceService.GetSelectedLiveDevices
to isolate eachLiveDevice
that has anIsSelected
boolean 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.Id
string
to create a validNotificationRequestResource
. - Adds the new
NotificationRequestResource
to aList
to match the expected parameter form_NotificationService.CreateNotificationsAsync(IEnumerable<NotificationRequestResource> notificationResources)
. - Uses
m_NotificationService
to create and post aNotificationResource
and 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:
IsLoggedIn
IsConnectedToMessagingService
WorkspaceId
FacilityId
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 singleTelemetry
specific to your data source. In this sample, that name is WindSpeed.DateTimeOffset startTime
: the earliestTimestamp
onTelemetry
included in the response.DateTimeOffset endTime
: the latestTimestamp
onTelemetry
included 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.Id
string
to create a request forTelemetryHistory
. At least one validDevice.Id
is required to request theTelemetryHistory
successfully. - Defines the remaining parameters required to request the
TelemetryHistory
. - Calls the
m_TelemetryHistoryService.GetHistoryAsync
with the defined parameters to retrieve theTelemetryHistory
that 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;
}