diff --git a/README.md b/README.md index 2f7ccbf..9169411 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # tjf - Testo JSON format This repository contains the schema definitions of the Testo JSON format (tjf). -The tjf is used for app to app (App2App) and device to device (Dev2Dev) communication with testo apps and devices. +The tjf is used for app to app (App2App), device to device (Dev2Dev) communication and exports with testo apps and devices. App2App is included into the following apps: @@ -31,6 +31,8 @@ Dev2Dev over Bluetooth Low Energy (BLE) is included into the following apps / de | --------- | -----| | testo 300 | t300 | +For more Information and examples please visit [Testo Interfaces](https://developers.testo.dev/t300/device-to-device/ "Visit developers.testo.dev") + ## Inter App Communication / App to App interface (App2App) Most testo apps can be called via an app to app interface (App2App) and report data back to the caller. This interface is available in the following apps and devices: @@ -42,63 +44,8 @@ Most testo apps can be called via an app to app interface (App2App) and report d | testo 400 | testosmartprobes | Yes | No | | testo Smart | testosmartprobes | Yes | Yes | -### Workflow -In the following examples `testosmartprobes` is used as a placeholder. Replace it with the proper application ID according to the table above. `com.example.demoapplication` is a placeholder for the app identifier of the caller. -1. Open `testosmartprobes://start?bundleid=com.example.demoapplication` via your application -2. Testo app will open, the measurement is performed (or a saved measurement is opened) and the export via JSON/TJF is selected. -3. Testo app opens an url like this: `testoapp+com.example.demoapplication://data?json=[base64_encoded_json_data]`. -4. Caller app receives the url and decodes the data. **Important:** to make the base64 URL compatible the testo app will replace some special characters, make sure to revert this after you receive the data. See the table below for more details. - -| Special character | Replacement in URL | -| ----------------- | ------------------ | -| Plus `+` | Minus `-` | -| Forward-Slash `/` | Underscore `_` | -| Equal Sign `=` | Colon `,` | +For more Information and examples please visit [Testo Interfaces](https://developers.testo.dev/app-to-app/ "Visit developers.testo.dev") ## Questions ? For questions/comments to the developer please create an issue with the corresponding label! -## Extended schema -The extended schema is designed to hold all possibly necessary data a measurement can contain. - -### Changelog - -#### 1.0.5 (07/2019) -- Added optional property "id" to the measurement type. -- Added optional property "id" to the measurement property type. -- xmlid, description are now marked optional - -#### 1.0.4 (12/2017) -- Added property `errors` - -#### 1.0.3 (10/2017) -Added optional properties `xmlid` -- `channelunit` : add optional property `xmlid` - - an optional property `xmlid` has been added to `channelunit` - which contains a mapping from the `channelunit` property `name` to XML ID Unit -- `channeltype` : add optional property `xmlid` - - an optional property `xmlid` has been added to `channeltype` - which contains a mapping from the `channeltype` property `name` to XML ID Channel Name - -#### 1.0.2 -- the 'value' property of measurementvalue now allows null values, indicating an invalid value. - - -#### 1.0.1 -- the definition of the channeltype has been changed in the following way: - - an additional property 'description' has been added, which now contains the value from 'name' but (possibly) translated into the current application language - - 'name' will now never be a translated string -- the documentation of properties of measurementvalue has been enhanced to reflect that in case the 'value' property contains an invalid value the 'description' property will contain a string like '----' or similar -- the 'value' property of measurementpropertyvalue can now be a number or a string - - -#### 1.0.0 -- initial version of the schema - - -## Slim schema -The slim schema is designed to hold a big amount of data, this means it omits a lot of meta data and redundant information. - -### Changelog -#### v1.0.6 -First publicly available version of the schema. diff --git a/schema/README.md b/schema/README.md new file mode 100644 index 0000000..6b9fc05 --- /dev/null +++ b/schema/README.md @@ -0,0 +1,14 @@ +# tjf - schema definitions + +The schemas nested within folders are remnants of a legacy system, retained primarily for compatibility reasons. However, for the majority of users, these schemas serve little purpose in the modern context and can be safely disregarded. + +## measurementCollection +The schema represents a structured collection of individual measurements like defined in [slim-schema](#slim-schema), each independent of the others. This collection is further enriched with some additional features, similar to those in slim-schema but only a small subset. + +## slim-schema +The schema delineates a comprehensive data structure exported by Testo applications. It encompasses various components, including measurements, device channels, customer and organization details, measuring point information, and measurement properties. + +## measurement-slim +This JSON schema, crucially used by the Testo 300 device when exporting measurement data using a QR code, defines a structured data object. + +Additionally, for those interested in delving deeper into the QR code functionality of the Testo 300 device, further information can be found at [this link](https://developers.testo.dev/t300/qrcode/). diff --git a/schema/measurementCollection-v1.1.0.json b/schema/measurementCollection-v1.1.0.json new file mode 100644 index 0000000..c38688d --- /dev/null +++ b/schema/measurementCollection-v1.1.0.json @@ -0,0 +1,119 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "A collection of measurements", + "type": "object", + "properties": { + "additionalMeasurementInformation": { + "description": "Additional information about the measurement", + "type": "array", + "items": { + "$ref": "#/definitions/measurementadditionalproperty" + } + }, + "measurements": { + "description": "An array of measurements that is part of this collection", + "type": "array", + "items": { + "$ref": "https://raw.githubusercontent.com/testo/tjf/public/schema/slim-schema-v1.2.0.json" + } + }, + "customer": { + "description": "Customer contact information", + "$ref": "#/definitions/contact" + }, + "organisation": { + "description": "Organisation contact information", + "$ref": "#/definitions/contact" + }, + "images": { + "description": "An array of image filenames", + "type": "array", + "items": { + "type": "string" + } + }, + "timeStamp": { + "description": "The time when the whole data set was created, unix timestamp in milliseconds", + "type": ["number","string"] + }, + "type": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "id", + "name" + ] + } + }, + "required": [ + "additionalMeasurementInformation", + "timeStamp", + "type" + ], + "definitions": { + "contact": { + "description": "An object containing contact information", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "street": { + "type": "string" + }, + "city": { + "type": "string" + }, + "country": { + "type": "string" + }, + "phone": { + "type": "string" + }, + "email": { + "type": "string" + }, + "personOfContact": { + "type": "string" + }, + "fax": { + "type": "string" + }, + "homepage": { + "type": "string" + }, + "logo": { + "type": "string" + } + } + }, + "measurementadditionalproperty": { + "description": "A description of an additional property of a measurement", + "type": "object", + "properties": { + "name": { + "description": "The name of the property, translated into the current language of the application", + "type": "string" + }, + "description": { + "description": "The description of the property, translated into the current language of the application", + "type": "string" + }, + "value": { + "description": "Additional value", + "type": [ "string", "integer", "number", "array", "object", "boolean" ], + "optional": true + } + }, + "required": [ "name" ], + "additionalProperties": false + } + } +} diff --git a/schema/slim-schema-v1.2.0.json b/schema/slim-schema-v1.2.0.json new file mode 100644 index 0000000..907d8a0 --- /dev/null +++ b/schema/slim-schema-v1.2.0.json @@ -0,0 +1,456 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "A data object exported by Testo applications", + "type": "object", + "properties": { + "schemaVersion": { + "description": "The version of the schema that this exported data set validates against", + "type": "string", + "pattern": "^[1-9].[0-9].[0-9]$" + }, + "channels": { + "description": "The measurement channels of all connected devices", + "type": "array", + "minItems": 1, + "items": { "$ref": "#/definitions/channel" } + }, + "device": { + "description": "The array of objects describing the connected devices, or, in case the Testo application can only connect to a single device, an object", + "type": [ "object", "array" ], + "minItems": 1, + "items": { "$ref": "#/definitions/device" } + }, + "customer": { + "description": "Customer contact information", + "$ref": "#/definitions/contact" + }, + "organisation": { + "description": "Organisation contact information", + "$ref": "#/definitions/contact" + }, + "measuringPoint": { + "description": "Measuring point of current measurement", + "$ref": "#/definitions/measuringpoint" + }, + "properties": { + "description": "Specific properties of the measurement described by the whole data set", + "type": "array", + "items": { "$ref": "#/definitions/measurementproperty" } + }, + "results": { + "description": "results of the measurement", + "type": "array", + "items": { "$ref": "#/definitions/measurementproperty" } + }, + "timeStamp": { + "description": "The time when the whole data set was created, either as a unix timestamp or as a date in ISO string format", + "type": [ "number", "string" ] + }, + "type": { + "description": "An object containing information about the type of measurement that is represented by the whole data set", + "type": "object", + "properties": { + "name": { + "description": "The name of the current measurement type in the language currently selected in the application", + "type": "string" + }, + "id": { + "description": "The id of the current measurement type", + "type": "string", + "optional": true + } + }, + "required": [ "name" ] + }, + "additionalMeasurementInformation": { + "description": "Additional properties that a measurement can have", + "type": "array", + "items": { "$ref": "#/definitions/measurementadditionalproperty" } + }, + "images": { + "description": "filenames of images related to this measurement. These files are not included in the json but might be attached when share", + "type": "array", + "items": { "type": "string" }, + "optional": true + }, + "snapshots": { + "description": "filenames of snapshots related to this measurement. These files are not included in the json but might be attached when share", + "type": "array", + "items": { "type": "string" }, + "optional": true + } + }, + "anyOf": [ + { "required": [ "channels", "device", "timeStamp", "type" ] }, + { "required": [ "channels", "device", "properties", "timeStamp", "type" ] }, + { "required": [ "channels", "device", "properties", "timeStamp", "type", "additionalMeasurementInformation" ] } + ], + "definitions": { + "channelunit": { + "description": "An object describing the unit of a data channel", + "type": "object", + "properties": { + "name": { + "description": "The unit of the channel as a string", + "type": "string" + }, + "xmlid": { + "description": "ZIV mapping id", + "type":"string", + "optional": true + } + }, + "required": [ "name" ], + "additionalProperties": false + }, + "channeltype": { + "description": "An object describing the type of a data channel", + "type": "object", + "properties": { + "name": { + "description": "The name of the channel as a string", + "type": "string" + }, + "description": { + "description": "The displayed and translated name of the channel", + "type": "string", + "optional": true + }, + "xmlid": { + "description": "ZIV mapping id", + "type":"string", + "optional": true + } + }, + "required": [ "name" ], + "additionalProperties": false + }, + "channel": { + "description": "An object describing a channel", + "type": "object", + "properties": { + "type": { "$ref": "#/definitions/channeltype" }, + "unit": { "$ref": "#/definitions/channelunit" }, + "additionalData": { + "items": { "$ref": "#/definitions/additionalData" } + }, + "alarmData": { + "items": { "$ref": "#/definitions/alarmData" } + }, + "values": { + "description": "An array containing the measurement values", + "type": "array", + "minItems": 1, + "items": { "$ref": "#/definitions/measurementvalue" } + } + }, + "required": [ "type", "unit", "values" ], + "additionalProperties": false + }, + "measurementvalueadditionaldata": { + "description": "An object describing additional properties a measurement value can have, like dilution factors or flags like the NOX flag", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "description": { + "description": "The value in textual form and appropriately translated", + "type": "string" + }, + "value": { + "description": "The value that the property has", + "type": [ "number", "boolean" ] + } + }, + "anyOf": [ + { "required": [ "name", "description" ] }, + { "required": [ "name", "value" ] }, + { "required": [ "name", "value", "description" ] } + ], + "additionalProperties": false + }, + "measurementvalue": { + "description": "An object describing a measurement value", + "type": "object", + "properties": { + "description": { + "description": "The measurement value in string form, with appropriate formatting applied", + "type": "string" + }, + "value": { + "description": "The actual measurement value in displayed unit as a number", + "type": "number" + }, + "exponent": { + "description": "The precision of the measurement value (depending on the Testo application it can be either the value of x in 10^x or the number of decimal places)", + "type": "integer" + }, + "timeStamp": { + "description": "The time when this measurement value was created, either as a unix timestamp or as a date in ISO string format", + "type": [ "number", "string" ] + }, + "status": { + "description": "Status of measurement value: (e.g. invalid, overrange, underrange, empty)", + "type": "string" + }, + "additionalData": { + "descriptions": "An array containing additional data objects a measurement value can have", + "type": "array", + "items": { "$ref": "#/definitions/measurementvalueadditionaldata" } + } + }, + "anyOf": [ + { "required": [ "timestamp" ] }, + { "required": [ "value", "timeStamp" ] }, + { "required": [ "description", "value", "timeStamp" ] }, + { "required": [ "description", "value", "exponent", "timeStamp" ] }, + { "required": [ "description", "value", "exponent", "timeStamp", "additionalData" ] } + ], + "additionalProperties": false + }, + "measurementpropertyvalue": { + "description": "An object describing a value of a measurement property", + "type": "object", + "properties": { + "description": { + "description": "The value in textual form including a unit", + "type": "string" + }, + "name": { + "description": "The name of the value, usually a translated string", + "type": "string" + }, + "value": { + "description": "The actual value", + "type": [ "number", "string", "boolean" ] + }, + "id": { + "description": "A language agnostic id", + "type": "string", + "optional": true + }, + "unit": { + "description": "Unit of value", + "type": "string", + "optional": true + }, + "baseUnit": { + "description": "The iso unit of the value", + "type": "string", + "optional": true + }, + "precision": { + "description": "precision of value in value property", + "type": "integer", + "optional": true + } + }, + "required": [ "value" ], + "additionalProperties": false + }, + "measurementproperty": { + "description": "A description of a specific property of a measurement, like fuel parameters for example", + "type": "object", + "properties": { + "name": { + "description": "The name of the property", + "type": "string" + }, + "description": { + "description": "The description of the property", + "type": "string" + }, + "id": { + "description": "The id of the property", + "type": "number" + }, + "values": { + "description": "An array containing objects that describe a value of a measurement property", + "type": "array", + "items": { "$ref": "#/definitions/measurementpropertyvalue" } + } + }, + "anyOf": [ + { "required": [ "name", "values" ] }, + { "required": [ "name", "description", "values" ] }, + { "required": [ "name", "description", "values", "id" ] } + ], + "additionalProperties": false + }, + "measurementadditionalproperty": { + "description": "A description of an additional property of a measurement", + "type": "object", + "properties": { + "name": { + "description": "The name of the property, translated into the current language of the application", + "type": "string" + }, + "description": { + "description": "The description of the property, translated into the current language of the application", + "type": "string" + }, + "value": { + "description": "Additional value", + "type": [ "string", "integer", "number", "array", "object", "boolean" ], + "optional": true + } + }, + "required": [ "name" ], + "additionalProperties": false + }, + "device": { + "description": "An object containing the properties of a connected device", + "type": "object", + "properties": { + "name": { + "description": "The name of the device", + "type": "string" + }, + "serial": { + "description": "The serial number of the device, either as a number or a string", + "type": [ "number", "string" ] + }, + "deviceIdentifier": { + "description": "The identifier of the device", + "type": "string" + }, + "partNumber": { + "description": "Part number of device", + "type": "string" + }, + "firmwareVersion": { + "description": "Firmware version of device", + "type": "string" + }, + "boardIndex": { + "type": "integer" + }, + "lastServiceDate": { + "description": "The last service date of the device", + "type": "string" + }, + "measCycle": { + "description": "Meas cycle of device in milliseconds", + "type": "integer" + }, + "measTypes": { + "description": "Measurement types of device's channels", + "type": "array", + "items": { "type": "string" } + }, + "additionalData": { + "items": { "$ref": "#/definitions/additionalData" } + } + }, + "anyOf": [ + { "required": [ "name", "serial" ] }, + { "required": [ "name", "serial", "deviceIdentifier", "lastServiceDate" ] } + ], + "additionalProperties": false + }, + "contact": { + "description": "An object containing contact information", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "street": { + "type": "string" + }, + "city": { + "type": "string" + }, + "country": { + "type": "string" + }, + "phone": { + "type": "string" + }, + "email": { + "type": "string" + }, + "personOfContact": { + "type": "string" + }, + "fax": { + "type": "string" + }, + "homepage": { + "type": "string" + }, + "logo": { + "type": "string" + } + }, + "required": [ "name" ], + "additionalProperties": false + }, + "measuringpoint": { + "description": "An object containing measuring point information", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "systemNumber": { + "type": "string" + }, + "systemType": { + "type": "string" + }, + "systemManufacturer": { + "type": "string" + }, + "systemSerial": { + "type": "string" + }, + "yearOfConstruction": { + "type": "string" + }, + "notes": { + "type": "string" + }, + "additionalData": { + "items": { "$ref": "#/definitions/measurementproperty" } + } + }, + "required": [ "name" ], + "additionalProperties": false + }, + "additionalData": { + "description": "additional data (e.g. calibration data for devices)", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": [ "string", "number", "integer", "boolean", "object", "array" ] + }, + "unit": { + "type": "string" + } + }, + "required": [ "name" ], + "additionalProperties": false + }, + "alarmData": { + "description": "alarm data (upper, upper warning, lower limits)", + "type": "object", + "properties": { + "upperAlarm": { + "type": "object" + }, + "upperWarning": { + "type": "object" + }, + "lowerAlarm": { + "type": "object" + } + }, + "additionalProperties": false + } + } +}