Community Tip - Learn all about the Community Ranking System, a fun gamification element of the PTC Community. X
This code creates an Extended List (supported since 6.1.6) of data item names, then finds that list and returns only the current and historical data items on the list for all the assets of a given model in XML. In this example, Extended Lists are used instead of data item groups to store a certain subset of data items that should be returned. In a real use case, the list of data item names would be created in a separate call, then the list would be accessed after the fact. For purposes of demonstration, this script does both.
Parameters:
import com.axeda.drm.sdk.Context
import com.axeda.drm.sdk.device.ModelFinder
import com.axeda.drm.sdk.device.Model
import com.axeda.drm.sdk.device.DeviceFinder
import com.axeda.drm.sdk.data.CurrentDataFinder
import com.axeda.drm.sdk.device.Device
import com.axeda.drm.sdk.data.HistoricalDataFinder
import com.axeda.sdk.v2.bridge.ExtendedListBridge
import com.axeda.sdk.v2.dsl.Bridges
import com.axeda.services.v2.ExtendedList
import com.axeda.services.v2.ExtendedListCriteria
import com.axeda.services.v2.ExtendedListReference
import groovy.xml.MarkupBuilder
/*
* DIListToXML.groovy
*
* Create a list of data items on an asset, then use that list to find selected data items for all assets in a given model.
*
* @param model_name - (REQ):Str name of the model.
* @param data_item_names - (REQ): Str list of data item names comma delimited, ie DataName1,DataName2
* @param from_time - (REQ):Long millisecond timestamp to begin query from.
* @param to_time - (REQ):Long millisecond timestamp to end query at.
*
* @note from_time and to_time should be provided because it limits the query size.
*
* @author Sara Streeter <sstreeter@axeda.com>
*/
def response = [:]
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
// measure the script run time
def timeProfiles = [:]
def scriptStartTime = new Date()
try {
// getUserContext is supported as of release 6.1.5 and higher
final def CONTEXT = Context.getUserContext()
// confirm that required parameters have been provided
validateParameters(actual: parameters, expected: ["model_name", "data_item_names", "from_time", "to_time"])
// find the model
def modelFinder = new ModelFinder(CONTEXT)
modelFinder.setName(parameters.model_name)
Model model = modelFinder.findOne()
// throw exception if no model found
if (!model) {
throw new Exception("No model found for ${parameters.model_name}.")
}
// find or create our Extended List
def listName = "${parameters.model_name}-data_item_list"
ExtendedListBridge listBridge = Bridges.extendedListBridge
def results = listBridge.find(listName)
def data_item_list
if (results.list != null) {
data_item_list = results
}
else {
data_item_list = new ExtendedList()
data_item_list.name = listName
}
// split out the data items into an Extended List
def items = parameters.data_item_names.tokenize(",")
items.each { entry ->
if (!data_item_list.list.contains(entry)) {
data_item_list.list.add(entry)
}
}
listBridge.save(data_item_list)
data_item_list.list.each {
}
// find all assets of that model
def assetFinder = new DeviceFinder(CONTEXT)
assetFinder.setModel(model)
def assets = assetFinder.findAll()
// find the current and historical data values for the data items on the list for each asset
//note: since device will be set on the datafinders going forward, a dummy device is set on instantiation which is not actually stored
def currentDataFinder = new CurrentDataFinder(CONTEXT, new Device(CONTEXT, "placeholder", model))
def historicalDataFinder = new HistoricalDataFinder(CONTEXT, new Device(CONTEXT, "placeholder", model))
historicalDataFinder.startDate = new Date(parameters.from_time as Long)
historicalDataFinder.endDate = new Date(parameters.to_time as Long)
def currentValue
def valueList = []
xml.Response() {
Assets() {
assets.each { Device asset ->
currentDataFinder.device = asset
Asset() {
id(asset.id)
name(asset.name)
serial_number(asset.serialNumber)
model_id(asset.model.id)
model_name(asset.model.name)
current_data() {
data_item_list.list.each { data ->
currentValue = currentDataFinder.find(data)
data_item() {
timestamp(currentValue?.getTimestamp()?.format("yyyyMMdd HH:mm"))
name(currentValue?.dataItem?.name)
value(currentValue?.asString())
}
}
}
historical_data() {
data_item_list.list.each { data ->
historicalDataFinder.device = asset
valueList = historicalDataFinder.find(currentValue.dataItem)
valueList.each { hd ->
data_item() {
timestamp(hd?.getTimestamp()?.format("yyyyMMdd HH:mm"))
name(hd?.dataItem?.name)
value(hd?.asString())
}
}
}
}
}
}
}
}
} catch (def ex) {
xml.Response() {
Fault {
Code('Groovy Exception')
Message(ex.getMessage())
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
ex.printStackTrace(pw);
Detail(sw.toString())
}
}
}
return ['Content-Type': 'text/xml', 'Content': writer.toString()]
private Map createTimeProfile(String label, Date startTime, Date endTime) {
[
(label): [
startTime: [timestamp: startTime.time, readable: startTime.toString()],
endTime: [timestamp: endTime.time, readable: endTime.toString()],
profile: [
elapsed_millis: endTime.time - startTime.time,
elapsed_secs: (endTime.time - startTime.time) / 1000
]
]
]
}
private validateParameters(Map args) {
if (!args.containsKey("actual")) {
throw new Exception("validateParameters(args) requires 'actual' key.")
}
if (!args.containsKey("expected")) {
throw new Exception("validateParameters(args) requires 'expected' key.")
}
def config = [
require_username: false
]
Map actualParameters = args.actual.clone() as Map
List expectedParameters = args.expected
config.each { key, value ->
if (args.options?.containsKey(key)) {
config[key] = args.options[key]
}
}
if (!config.require_username) { actualParameters.remove("username") }
expectedParameters.each { paramName ->
if (!actualParameters.containsKey(paramName) || !actualParameters[paramName]) {
throw new IllegalArgumentException(
"Parameter '${paramName}' was not found in the query; '${paramName}' is a reqd. parameter.")
}
}
}
Sample Output:
<Response>
<Assets>
<Asset>
<id>5052</id>
<name>VendingMachine_1</name>
<serial_number>VendingMachine_1</serial_number>
<model_id>1616</model_id>
<model_name>VendingMachineModel</model_name>
<current_data>
<data_item>
<timestamp>20120419 02:55</timestamp>
<name>CurrentBalance</name>
<value>0.0</value>
</data_item>
<data_item>
<timestamp>20120419 02:55</timestamp>
<name>CurrentStock</name>
<value>180.0</value>
</data_item>
</current_data>
<historical_data />
</Asset>
<Asset>
<id>5056</id>
<name>VendingMachine_5</name>
<serial_number>VendingMachine_5</serial_number>
<model_id>1616</model_id>
<model_name>VendingMachineModel</model_name>
<current_data>
<data_item>
<timestamp>20120419 02:55</timestamp>
<name>CurrentBalance</name>
<value>0.0</value>
</data_item>
<data_item>
<timestamp>20120419 02:55</timestamp>
<name>CurrentStock</name>
<value>180.0</value>
</data_item>
</current_data>
<historical_data />
</Asset>
<Asset>
<id>5054</id>
<name>VendingMachine_3</name>
<serial_number>VendingMachine_3</serial_number>
<model_id>1616</model_id>
<model_name>VendingMachineModel</model_name>
<current_data>
<data_item>
<timestamp>20120419 02:55</timestamp>
<name>CurrentBalance</name>
<value>0.0</value>
</data_item>
<data_item>
<timestamp>20120419 02:55</timestamp>
<name>CurrentStock</name>
<value>180.0</value>
</data_item>
</current_data>
<historical_data />
</Asset>
<Asset>
<id>5053</id>
<name>VendingMachine_2</name>
<serial_number>VendingMachine_2</serial_number>
<model_id>1616</model_id>
<model_name>VendingMachineModel</model_name>
<current_data>
<data_item>
<timestamp>20120419 02:55</timestamp>
<name>CurrentBalance</name>
<value>0.0</value>
</data_item>
<data_item>
<timestamp>20120419 02:55</timestamp>
<name>CurrentStock</name>
<value>180.0</value>
</data_item>
</current_data>
<historical_data />
</Asset>
<Asset>
<id>5055</id>
<name>VendingMachine_4</name>
<serial_number>VendingMachine_4</serial_number>
<model_id>1616</model_id>
<model_name>VendingMachineModel</model_name>
<current_data>
<data_item>
<timestamp>20120419 02:55</timestamp>
<name>CurrentBalance</name>
<value>0.0</value>
</data_item>
<data_item>
<timestamp>20120419 02:55</timestamp>
<name>CurrentStock</name>
<value>180.0</value>
</data_item>
</current_data>
<historical_data />
</Asset>
</Assets>
</Response>