mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-01-17 14:35:02 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1ccdeda5ed | ||
|
|
f113b0df63 | ||
|
|
cb6dcc7de9 | ||
|
|
740c944f54 | ||
|
|
bd7831146d | ||
|
|
aa64cc917c | ||
|
|
1017464980 | ||
|
|
47f4d90c5a | ||
|
|
c3dbd41942 | ||
|
|
45788a4d6b | ||
|
|
d63787bc78 | ||
|
|
d269a04bab | ||
|
|
cc5889385e | ||
|
|
fe14d543d6 |
@@ -223,6 +223,8 @@ namespace PepperDash.Essentials
|
||||
|
||||
CrestronEnvironment.Sleep(1000);
|
||||
|
||||
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Shutting down room");
|
||||
|
||||
RunRouteAction("roomOff");
|
||||
}
|
||||
|
||||
@@ -275,8 +277,8 @@ namespace PepperDash.Essentials
|
||||
// Run this on a separate thread
|
||||
new CTimer(o =>
|
||||
{
|
||||
Debug.Console(1, this, "Run route action '{0}'", routeKey);
|
||||
var dict = ConfigReader.ConfigObject.GetSourceListForKey(SourceListKey);
|
||||
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Run route action '{0}'", routeKey);
|
||||
var dict = ConfigReader.ConfigObject.GetSourceListForKey(SourceListKey);
|
||||
if(dict == null)
|
||||
{
|
||||
Debug.Console(1, this, "WARNING: Config source list '{0}' not found", SourceListKey);
|
||||
|
||||
@@ -334,8 +334,11 @@ namespace PepperDash.Essentials
|
||||
{
|
||||
// Add Occupancy object from config
|
||||
if (PropertiesConfig.Occupancy != null)
|
||||
{
|
||||
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Setting Occupancy Provider for room");
|
||||
this.SetRoomOccupancy(DeviceManager.GetDeviceForKey(PropertiesConfig.Occupancy.DeviceKey) as
|
||||
IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimeoutMinutes);
|
||||
}
|
||||
|
||||
this.LogoUrl = PropertiesConfig.Logo.GetUrl();
|
||||
this.SourceListKey = PropertiesConfig.SourceListKey;
|
||||
@@ -359,6 +362,8 @@ namespace PepperDash.Essentials
|
||||
|
||||
CrestronEnvironment.Sleep(1000);
|
||||
|
||||
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Shutting down room");
|
||||
|
||||
RunRouteAction("roomOff");
|
||||
}
|
||||
|
||||
@@ -408,7 +413,7 @@ namespace PepperDash.Essentials
|
||||
try
|
||||
{
|
||||
|
||||
Debug.Console(1, this, "Run route action '{0}'", routeKey);
|
||||
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Run route action '{0}'", routeKey);
|
||||
var dict = ConfigReader.ConfigObject.GetSourceListForKey(SourceListKey);
|
||||
if (dict == null)
|
||||
{
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -11,24 +11,43 @@ using PepperDash.Essentials.Core;
|
||||
|
||||
namespace PepperDash.Essentials.Core.Config
|
||||
{
|
||||
public class DeviceConfig
|
||||
public class DeviceConfig : PropertiesConfigBase
|
||||
{
|
||||
[JsonProperty("key")]
|
||||
/// <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; }
|
||||
|
||||
[JsonProperty("type")]
|
||||
/// <summary>
|
||||
/// The type of the device to instantiate
|
||||
/// </summary>
|
||||
[JsonProperty("type", Required = Required.Always)]
|
||||
public string Type { get; set; }
|
||||
|
||||
[JsonProperty("properties")]
|
||||
/// <summary>
|
||||
/// The properties necessary to define the device
|
||||
/// </summary>
|
||||
[JsonProperty("properties", Required = Required.Always)]
|
||||
[JsonConverter(typeof(DevicePropertiesConverter))]
|
||||
public JToken Properties { get; set; }
|
||||
}
|
||||
@@ -59,7 +78,7 @@ namespace PepperDash.Essentials.Core.Config
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
throw new NotImplementedException("SOD OFF HOSER");
|
||||
throw new NotImplementedException("Not Supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharp.CrestronIO;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json.Schema;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Core.Config;
|
||||
|
||||
@@ -91,9 +92,24 @@ namespace PepperDash.Essentials.Core.Config
|
||||
{
|
||||
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Loading config file: '{0}'", filePath);
|
||||
|
||||
var directoryPrefix = string.Format("{0}Config{1}Schema{1}", Global.ApplicationDirectoryPrefix, Global.DirectorySeparator);
|
||||
|
||||
var schemaFilePath = directoryPrefix + "EssentialsConfigSchema.json";
|
||||
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Loading Schema from path: {0}", schemaFilePath);
|
||||
|
||||
var jsonConfig = fs.ReadToEnd();
|
||||
|
||||
if(File.Exists(schemaFilePath))
|
||||
{
|
||||
// Attempt to validate config against schema
|
||||
ValidateSchema(jsonConfig, schemaFilePath);
|
||||
}
|
||||
else
|
||||
Debug.Console(0, Debug.ErrorLogLevel.Warning, "No Schema found at path: {0}", schemaFilePath);
|
||||
|
||||
if (localConfigFound)
|
||||
{
|
||||
ConfigObject = JObject.Parse(fs.ReadToEnd()).ToObject<EssentialsConfig>();
|
||||
ConfigObject = JObject.Parse(jsonConfig).ToObject<EssentialsConfig>();
|
||||
|
||||
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Successfully Loaded Local Config");
|
||||
|
||||
@@ -101,7 +117,7 @@ namespace PepperDash.Essentials.Core.Config
|
||||
}
|
||||
else
|
||||
{
|
||||
var doubleObj = JObject.Parse(fs.ReadToEnd());
|
||||
var doubleObj = JObject.Parse(jsonConfig);
|
||||
ConfigObject = PortalConfigReader.MergeConfigs(doubleObj).ToObject<EssentialsConfig>();
|
||||
|
||||
// Extract SystemUrl and TemplateUrl into final config output
|
||||
@@ -129,6 +145,40 @@ namespace PepperDash.Essentials.Core.Config
|
||||
}
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Validating Config File against Schema...");
|
||||
JObject config = JObject.Parse(json);
|
||||
|
||||
using (StreamReader fileStream = new StreamReader(schemaFileName))
|
||||
{
|
||||
JsonSchema schema = JsonSchema.Parse(fileStream.ReadToEnd());
|
||||
|
||||
if (config.IsValid(schema))
|
||||
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Configuration successfully Validated Against Schema");
|
||||
else
|
||||
{
|
||||
Debug.Console(0, Debug.ErrorLogLevel.Warning, "Validation Errors Found in Configuration:");
|
||||
config.Validate(schema, Json_ValidationEventHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <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, "JSON Validation error at line {0} position {1}: {2}", args.Exception.LineNumber, args.Exception.LinePosition, args.Message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all the files from the directory specified.
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"title": "Control Properties",
|
||||
"$ref": "#/definitions/ControlPropertiesConfig",
|
||||
"definitions": {
|
||||
"ControlPropertiesConfig": {
|
||||
"description": "The method of communicating with the device",
|
||||
"properties": {
|
||||
"method": {
|
||||
"type": "string",
|
||||
"title": "Communication Method",
|
||||
"enum": [
|
||||
"none",
|
||||
"com",
|
||||
"ipid",
|
||||
"ipidtcp",
|
||||
"ir",
|
||||
"ssh",
|
||||
"tcpip",
|
||||
"telnet",
|
||||
"cresnet",
|
||||
"cec",
|
||||
"udp"
|
||||
]
|
||||
},
|
||||
"tcpSshProperties": {
|
||||
"$ref":"TcpSshPropertiesConfigSchema.json#definitions/TcpSshPropertiesConfig",
|
||||
"title": "Properties for IP based communication",
|
||||
"default": null
|
||||
},
|
||||
"comParams": {
|
||||
"title":"Com Port parameters",
|
||||
"description": "The parameters to configure the COM port",
|
||||
"type":"object",
|
||||
"protocol":{
|
||||
"title":"Protocol",
|
||||
"type":"string",
|
||||
"enum":[
|
||||
"RS232",
|
||||
"RS422",
|
||||
"RS485"
|
||||
]
|
||||
},
|
||||
"baudRate":{
|
||||
"title":"Baud Rate",
|
||||
"type":"integer",
|
||||
"enum":[
|
||||
300,
|
||||
600,
|
||||
1200,
|
||||
1800,
|
||||
2400,
|
||||
3600,
|
||||
4800,
|
||||
7200,
|
||||
9600,
|
||||
14400,
|
||||
19200,
|
||||
28800,
|
||||
38400,
|
||||
57600,
|
||||
115200
|
||||
]
|
||||
},
|
||||
"dataBits":{
|
||||
"title":"Data Bits",
|
||||
"type":"integer",
|
||||
"enum":[
|
||||
7,
|
||||
8
|
||||
]
|
||||
},
|
||||
"stopBits":{
|
||||
"title":"Stop Bits",
|
||||
"type":"integer",
|
||||
"enum":[
|
||||
1,
|
||||
2
|
||||
]
|
||||
},
|
||||
"parity":{
|
||||
"title":"Parity",
|
||||
"type":"string",
|
||||
"enum":[
|
||||
"None",
|
||||
"Even",
|
||||
"One"
|
||||
]
|
||||
},
|
||||
"softwareHandshake":{
|
||||
"title":"Software Handshake",
|
||||
"type":"string",
|
||||
"enum":[
|
||||
"None",
|
||||
"RTS",
|
||||
"CTS",
|
||||
"RTSCTS"
|
||||
]
|
||||
},
|
||||
"hardwareHandshake":{
|
||||
"title":"Hardware Handshake",
|
||||
"type":"string",
|
||||
"enum":[
|
||||
"None",
|
||||
"XON",
|
||||
"XONT",
|
||||
"XONR"
|
||||
]
|
||||
},
|
||||
"pacing":{
|
||||
"title":"Pacing",
|
||||
"type":"integer"
|
||||
}
|
||||
},
|
||||
"cresnetId":{
|
||||
"type": "string",
|
||||
"title":"Cresnet ID",
|
||||
"description": "Cresnet ID of the device",
|
||||
"default": "",
|
||||
"examples": [
|
||||
"13",
|
||||
"03",
|
||||
"0A",
|
||||
"F1"
|
||||
],
|
||||
"pattern": "^(?!00|01|02|FF)[0-9,A-F,a-f][0-9,A-F,a-f]$"
|
||||
},
|
||||
"controlPortDevKey": {
|
||||
"type": "string",
|
||||
"title":"Port Device",
|
||||
"description": "Key of the device where the control port is found",
|
||||
"examples": [
|
||||
"processor"
|
||||
]
|
||||
},
|
||||
"controlPortNumber": {
|
||||
"type": "integer",
|
||||
"title": "Port Number",
|
||||
"description": "Control Port Number on the device referenced by controlPortDevKey",
|
||||
"examples": [
|
||||
1
|
||||
]
|
||||
},
|
||||
"controlPortName": {
|
||||
"type": "string",
|
||||
"title": "Port Name",
|
||||
"description": "Control Port Name on the device referenced by controlPortDevKey",
|
||||
"examples": [
|
||||
"hdmi1"
|
||||
]
|
||||
},
|
||||
"irFile": {
|
||||
"type": "string",
|
||||
"title": "IR File",
|
||||
"description": "IR Filename",
|
||||
"default": "",
|
||||
"examples": [
|
||||
"Comcast Motorola DVR.ir"
|
||||
],
|
||||
"pattern": "^(.*).ir$"
|
||||
},
|
||||
"ipid": {
|
||||
"type": "string",
|
||||
"title": "IPID",
|
||||
"default": "",
|
||||
"examples": [
|
||||
"13",
|
||||
"03",
|
||||
"0A",
|
||||
"F1"
|
||||
],
|
||||
"pattern": "^(?!00|01|02|FF)[0-9,A-F,a-f][0-9,A-F,a-f]$"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"method"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Essentials Configuration File Schema",
|
||||
"description": "",
|
||||
"type": "object",
|
||||
"$ref":"#/definitions/EssentialsConfig",
|
||||
"definitions": {
|
||||
"EssentialsConfig": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"template": {
|
||||
"$ref": "#/definitions/BasicConfig"
|
||||
},
|
||||
"system_url": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"qt-uri-protocols": [
|
||||
"https"
|
||||
]
|
||||
},
|
||||
"system": {
|
||||
"$ref": "#/definitions/BasicConfig"
|
||||
},
|
||||
"template_url": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"qt-uri-protocols": [
|
||||
"https"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"system",
|
||||
"template"
|
||||
],
|
||||
"title": "Essentials Configuration"
|
||||
},
|
||||
"BasicConfig": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"devices": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Device"
|
||||
}
|
||||
},
|
||||
"rooms": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Room"
|
||||
}
|
||||
},
|
||||
"info": {
|
||||
"$ref": "#/definitions/Info"
|
||||
},
|
||||
"sourceLists": {
|
||||
"$ref": "#/definitions/SourceLists"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
],
|
||||
"title": "Basic Config"
|
||||
},
|
||||
"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": true,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"group": {
|
||||
"type": "string"
|
||||
},
|
||||
"properties": {
|
||||
"type":"object"
|
||||
},
|
||||
"uid": {
|
||||
"type": "integer"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"group",
|
||||
"key",
|
||||
"properties",
|
||||
"type"
|
||||
],
|
||||
"title": "Device"
|
||||
},
|
||||
|
||||
"Room": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"properties": {
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"key",
|
||||
"name",
|
||||
"properties",
|
||||
"type"
|
||||
],
|
||||
"title": "Room"
|
||||
},
|
||||
"SourceLists": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"default":{
|
||||
"$ref":"#/definitions/SourceList"
|
||||
}
|
||||
},
|
||||
"title": "SourceLists"
|
||||
},
|
||||
"SourceList": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
},
|
||||
"title": "Source List"
|
||||
},
|
||||
"Source": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"icon": {
|
||||
"type": "string"
|
||||
},
|
||||
"volumeControlKey": {
|
||||
"type": "string"
|
||||
},
|
||||
"sourceKey": {
|
||||
"type": "string"
|
||||
},
|
||||
"routeList": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/RouteList"
|
||||
}
|
||||
},
|
||||
"includeInSourceList": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum":[
|
||||
"route",
|
||||
"off",
|
||||
"other"
|
||||
]
|
||||
},
|
||||
"altIcon": {
|
||||
"type": "string"
|
||||
},
|
||||
"order": {
|
||||
"type": "integer"
|
||||
},
|
||||
"disableCodecSharing": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"includeInSourceList",
|
||||
"order",
|
||||
"routeList",
|
||||
"sourceKey",
|
||||
"type",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"title": "TcpSshPropertiesConfig",
|
||||
"$ref": "#/definitions/TcpSshPropertiesConfig",
|
||||
"definitions": {
|
||||
"TcpSshPropertiesConfig": {
|
||||
"properties": {
|
||||
"username": {
|
||||
"type": "string",
|
||||
"title": "Username",
|
||||
"default":"",
|
||||
"examples": [
|
||||
"admin"
|
||||
],
|
||||
"pattern": "^(.*)$"
|
||||
},
|
||||
"port": {
|
||||
"type": "integer",
|
||||
"title": "Port Number",
|
||||
"minimum": 1,
|
||||
"maximum": 65535,
|
||||
"examples": [
|
||||
22,
|
||||
23,
|
||||
1515
|
||||
]
|
||||
},
|
||||
"address": {
|
||||
"type": "string",
|
||||
"title": "IP Address or Hostname",
|
||||
"examples": [
|
||||
"192.168.99.100",
|
||||
"myDeviceHostname"
|
||||
],
|
||||
"pattern": "^(.*)$"
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
"title": "Password",
|
||||
"default":"",
|
||||
"examples": [
|
||||
"password"
|
||||
],
|
||||
"pattern": "^(.*)$"
|
||||
},
|
||||
"autoReconnect": {
|
||||
"type": "boolean",
|
||||
"title": "Auto Reconnect",
|
||||
"description": "Indicates if automatic attemtps to reconnect should be made if communication is lost with the device",
|
||||
"default": true,
|
||||
"examples": [
|
||||
true
|
||||
]
|
||||
},
|
||||
"autoReconnectIntervalMs": {
|
||||
"type": "integer",
|
||||
"title": "Auto Reconnect Interval (Milliseconds)",
|
||||
"description": "If Auto Reconnect is enabled, how often should reconnect attempts be made",
|
||||
"default": 5000,
|
||||
"examples": [
|
||||
2000
|
||||
]
|
||||
},
|
||||
"bufferSize": {
|
||||
"type": "integer",
|
||||
"title": "Buffer Size",
|
||||
"description": "The size of the receive buffer to use",
|
||||
"default": 32768,
|
||||
"examples": [
|
||||
32768
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"port",
|
||||
"address"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharpPro;
|
||||
using Crestron.SimplSharpPro.GeneralIO;
|
||||
|
||||
using PepperDash.Core;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Wrapper class for CEN-IO-DIGIN-104 digital input module
|
||||
/// </summary>
|
||||
public class CenIoDigIn104Controller : Device, IDigitalInputPorts
|
||||
{
|
||||
public CenIoDi104 Di104 { get; private set; }
|
||||
|
||||
public CenIoDigIn104Controller(string key, string name, CenIoDi104 di104)
|
||||
: base(key, name)
|
||||
{
|
||||
Di104 = di104;
|
||||
}
|
||||
|
||||
#region IDigitalInputPorts Members
|
||||
|
||||
public CrestronCollection<DigitalInput> DigitalInputPorts
|
||||
{
|
||||
get { return Di104.DigitalInputPorts; }
|
||||
}
|
||||
|
||||
public int NumberOfDigitalInputPorts
|
||||
{
|
||||
get { return Di104.NumberOfDigitalInputPorts; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,9 @@ using PepperDash.Essentials.Core.Config;
|
||||
namespace PepperDash.Essentials.Core.Devices
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// This class should be inherited from when the configuration can be modified at runtime from another source other than the configuration file.
|
||||
/// It contains the necessary properties, methods and events to allot the initial device configuration to be overridden and then notifies the
|
||||
/// ConfigWriter to write out the new values to a local file to be read on next boot.
|
||||
/// </summary>
|
||||
public abstract class ReconfigurableDevice : Device
|
||||
{
|
||||
|
||||
@@ -67,34 +67,64 @@ namespace PepperDash.Essentials.Core
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The icon to display
|
||||
/// </summary>
|
||||
[JsonProperty("icon")]
|
||||
public string Icon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Alternate icon to display
|
||||
/// </summary>
|
||||
[JsonProperty("altIcon")]
|
||||
public string AltIcon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the source should be included in the list
|
||||
/// </summary>
|
||||
[JsonProperty("includeInSourceList")]
|
||||
public bool IncludeInSourceList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines the order the source appears in the list (ascending)
|
||||
/// </summary>
|
||||
[JsonProperty("order")]
|
||||
public int Order { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Key of the volume control device for the source
|
||||
/// </summary>
|
||||
[JsonProperty("volumeControlKey")]
|
||||
public string VolumeControlKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of source list item
|
||||
/// </summary>
|
||||
[JsonProperty("type")]
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public eSourceListItemType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of routes to run when source is selected
|
||||
/// </summary>
|
||||
[JsonProperty("routeList")]
|
||||
public List<SourceRouteListItem> RouteList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if this source should be disabled for sharing via codec content
|
||||
/// </summary>
|
||||
[JsonProperty("disableCodecSharing")]
|
||||
public bool DisableCodecSharing { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if this source should be disabled for local routing
|
||||
/// </summary>
|
||||
[JsonProperty("disableRoutedSharing")]
|
||||
public bool DisableRoutedSharing { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of valid destination types for this source
|
||||
/// </summary>
|
||||
[JsonProperty("destinations")]
|
||||
public List<eSourceListItemDestinationTypes> Destinations { get; set; }
|
||||
|
||||
|
||||
@@ -52,6 +52,13 @@ namespace PepperDash.Essentials.Core
|
||||
Debug.Console(1, "Factory Attempting to create new Generic Comm Device");
|
||||
return new GenericComm(dc);
|
||||
}
|
||||
else if (typeName == "ceniodigin104")
|
||||
{
|
||||
var control = CommFactory.GetControlPropertiesConfig(dc);
|
||||
var ipid = control.CresnetIdInt;
|
||||
|
||||
return new CenIoDigIn104Controller(key, name, new Crestron.SimplSharpPro.GeneralIO.CenIoDi104(ipid, Global.ControlSystem));
|
||||
}
|
||||
|
||||
// then check for types that have been added by plugin dlls.
|
||||
if (FactoryMethods.ContainsKey(typeName))
|
||||
|
||||
@@ -9,8 +9,14 @@ using PepperDash.Essentials.License;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Global application properties
|
||||
/// </summary>
|
||||
public static class Global
|
||||
{
|
||||
/// <summary>
|
||||
/// The control system the application is running on
|
||||
/// </summary>
|
||||
public static CrestronControlSystem ControlSystem { get; set; }
|
||||
|
||||
public static LicenseManager LicenseManager { get; set; }
|
||||
@@ -31,6 +37,19 @@ namespace PepperDash.Essentials.Core
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The file path prefix to the folder containing the application files (including embedded resources)
|
||||
/// </summary>
|
||||
public static string ApplicationDirectoryPrefix
|
||||
{
|
||||
get
|
||||
{
|
||||
string fmt = "00.##";
|
||||
var appNumber = InitialParametersClass.ApplicationNumber.ToString(fmt);
|
||||
return string.Format("{0}{1}Simpl{1}app{2}{1}", Crestron.SimplSharp.CrestronIO.Directory.GetApplicationRootDirectory(), Global.DirectorySeparator,appNumber );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wildcarded config file name for global reference
|
||||
/// </summary>
|
||||
|
||||
@@ -62,6 +62,10 @@
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.Fusion.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Crestron.SimplSharpPro.GeneralIO, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.GeneralIO.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Crestron.SimplSharpPro.Remotes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.Remotes.dll</HintPath>
|
||||
@@ -114,6 +118,7 @@
|
||||
<Compile Include="Config\Essentials\ConfigWriter.cs" />
|
||||
<Compile Include="Config\Essentials\EssentialsConfig.cs" />
|
||||
<Compile Include="Config\SourceDevicePropertiesConfigBase.cs" />
|
||||
<Compile Include="Crestron IO\Inputs\CenIoDigIn104Controller.cs" />
|
||||
<Compile Include="Crestron IO\Inputs\GenericDigitalInputDevice.cs" />
|
||||
<Compile Include="Crestron IO\Inputs\GenericVersiportInputDevice.cs" />
|
||||
<Compile Include="Crestron IO\Inputs\IDigitalInput.cs" />
|
||||
@@ -262,6 +267,15 @@
|
||||
<Compile Include="SmartObjects\SubpageReferencList\SubpageReferenceList.cs" />
|
||||
<Compile Include="SmartObjects\SubpageReferencList\SubpageReferenceListItem.cs" />
|
||||
<None Include="app.config" />
|
||||
<EmbeddedResource Include="Config\Schema\EssentialsConfigSchema.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Config\Schema\ControlPropertiesConfigSchema.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Config\Schema\TcpSshPropertiesConfigSchema.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
<None Include="Properties\ControlSystem.cfg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -100,7 +100,8 @@ namespace PepperDash.Essentials.Core
|
||||
ShutdownPromptTimer.HasFinished += (o, a) => Shutdown(); // Shutdown is triggered
|
||||
|
||||
ShutdownPromptSeconds = 60;
|
||||
ShutdownVacancySeconds = 120;
|
||||
ShutdownVacancySeconds = 120;
|
||||
|
||||
ShutdownType = eShutdownType.None;
|
||||
|
||||
RoomVacancyShutdownTimer = new SecondsCountdownTimer(Key + "-vacancyOffTimer");
|
||||
@@ -140,7 +141,7 @@ namespace PepperDash.Essentials.Core
|
||||
case eVacancyMode.InShutdownWarning:
|
||||
{
|
||||
StartShutdown(eShutdownType.Vacancy);
|
||||
Debug.Console(0, this, "Shutting Down due to vacancy.");
|
||||
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Shutting Down due to vacancy.");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -163,7 +164,7 @@ namespace PepperDash.Essentials.Core
|
||||
ShutdownType = type;
|
||||
ShutdownPromptTimer.Start();
|
||||
|
||||
Debug.Console(0, this, "ShutdwonPromptTimer Started. Type: {0}. Seconds: {1}", ShutdownType, ShutdownPromptTimer.SecondsToCount);
|
||||
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "ShutdownPromptTimer Started. Type: {0}. Seconds: {1}", ShutdownType, ShutdownPromptTimer.SecondsToCount);
|
||||
}
|
||||
|
||||
public void StartRoomVacancyTimer(eVacancyMode mode)
|
||||
@@ -175,7 +176,7 @@ namespace PepperDash.Essentials.Core
|
||||
VacancyMode = mode;
|
||||
RoomVacancyShutdownTimer.Start();
|
||||
|
||||
Debug.Console(0, this, "Vacancy Timer Started. Mode: {0}. Seconds: {1}", VacancyMode, RoomVacancyShutdownTimer.SecondsToCount);
|
||||
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Vacancy Timer Started. Mode: {0}. Seconds: {1}", VacancyMode, RoomVacancyShutdownTimer.SecondsToCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -211,6 +212,9 @@ namespace PepperDash.Essentials.Core
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Room Occupancy set to device: '{0}'", (statusProvider as Device).Key);
|
||||
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Timeout Minutes from Config is: {0}", timeoutMinutes);
|
||||
|
||||
// If status provider is fusion, set flag to remote
|
||||
if (statusProvider is Core.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase)
|
||||
OccupancyStatusProviderIsRemote = true;
|
||||
@@ -218,16 +222,14 @@ namespace PepperDash.Essentials.Core
|
||||
if(timeoutMinutes > 0)
|
||||
RoomVacancyShutdownSeconds = timeoutMinutes * 60;
|
||||
|
||||
Debug.Console(1, this, "RoomVacancyShutdownSeconds set to {0}", RoomVacancyShutdownSeconds);
|
||||
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "RoomVacancyShutdownSeconds set to {0}", RoomVacancyShutdownSeconds);
|
||||
|
||||
RoomOccupancy = statusProvider;
|
||||
|
||||
OnRoomOccupancyIsSet();
|
||||
|
||||
RoomOccupancy.RoomIsOccupiedFeedback.OutputChange -= RoomIsOccupiedFeedback_OutputChange;
|
||||
RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += RoomIsOccupiedFeedback_OutputChange;
|
||||
|
||||
Debug.Console(0, this, "Room Occupancy set to device: '{0}'", (statusProvider as Device).Key);
|
||||
OnRoomOccupancyIsSet();
|
||||
}
|
||||
|
||||
void OnRoomOccupancyIsSet()
|
||||
@@ -252,13 +254,13 @@ namespace PepperDash.Essentials.Core
|
||||
{
|
||||
if (RoomOccupancy.RoomIsOccupiedFeedback.BoolValue == false)
|
||||
{
|
||||
Debug.Console(1, this, "Notice: Vacancy Detected");
|
||||
Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Notice: Vacancy Detected");
|
||||
// Trigger the timer when the room is vacant
|
||||
StartRoomVacancyTimer(eVacancyMode.InInitialVacancy);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Console(1, this, "Notice: Occupancy Detected");
|
||||
Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Notice: Occupancy Detected");
|
||||
// Reset the timer when the room is occupied
|
||||
RoomVacancyShutdownTimer.Cancel();
|
||||
}
|
||||
|
||||
@@ -17,21 +17,42 @@ namespace PepperDash.Essentials.DM.Config
|
||||
[JsonProperty("control")]
|
||||
public ControlPropertiesConfig Control { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The available volume controls
|
||||
/// </summary>
|
||||
[JsonProperty("volumeControls")]
|
||||
public Dictionary<uint, DmCardAudioPropertiesConfig> VolumeControls { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The input cards
|
||||
/// </summary>
|
||||
[JsonProperty("inputSlots")]
|
||||
public Dictionary<uint, string> InputSlots { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The output cards (each card represents a pair of outputs)
|
||||
/// </summary>
|
||||
[JsonProperty("outputSlots")]
|
||||
public Dictionary<uint, string> OutputSlots { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The names of the Inputs
|
||||
/// </summary>
|
||||
[JsonProperty("inputNames")]
|
||||
public Dictionary<uint, string> InputNames { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The names of the Outputs
|
||||
/// </summary>
|
||||
[JsonProperty("outputNames")]
|
||||
public Dictionary<uint, string> OutputNames { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The string to use when no route is set for a given output
|
||||
/// </summary>
|
||||
[JsonProperty("noRouteText")]
|
||||
public string NoRouteText { get; set; }
|
||||
|
||||
[JsonProperty("inputSlotSupportsHdcp2")]
|
||||
public Dictionary<uint, bool> InputSlotSupportsHdcp2 { get; set; }
|
||||
|
||||
@@ -46,9 +67,15 @@ namespace PepperDash.Essentials.DM.Config
|
||||
/// </summary>
|
||||
public class DmCardAudioPropertiesConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// The level to set on the output
|
||||
/// </summary>
|
||||
[JsonProperty("outLevel")]
|
||||
public int OutLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines if this level is adjustable or not
|
||||
/// </summary>
|
||||
[JsonProperty("isVolumeControlPoint")]
|
||||
public bool IsVolumeControlPoint { get; set; }
|
||||
}
|
||||
@@ -20,6 +20,9 @@ namespace PepperDash.Essentials.DM.Config
|
||||
[JsonProperty("outputNames")]
|
||||
public Dictionary<uint, string> OutputNames { get; set; }
|
||||
|
||||
[JsonProperty("noRouteText")]
|
||||
public string NoRouteText { get; set; }
|
||||
|
||||
public DmpsRoutingPropertiesConfig()
|
||||
{
|
||||
InputNames = new Dictionary<uint, string>();
|
||||
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "DmChassisController Properties Config Schema",
|
||||
"description": "",
|
||||
"$ref":"EssentialsConfigSchema.json#definitions/Device",
|
||||
"properties":{
|
||||
"properties":{
|
||||
"$ref":"#/definitions/propertiesConfig"
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"propertiesConfig": {
|
||||
"type":"object",
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"control":{
|
||||
"type":"object",
|
||||
"$ref":"ControlPropertiesConfigSchema.json#definitions/ControlPropertiesConfig"
|
||||
},
|
||||
"volumeControls":{
|
||||
"type":"object",
|
||||
"additionalProperties": {
|
||||
"type":"object",
|
||||
"$ref": "#definitions/dmAudioCardPropertiesConfig"
|
||||
}
|
||||
},
|
||||
"inputSlots":{
|
||||
"type":"object",
|
||||
"additionalProperties": {
|
||||
"type":"string"
|
||||
}
|
||||
},
|
||||
"outputSlots":{
|
||||
"type":"object",
|
||||
"additionalProperties": {
|
||||
"type":"string"
|
||||
}
|
||||
},
|
||||
"inputNames":{
|
||||
"type":"object",
|
||||
"additionalProperties": {
|
||||
"type":"string"
|
||||
}
|
||||
},
|
||||
"outputNames":{
|
||||
"type":"object",
|
||||
"additionalProperties": {
|
||||
"type":"string"
|
||||
}
|
||||
},
|
||||
"noRouteText":{
|
||||
"type":"string"
|
||||
},
|
||||
"inputSlotSupportsHdcp2":{
|
||||
"type":"object",
|
||||
"additionalProperties": {
|
||||
"type":"boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"dmAudioCardPropertiesConfig":{
|
||||
"type":"object",
|
||||
"properties": {
|
||||
"OutLevel":{
|
||||
"type":"integer"
|
||||
},
|
||||
"isVolumeControlPoint":{
|
||||
"type":"boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,6 +66,11 @@ namespace PepperDash.Essentials.DM
|
||||
public const int RouteOffTime = 500;
|
||||
Dictionary<PortNumberType, CTimer> RouteOffTimers = new Dictionary<PortNumberType, CTimer>();
|
||||
|
||||
/// <summary>
|
||||
/// Text that represents when an output has no source routed to it
|
||||
/// </summary>
|
||||
public string NoRouteText = "";
|
||||
|
||||
/// <summary>
|
||||
/// Factory method to create a new chassis controller from config data. Limited to 8x8 right now
|
||||
/// </summary>
|
||||
@@ -128,6 +133,10 @@ namespace PepperDash.Essentials.DM
|
||||
|
||||
controller.InputNames = properties.InputNames;
|
||||
controller.OutputNames = properties.OutputNames;
|
||||
|
||||
if (!string.IsNullOrEmpty(properties.NoRouteText))
|
||||
controller.NoRouteText = properties.NoRouteText;
|
||||
|
||||
controller.PropertiesConfig = properties;
|
||||
return controller;
|
||||
}
|
||||
@@ -217,7 +226,7 @@ namespace PepperDash.Essentials.DM
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
return NoRouteText;
|
||||
}
|
||||
});
|
||||
OutputAudioRouteNameFeedbacks[tempX] = new StringFeedback(() =>
|
||||
@@ -228,7 +237,7 @@ namespace PepperDash.Essentials.DM
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
return NoRouteText;
|
||||
|
||||
}
|
||||
});
|
||||
@@ -747,13 +756,19 @@ namespace PepperDash.Essentials.DM
|
||||
case DMInputEventIds.UsbRoutedToEventId:
|
||||
{
|
||||
Debug.Console(2, this, "DM Input {0} UsbRoutedToEventId", args.Number);
|
||||
UsbInputRoutedToFeebacks[args.Number].FireUpdate();
|
||||
if(UsbInputRoutedToFeebacks[args.Number] != null)
|
||||
UsbInputRoutedToFeebacks[args.Number].FireUpdate();
|
||||
else
|
||||
Debug.Console(1, this, "No index of {0} found in UsbInputRoutedToFeedbacks");
|
||||
break;
|
||||
}
|
||||
case DMInputEventIds.HdcpCapabilityFeedbackEventId:
|
||||
{
|
||||
Debug.Console(2, this, "DM Input {0} HdcpCapabilityFeedbackEventId", args.Number);
|
||||
InputCardHdcpCapabilityFeedbacks[args.Number].FireUpdate();
|
||||
if (InputCardHdcpCapabilityFeedbacks[args.Number] != null)
|
||||
InputCardHdcpCapabilityFeedbacks[args.Number].FireUpdate();
|
||||
else
|
||||
Debug.Console(1, this, "No index of {0} found in InputCardHdcpCapabilityFeedbacks");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -818,6 +833,10 @@ namespace PepperDash.Essentials.DM
|
||||
{
|
||||
AudioOutputFeedbacks[output].FireUpdate();
|
||||
}
|
||||
if (OutputAudioRouteNameFeedbacks.ContainsKey(output))
|
||||
{
|
||||
OutputAudioRouteNameFeedbacks[output].FireUpdate();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DMOutputEventIds.OutputNameEventId:
|
||||
|
||||
@@ -48,6 +48,11 @@ namespace PepperDash.Essentials.DM
|
||||
public const int RouteOffTime = 500;
|
||||
Dictionary<PortNumberType, CTimer> RouteOffTimers = new Dictionary<PortNumberType, CTimer>();
|
||||
|
||||
/// <summary>
|
||||
/// Text that represents when an output has no source routed to it
|
||||
/// </summary>
|
||||
public string NoRouteText = "";
|
||||
|
||||
public static DmpsRoutingController GetDmpsRoutingController(string key, string name,
|
||||
DmpsRoutingPropertiesConfig properties)
|
||||
{
|
||||
@@ -67,6 +72,9 @@ namespace PepperDash.Essentials.DM
|
||||
controller.InputNames = properties.InputNames;
|
||||
controller.OutputNames = properties.OutputNames;
|
||||
|
||||
if (!string.IsNullOrEmpty(properties.NoRouteText))
|
||||
controller.NoRouteText = properties.NoRouteText;
|
||||
|
||||
return controller;
|
||||
|
||||
}
|
||||
@@ -191,7 +199,7 @@ namespace PepperDash.Essentials.DM
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
return NoRouteText;
|
||||
}
|
||||
});
|
||||
OutputAudioRouteNameFeedbacks[outputCard.Number] = new StringFeedback(() =>
|
||||
@@ -202,7 +210,7 @@ namespace PepperDash.Essentials.DM
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
return NoRouteText;
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
@@ -103,10 +103,10 @@
|
||||
<Compile Include="Chassis\DmpsRoutingController.cs" />
|
||||
<Compile Include="Chassis\HdMdNxM4kEController.cs" />
|
||||
<Compile Include="IDmSwitch.cs" />
|
||||
<Compile Include="Config\DmpsRoutingConfig.cs" />
|
||||
<Compile Include="Chassis\Config\DmpsRoutingConfig.cs" />
|
||||
<Compile Include="Config\DmRmcConfig.cs" />
|
||||
<Compile Include="Config\DmTxConfig.cs" />
|
||||
<Compile Include="Config\DMChassisConfig.cs" />
|
||||
<Compile Include="Chassis\Config\DMChassisConfig.cs" />
|
||||
<Compile Include="Config\HdMdNxM4kEPropertiesConfig.cs" />
|
||||
<Compile Include="Config\InputPropertiesConfig.cs" />
|
||||
<Compile Include="DmPortName.cs" />
|
||||
@@ -148,6 +148,9 @@
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="VideoStatusHelpers.cs" />
|
||||
<None Include="app.config" />
|
||||
<EmbeddedResource Include="Chassis\Config\Schema\DmChassisControllerPropertiesConfigSchema.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
<None Include="Properties\ControlSystem.cfg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -167,84 +167,91 @@ namespace PepperDash.Essentials.Devices.Displays
|
||||
/// <param name="sender"></param>
|
||||
void Communication_BytesReceived(object sender, GenericCommMethodReceiveBytesArgs e)
|
||||
{
|
||||
// This is probably not thread-safe buffering
|
||||
// Append the incoming bytes with whatever is in the buffer
|
||||
var newBytes = new byte[IncomingBuffer.Length + e.Bytes.Length];
|
||||
IncomingBuffer.CopyTo(newBytes, 0);
|
||||
e.Bytes.CopyTo(newBytes, IncomingBuffer.Length);
|
||||
|
||||
if (Debug.Level == 2) // This check is here to prevent following string format from building unnecessarily on level 0 or 1
|
||||
Debug.Console(2, this, "Received:{0}", ComTextHelper.GetEscapedText(newBytes));
|
||||
|
||||
// Need to find AA FF and have
|
||||
for (int i = 0; i < newBytes.Length; i++)
|
||||
try
|
||||
{
|
||||
if (newBytes[i] == 0xAA && newBytes[i + 1] == 0xFF)
|
||||
// This is probably not thread-safe buffering
|
||||
// Append the incoming bytes with whatever is in the buffer
|
||||
var newBytes = new byte[IncomingBuffer.Length + e.Bytes.Length];
|
||||
IncomingBuffer.CopyTo(newBytes, 0);
|
||||
e.Bytes.CopyTo(newBytes, IncomingBuffer.Length);
|
||||
|
||||
if (Debug.Level == 2) // This check is here to prevent following string format from building unnecessarily on level 0 or 1
|
||||
Debug.Console(2, this, "Received:{0}", ComTextHelper.GetEscapedText(newBytes));
|
||||
|
||||
// Need to find AA FF and have
|
||||
for (int i = 0; i < newBytes.Length; i++)
|
||||
{
|
||||
newBytes = newBytes.Skip(i).ToArray(); // Trim off junk if there's "dirt" in the buffer
|
||||
|
||||
// parse it
|
||||
// If it's at least got the header, then process it,
|
||||
while (newBytes.Length > 4 && newBytes[0] == 0xAA && newBytes[1] == 0xFF)
|
||||
if (newBytes[i] == 0xAA && newBytes[i + 1] == 0xFF)
|
||||
{
|
||||
var msgLen = newBytes[3];
|
||||
// if the buffer is shorter than the header (3) + message (msgLen) + checksum (1),
|
||||
// give and save it for next time
|
||||
if (newBytes.Length < msgLen + 4)
|
||||
break;
|
||||
newBytes = newBytes.Skip(i).ToArray(); // Trim off junk if there's "dirt" in the buffer
|
||||
|
||||
// Good length, grab the message
|
||||
var message = newBytes.Skip(4).Take(msgLen).ToArray();
|
||||
|
||||
// At this point, the ack/nak is the first byte
|
||||
if (message[0] == 0x41)
|
||||
// parse it
|
||||
// If it's at least got the header, then process it,
|
||||
while (newBytes.Length > 4 && newBytes[0] == 0xAA && newBytes[1] == 0xFF)
|
||||
{
|
||||
switch (message[1]) // type byte
|
||||
var msgLen = newBytes[3];
|
||||
// if the buffer is shorter than the header (3) + message (msgLen) + checksum (1),
|
||||
// give and save it for next time
|
||||
if (newBytes.Length < msgLen + 4)
|
||||
break;
|
||||
|
||||
// Good length, grab the message
|
||||
var message = newBytes.Skip(4).Take(msgLen).ToArray();
|
||||
|
||||
// At this point, the ack/nak is the first byte
|
||||
if (message[0] == 0x41)
|
||||
{
|
||||
case 0x00: // General status
|
||||
//UpdatePowerFB(message[2], message[5]); // "power" can be misrepresented when the display sleeps
|
||||
switch (message[1]) // type byte
|
||||
{
|
||||
case 0x00: // General status
|
||||
//UpdatePowerFB(message[2], message[5]); // "power" can be misrepresented when the display sleeps
|
||||
|
||||
// Handle the first power on fb when waiting for it.
|
||||
if (IsPoweringOnIgnorePowerFb && message[2] == 0x01)
|
||||
IsPoweringOnIgnorePowerFb = false;
|
||||
// Ignore general-status power off messages when powering up
|
||||
if (!(IsPoweringOnIgnorePowerFb && message[2] == 0x00))
|
||||
UpdatePowerFB(message[2]);
|
||||
UpdateVolumeFB(message[3]);
|
||||
UpdateMuteFb(message[4]);
|
||||
UpdateInputFb(message[5]);
|
||||
break;
|
||||
// Handle the first power on fb when waiting for it.
|
||||
if (IsPoweringOnIgnorePowerFb && message[2] == 0x01)
|
||||
IsPoweringOnIgnorePowerFb = false;
|
||||
// Ignore general-status power off messages when powering up
|
||||
if (!(IsPoweringOnIgnorePowerFb && message[2] == 0x00))
|
||||
UpdatePowerFB(message[2]);
|
||||
UpdateVolumeFB(message[3]);
|
||||
UpdateMuteFb(message[4]);
|
||||
UpdateInputFb(message[5]);
|
||||
break;
|
||||
|
||||
case 0x11:
|
||||
UpdatePowerFB(message[2]);
|
||||
break;
|
||||
case 0x11:
|
||||
UpdatePowerFB(message[2]);
|
||||
break;
|
||||
|
||||
case 0x12:
|
||||
UpdateVolumeFB(message[2]);
|
||||
break;
|
||||
case 0x12:
|
||||
UpdateVolumeFB(message[2]);
|
||||
break;
|
||||
|
||||
case 0x13:
|
||||
UpdateMuteFb(message[2]);
|
||||
break;
|
||||
case 0x13:
|
||||
UpdateMuteFb(message[2]);
|
||||
break;
|
||||
|
||||
case 0x14:
|
||||
UpdateInputFb(message[2]);
|
||||
break;
|
||||
case 0x14:
|
||||
UpdateInputFb(message[2]);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Skip over what we've used and save the rest for next time
|
||||
newBytes = newBytes.Skip(5 + msgLen).ToArray();
|
||||
}
|
||||
// Skip over what we've used and save the rest for next time
|
||||
newBytes = newBytes.Skip(5 + msgLen).ToArray();
|
||||
}
|
||||
|
||||
break; // parsing will mean we can stop looking for header in loop
|
||||
}
|
||||
}
|
||||
|
||||
// Save whatever partial message is here
|
||||
IncomingBuffer = newBytes;
|
||||
break; // parsing will mean we can stop looking for header in loop
|
||||
}
|
||||
}
|
||||
|
||||
// Save whatever partial message is here
|
||||
IncomingBuffer = newBytes;
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
Debug.Console(2, this, "Error parsing feedback: {0}", err);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -256,6 +263,7 @@ namespace PepperDash.Essentials.Devices.Displays
|
||||
if (newVal != _PowerIsOn)
|
||||
{
|
||||
_PowerIsOn = newVal;
|
||||
Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Feedback Power State: {0}", _PowerIsOn);
|
||||
PowerIsOnFeedback.FireUpdate();
|
||||
}
|
||||
}
|
||||
@@ -364,6 +372,8 @@ namespace PepperDash.Essentials.Devices.Displays
|
||||
/// </summary>
|
||||
public override void PowerOn()
|
||||
{
|
||||
Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Powering On Display");
|
||||
|
||||
IsPoweringOnIgnorePowerFb = true;
|
||||
//Send(PowerOnCmd);
|
||||
SendBytes(new byte[] { 0xAA, 0x11, 0x00, 0x01, 0x01, 0x00 });
|
||||
@@ -387,6 +397,8 @@ namespace PepperDash.Essentials.Devices.Displays
|
||||
/// </summary>
|
||||
public override void PowerOff()
|
||||
{
|
||||
Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Powering Off Display");
|
||||
|
||||
IsPoweringOnIgnorePowerFb = false;
|
||||
// If a display has unreliable-power off feedback, just override this and
|
||||
// remove this check.
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "SamsungMDC Properties Config Schema v1",
|
||||
"description": "",
|
||||
"$ref":"EssentialsConfigSchema.json#/definitions/Device",
|
||||
"properties":{
|
||||
"properties":{
|
||||
"$ref":"#/definitions/propertiesConfig"
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"propertiesConfig": {
|
||||
"type":"object",
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"control":{
|
||||
"type":"object",
|
||||
"$ref":"ControlPropertiesConfigSchema.json#definitions/ControlPropertiesConfig"
|
||||
},
|
||||
"id":{
|
||||
"title":"Display ID",
|
||||
"description": "This must match the ID set in the display's on screen menu",
|
||||
"type":"string",
|
||||
"pattern": "^(?!FF)[0-9,A-F,a-f][0-9,A-F,a-f]$"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"control",
|
||||
"id"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -182,6 +182,9 @@
|
||||
<Compile Include="VideoCodec\ZoomRoom\ZoomRoom.cs" />
|
||||
<Compile Include="VideoCodec\ZoomRoom\ZoomRoomCamera.cs" />
|
||||
<Compile Include="VideoCodec\ZoomRoom\ZoomRoomPropertiesConfig.cs" />
|
||||
<EmbeddedResource Include="Display\Schema\SamsungMDCPropertiesConfigSchema.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
<None Include="Properties\ControlSystem.cfg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user