Merge branch 'main' into hotfix/sys-monitor-not-updating-bridge

This commit is contained in:
Neil Dorin
2021-01-12 15:34:48 -07:00
committed by GitHub
31 changed files with 3923 additions and 2701 deletions

Binary file not shown.

Binary file not shown.

View File

@@ -70,6 +70,14 @@ namespace PepperDash.Essentials.Bridges
/// Range reports the highest supported HDCP state level for the corresponding input card /// Range reports the highest supported HDCP state level for the corresponding input card
/// </summary> /// </summary>
public uint HdcpSupportCapability { get; set; } public uint HdcpSupportCapability { get; set; }
/// <summary>
/// DM Chassis Stream Input Start (1), Stop (2), Pause (3) with Feedback
/// </summary>
public uint InputStreamCardStatus { get; set; }
/// <summary>
/// DM Chassis Stream Output Start (1), Stop (2), Pause (3) with Feedback
/// </summary>
public uint OutputStreamCardStatus { get; set; }
#endregion #endregion
#region Serials #region Serials
@@ -115,6 +123,8 @@ namespace PepperDash.Essentials.Bridges
InputUsb = 700; //701-899 InputUsb = 700; //701-899
HdcpSupportState = 1000; //1001-1199 HdcpSupportState = 1000; //1001-1199
HdcpSupportCapability = 1200; //1201-1399 HdcpSupportCapability = 1200; //1201-1399
InputStreamCardStatus = 1500; //1501-1532
OutputStreamCardStatus = 1600; //1601-1632
//Serial //Serial
@@ -145,6 +155,8 @@ namespace PepperDash.Essentials.Bridges
OutputEndpointOnline = OutputEndpointOnline + joinOffset; OutputEndpointOnline = OutputEndpointOnline + joinOffset;
HdcpSupportState = HdcpSupportState + joinOffset; HdcpSupportState = HdcpSupportState + joinOffset;
HdcpSupportCapability = HdcpSupportCapability + joinOffset; HdcpSupportCapability = HdcpSupportCapability + joinOffset;
InputStreamCardStatus = InputStreamCardStatus + joinOffset;
OutputStreamCardStatus = OutputStreamCardStatus + joinOffset;
OutputDisabledByHdcp = OutputDisabledByHdcp + joinOffset; OutputDisabledByHdcp = OutputDisabledByHdcp + joinOffset;
TxAdvancedIsPresent = TxAdvancedIsPresent + joinOffset; TxAdvancedIsPresent = TxAdvancedIsPresent + joinOffset;
} }

View File

@@ -12,6 +12,7 @@ using PepperDash.Core;
using PepperDash.Essentials.Core; using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Bridges;
using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Fusion;
using PepperDash.Essentials.Devices.Common; using PepperDash.Essentials.Devices.Common;
using PepperDash.Essentials.DM; using PepperDash.Essentials.DM;
using PepperDash.Essentials.Fusion; using PepperDash.Essentials.Fusion;
@@ -52,7 +53,7 @@ namespace PepperDash.Essentials
if (Debug.DoNotLoadOnNextBoot) if (Debug.DoNotLoadOnNextBoot)
{ {
CrestronConsole.AddNewConsoleCommand(s => GoWithLoad(), "go", "Loads configuration file", CrestronConsole.AddNewConsoleCommand(s => CrestronInvoke.BeginInvoke((o) => GoWithLoad()), "go", "Loads configuration file",
ConsoleAccessLevelEnum.AccessOperator); ConsoleAccessLevelEnum.AccessOperator);
} }
@@ -436,7 +437,7 @@ namespace PepperDash.Essentials
DeviceManager.AddDevice(room); DeviceManager.AddDevice(room);
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleSpaceRoom, attempting to add to DeviceManager with Fusion"); Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleSpaceRoom, attempting to add to DeviceManager with Fusion");
DeviceManager.AddDevice(new Core.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase((EssentialsHuddleSpaceRoom)room, 0xf1)); DeviceManager.AddDevice(new Core.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase(room, 0xf1));
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge..."); Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge...");
@@ -454,6 +455,18 @@ namespace PepperDash.Essentials
CreateMobileControlBridge(room); CreateMobileControlBridge(room);
} }
else if (room is EssentialsTechRoom)
{
DeviceManager.AddDevice(room);
Debug.Console(0, Debug.ErrorLogLevel.Notice,
"Room is EssentialsTechRoom, Attempting to add to DeviceManager with Fusion");
DeviceManager.AddDevice(new EssentialsHuddleSpaceFusionSystemControllerBase(room, 0xF1));
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge");
CreateMobileControlBridge(room);
}
else else
{ {
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is NOT EssentialsRoom, attempting to add to DeviceManager w/o Fusion"); Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is NOT EssentialsRoom, attempting to add to DeviceManager w/o Fusion");

View File

@@ -141,11 +141,13 @@
<Compile Include="Room\Config\EssentialsHuddleRoomPropertiesConfig.cs" /> <Compile Include="Room\Config\EssentialsHuddleRoomPropertiesConfig.cs" />
<Compile Include="Room\Config\EssentialsHuddleVtc1PropertiesConfig.cs" /> <Compile Include="Room\Config\EssentialsHuddleVtc1PropertiesConfig.cs" />
<Compile Include="Room\Config\EssentialsRoomEmergencyConfig.cs" /> <Compile Include="Room\Config\EssentialsRoomEmergencyConfig.cs" />
<Compile Include="Room\Config\EssentialsTechRoomConfig.cs" />
<Compile Include="Room\Emergency\EsentialsRoomEmergencyContactClosure.cs" /> <Compile Include="Room\Emergency\EsentialsRoomEmergencyContactClosure.cs" />
<Compile Include="Room\Types\EssentialsDualDisplayRoom.cs" /> <Compile Include="Room\Types\EssentialsDualDisplayRoom.cs" />
<Compile Include="Room\Types\EssentialsHuddleVtc1Room.cs" /> <Compile Include="Room\Types\EssentialsHuddleVtc1Room.cs" />
<Compile Include="Room\Types\EssentialsNDisplayRoomBase.cs" /> <Compile Include="Room\Types\EssentialsNDisplayRoomBase.cs" />
<Compile Include="Room\Config\EssentialsRoomConfig.cs" /> <Compile Include="Room\Config\EssentialsRoomConfig.cs" />
<Compile Include="Room\Types\EssentialsTechRoom.cs" />
<Compile Include="UIDrivers\Environment Drivers\EssentialsEnvironmentDriver.cs" /> <Compile Include="UIDrivers\Environment Drivers\EssentialsEnvironmentDriver.cs" />
<Compile Include="UIDrivers\Environment Drivers\EssentialsLightingDriver.cs" /> <Compile Include="UIDrivers\Environment Drivers\EssentialsLightingDriver.cs" />
<Compile Include="UIDrivers\Environment Drivers\EssentialsShadeDriver.cs" /> <Compile Include="UIDrivers\Environment Drivers\EssentialsShadeDriver.cs" />

View File

@@ -22,30 +22,25 @@ namespace PepperDash.Essentials.Room.Config
public static Device GetRoomObject(DeviceConfig roomConfig) public static Device GetRoomObject(DeviceConfig roomConfig)
{ {
var typeName = roomConfig.Type.ToLower(); var typeName = roomConfig.Type.ToLower();
if (typeName == "huddle") if (typeName == "huddle")
{ {
var huddle = new EssentialsHuddleSpaceRoom(roomConfig); return new EssentialsHuddleSpaceRoom(roomConfig);
return huddle;
} }
else if (typeName == "huddlevtc1") if (typeName == "huddlevtc1")
{ {
var rm = new EssentialsHuddleVtc1Room(roomConfig); return new EssentialsHuddleVtc1Room(roomConfig);
}
if (typeName == "ddvc01bridge")
{
return new Device(roomConfig.Key, roomConfig.Name); // placeholder device that does nothing.
}
if (typeName == "dualdisplay")
{
return new EssentialsDualDisplayRoom(roomConfig);
}
return rm; return typeName != "techroom" ? null : new EssentialsTechRoom(roomConfig);
}
else if (typeName == "ddvc01Bridge")
{
return new Device(roomConfig.Key, roomConfig.Name); // placeholder device that does nothing.
}
else if (typeName == "dualdisplay")
{
var rm = new EssentialsDualDisplayRoom(roomConfig);
return rm;
}
return null;
} }
/// <summary> /// <summary>

View File

@@ -0,0 +1,40 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Room.Config
{
public class EssentialsTechRoomConfig
{
[JsonProperty("dummySourceKey")]
public string DummySourceKey { get; set; }
[JsonProperty("displays")]
public List<string> Displays;
[JsonProperty("tuners")]
public List<string> Tuners;
[JsonProperty("userPin")]
public string UserPin;
[JsonProperty("techPin")]
public string TechPin;
[JsonProperty("presetsFileName")]
public string PresetsFileName;
[JsonProperty("scheduledEvents")]
public List<ScheduledEventConfig> ScheduledEvents;
[JsonProperty("isPrimary")] public bool IsPrimary;
[JsonProperty("isTvPresetsProvider")] public bool IsTvPresetsProvider;
public EssentialsTechRoomConfig()
{
Displays = new List<string>();
Tuners = new List<string>();
ScheduledEvents = new List<ScheduledEventConfig>();
}
}
}

View File

@@ -0,0 +1,473 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Crestron.SimplSharp;
using Crestron.SimplSharp.Scheduler;
using Crestron.SimplSharpPro.DeviceSupport;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Bridges;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using PepperDash.Essentials.Core.Presets;
using PepperDash.Essentials.Devices.Common;
using PepperDash.Essentials.Room.Config;
namespace PepperDash.Essentials
{
public class EssentialsTechRoom : EssentialsRoomBase, ITvPresetsProvider, IBridgeAdvanced, IRunDirectRouteAction
{
private readonly EssentialsTechRoomConfig _config;
private readonly Dictionary<string, TwoWayDisplayBase> _displays;
private readonly DevicePresetsModel _tunerPresets;
private readonly Dictionary<string, IRSetTopBoxBase> _tuners;
private Dictionary<string, string> _currentPresets;
private ScheduledEventGroup _roomScheduledEventGroup;
/// <summary>
///
/// </summary>
protected override Func<bool> IsWarmingFeedbackFunc
{
get
{
return () =>
{
return _displays.All(kv => kv.Value.IsWarmingUpFeedback.BoolValue);
};
}
}
/// <summary>
///
/// </summary>
protected override Func<bool> IsCoolingFeedbackFunc
{
get
{
return () =>
{
return _displays.All(kv => kv.Value.IsCoolingDownFeedback.BoolValue);
};
}
}
public EssentialsTechRoom(DeviceConfig config) : base(config)
{
_config = config.Properties.ToObject<EssentialsTechRoomConfig>();
_tunerPresets = new DevicePresetsModel(String.Format("{0}-presets", config.Key), _config.PresetsFileName);
_tunerPresets.SetFileName(_config.PresetsFileName);
_tunerPresets.PresetRecalled += TunerPresetsOnPresetRecalled;
_tuners = GetDevices<IRSetTopBoxBase>(_config.Tuners);
_displays = GetDevices<TwoWayDisplayBase>(_config.Displays);
RoomPowerIsOnFeedback = new BoolFeedback(() => RoomPowerIsOn);
SetUpTunerPresetsFeedback();
SubscribeToDisplayFeedbacks();
CreateOrUpdateScheduledEvents();
}
public Dictionary<string, StringFeedback> CurrentPresetsFeedbacks { get; private set; }
public Dictionary<string, IRSetTopBoxBase> Tuners
{
get { return _tuners; }
}
public Dictionary<string, TwoWayDisplayBase> Displays
{
get { return _displays; }
}
public BoolFeedback RoomPowerIsOnFeedback { get; private set; }
public bool RoomPowerIsOn
{
get { return _displays.All(kv => kv.Value.PowerIsOnFeedback.BoolValue); }
}
#region ITvPresetsProvider Members
public DevicePresetsModel TvPresets
{
get { return _tunerPresets; }
}
#endregion
private void TunerPresetsOnPresetRecalled(ISetTopBoxNumericKeypad device, string channel)
{
if (!_currentPresets.ContainsKey(device.Key))
{
return;
}
_currentPresets[device.Key] = channel;
if (!CurrentPresetsFeedbacks.ContainsKey(device.Key))
{
CurrentPresetsFeedbacks[device.Key].FireUpdate();
}
}
private void SetUpTunerPresetsFeedback()
{
_currentPresets = new Dictionary<string, string>();
CurrentPresetsFeedbacks = new Dictionary<string, StringFeedback>();
foreach (var setTopBox in _tuners)
{
var tuner = setTopBox.Value;
_currentPresets.Add(tuner.Key, String.Empty);
CurrentPresetsFeedbacks.Add(tuner.Key, new StringFeedback(() => _currentPresets[tuner.Key]));
}
}
private void SubscribeToDisplayFeedbacks()
{
foreach (var display in _displays)
{
display.Value.PowerIsOnFeedback.OutputChange +=
(sender, args) =>
{
RoomPowerIsOnFeedback.InvokeFireUpdate();
IsWarmingUpFeedback.InvokeFireUpdate();
IsCoolingDownFeedback.InvokeFireUpdate();
};
}
}
private void CreateOrUpdateScheduledEvents()
{
var eventsConfig = _config.ScheduledEvents;
GetOrCreateScheduleGroup();
foreach (var eventConfig in eventsConfig)
{
CreateOrUpdateSingleEvent(eventConfig);
}
_roomScheduledEventGroup.UserGroupCallBack += HandleScheduledEvent;
}
private void GetOrCreateScheduleGroup()
{
if (_roomScheduledEventGroup == null)
{
_roomScheduledEventGroup = Scheduler.GetEventGroup(Key) ?? new ScheduledEventGroup(Key);
Scheduler.AddEventGroup(_roomScheduledEventGroup);
}
_roomScheduledEventGroup.RetrieveAllEvents();
}
private void CreateOrUpdateSingleEvent(ScheduledEventConfig scheduledEvent)
{
if (!_roomScheduledEventGroup.ScheduledEvents.ContainsKey(scheduledEvent.Key))
{
SchedulerUtilities.CreateEventFromConfig(scheduledEvent, _roomScheduledEventGroup, HandleScheduledEvent);
return;
}
var roomEvent = _roomScheduledEventGroup.ScheduledEvents[scheduledEvent.Key];
if (!SchedulerUtilities.CheckEventTimeForMatch(roomEvent, DateTime.Parse(scheduledEvent.Time)) &&
!SchedulerUtilities.CheckEventRecurrenceForMatch(roomEvent, scheduledEvent.Days))
{
return;
}
Debug.Console(1, this,
"Existing event does not match new config properties. Deleting existing event '{0}' and creating new event from configuration",
roomEvent.Name);
_roomScheduledEventGroup.DeleteEvent(roomEvent);
SchedulerUtilities.CreateEventFromConfig(scheduledEvent, _roomScheduledEventGroup, HandleScheduledEvent);
}
public void AddOrUpdateScheduledEvent(ScheduledEventConfig scheduledEvent)
{
//update config based on key of scheduleEvent
GetOrCreateScheduleGroup();
var existingEventIndex = _config.ScheduledEvents.FindIndex((e) => e.Key == scheduledEvent.Key);
if (existingEventIndex < 0)
{
_config.ScheduledEvents.Add(scheduledEvent);
}
else
{
_config.ScheduledEvents[existingEventIndex] = scheduledEvent;
}
//create or update event based on config
CreateOrUpdateSingleEvent(scheduledEvent);
//save config
Config.Properties = JToken.FromObject(_config);
CustomSetConfig(Config);
//Fire Event
OnScheduledEventUpdate();
}
public List<ScheduledEventConfig> GetScheduledEvents()
{
return _config.ScheduledEvents ?? new List<ScheduledEventConfig>();
}
private void OnScheduledEventUpdate()
{
var handler = ScheduledEventsChanged;
if (handler == null)
{
return;
}
handler(this, new ScheduledEventEventArgs {ScheduledEvents = _config.ScheduledEvents});
}
public event EventHandler<ScheduledEventEventArgs> ScheduledEventsChanged;
private void HandleScheduledEvent(ScheduledEvent schevent, ScheduledEventCommon.eCallbackReason type)
{
var eventConfig = _config.ScheduledEvents.FirstOrDefault(e => e.Key == schevent.Name);
if (eventConfig == null)
{
Debug.Console(1, this, "Event with name {0} not found", schevent.Name);
return;
}
Debug.Console(1, this, "Running actions for event {0}", schevent.Name);
if (eventConfig.Acknowledgeable)
{
schevent.Acknowledge();
}
CrestronInvoke.BeginInvoke((o) =>
{
Debug.Console(2, this, "There are {0} actions to execute for this event.", eventConfig.Actions.Count);
foreach (var a in eventConfig.Actions)
{
Debug.Console(2, this,
@"Attempting to run action:
DeviceKey: {0}
MethodName: {1}
Params: {2}"
, a.DeviceKey, a.MethodName, a.Params);
DeviceJsonApi.DoDeviceAction(a);
}
});
}
public void RoomPowerOn()
{
Debug.Console(2, this, "Room Powering On");
var dummySource = DeviceManager.GetDeviceForKey(_config.DummySourceKey) as IRoutingOutputs;
if (dummySource == null)
{
Debug.Console(1, this, "Unable to get source with key: {0}", _config.DummySourceKey);
return;
}
foreach (var display in _displays)
{
RunDirectRoute(dummySource, display.Value);
}
}
public void RoomPowerOff()
{
Debug.Console(2, this, "Room Powering Off");
foreach (var display in _displays)
{
display.Value.PowerOff();
}
}
private Dictionary<string, T> GetDevices<T>(ICollection<string> config) where T : IKeyed
{
try
{
var returnValue = DeviceManager.AllDevices.OfType<T>()
.Where(d => config.Contains(d.Key))
.ToDictionary(d => d.Key, d => d);
return returnValue;
}
catch
{
Debug.Console(0, this, Debug.ErrorLogLevel.Error,
"Error getting devices. Check Essentials Configuration");
return null;
}
}
#region Overrides of EssentialsRoomBase
protected override Func<bool> OnFeedbackFunc
{
get { return () => RoomPowerIsOn; }
}
protected override void EndShutdown()
{
}
public override void SetDefaultLevels()
{
}
public override void PowerOnToDefaultOrLastSource()
{
}
public override bool RunDefaultPresentRoute()
{
return false;
}
public override void RoomVacatedForTimeoutPeriod(object o)
{
}
#endregion
#region Implementation of IBridgeAdvanced
public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge)
{
var joinMap = new EssentialsTechRoomJoinMap(joinStart);
var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey);
if (!String.IsNullOrEmpty(joinMapSerialized))
{
joinMap = JsonConvert.DeserializeObject<EssentialsTechRoomJoinMap>(joinMapSerialized);
}
if (bridge != null)
{
bridge.AddJoinMap(Key, joinMap);
}
uint i;
if (_config.IsPrimary)
{
i = 0;
foreach (var feedback in CurrentPresetsFeedbacks)
{
feedback.Value.LinkInputSig(trilist.StringInput[(uint) (joinMap.CurrentPreset.JoinNumber + i)]);
i++;
}
trilist.OnlineStatusChange += (device, args) =>
{
if (!args.DeviceOnLine)
{
return;
}
foreach (var feedback in CurrentPresetsFeedbacks)
{
feedback.Value.FireUpdate();
}
};
return;
}
i = 0;
foreach (var setTopBox in _tuners)
{
var tuner = setTopBox;
trilist.SetStringSigAction(joinMap.CurrentPreset.JoinNumber + i, s => _tunerPresets.Dial(s, tuner.Value));
i++;
}
}
#endregion
private class EssentialsTechRoomJoinMap : JoinMapBaseAdvanced
{
[JoinName("currentPreset")]
public JoinDataComplete CurrentPreset = new JoinDataComplete(new JoinData {JoinNumber = 1, JoinSpan = 16},
new JoinMetadata {Description = "Current Tuner Preset", JoinType = eJoinType.Serial});
public EssentialsTechRoomJoinMap(uint joinStart) : base(joinStart, typeof(EssentialsTechRoomJoinMap))
{
}
}
#region IRunDirectRouteAction Members
private void RunDirectRoute(IRoutingOutputs source, IRoutingSink dest)
{
if (dest == null)
{
Debug.Console(1, this, "Cannot route, unknown destination '{0}'", dest.Key);
return;
}
if (source == null)
{
dest.ReleaseRoute();
if (dest is IHasPowerControl)
(dest as IHasPowerControl).PowerOff();
}
else
{
dest.ReleaseAndMakeRoute(source, eRoutingSignalType.Video);
}
}
/// <summary>
/// Attempts to route directly between a source and destination
/// </summary>
/// <param name="sourceKey"></param>
/// <param name="destinationKey"></param>
public void RunDirectRoute(string sourceKey, string destinationKey)
{
IRoutingSink dest = null;
dest = DeviceManager.GetDeviceForKey(destinationKey) as IRoutingSink;
var source = DeviceManager.GetDeviceForKey(sourceKey) as IRoutingOutputs;
if (source == null || dest == null)
{
Debug.Console(1, this, "Cannot route unknown source or destination '{0}' to {1}", sourceKey, destinationKey);
return;
}
RunDirectRoute(source, dest);
}
#endregion
}
public class ScheduledEventEventArgs : EventArgs
{
public List<ScheduledEventConfig> ScheduledEvents;
}
}

View File

@@ -78,7 +78,7 @@ namespace PepperDash.Essentials.Core.Bridges
/// <summary> /// <summary>
/// Bridge API using EISC /// Bridge API using EISC
/// </summary> /// </summary>
public class EiscApiAdvanced : BridgeApi public class EiscApiAdvanced : BridgeApi, ICommunicationMonitor
{ {
public EiscApiPropertiesConfig PropertiesConfig { get; private set; } public EiscApiPropertiesConfig PropertiesConfig { get; private set; }
@@ -98,13 +98,35 @@ namespace PepperDash.Essentials.Core.Bridges
Eisc.SigChange += Eisc_SigChange; Eisc.SigChange += Eisc_SigChange;
CommunicationMonitor = new CrestronGenericBaseCommunicationMonitor(this, Eisc, 120000, 300000);
AddPostActivationAction(LinkDevices); AddPostActivationAction(LinkDevices);
AddPostActivationAction(LinkRooms);
AddPostActivationAction(RegisterEisc);
}
public override bool CustomActivate()
{
CommunicationMonitor.Start();
return base.CustomActivate();
}
public override bool Deactivate()
{
CommunicationMonitor.Stop();
return base.Deactivate();
} }
private void LinkDevices() private void LinkDevices()
{ {
Debug.Console(1, this, "Linking Devices..."); Debug.Console(1, this, "Linking Devices...");
if (PropertiesConfig.Devices == null)
{
Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "No devices linked to this bridge");
return;
}
foreach (var d in PropertiesConfig.Devices) foreach (var d in PropertiesConfig.Devices)
{ {
var device = DeviceManager.GetDeviceForKey(d.DeviceKey); var device = DeviceManager.GetDeviceForKey(d.DeviceKey);
@@ -130,6 +152,14 @@ namespace PepperDash.Essentials.Core.Bridges
bridge.LinkToApi(Eisc, d.JoinStart, d.JoinMapKey, this); bridge.LinkToApi(Eisc, d.JoinStart, d.JoinMapKey, this);
} }
} }
}
private void RegisterEisc()
{
if (Eisc.Registered)
{
return;
}
var registerResult = Eisc.Register(); var registerResult = Eisc.Register();
@@ -142,6 +172,31 @@ namespace PepperDash.Essentials.Core.Bridges
Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "EISC registration successful"); Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "EISC registration successful");
} }
public void LinkRooms()
{
Debug.Console(1, this, "Linking Rooms...");
if (PropertiesConfig.Rooms == null)
{
Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "No rooms linked to this bridge.");
return;
}
foreach (var room in PropertiesConfig.Rooms)
{
var rm = DeviceManager.GetDeviceForKey(room.RoomKey) as IBridgeAdvanced;
if (rm == null)
{
Debug.Console(1, this, Debug.ErrorLogLevel.Notice,
"Room {0} does not implement IBridgeAdvanced. Skipping...", room.RoomKey);
continue;
}
rm.LinkToApi(Eisc, room.JoinStart, room.JoinMapKey, this);
}
}
/// <summary> /// <summary>
/// Adds a join map /// Adds a join map
/// </summary> /// </summary>
@@ -280,6 +335,12 @@ namespace PepperDash.Essentials.Core.Bridges
Debug.Console(2, this, "Error in Eisc_SigChange handler: {0}", e); Debug.Console(2, this, "Error in Eisc_SigChange handler: {0}", e);
} }
} }
#region Implementation of ICommunicationMonitor
public StatusMonitorBase CommunicationMonitor { get; private set; }
#endregion
} }
public class EiscApiPropertiesConfig public class EiscApiPropertiesConfig
@@ -290,6 +351,9 @@ namespace PepperDash.Essentials.Core.Bridges
[JsonProperty("devices")] [JsonProperty("devices")]
public List<ApiDevicePropertiesConfig> Devices { get; set; } public List<ApiDevicePropertiesConfig> Devices { get; set; }
[JsonProperty("rooms")]
public List<ApiRoomPropertiesConfig> Rooms { get; set; }
public class ApiDevicePropertiesConfig public class ApiDevicePropertiesConfig
{ {
@@ -303,6 +367,18 @@ namespace PepperDash.Essentials.Core.Bridges
public string JoinMapKey { get; set; } public string JoinMapKey { get; set; }
} }
public class ApiRoomPropertiesConfig
{
[JsonProperty("roomKey")]
public string RoomKey { get; set; }
[JsonProperty("joinStart")]
public uint JoinStart { get; set; }
[JsonProperty("joinMapKey")]
public string JoinMapKey { get; set; }
}
} }
public class EiscApiAdvancedFactory : EssentialsDeviceFactory<EiscApiAdvanced> public class EiscApiAdvancedFactory : EssentialsDeviceFactory<EiscApiAdvanced>

View File

@@ -76,6 +76,14 @@ namespace PepperDash.Essentials.Core.Bridges
public JoinDataComplete HdcpSupportCapability = new JoinDataComplete(new JoinData { JoinNumber = 1201, JoinSpan = 32 }, public JoinDataComplete HdcpSupportCapability = new JoinDataComplete(new JoinData { JoinNumber = 1201, JoinSpan = 32 },
new JoinMetadata { Description = "DM Chassis Input HDCP Support Capability", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); new JoinMetadata { Description = "DM Chassis Input HDCP Support Capability", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog });
[JoinName("InputStreamCardState")]
public JoinDataComplete InputStreamCardState = new JoinDataComplete(new JoinData { JoinNumber = 1501, JoinSpan = 32 },
new JoinMetadata { Description = "DM Chassis Stream Input Start (1), Stop (2), Pause (3) with Feedback", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog });
[JoinName("OutputStreamCardState")]
public JoinDataComplete OutputStreamCardState = new JoinDataComplete(new JoinData { JoinNumber = 1601, JoinSpan = 32 },
new JoinMetadata { Description = "DM Chassis Stream Output Start (1), Stop (2), Pause (3) with Feedback", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog });
[JoinName("InputNames")] [JoinName("InputNames")]
public JoinDataComplete InputNames = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 32 }, public JoinDataComplete InputNames = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 32 },
new JoinMetadata { Description = "DM Chassis Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); new JoinMetadata { Description = "DM Chassis Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial });

View File

@@ -56,6 +56,11 @@ namespace PepperDash.Essentials.Core
private void RegisterAndConfigureComPort() private void RegisterAndConfigureComPort()
{ {
if (Port == null)
{
Debug.Console(0,this,Debug.ErrorLogLevel.Error, "Configured com Port for this device does not exist.");
return;
}
if (Port.Parent is CrestronControlSystem) if (Port.Parent is CrestronControlSystem)
{ {
var result = Port.Register(); var result = Port.Register();

View File

@@ -104,7 +104,7 @@ namespace PepperDash.Essentials.Core
var dev = GetIComPortsDeviceFromManagedDevice(config.ControlPortDevKey); var dev = GetIComPortsDeviceFromManagedDevice(config.ControlPortDevKey);
if (dev != null && config.ControlPortNumber <= dev.NumberOfComPorts) if (dev != null && config.ControlPortNumber <= dev.NumberOfComPorts)
return dev.ComPorts[config.ControlPortNumber]; return dev.ComPorts[config.ControlPortNumber];
Debug.Console(0, "GetComPort: Device '{0}' does not have com port {1}", config.ControlPortDevKey, config.ControlPortNumber); Debug.Console(0,Debug.ErrorLogLevel.Notice, "GetComPort: Device '{0}' does not have com port {1}", config.ControlPortDevKey, config.ControlPortNumber);
return null; return null;
} }

View File

@@ -1,5 +1,5 @@
using Crestron.SimplSharpPro.DeviceSupport; using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core; using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.SmartObjects; using PepperDash.Essentials.Core.SmartObjects;
@@ -8,7 +8,7 @@ namespace PepperDash.Essentials.Core
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public interface INumericKeypad public interface INumericKeypad:IKeyed
{ {
void Digit0(bool pressRelease); void Digit0(bool pressRelease);
void Digit1(bool pressRelease); void Digit1(bool pressRelease);

View File

@@ -0,0 +1,9 @@
using PepperDash.Essentials.Core.Presets;
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
{
public interface ITvPresetsProvider
{
DevicePresetsModel TvPresets { get; }
}
}

View File

@@ -84,8 +84,6 @@ namespace PepperDash.Essentials.Core
} }
public abstract void PowerOn(); public abstract void PowerOn();
public abstract void PowerOff(); public abstract void PowerOff();
public abstract void PowerToggle(); public abstract void PowerToggle();
@@ -102,7 +100,7 @@ namespace PepperDash.Essentials.Core
} }
} }
public abstract void ExecuteSwitch(object selector); public abstract void ExecuteSwitch(object selector);
protected void LinkDisplayToApi(DisplayBase displayDevice, BasicTriList trilist, uint joinStart, string joinMapKey, protected void LinkDisplayToApi(DisplayBase displayDevice, BasicTriList trilist, uint joinStart, string joinMapKey,
EiscApiAdvanced bridge) EiscApiAdvanced bridge)
@@ -319,7 +317,5 @@ namespace PepperDash.Essentials.Core
var newEvent = NumericSwitchChange; var newEvent = NumericSwitchChange;
if (newEvent != null) newEvent(this, e); if (newEvent != null) newEvent(this, e);
} }
} }
} }

View File

@@ -1,11 +1,14 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Crestron.SimplSharp.Reflection;
using Crestron.SimplSharp.Scheduler; using Crestron.SimplSharp.Scheduler;
using PepperDash.Core; using PepperDash.Core;
using PepperDash.Essentials.Core.Fusion;
using PepperDash.Essentials.Room.Config;
using Activator = System.Activator;
namespace PepperDash.Essentials.Core namespace PepperDash.Essentials.Core
{ {
@@ -14,7 +17,7 @@ namespace PepperDash.Essentials.Core
/// </summary> /// </summary>
public static class Scheduler public static class Scheduler
{ {
private static Dictionary<string, ScheduledEventGroup> EventGroups = new Dictionary<string,ScheduledEventGroup>(); private static readonly Dictionary<string, ScheduledEventGroup> EventGroups = new Dictionary<string,ScheduledEventGroup>();
static Scheduler() static Scheduler()
{ {
@@ -49,7 +52,6 @@ namespace PepperDash.Essentials.Core
/// <summary> /// <summary>
/// Adds the event group to the global list /// Adds the event group to the global list
/// </summary> /// </summary>
/// <param name="name"></param>
/// <returns></returns> /// <returns></returns>
public static void AddEventGroup(ScheduledEventGroup eventGroup) public static void AddEventGroup(ScheduledEventGroup eventGroup)
{ {
@@ -67,6 +69,13 @@ namespace PepperDash.Essentials.Core
if(!EventGroups.ContainsKey(eventGroup.Name)) if(!EventGroups.ContainsKey(eventGroup.Name))
EventGroups.Remove(eventGroup.Name); EventGroups.Remove(eventGroup.Name);
} }
public static ScheduledEventGroup GetEventGroup(string key)
{
ScheduledEventGroup returnValue;
return EventGroups.TryGetValue(key, out returnValue) ? returnValue : null;
}
} }
public static class SchedulerUtilities public static class SchedulerUtilities
@@ -135,5 +144,90 @@ namespace PepperDash.Essentials.Core
return isMatch; return isMatch;
} }
public static bool CheckEventTimeForMatch(ScheduledEvent evnt, DateTime time)
{
return evnt.DateAndTime.Hour == time.Hour && evnt.DateAndTime.Minute == time.Minute;
}
public static bool CheckEventRecurrenceForMatch(ScheduledEvent evnt, ScheduledEventCommon.eWeekDays days)
{
return evnt.Recurrence.RecurrenceDays == days;
}
public static void CreateEventFromConfig(ScheduledEventConfig config, ScheduledEventGroup group, ScheduledEvent.UserEventCallBack handler)
{
if (group == null)
{
Debug.Console(0, "Unable to create event. Group is null");
return;
}
var scheduledEvent = new ScheduledEvent(config.Key, group)
{
Acknowledgeable = config.Acknowledgeable,
Persistent = config.Persistent
};
scheduledEvent.UserCallBack += handler;
scheduledEvent.DateAndTime.SetFirstDayOfWeek(ScheduledEventCommon.eFirstDayOfWeek.Sunday);
var eventTime = DateTime.Parse(config.Time);
if (DateTime.Now > eventTime)
{
eventTime = eventTime.AddDays(1);
}
Debug.Console(2, "[Scheduler] Current Date day of week: {0} recurrence days: {1}", eventTime.DayOfWeek,
config.Days);
var dayOfWeekConverted = ConvertDayOfWeek(eventTime);
Debug.Console(1, "[Scheduler] eventTime Day: {0}", dayOfWeekConverted);
while (!dayOfWeekConverted.IsFlagSet(config.Days))
{
eventTime = eventTime.AddDays(1);
dayOfWeekConverted = ConvertDayOfWeek(eventTime);
}
scheduledEvent.DateAndTime.SetAbsoluteEventTime(eventTime);
scheduledEvent.Recurrence.Weekly(config.Days);
if (config.Enable)
{
scheduledEvent.Enable();
}
else
{
scheduledEvent.Disable();
}
}
private static ScheduledEventCommon.eWeekDays ConvertDayOfWeek(DateTime eventTime)
{
return (ScheduledEventCommon.eWeekDays) Enum.Parse(typeof(ScheduledEventCommon.eWeekDays), eventTime.DayOfWeek.ToString(), true);
}
private static bool IsFlagSet<T>(this T value, T flag) where T : struct
{
CheckIsEnum<T>(true);
var lValue = Convert.ToInt64(value);
var lFlag = Convert.ToInt64(flag);
return (lValue & lFlag) != 0;
}
private static void CheckIsEnum<T>(bool withFlags)
{
if (!typeof(T).IsEnum)
throw new ArgumentException(string.Format("Type '{0}' is not an enum", typeof(T).FullName));
if (withFlags && !Attribute.IsDefined(typeof(T), typeof(FlagsAttribute)))
throw new ArgumentException(string.Format("Type '{0}' doesn't have the 'Flags' attribute", typeof(T).FullName));
}
} }
} }

View File

@@ -199,6 +199,7 @@
<Compile Include="Devices\PC\Laptop.cs" /> <Compile Include="Devices\PC\Laptop.cs" />
<Compile Include="Devices\ReconfigurableDevice.cs" /> <Compile Include="Devices\ReconfigurableDevice.cs" />
<Compile Include="Devices\VolumeDeviceChangeEventArgs.cs" /> <Compile Include="Devices\VolumeDeviceChangeEventArgs.cs" />
<Compile Include="DeviceTypeInterfaces\ITvPresetsProvider.cs" />
<Compile Include="DeviceTypeInterfaces\LanguageLabel.cs" /> <Compile Include="DeviceTypeInterfaces\LanguageLabel.cs" />
<Compile Include="DeviceTypeInterfaces\ILanguageProvider.cs" /> <Compile Include="DeviceTypeInterfaces\ILanguageProvider.cs" />
<Compile Include="DeviceTypeInterfaces\IHasBranding.cs" /> <Compile Include="DeviceTypeInterfaces\IHasBranding.cs" />
@@ -278,6 +279,7 @@
<Compile Include="Remotes\Hrxx0WirelessRemoteController.cs" /> <Compile Include="Remotes\Hrxx0WirelessRemoteController.cs" />
<Compile Include="Room\Behaviours\RoomOnToDefaultSourceWhenOccupied.cs" /> <Compile Include="Room\Behaviours\RoomOnToDefaultSourceWhenOccupied.cs" />
<Compile Include="Room\EssentialsRoomBase.cs" /> <Compile Include="Room\EssentialsRoomBase.cs" />
<Compile Include="Room\Config\EssentialsRoomScheduledEventsConfig.cs" />
<Compile Include="Room\Interfaces.cs" /> <Compile Include="Room\Interfaces.cs" />
<Compile Include="Room\iOccupancyStatusProvider.cs" /> <Compile Include="Room\iOccupancyStatusProvider.cs" />
<Compile Include="Routing\DummyRoutingInputsDevice.cs" /> <Compile Include="Routing\DummyRoutingInputsDevice.cs" />

View File

@@ -14,7 +14,7 @@
<tags>crestron 3series 4series</tags> <tags>crestron 3series 4series</tags>
<repository type="git" url="https://github.com/PepperDash/Essentials"/> <repository type="git" url="https://github.com/PepperDash/Essentials"/>
<dependencies> <dependencies>
<dependency id="PepperDashCore" version="[1.0.43, 1.1.0)"/> <dependency id="PepperDashCore" version="[1.0.44, 1.1.0)"/>
</dependencies> </dependencies>
</metadata> </metadata>
<files> <files>

View File

@@ -402,13 +402,16 @@ namespace PepperDash.Essentials
/// Loads a /// Loads a
/// </summary> /// </summary>
/// <param name="plugin"></param> /// <param name="plugin"></param>
/// <param name="loadedAssembly"></param>
static void LoadCustomPlugin(IPluginDeviceFactory plugin, LoadedAssembly loadedAssembly) static void LoadCustomPlugin(IPluginDeviceFactory plugin, LoadedAssembly loadedAssembly)
{ {
var passed = Global.IsRunningMinimumVersionOrHigher(plugin.MinimumEssentialsFrameworkVersion); var passed = Global.IsRunningMinimumVersionOrHigher(plugin.MinimumEssentialsFrameworkVersion);
if (!passed) if (!passed)
{ {
Debug.Console(0, Debug.ErrorLogLevel.Error, "Plugin indicates minimum Essentials version {0}. Dependency check failed. Skipping Plugin", plugin.MinimumEssentialsFrameworkVersion); Debug.Console(0, Debug.ErrorLogLevel.Error,
"\r\n********************\r\n\tPlugin indicates minimum Essentials version {0}. Dependency check failed. Skipping Plugin {1}\r\n********************",
plugin.MinimumEssentialsFrameworkVersion, loadedAssembly.Name);
return; return;
} }
else else

View File

@@ -1,178 +1,300 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharp.CrestronIO;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core; using PepperDash.Core;
//using SSMono.IO; //using SSMono.IO;
using PepperDash.Core.WebApi.Presets;
namespace PepperDash.Essentials.Core.Presets namespace PepperDash.Essentials.Core.Presets
{ {
/// <summary> /// <summary>
/// Class that represents the model behind presets display /// Class that represents the model behind presets display
/// </summary> /// </summary>
public class DevicePresetsModel : Device public class DevicePresetsModel : Device
{ {
public event EventHandler PresetsLoaded; public delegate void PresetRecalledCallback(ISetTopBoxNumericKeypad device, string channel);
public int PulseTime { get; set; } public delegate void PresetsSavedCallback(List<PresetChannel> presets);
public int DigitSpacingMS { get; set; }
public bool PresetsAreLoaded { get; private set; }
public List<PresetChannel> PresetsList { get { return _PresetsList.ToList(); } } private readonly CCriticalSection _fileOps = new CCriticalSection();
List<PresetChannel> _PresetsList; private readonly bool _initSuccess;
public int Count { get { return PresetsList != null ? PresetsList.Count : 0; } }
public bool UseLocalImageStorage { get; set; } private readonly ISetTopBoxNumericKeypad _setTopBox;
public string ImagesLocalHostPrefix { get; set; }
public string ImagesPathPrefix { get; set; }
public string ListPathPrefix { get; set; }
/// <summary> /// <summary>
/// The methods on the STB device to call when dialing /// The methods on the STB device to call when dialing
/// </summary> /// </summary>
Dictionary<char, Action<bool>> DialFunctions; private Dictionary<char, Action<bool>> _dialFunctions;
Action<bool> EnterFunction;
bool DialIsRunning; private bool _dialIsRunning;
string FilePath; private Action<bool> _enterFunction;
bool InitSuccess; private string _filePath;
//SSMono.IO.FileSystemWatcher ListWatcher;
public DevicePresetsModel(string key, ISetTopBoxNumericKeypad setTopBox, string fileName) public DevicePresetsModel(string key, ISetTopBoxNumericKeypad setTopBox, string fileName)
: base(key) : this(key, fileName)
{ {
PulseTime = 150; try
DigitSpacingMS = 150; {
_setTopBox = setTopBox;
try // Grab the digit functions from the device
{ // If any fail, the whole thing fails peacefully
// Grab the digit functions from the device _dialFunctions = new Dictionary<char, Action<bool>>(10)
// If any fail, the whole thing fails peacefully {
DialFunctions = new Dictionary<char, Action<bool>>(10) {'1', setTopBox.Digit1},
{ {'2', setTopBox.Digit2},
{ '1', setTopBox.Digit1 }, {'3', setTopBox.Digit3},
{ '2', setTopBox.Digit2 }, {'4', setTopBox.Digit4},
{ '3', setTopBox.Digit3 }, {'5', setTopBox.Digit5},
{ '4', setTopBox.Digit4 }, {'6', setTopBox.Digit6},
{ '5', setTopBox.Digit5 }, {'7', setTopBox.Digit7},
{ '6', setTopBox.Digit6 }, {'8', setTopBox.Digit8},
{ '7', setTopBox.Digit7 }, {'9', setTopBox.Digit9},
{ '8', setTopBox.Digit8 }, {'0', setTopBox.Digit0},
{ '9', setTopBox.Digit9 }, {'-', setTopBox.Dash}
{ '0', setTopBox.Digit0 }, };
{ '-', setTopBox.Dash } }
}; catch
} {
catch Debug.Console(0, "DevicePresets '{0}', not attached to INumericKeypad device. Ignoring", key);
{ _dialFunctions = null;
Debug.Console(0, "DevicePresets '{0}', not attached to INumericKeypad device. Ignoring", key); return;
DialFunctions = null; }
return;
}
EnterFunction = setTopBox.KeypadEnter; _enterFunction = setTopBox.KeypadEnter;
}
UseLocalImageStorage = true; public DevicePresetsModel(string key, string fileName) : base(key)
{
PulseTime = 150;
DigitSpacingMs = 150;
ImagesLocalHostPrefix = "http://" + CrestronEthernetHelper.GetEthernetParameter( UseLocalImageStorage = true;
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS,0);
ImagesPathPrefix = @"/presets/images.zip/";
ListPathPrefix = @"/html/presets/lists/";
SetFileName(fileName); ImagesLocalHostPrefix = "http://" + CrestronEthernetHelper.GetEthernetParameter(
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0);
ImagesPathPrefix = @"/presets/images.zip/";
ListPathPrefix = @"/html/presets/lists/";
//ListWatcher = new FileSystemWatcher(@"\HTML\presets\lists"); SetFileName(fileName);
//ListWatcher.NotifyFilter = NotifyFilters.LastWrite;
//ListWatcher.EnableRaisingEvents = true; _initSuccess = true;
//ListWatcher.Changed += ListWatcher_Changed; }
InitSuccess = true;
} public event PresetRecalledCallback PresetRecalled;
public event PresetsSavedCallback PresetsSaved;
public int PulseTime { get; set; }
public int DigitSpacingMs { get; set; }
public bool PresetsAreLoaded { get; private set; }
public List<PresetChannel> PresetsList { get; private set; }
public int Count
{
get { return PresetsList != null ? PresetsList.Count : 0; }
}
public bool UseLocalImageStorage { get; set; }
public string ImagesLocalHostPrefix { get; set; }
public string ImagesPathPrefix { get; set; }
public string ListPathPrefix { get; set; }
public event EventHandler PresetsLoaded;
public void SetFileName(string path) public void SetFileName(string path)
{ {
FilePath = ListPathPrefix + path; _filePath = ListPathPrefix + path;
LoadChannels();
}
public void LoadChannels() Debug.Console(2, this, "Setting presets file path to {0}", _filePath);
{ LoadChannels();
PresetsAreLoaded = false; }
try
{
var pl = JsonConvert.DeserializeObject<PresetsList>(Crestron.SimplSharp.CrestronIO.File.ReadToEnd(FilePath, Encoding.ASCII));
Name = pl.Name;
_PresetsList = pl.Channels;
}
catch (Exception e)
{
Debug.Console(2, this, "LoadChannels: Error reading presets file. These presets will be empty:\r '{0}'\r Error:{1}", FilePath, e.Message);
// Just save a default empty list
_PresetsList = new List<PresetChannel>();
}
PresetsAreLoaded = true;
var handler = PresetsLoaded; public void LoadChannels()
if (handler != null) {
handler(this, EventArgs.Empty); try
} {
_fileOps.Enter();
public void Dial(int presetNum) Debug.Console(2, this, "Loading presets from {0}", _filePath);
{ PresetsAreLoaded = false;
if (presetNum <= _PresetsList.Count) try
Dial(_PresetsList[presetNum - 1].Channel); {
} var pl = JsonConvert.DeserializeObject<PresetsList>(File.ReadToEnd(_filePath, Encoding.ASCII));
Name = pl.Name;
PresetsList = pl.Channels;
}
catch (Exception e)
{
Debug.Console(2, this,
"LoadChannels: Error reading presets file. These presets will be empty:\r '{0}'\r Error:{1}",
_filePath, e.Message);
// Just save a default empty list
PresetsList = new List<PresetChannel>();
}
PresetsAreLoaded = true;
public void Dial(string chanNum) var handler = PresetsLoaded;
{ if (handler != null)
if (DialIsRunning || !InitSuccess) return; {
if (DialFunctions == null) handler(this, EventArgs.Empty);
{ }
Debug.Console(1, "DevicePresets '{0}', not attached to keypad device. Ignoring channel", Key); }
return; finally
} {
_fileOps.Leave();
}
}
DialIsRunning = true; public void Dial(int presetNum)
CrestronInvoke.BeginInvoke(o => {
{ if (presetNum <= PresetsList.Count)
foreach (var c in chanNum.ToCharArray()) {
{ Dial(PresetsList[presetNum - 1].Channel);
if (DialFunctions.ContainsKey(c)) }
Pulse(DialFunctions[c]); }
CrestronEnvironment.Sleep(DigitSpacingMS);
}
if (EnterFunction != null) public void Dial(string chanNum)
Pulse(EnterFunction); {
DialIsRunning = false; if (_dialIsRunning || !_initSuccess)
}); {
} return;
}
if (_dialFunctions == null)
{
Debug.Console(1, "DevicePresets '{0}', not attached to keypad device. Ignoring channel", Key);
return;
}
void Pulse(Action<bool> act) _dialIsRunning = true;
{ CrestronInvoke.BeginInvoke(o =>
act(true); {
CrestronEnvironment.Sleep(PulseTime); foreach (var c in chanNum.ToCharArray())
act(false); {
} if (_dialFunctions.ContainsKey(c))
{
Pulse(_dialFunctions[c]);
}
CrestronEnvironment.Sleep(DigitSpacingMs);
}
/// <summary> if (_enterFunction != null)
/// Event handler for filesystem watcher. When directory changes, this is called {
/// </summary> Pulse(_enterFunction);
//void ListWatcher_Changed(object sender, FileSystemEventArgs e) }
//{ _dialIsRunning = false;
// Debug.Console(1, this, "folder modified: {0}", e.FullPath); });
// if (e.FullPath.Equals(FilePath, StringComparison.OrdinalIgnoreCase))
// { if (_setTopBox == null) return;
// Debug.Console(1, this, "File changed: {0}", e.ChangeType);
// LoadChannels(); OnPresetRecalled(_setTopBox, chanNum);
// } }
//}
} public void Dial(int presetNum, ISetTopBoxNumericKeypad setTopBox)
{
if (presetNum <= PresetsList.Count)
{
Dial(PresetsList[presetNum - 1].Channel, setTopBox);
}
}
public void Dial(string chanNum, ISetTopBoxNumericKeypad setTopBox)
{
_dialFunctions = new Dictionary<char, Action<bool>>(10)
{
{'1', setTopBox.Digit1},
{'2', setTopBox.Digit2},
{'3', setTopBox.Digit3},
{'4', setTopBox.Digit4},
{'5', setTopBox.Digit5},
{'6', setTopBox.Digit6},
{'7', setTopBox.Digit7},
{'8', setTopBox.Digit8},
{'9', setTopBox.Digit9},
{'0', setTopBox.Digit0},
{'-', setTopBox.Dash}
};
_enterFunction = setTopBox.KeypadEnter;
OnPresetRecalled(setTopBox, chanNum);
Dial(chanNum);
}
private void OnPresetRecalled(ISetTopBoxNumericKeypad setTopBox, string channel)
{
var handler = PresetRecalled;
if (handler == null)
{
return;
}
handler(setTopBox, channel);
}
public void UpdatePreset(int index, PresetChannel preset)
{
if (index >= PresetsList.Count)
{
return;
}
PresetsList[index] = preset;
SavePresets();
OnPresetsSaved();
}
public void UpdatePresets(List<PresetChannel> presets)
{
PresetsList = presets;
SavePresets();
OnPresetsSaved();
}
private void SavePresets()
{
try
{
_fileOps.Enter();
var pl = new PresetsList {Channels = PresetsList, Name = Name};
var json = JsonConvert.SerializeObject(pl, Formatting.Indented);
using (var file = File.Open(_filePath, FileMode.Truncate))
{
file.Write(json, Encoding.UTF8);
}
}
finally
{
_fileOps.Leave();
}
}
private void OnPresetsSaved()
{
var handler = PresetsSaved;
if (handler == null) return;
handler(PresetsList);
}
private void Pulse(Action<bool> act)
{
act(true);
CrestronEnvironment.Sleep(PulseTime);
act(false);
}
}
} }

View File

@@ -10,19 +10,22 @@ namespace PepperDash.Essentials.Core.Presets
public class PresetChannel public class PresetChannel
{ {
[JsonProperty(Required = Required.Always)] [JsonProperty(Required = Required.Always,PropertyName = "name")]
public string Name { get; set; } public string Name { get; set; }
[JsonProperty(Required = Required.Always)]
[JsonProperty(Required = Required.Always, PropertyName = "iconUrl")]
public string IconUrl { get; set; } public string IconUrl { get; set; }
[JsonProperty(Required = Required.Always)]
[JsonProperty(Required = Required.Always, PropertyName = "channel")]
public string Channel { get; set; } public string Channel { get; set; }
} }
public class PresetsList public class PresetsList
{ {
[JsonProperty(Required=Required.Always)] [JsonProperty(Required=Required.Always,PropertyName = "name")]
public string Name { get; set; } public string Name { get; set; }
[JsonProperty(Required = Required.Always)]
[JsonProperty(Required = Required.Always, PropertyName = "channels")]
public List<PresetChannel> Channels { get; set; } public List<PresetChannel> Channels { get; set; }
} }
} }

View File

@@ -0,0 +1,41 @@
using System.Collections.Generic;
using Crestron.SimplSharp.Scheduler;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Room.Config
{
public class EssentialsRoomScheduledEventsConfig
{
[JsonProperty("scheduledEvents")]
public List<ScheduledEventConfig> ScheduledEvents;
}
public class ScheduledEventConfig
{
[JsonProperty("key")]
public string Key;
[JsonProperty("name")]
public string Name;
[JsonProperty("days")]
public ScheduledEventCommon.eWeekDays Days;
[JsonProperty("time")]
public string Time;
[JsonProperty("actions")]
public List<DeviceActionWrapper> Actions;
[JsonProperty("persistent")]
public bool Persistent;
[JsonProperty("acknowledgeable")]
public bool Acknowledgeable;
[JsonProperty("enable")]
public bool Enable;
}
}

View File

@@ -41,6 +41,14 @@ namespace PepperDash.Essentials.Core
} }
/// <summary>
/// Simplified routing direct from source to destination
/// </summary>
public interface IRunDirectRouteAction
{
void RunDirectRoute(string sourceKey, string destinationKey);
}
/// <summary> /// <summary>
/// For rooms that default presentation only routing /// For rooms that default presentation only routing
/// </summary> /// </summary>

View File

@@ -50,6 +50,8 @@ namespace PepperDash.Essentials.DM
public BoolFeedback EnableUsbBreakawayFeedback { get; private set; } public BoolFeedback EnableUsbBreakawayFeedback { get; private set; }
public Dictionary<uint, IntFeedback> InputCardHdcpStateFeedbacks { get; private set; } public Dictionary<uint, IntFeedback> InputCardHdcpStateFeedbacks { get; private set; }
public Dictionary<uint, IntFeedback> InputStreamCardStateFeedbacks { get; private set; }
public Dictionary<uint, IntFeedback> OutputStreamCardStateFeedbacks { get; private set; }
public Dictionary<uint, eHdcpCapabilityType> InputCardHdcpCapabilityTypes { get; private set; } public Dictionary<uint, eHdcpCapabilityType> InputCardHdcpCapabilityTypes { get; private set; }
@@ -224,6 +226,8 @@ namespace PepperDash.Essentials.DM
new BoolFeedback(() => (Chassis as DmMDMnxn).EnableUSBBreakawayFeedback.BoolValue); new BoolFeedback(() => (Chassis as DmMDMnxn).EnableUSBBreakawayFeedback.BoolValue);
InputCardHdcpStateFeedbacks = new Dictionary<uint, IntFeedback>(); InputCardHdcpStateFeedbacks = new Dictionary<uint, IntFeedback>();
InputStreamCardStateFeedbacks = new Dictionary<uint, IntFeedback>();
OutputStreamCardStateFeedbacks = new Dictionary<uint, IntFeedback>();
InputCardHdcpCapabilityTypes = new Dictionary<uint, eHdcpCapabilityType>(); InputCardHdcpCapabilityTypes = new Dictionary<uint, eHdcpCapabilityType>();
for (uint x = 1; x <= Chassis.NumberOfOutputs; x++) for (uint x = 1; x <= Chassis.NumberOfOutputs; x++)
@@ -308,6 +312,33 @@ namespace PepperDash.Essentials.DM
return false; return false;
}); });
OutputStreamCardStateFeedbacks[tempX] = new IntFeedback(() =>
{
try
{
var outputCard = Chassis.Outputs[tempX];
if (outputCard.Card is DmcStroAV)
{
Debug.Console(2, "Found output stream card in slot: {0}.", tempX);
var streamCard = outputCard.Card as DmcStroAV;
if (streamCard.Control.StartFeedback.BoolValue == true)
return 1;
else if (streamCard.Control.StopFeedback.BoolValue == true)
return 2;
else if (streamCard.Control.PauseFeedback.BoolValue == true)
return 3;
else
return 0;
}
return 0;
}
catch (InvalidOperationException iopex)
{
Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "Error adding output stream card in slot: {0}. Error: {1}", tempX, iopex);
return 0;
}
});
} }
if (Chassis.Inputs[tempX] != null) if (Chassis.Inputs[tempX] != null)
@@ -407,6 +438,33 @@ namespace PepperDash.Essentials.DM
return 0; return 0;
} }
}); });
InputStreamCardStateFeedbacks[tempX] = new IntFeedback(() =>
{
try
{
var inputCard = Chassis.Inputs[tempX];
if (inputCard.Card is DmcStr)
{
Debug.Console(2, "Found input stream card in slot: {0}.", tempX);
var streamCard = inputCard.Card as DmcStr;
if (streamCard.Control.StartFeedback.BoolValue == true)
return 1;
else if (streamCard.Control.StopFeedback.BoolValue == true)
return 2;
else if (streamCard.Control.PauseFeedback.BoolValue == true)
return 3;
else
return 0;
}
return 0;
}
catch (InvalidOperationException iopex)
{
Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "Error adding input stream card in slot: {0}. Error: {1}", tempX, iopex);
return 0;
}
});
} }
} }
} }
@@ -916,6 +974,19 @@ namespace PepperDash.Essentials.DM
Debug.Console(1, this, "No index of {0} found in InputCardHdcpCapabilityFeedbacks"); Debug.Console(1, this, "No index of {0} found in InputCardHdcpCapabilityFeedbacks");
break; break;
} }
case DMInputEventIds.StartEventId:
case DMInputEventIds.StopEventId:
case DMInputEventIds.PauseEventId:
{
Debug.Console(2, this, "DM Input {0} Stream Status EventId", args.Number);
if (InputStreamCardStateFeedbacks[args.Number] != null)
{
InputStreamCardStateFeedbacks[args.Number].FireUpdate();
}
else
Debug.Console(2, this, "No index of {0} found in InputStreamCardStateFeedbacks");
break;
}
default: default:
{ {
Debug.Console(2, this, "DMInputChange fired for Input {0} with Unhandled EventId: {1}", args.Number, args.EventId); Debug.Console(2, this, "DMInputChange fired for Input {0} with Unhandled EventId: {1}", args.Number, args.EventId);
@@ -1044,6 +1115,19 @@ namespace PepperDash.Essentials.DM
OutputDisabledByHdcpFeedbacks[args.Number].FireUpdate(); OutputDisabledByHdcpFeedbacks[args.Number].FireUpdate();
break; break;
} }
case DMOutputEventIds.StartEventId:
case DMOutputEventIds.StopEventId:
case DMOutputEventIds.PauseEventId:
{
Debug.Console(2, this, "DM Output {0} Stream Status EventId", args.Number);
if (OutputStreamCardStateFeedbacks[args.Number] != null)
{
OutputStreamCardStateFeedbacks[args.Number].FireUpdate();
}
else
Debug.Console(2, this, "No index of {0} found in OutputStreamCardStateFeedbacks");
break;
}
default: default:
{ {
Debug.Console(2, this, "DMOutputChange fired for Output {0} with Unhandled EventId: {1}", args.Number, args.EventId); Debug.Console(2, this, "DMOutputChange fired for Output {0} with Unhandled EventId: {1}", args.Number, args.EventId);
@@ -1243,12 +1327,15 @@ namespace PepperDash.Essentials.DM
else else
{ {
LinkHdmiInputToApi(trilist, ioSlot, joinMap, ioSlotJoin); LinkHdmiInputToApi(trilist, ioSlot, joinMap, ioSlotJoin);
LinkStreamInputToApi(trilist, ioSlot, joinMap, ioSlotJoin);
} }
if (RxDictionary.ContainsKey(ioSlot)) if (RxDictionary.ContainsKey(ioSlot))
{ {
LinkRxToApi(trilist, ioSlot, joinMap, ioSlotJoin); LinkRxToApi(trilist, ioSlot, joinMap, ioSlotJoin);
} }
else
LinkStreamOutputToApi(trilist, ioSlot, joinMap, ioSlotJoin);
} }
} }
@@ -1297,6 +1384,86 @@ namespace PepperDash.Essentials.DM
} }
} }
private void LinkStreamInputToApi(BasicTriList trilist, uint ioSlot, DmChassisControllerJoinMap joinMap, uint ioSlotJoin)
{
var inputPort = InputPorts[string.Format("inputCard{0}--streamIn", ioSlot)];
if (inputPort == null)
{
return;
}
var streamCard = Chassis.Inputs[ioSlot].Card as DmcStr;
var join = joinMap.InputStreamCardState.JoinNumber + ioSlotJoin;
Debug.Console(1, "Port value for input card {0} is set as a stream card", ioSlot);
trilist.SetUShortSigAction(join, s =>
{
if (s == 1)
{
Debug.Console(2, this, "Join {0} value {1}: Setting stream state to start", join, s);
streamCard.Control.Start();
}
else if (s == 2)
{
Debug.Console(2, this, "Join {0} value {1}: Setting stream state to stop", join, s);
streamCard.Control.Stop();
}
else if (s == 3)
{
Debug.Console(2, this, "Join {0} value {1}: Setting stream state to pause", join, s);
streamCard.Control.Pause();
}
else
{
Debug.Console(2, this, "Join {0} value {1}: Ignore stream state", join, s);
}
});
InputStreamCardStateFeedbacks[ioSlot].LinkInputSig(trilist.UShortInput[join]);
trilist.UShortInput[join].UShortValue = InputStreamCardStateFeedbacks[ioSlot].UShortValue;
}
private void LinkStreamOutputToApi(BasicTriList trilist, uint ioSlot, DmChassisControllerJoinMap joinMap, uint ioSlotJoin)
{
var outputPort = OutputPorts[string.Format("outputCard{0}--streamOut", ioSlot)];
if (outputPort == null)
{
return;
}
var streamCard = Chassis.Outputs[ioSlot].Card as DmcStroAV;
var join = joinMap.OutputStreamCardState.JoinNumber + ioSlotJoin;
Debug.Console(1, "Port value for output card {0} is set as a stream card", ioSlot);
trilist.SetUShortSigAction(join, s =>
{
if (s == 1)
{
Debug.Console(2, this, "Join {0} value {1}: Setting stream state to start", join, s);
streamCard.Control.Start();
}
else if (s == 2)
{
Debug.Console(2, this, "Join {0} value {1}: Setting stream state to stop", join, s);
streamCard.Control.Stop();
}
else if (s == 3)
{
Debug.Console(2, this, "Join {0} value {1}: Setting stream state to pause", join, s);
streamCard.Control.Pause();
}
else
{
Debug.Console(2, this, "Join {0} value {1}: Ignore stream state", join, s);
}
});
OutputStreamCardStateFeedbacks[ioSlot].LinkInputSig(trilist.UShortInput[join]);
trilist.UShortInput[join].UShortValue = OutputStreamCardStateFeedbacks[ioSlot].UShortValue;
}
private void LinkRxToApi(BasicTriList trilist, uint ioSlot, DmChassisControllerJoinMap joinMap, uint ioSlotJoin) private void LinkRxToApi(BasicTriList trilist, uint ioSlot, DmChassisControllerJoinMap joinMap, uint ioSlotJoin)
{ {
Debug.Console(2, "Creating Rx Feedbacks {0}", ioSlot); Debug.Console(2, "Creating Rx Feedbacks {0}", ioSlot);

View File

@@ -39,12 +39,12 @@ namespace PepperDash.Essentials.DM.Endpoints.DGEs
{ {
_dge = device; _dge = device;
_dgeEthernetInfo = _dge.ExtenderEthernetReservedSigs; _dgeEthernetInfo = _dge.ExtenderEthernetReservedSigs;
_dgeEthernetInfo.DeviceExtenderSigChange += (extender, args) => UpdateDeviceInfo(); //_dgeEthernetInfo.DeviceExtenderSigChange += (extender, args) => UpdateDeviceInfo();
_dgeEthernetInfo.Use(); _dgeEthernetInfo.Use();
DeviceInfo = new DeviceInfo(); DeviceInfo = new DeviceInfo();
_dge.OnlineStatusChange += (currentDevice, args) => { if (args.DeviceOnLine) UpdateDeviceInfo(); }; //_dge.OnlineStatusChange += (currentDevice, args) => { if (args.DeviceOnLine) UpdateDeviceInfo(); };
_dc = dc; _dc = dc;

View File

@@ -259,29 +259,35 @@ namespace PepperDash.Essentials.DM
{ {
case 0: case 0:
{ {
ExecuteSwitch(eVst.Auto, null, eRoutingSignalType.Audio | eRoutingSignalType.Video); ExecuteSwitch(eVst.Auto, null, type);
break; break;
} }
case 1: case 1:
{ {
ExecuteSwitch(HdmiIn1.Selector, null, eRoutingSignalType.Audio | eRoutingSignalType.Video); ExecuteSwitch(HdmiIn1.Selector, null, type);
break; break;
} }
case 2: case 2:
{ {
ExecuteSwitch(HdmiIn2.Selector, null, eRoutingSignalType.Audio | eRoutingSignalType.Video); ExecuteSwitch(HdmiIn2.Selector, null, type);
break; break;
} }
case 3: case 3:
{ {
ExecuteSwitch(DisplayPortIn.Selector, null, eRoutingSignalType.Audio | eRoutingSignalType.Video); ExecuteSwitch(DisplayPortIn.Selector, null, type);
break; break;
} }
case 4: case 4:
{ {
ExecuteSwitch(eVst.AllDisabled, null, eRoutingSignalType.Audio | eRoutingSignalType.Video); ExecuteSwitch(eVst.AllDisabled, null, type);
break; break;
} }
default:
{
Debug.Console(2, this, "Unable to execute numeric switch to input {0}", input);
break;
}
} }
@@ -289,15 +295,23 @@ namespace PepperDash.Essentials.DM
public void ExecuteSwitch(object inputSelector, object outputSelector, eRoutingSignalType signalType) public void ExecuteSwitch(object inputSelector, object outputSelector, eRoutingSignalType signalType)
{ {
if ((signalType | eRoutingSignalType.Video) == eRoutingSignalType.Video) try
Tx.VideoSource = (eVst)inputSelector; {
Debug.Console(2, this, "Attempting to switch InputSelector {0}", ((eVst)inputSelector).ToString());
if ((signalType | eRoutingSignalType.Video) == eRoutingSignalType.Video)
Tx.VideoSource = (eVst)inputSelector;
// NOTE: It's possible that this particular TX model may not like the AudioSource property being set. // NOTE: It's possible that this particular TX model may not like the AudioSource property being set.
// The SIMPL definition only shows a single analog for AudioVideo Source // The SIMPL definition only shows a single analog for AudioVideo Source
if ((signalType | eRoutingSignalType.Audio) == eRoutingSignalType.Audio) if ((signalType | eRoutingSignalType.Audio) == eRoutingSignalType.Audio)
//it doesn't //it doesn't
Debug.Console(2, this, "Unable to execute audio-only switch for tx {0}", Key); Debug.Console(2, this, "Unable to execute audio-only switch for tx {0}", Key);
//Tx.AudioSource = (eAst)inputSelector; //Tx.AudioSource = (eAst)inputSelector;
}
catch (Exception e)
{
Debug.Console(2, this, "Exception in ExecuteSwitch: {0}", e);
}
} }
void InputStreamChangeEvent(EndpointInputStream inputStream, EndpointInputStreamEventArgs args) void InputStreamChangeEvent(EndpointInputStream inputStream, EndpointInputStreamEventArgs args)

View File

@@ -54,7 +54,7 @@ namespace PepperDash.Essentials.Devices.Common
KeypadAccessoryButton1Label = "-"; KeypadAccessoryButton1Label = "-";
HasKeypadAccessoryButton2 = true; HasKeypadAccessoryButton2 = true;
KeypadAccessoryButton2Command = "NumericEnter"; KeypadAccessoryButton2Command = "KEYPAD_ENTER";
KeypadAccessoryButton2Label = "Enter"; KeypadAccessoryButton2Label = "Enter";
AnyVideoOut = new RoutingOutputPort(RoutingPortNames.AnyVideoOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, AnyVideoOut = new RoutingOutputPort(RoutingPortNames.AnyVideoOut, eRoutingSignalType.Audio | eRoutingSignalType.Video,

View File

@@ -516,12 +516,16 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
SendText("xconfiguration userinterface custommessage: \"Scan the QR code with a mobile phone to get started\""); SendText("xconfiguration userinterface custommessage: \"Scan the QR code with a mobile phone to get started\"");
SendText("xconfiguration userinterface osd halfwakemessage: \"Tap the touch panel or scan the QR code with a mobile phone to get started\""); SendText("xconfiguration userinterface osd halfwakemessage: \"Tap the touch panel or scan the QR code with a mobile phone to get started\"");
var checksum = !String.IsNullOrEmpty(mcBridge.QrCodeChecksum)
? String.Format("checksum: {0} ", mcBridge.QrCodeChecksum)
: String.Empty;
SendText(String.Format( SendText(String.Format(
"xcommand userinterface branding fetch type: branding url: {0}", "xcommand userinterface branding fetch {1}type: branding url: {0}",
mcBridge.QrCodeUrl)); mcBridge.QrCodeUrl, checksum));
SendText(String.Format( SendText(String.Format(
"xcommand userinterface branding fetch type: halfwakebranding url: {0}", "xcommand userinterface branding fetch {1}type: halfwakebranding url: {0}",
mcBridge.QrCodeUrl)); mcBridge.QrCodeUrl, checksum));
} }
private void SendBrandingUrl() private void SendBrandingUrl()

View File

@@ -1,3 +1,3 @@
<packages> <packages>
<package id="PepperDashCore" version="1.0.43" targetFramework="net35" allowedVersions="[1.0,1.1)"/> <package id="PepperDashCore" version="1.0.44" targetFramework="net35" allowedVersions="[1.0,1.1)"/>
</packages> </packages>