Tested schema and working in web tool. Can't get Essentials to load schema file at specified path yet. Adds addtional XML help for config properties.

This commit is contained in:
Neil Dorin
2020-01-20 22:05:46 -07:00
parent aa64cc917c
commit bd7831146d
7 changed files with 227 additions and 656 deletions

View File

@@ -17,15 +17,27 @@ namespace PepperDash.Essentials.Core.Config
[JsonProperty("info")]
public InfoConfig Info { get; set; }
/// <summary>
/// Defines the devices in the system
/// </summary>
[JsonProperty("devices")]
public List<DeviceConfig> Devices { get; set; }
/// <summary>
/// Defines the source list for the system
/// </summary>
[JsonProperty("sourceLists")]
public Dictionary<string, Dictionary<string, SourceListItem>> SourceLists { get; set; }
/// <summary>
/// Defines all the tie lines for system routing
/// </summary>
[JsonProperty("tieLines")]
public List<TieLineConfig> TieLines { get; set; }
/// <summary>
/// Defines any join maps to override the default join maps
/// </summary>
[JsonProperty("joinMaps")]
public Dictionary<string, string> JoinMaps { get; set; }

View File

@@ -13,99 +13,43 @@ namespace PepperDash.Essentials.Core.Config
{
public class DeviceConfig : PropertiesConfigBase
{
/// <summary>
/// The unique idendifier for the device
/// </summary>
[JsonProperty("key", Required = Required.Always)]
public string Key { get; set; }
/// <summary>
/// A unique ID for each device instance. Used to differentiate between devices of the same type that may have
/// been added/removed from the system
/// </summary>
[JsonProperty("uid")]
public int Uid { get; set; }
/// <summary>
/// The name of the device
/// </summary>
[JsonProperty("name")]
public string Name { get; set; }
/// <summary>
/// The group for the device
/// </summary>
[JsonProperty("group")]
public string Group { get; set; }
/// <summary>
/// The type of the device to instantiate
/// </summary>
[JsonProperty("type", Required = Required.Always)]
public string Type { get; set; }
/// <summary>
/// The properties necessary to define the device
/// </summary>
[JsonProperty("properties", Required = Required.Always)]
[JsonConverter(typeof(DevicePropertiesConverter))]
public JToken Properties { get; set; }
public DeviceConfig()
{
SchemaJson = @"
{
'definitions': {},
'$schema': 'http://json-schema.org/draft-07/schema#',
'$id': 'http://example.com/root.json',
'type': 'object',
'title': 'The Root Schema',
'properties': {
'name': {
'$id': '#/properties/name',
'type': 'string',
'title': 'The Name Schema',
'default': '',
'examples': [
'App Server'
],
'pattern': '^(.*)$'
},
'group': {
'$id': '#/properties/group',
'type': 'string',
'title': 'The Group Schema',
'default': '',
'examples': [
'appServer'
],
'pattern': '^(.*)$'
},
'properties': {
'$id': '#/properties/properties',
'type': 'object',
'title': 'The Properties Schema'
},
'uid': {
'$id': '#/properties/uid',
'type': 'integer',
'title': 'The Uid Schema',
'default': 0,
'examples': [
4
]
},
'key': {
'$id': '#/properties/key',
'type': 'string',
'title': 'The Key Schema',
'default': '',
'examples': [
'display-1'
],
'pattern': '^(.*)$'
},
'type': {
'$id': '#/properties/type',
'type': 'string',
'title': 'The Type Schema',
'default': '',
'examples': [
'appServer'
],
'pattern': '^(.*)$'
}
},
'required': [
'group',
'properties',
'key',
'type'
]
}
";
}
}
/// <summary>

View File

@@ -92,8 +92,18 @@ namespace PepperDash.Essentials.Core.Config
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Loading config file: '{0}'", filePath);
// Attempt to validate config against schema
ValidateSchema(fs.ReadToEnd());
var directoryPrefix = Crestron.SimplSharp.CrestronIO.Directory.GetApplicationRootDirectory();
var schemaFilePath = directoryPrefix + Global.DirectorySeparator + "Config" + Global.DirectorySeparator + "Schema" + Global.DirectorySeparator + "EssentialsConfigSchema.json";
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Loading Schema from path: {0}", schemaFilePath);
if(File.Exists(schemaFilePath))
{
// Attempt to validate config against schema
ValidateSchema(fs.ReadToEnd(), schemaFilePath);
}
else
Debug.Console(0, Debug.ErrorLogLevel.Warning, "No Schema found at path: {0}", schemaFilePath);
if (localConfigFound)
{
@@ -133,20 +143,31 @@ namespace PepperDash.Essentials.Core.Config
}
}
public static void ValidateSchema(string json)
/// <summary>
/// Attempts to validate the JSON against the specified schema
/// </summary>
/// <param name="json">JSON to be validated</param>
/// <param name="schemaFileName">File name of schema to validate against</param>
public static void ValidateSchema(string json, string schemaFileName)
{
JToken config = JToken.Parse(json);
var deviceConfig = new DeviceConfig();
using (StreamReader fs = new StreamReader(schemaFileName))
{
JsonSchema schema = JsonSchema.Parse(fs.ReadToEnd());
JsonSchema schema = JsonSchema.Parse(deviceConfig.SchemaJson);
config.Validate(schema, _ValidationEventHandler);
config.Validate(schema, Json_ValidationEventHandler);
}
}
public static void _ValidationEventHandler(object sender, ValidationEventArgs args)
/// <summary>
/// Event Handler callback for JSON validation
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
public static void Json_ValidationEventHandler(object sender, ValidationEventArgs args)
{
Debug.Console(0, "{0}", args.Message);
Debug.Console(0, "JSON Validation error at line {0} position {1}: {2}", args.Exception.LineNumber, args.Exception.LinePosition, args.Message);
}
/// <summary>

View File

@@ -35,43 +35,7 @@
"template"
],
"title": "Essentials Configuration"
},
"Info": {
"type": "object",
"additionalProperties": false,
"properties": {
"name":{
"type":"string"
},
"date":{
"type":"string",
"format": "date-time"
},
"version":{
"type":"string"
},
"runtimeInfo":{
"type":"object"
},
"comment":{
"type":"string"
},
"hostname":{
"type":"string"
},
"appNumber":{
"type":"integer"
},
"lastModifiedDate": {
"type": "string",
"format": "date-time"
}
},
"required": [
"lastModifiedDate"
],
"title": "SystemInfo"
},
},
"BasicConfig": {
"type": "object",
"additionalProperties": false,
@@ -96,32 +60,84 @@
}
},
"required": [
"devices",
"info",
"rooms",
"sourceLists",
"tieLines"
],
"title": "Template"
},
"Info": {
"type": "object",
"additionalProperties": true,
"properties": {
"name":{
"type":"string"
},
"date":{
"type":"string",
"format": "date-time"
},
"version":{
"type":"string"
},
"runtimeInfo":{
"$ref":"#/definitions/RuntimeInfo"
},
"comment":{
"type":"string"
},
"hostname":{
"type":"string"
},
"appNumber":{
"type":"integer"
},
"lastModifiedDate": {
"type": "string",
"format": "date-time"
},
"lastUid":{
"type":"integer"
},
"processorType":{
"type":"string"
},
"systemType":{
"type":"string"
},
"requiredControlSoftwareVersion":{
"type":"string"
}
},
"required": [
],
"title": "Info"
},
"RuntimeInfo":{
"type":"object",
"additionalProperties": false,
"properties": {
"appName":{
"type":"string"
},
"assemblyVersion": {
"type":"string"
},
"osVersion":{
"type":"string"
}
}
},
"Device": {
"type": "object",
"additionalProperties": false,
"additionalProperties": true,
"properties": {
"name": {
"type": "string"
},
"supportedConfigModes": {
"type": "array",
"items": {
"type": "string"
}
},
"group": {
"type": "string"
},
"properties": {
"$ref": "#/definitions/DeviceProperties"
"type":"object"
},
"uid": {
"type": "integer"
@@ -131,302 +147,17 @@
},
"type": {
"type": "string"
},
"supportsCompliance": {
"type": "boolean"
},
"supportedSystemTypes": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"group",
"key",
"name",
"properties",
"type",
"uid"
"type"
],
"title": "Device"
},
"DeviceProperties": {
"type": "object",
"additionalProperties": false,
"properties": {
"numberOfRelays": {
"type": "integer"
},
"numberOfComPorts": {
"type": "integer"
},
"numberOfDIOPorts": {
"type": "integer"
},
"numberOfIrPorts": {
"type": "integer"
},
"hasControls": {
"type": "boolean"
},
"isDefault": {
"type": "boolean"
},
"hasAudio": {
"type": "boolean"
},
"hasDpad": {
"type": "boolean"
},
"hasNumeric": {
"type": "boolean"
},
"hasDvr": {
"type": "boolean"
},
"disableCodecSharing": {
"type": "boolean"
},
"control": {
"$ref": "#/definitions/Control"
},
"serverUrl": {
"type": "string"
},
"communicationMonitorProperties": {
"$ref": "#/definitions/CommunicationMonitorProperties"
},
"phonebookMode": {
"type": "string"
},
"occupancy": {
"$ref": "#/definitions/Occupancy"
},
"favorites": {
"type": "array",
"items": {
"$ref": "#/definitions/Favorite"
}
},
"sgdFile": {
"type": "string"
},
"showTime": {
"type": "boolean"
},
"showVolumeGauge": {
"type": "boolean"
},
"sourcesOverflowCount": {
"type": "integer"
},
"showDate": {
"type": "boolean"
},
"headerStyle": {
"type": "string"
},
"usesSplashPage": {
"type": "boolean"
},
"roomListKey": {
"type": "string"
},
"defaultRoomKey": {
"type": "string"
}
},
"required": [],
"title": "DeviceProperties"
},
"CommunicationMonitorProperties": {
"type": "object",
"additionalProperties": false,
"properties": {
"timeToError": {
"type": "integer"
},
"timeToWarning": {
"type": "integer"
},
"pollInterval": {
"type": "integer"
},
"pollString": {
"type": "string"
}
},
"required": [
"pollInterval",
"pollString",
"timeToError",
"timeToWarning"
],
"title": "CommunicationMonitorProperties"
},
"Control": {
"type": "object",
"additionalProperties": false,
"properties": {
"irFile": {
"type": "string"
},
"controlPortNumber": {
"type": "integer"
},
"controlPortDevKey": {
"type": "string"
},
"method": {
"type": "string"
},
"tcpSshProperties": {
"$ref": "#/definitions/TCPSSHProperties"
},
"controlPortName": {
"type": "string"
},
"ipid": {
"type": "string",
"format": "integer"
},
"endOfLineChar": {
"type": "string"
},
"endOfLineString": {
"type": "string"
},
"deviceReadyResponsePattern": {
"type": "string"
},
"params": {
"$ref": "#/definitions/Params"
}
},
"required": [],
"title": "Control"
},
"Params": {
"type": "object",
"additionalProperties": false,
"properties": {
"deviceReadyResponsePattern": {
"type": "string"
},
"endOfLineString": {
"type": "string"
}
},
"required": [
"deviceReadyResponsePattern",
"endOfLineString"
],
"title": "Params"
},
"TCPSSHProperties": {
"type": "object",
"additionalProperties": false,
"properties": {
"username": {
"type": "string"
},
"port": {
"type": "integer"
},
"address": {
"type": "string"
},
"password": {
"type": "string"
},
"autoReconnect": {
"type": "boolean"
},
"autoReconnectIntervalMs": {
"type": "integer"
},
"bufferSize": {
"type": "integer"
}
},
"required": [
"address",
"autoReconnect",
"autoReconnectIntervalMs",
"bufferSize",
"password",
"port",
"username"
],
"title": "TCPSSHProperties"
},
"Favorite": {
"type": "object",
"additionalProperties": false,
"properties": {
"name": {
"type": "string"
},
"number": {
"type": "string",
"format": "integer"
}
},
"required": [
"name",
"number"
],
"title": "Favorite"
},
"Occupancy": {
"type": "object",
"additionalProperties": false,
"properties": {
"available": {
"type": "boolean"
}
},
"required": [
"available"
],
"title": "Occupancy"
},
"TemplateInfo": {
"type": "object",
"additionalProperties": false,
"properties": {
"lastUid": {
"type": "integer"
},
"processorType": {
"type": "string"
},
"systemType": {
"type": "string"
},
"lastModifiedDate": {
"type": "string",
"format": "date-time"
},
"requiredControlSofwareVersion": {
"type": "string"
},
"comment": {
"type": "string"
}
},
"required": [
"comment",
"lastModifiedDate",
"lastUid",
"processorType",
"requiredControlSofwareVersion",
"systemType"
],
"title": "TemplateInfo"
},
"Room": {
"type": "object",
"additionalProperties": false,
@@ -438,7 +169,7 @@
"type": "string"
},
"properties": {
"$ref": "#/definitions/RoomProperties"
"type": "object"
},
"type": {
"type": "string"
@@ -452,246 +183,22 @@
],
"title": "Room"
},
"RoomProperties": {
"type": "object",
"additionalProperties": false,
"properties": {
"description": {
"type": "string"
},
"volumes": {
"$ref": "#/definitions/Volumes"
},
"defaultDisplayKey": {
"type": "string"
},
"defaultAudioKey": {
"type": "string"
},
"helpMessage": {
"type": "string"
},
"hasDsp": {
"type": "boolean"
},
"defaultSourceItem": {
"type": "string"
},
"logo": {
"$ref": "#/definitions/Logo"
},
"environment": {
"$ref": "#/definitions/Environment"
},
"defaultVideoBehavior": {
"type": "string"
},
"videoCodecKey": {
"type": "string"
},
"sourceListKey": {
"type": "string"
}
},
"required": [
"defaultAudioKey",
"defaultDisplayKey",
"defaultSourceItem",
"defaultVideoBehavior",
"description",
"environment",
"hasDsp",
"helpMessage",
"logo",
"sourceListKey",
"videoCodecKey",
"volumes"
],
"title": "RoomProperties"
},
"Environment": {
"type": "object",
"additionalProperties": false,
"properties": {
"deviceKeys": {
"type": "array",
"items": {}
}
},
"required": [
"deviceKeys"
],
"title": "Environment"
},
"Logo": {
"type": "object",
"additionalProperties": false,
"properties": {
"url": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"type",
"url"
],
"title": "Logo"
},
"Volumes": {
"type": "object",
"additionalProperties": false,
"properties": {
"master": {
"$ref": "#/definitions/Master"
}
},
"required": [
"master"
],
"title": "Volumes"
},
"Master": {
"type": "object",
"additionalProperties": false,
"properties": {
"level": {
"type": "integer"
},
"deviceKey": {
"type": "string"
},
"label": {
"type": "string"
}
},
"required": [
"deviceKey",
"label",
"level"
],
"title": "Master"
},
"SourceLists": {
"type": "object",
"additionalProperties": false,
"additionalProperties": true,
"properties": {
"default": {
"$ref": "#/definitions/Default"
"default":{
"$ref":"#/definitions/SourceList"
}
},
"required": [
"default"
],
"title": "SourceLists"
},
"Default": {
"SourceList": {
"type": "object",
"additionalProperties": false,
"additionalProperties": true,
"properties": {
"codecOsd": {
"$ref": "#/definitions/CodecOsd"
},
"source-1": {
"$ref": "#/definitions/Source"
},
"roomOff": {
"$ref": "#/definitions/RoomOff"
},
"source-2": {
"$ref": "#/definitions/Source"
}
},
"required": [
"codecOsd",
"roomOff",
"source-1",
"source-2"
],
"title": "Default"
},
"CodecOsd": {
"type": "object",
"additionalProperties": false,
"properties": {
"sourceKey": {
"type": "string"
},
"name": {
"type": "string"
},
"routeList": {
"type": "array",
"items": {
"$ref": "#/definitions/RouteList"
}
},
"includeInSourceList": {
"type": "boolean"
},
"type": {
"type": "string"
},
"order": {
"type": "integer"
}
},
"required": [
"includeInSourceList",
"name",
"order",
"routeList",
"sourceKey",
"type"
],
"title": "CodecOsd"
},
"RouteList": {
"type": "object",
"additionalProperties": false,
"properties": {
"destinationKey": {
"type": "string"
},
"sourceKey": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"destinationKey",
"sourceKey",
"type"
],
"title": "RouteList"
},
"RoomOff": {
"type": "object",
"additionalProperties": false,
"properties": {
"sourceKey": {
"type": "string"
},
"routeList": {
"type": "array",
"items": {
"$ref": "#/definitions/RouteList"
}
},
"type": {
"type": "string"
}
},
"required": [
"routeList",
"sourceKey",
"type"
],
"title": "RoomOff"
"title": "Source List"
},
"Source": {
"type": "object",
@@ -716,7 +223,12 @@
"type": "boolean"
},
"type": {
"type": "string"
"type": "string",
"enum":[
"route",
"off",
"other"
]
},
"altIcon": {
"type": "string"
@@ -729,8 +241,6 @@
}
},
"required": [
"altIcon",
"icon",
"includeInSourceList",
"order",
"routeList",
@@ -739,6 +249,34 @@
"volumeControlKey"
],
"title": "Source"
},
"RouteList": {
"type": "object",
"additionalProperties": false,
"properties": {
"destinationKey": {
"type": "string"
},
"sourceKey": {
"type": "string"
},
"type": {
"type": "string",
"enum":[
"audio",
"video",
"audioVideo",
"usbOutput",
"usbInput"
]
}
},
"required": [
"destinationKey",
"sourceKey",
"type"
],
"title": "RouteList"
}
}
}