mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-02-03 06:44:58 +00:00
Compare commits
27 Commits
1.9.5-hotf
...
1.9.2-alph
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6542c062b9 | ||
|
|
2db397b474 | ||
|
|
bfa48091d9 | ||
|
|
c4752b2ac2 | ||
|
|
152dcbe81e | ||
|
|
56f9a29c61 | ||
|
|
290e887903 | ||
|
|
de7a74eaff | ||
|
|
88e5c49663 | ||
|
|
1415999d86 | ||
|
|
61d8370329 | ||
|
|
c8b0c7dd01 | ||
|
|
5f6b650dba | ||
|
|
94c0e92f6b | ||
|
|
a5046df671 | ||
|
|
5a4f7b6a28 | ||
|
|
dfaaa3f6bc | ||
|
|
377cccf912 | ||
|
|
9795637d75 | ||
|
|
6f6ca50c37 | ||
|
|
7b7ec53355 | ||
|
|
e3920132bf | ||
|
|
c2e5bd290a | ||
|
|
7fd52814a0 | ||
|
|
06a3dda2e4 | ||
|
|
d97ca6d5a4 | ||
|
|
4c50d6980f |
@@ -450,14 +450,13 @@ namespace PepperDash.Essentials
|
||||
return;
|
||||
}
|
||||
|
||||
uint fusionIpId = 0xf1;
|
||||
|
||||
foreach (var roomConfig in ConfigReader.ConfigObject.Rooms)
|
||||
{
|
||||
var room = EssentialsRoomConfigHelper.GetRoomObject(roomConfig) as IEssentialsRoom;
|
||||
if (room != null)
|
||||
{
|
||||
// default IPID
|
||||
uint fusionIpId = 0xf1;
|
||||
|
||||
// default to no join map key
|
||||
string fusionJoinMapKey = string.Empty;
|
||||
|
||||
@@ -478,7 +477,7 @@ namespace PepperDash.Essentials
|
||||
{
|
||||
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 with IP-ID {0:X2}", fusionIpId);
|
||||
DeviceManager.AddDevice(new Core.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase(room, fusionIpId, fusionJoinMapKey));
|
||||
|
||||
|
||||
@@ -490,8 +489,11 @@ namespace PepperDash.Essentials
|
||||
{
|
||||
DeviceManager.AddDevice(room);
|
||||
|
||||
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleVtc1Room, attempting to add to DeviceManager with Fusion");
|
||||
DeviceManager.AddDevice(new EssentialsHuddleVtc1FusionController((IEssentialsHuddleVtc1Room)room, fusionIpId, fusionJoinMapKey));
|
||||
if (!(room is EssentialsCombinedHuddleVtc1Room))
|
||||
{
|
||||
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleVtc1Room, attempting to add to DeviceManager with Fusion with IP-ID {0:X2}", fusionIpId);
|
||||
DeviceManager.AddDevice(new EssentialsHuddleVtc1FusionController((IEssentialsHuddleVtc1Room)room, fusionIpId, fusionJoinMapKey));
|
||||
}
|
||||
|
||||
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge...");
|
||||
|
||||
@@ -502,7 +504,7 @@ namespace PepperDash.Essentials
|
||||
DeviceManager.AddDevice(room);
|
||||
|
||||
Debug.Console(0, Debug.ErrorLogLevel.Notice,
|
||||
"Room is EssentialsTechRoom, Attempting to add to DeviceManager with Fusion");
|
||||
"Room is EssentialsTechRoom, Attempting to add to DeviceManager with Fusion with IP-ID {0:X2}", fusionIpId);
|
||||
DeviceManager.AddDevice(new EssentialsTechRoomFusionSystemController((EssentialsTechRoom)room, fusionIpId, fusionJoinMapKey));
|
||||
|
||||
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge");
|
||||
@@ -515,9 +517,13 @@ namespace PepperDash.Essentials
|
||||
DeviceManager.AddDevice(room);
|
||||
}
|
||||
|
||||
fusionIpId += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Notice: Cannot create room from config, key '{0}' - Is this intentional? This may be a valid configuration.", roomConfig.Key);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Console(0, Debug.ErrorLogLevel.Notice, "All Rooms Loaded.");
|
||||
|
||||
@@ -150,7 +150,7 @@ namespace PepperDash.Essentials.Fusion
|
||||
|
||||
protected override void CreateSymbolAndBasicSigs(uint ipId)
|
||||
{
|
||||
Debug.Console(1, this, "Creating Fusion Room symbol with GUID: {0}", RoomGuid);
|
||||
Debug.Console(0, this, "Creating Fusion Room symbol with GUID: {0} and IP-ID {1:X2}", RoomGuid, ipId);
|
||||
|
||||
FusionRoom = new FusionRoom(ipId, Global.ControlSystem, Room.Name, RoomGuid);
|
||||
FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.Use();
|
||||
|
||||
@@ -144,12 +144,14 @@
|
||||
<Compile Include="Room\Config\EssentialsRoomEmergencyConfig.cs" />
|
||||
<Compile Include="Room\Config\EssentialsTechRoomConfig.cs" />
|
||||
<Compile Include="Room\Emergency\EsentialsRoomEmergencyContactClosure.cs" />
|
||||
<Compile Include="Room\Types\EssentialsCombinedHuddleVtc1Room.cs" />
|
||||
<Compile Include="Room\Types\EssentialsDualDisplayRoom.cs" />
|
||||
<Compile Include="Room\Types\EssentialsHuddleVtc1Room.cs" />
|
||||
<Compile Include="Room\Types\EssentialsNDisplayRoomBase.cs" />
|
||||
<Compile Include="Room\Config\EssentialsRoomConfig.cs" />
|
||||
<Compile Include="Room\Types\EssentialsTechRoom.cs" />
|
||||
<Compile Include="Room\Types\IEssentialsHuddleSpaceRoom.cs" />
|
||||
<Compile Include="Room\Types\Interfaces\IEssentialsHuddleSpaceRoom.cs" />
|
||||
<Compile Include="Room\Types\Interfaces\IEssentialsHuddleVtc1Room.cs" />
|
||||
<Compile Include="UIDrivers\Environment Drivers\EssentialsEnvironmentDriver.cs" />
|
||||
<Compile Include="UIDrivers\Environment Drivers\EssentialsLightingDriver.cs" />
|
||||
<Compile Include="UIDrivers\Environment Drivers\EssentialsShadeDriver.cs" />
|
||||
|
||||
@@ -39,6 +39,10 @@ namespace PepperDash.Essentials.Room.Config
|
||||
{
|
||||
return new EssentialsDualDisplayRoom(roomConfig);
|
||||
}
|
||||
if (typeName == "combinedhuddlevtc1")
|
||||
{
|
||||
return new EssentialsCombinedHuddleVtc1Room(roomConfig);
|
||||
}
|
||||
|
||||
return typeName != "techroom" ? null : new EssentialsTechRoom(roomConfig);
|
||||
}
|
||||
@@ -183,6 +187,12 @@ namespace PepperDash.Essentials.Room.Config
|
||||
[JsonProperty("zeroVolumeWhenSwtichingVolumeDevices")]
|
||||
public bool ZeroVolumeWhenSwtichingVolumeDevices { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if this room represents a combination of other rooms
|
||||
/// </summary>
|
||||
[JsonProperty("isRoomCombinationScenario")]
|
||||
public bool IsRoomCombinationScenario { get; set; }
|
||||
|
||||
public EssentialsRoomPropertiesConfig()
|
||||
{
|
||||
LogoLight = new EssentialsLogoPropertiesConfig();
|
||||
|
||||
@@ -0,0 +1,852 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
using PepperDash.Essentials.Room.Config;
|
||||
using PepperDash.Essentials.Devices.Common.Codec;
|
||||
using PepperDash.Essentials.Devices.Common.VideoCodec;
|
||||
using PepperDash.Essentials.Devices.Common.AudioCodec;
|
||||
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
|
||||
|
||||
namespace PepperDash.Essentials
|
||||
{
|
||||
public class EssentialsCombinedHuddleVtc1Room : EssentialsRoomBase, IEssentialsHuddleVtc1Room
|
||||
{
|
||||
private bool _codecExternalSourceChange;
|
||||
public event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
|
||||
public event SourceInfoChangeHandler CurrentSourceChange;
|
||||
|
||||
|
||||
//************************
|
||||
// Call-related stuff
|
||||
|
||||
public BoolFeedback InCallFeedback { get; private set; }
|
||||
|
||||
///// <summary>
|
||||
///// Make this more specific
|
||||
///// </summary>
|
||||
//public List<CodecActiveCallItem> ActiveCalls { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// States: 0 for on hook, 1 for video, 2 for audio, 3 for telekenesis
|
||||
/// </summary>
|
||||
public IntFeedback CallTypeFeedback { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public BoolFeedback PrivacyModeIsOnFeedback { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// When something in the room is sharing with the far end or through other means
|
||||
/// </summary>
|
||||
public BoolFeedback IsSharingFeedback { get; private set; }
|
||||
|
||||
//************************
|
||||
|
||||
protected override Func<bool> OnFeedbackFunc
|
||||
{
|
||||
get
|
||||
{
|
||||
return () =>
|
||||
{
|
||||
var displays = Displays.Where((d) => d is DisplayBase) as List<DisplayBase>;
|
||||
|
||||
var val = CurrentSourceInfo != null
|
||||
&& CurrentSourceInfo.Type == eSourceListItemType.Route
|
||||
&& displays.Count() > 0;
|
||||
//&& disp.PowerIsOnFeedback.BoolValue;
|
||||
return val;
|
||||
};
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected override Func<bool> IsWarmingFeedbackFunc
|
||||
{
|
||||
get
|
||||
{
|
||||
return () =>
|
||||
{
|
||||
var displays = Displays.Where((d) => d is TwoWayDisplayBase) as List<TwoWayDisplayBase>;
|
||||
if (displays != null)
|
||||
{
|
||||
var warmingDisplays = displays.Where((d) => d.IsWarmingUpFeedback.BoolValue);
|
||||
|
||||
if (warmingDisplays.Count() > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
};
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected override Func<bool> IsCoolingFeedbackFunc
|
||||
{
|
||||
get
|
||||
{
|
||||
return () =>
|
||||
{
|
||||
var displays = Displays.Where((d) => d is TwoWayDisplayBase) as List<TwoWayDisplayBase>;
|
||||
if (displays != null)
|
||||
{
|
||||
var coolingDisplays = displays.Where((d) => d.IsCoolingDownFeedback.BoolValue);
|
||||
|
||||
if (coolingDisplays.Count() > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public EssentialsConferenceRoomPropertiesConfig PropertiesConfig { get; private set; }
|
||||
|
||||
private List<IRoutingSinkWithSwitching> Displays;
|
||||
|
||||
public IRoutingSinkWithSwitching DefaultDisplay { get; private set; }
|
||||
|
||||
public IBasicVolumeControls DefaultAudioDevice { get; private set; }
|
||||
public IBasicVolumeControls DefaultVolumeControls { get; private set; }
|
||||
|
||||
public VideoCodecBase VideoCodec { get; private set; }
|
||||
|
||||
public AudioCodecBase AudioCodec { get; private set; }
|
||||
|
||||
public bool ExcludeFromGlobalFunctions { get; set; }
|
||||
|
||||
public string DefaultSourceItem { get; set; }
|
||||
|
||||
public ushort DefaultVolume { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If room is off, enables power on to last source. Default true
|
||||
/// </summary>
|
||||
public bool EnablePowerOnToLastSource { get; set; }
|
||||
string LastSourceKey;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the volume control device, and attaches/removes InUseTrackers with "audio"
|
||||
/// tag to device.
|
||||
/// </summary>
|
||||
public IBasicVolumeControls CurrentVolumeControls
|
||||
{
|
||||
get { return _CurrentAudioDevice; }
|
||||
set
|
||||
{
|
||||
if (value == _CurrentAudioDevice) return;
|
||||
|
||||
var oldDev = _CurrentAudioDevice;
|
||||
// derigister this room from the device, if it can
|
||||
if (oldDev is IInUseTracking)
|
||||
(oldDev as IInUseTracking).InUseTracker.RemoveUser(this, "audio");
|
||||
var handler = CurrentVolumeDeviceChange;
|
||||
if (handler != null)
|
||||
CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(oldDev, value, ChangeType.WillChange));
|
||||
_CurrentAudioDevice = value;
|
||||
if (handler != null)
|
||||
CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(oldDev, value, ChangeType.DidChange));
|
||||
// register this room with new device, if it can
|
||||
if (_CurrentAudioDevice is IInUseTracking)
|
||||
(_CurrentAudioDevice as IInUseTracking).InUseTracker.AddUser(this, "audio");
|
||||
}
|
||||
}
|
||||
IBasicVolumeControls _CurrentAudioDevice;
|
||||
|
||||
/// <summary>
|
||||
/// The SourceListItem last run - containing names and icons
|
||||
/// </summary>
|
||||
public SourceListItem CurrentSourceInfo
|
||||
{
|
||||
get { return _CurrentSourceInfo; }
|
||||
set
|
||||
{
|
||||
if (value == _CurrentSourceInfo) return;
|
||||
|
||||
var handler = CurrentSourceChange;
|
||||
// remove from in-use tracker, if so equipped
|
||||
if (_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking)
|
||||
(_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.RemoveUser(this, "control");
|
||||
|
||||
if (handler != null)
|
||||
handler(_CurrentSourceInfo, ChangeType.WillChange);
|
||||
|
||||
_CurrentSourceInfo = value;
|
||||
|
||||
// add to in-use tracking
|
||||
if (_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking)
|
||||
(_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.AddUser(this, "control");
|
||||
if (handler != null)
|
||||
handler(_CurrentSourceInfo, ChangeType.DidChange);
|
||||
|
||||
var vc = VideoCodec as IHasExternalSourceSwitching;
|
||||
if (vc != null && !_codecExternalSourceChange)
|
||||
{
|
||||
vc.SetSelectedSource(CurrentSourceInfoKey);
|
||||
}
|
||||
|
||||
_codecExternalSourceChange = false;
|
||||
}
|
||||
}
|
||||
SourceListItem _CurrentSourceInfo;
|
||||
|
||||
public string CurrentSourceInfoKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// "codecOsd"
|
||||
/// </summary>
|
||||
public string DefaultCodecRouteString { get { return "codecOsd"; } }
|
||||
|
||||
/// <summary>
|
||||
/// Temporary implementation. Returns the schedule-ready object or null if none. Fow now,
|
||||
/// always returns the VideoCodec if it is capable
|
||||
/// </summary>
|
||||
public IHasScheduleAwareness ScheduleSource { get { return VideoCodec as IHasScheduleAwareness; } }
|
||||
|
||||
CCriticalSection SourceSelectLock = new CCriticalSection();
|
||||
|
||||
public EssentialsCombinedHuddleVtc1Room(DeviceConfig config)
|
||||
: base(config)
|
||||
{
|
||||
try
|
||||
{
|
||||
PropertiesConfig = JsonConvert.DeserializeObject<EssentialsConferenceRoomPropertiesConfig>
|
||||
(config.Properties.ToString());
|
||||
|
||||
VideoCodec = DeviceManager.GetDeviceForKey(PropertiesConfig.VideoCodecKey) as
|
||||
PepperDash.Essentials.Devices.Common.VideoCodec.VideoCodecBase;
|
||||
|
||||
|
||||
if (VideoCodec == null)
|
||||
throw new ArgumentNullException("codec cannot be null");
|
||||
|
||||
AudioCodec = DeviceManager.GetDeviceForKey(PropertiesConfig.AudioCodecKey) as
|
||||
PepperDash.Essentials.Devices.Common.AudioCodec.AudioCodecBase;
|
||||
if (AudioCodec == null)
|
||||
Debug.Console(0, this, "No Audio Codec Found");
|
||||
|
||||
DefaultAudioDevice = DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultAudioKey) as IBasicVolumeControls;
|
||||
|
||||
Displays = new List<IRoutingSinkWithSwitching>();
|
||||
|
||||
Initialize();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Console(1, this, "Error building room: \n{0}", e);
|
||||
}
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (DefaultAudioDevice is IBasicVolumeControls)
|
||||
DefaultVolumeControls = DefaultAudioDevice as IBasicVolumeControls;
|
||||
else if (DefaultAudioDevice is IHasVolumeDevice)
|
||||
DefaultVolumeControls = (DefaultAudioDevice as IHasVolumeDevice).VolumeDevice;
|
||||
CurrentVolumeControls = DefaultVolumeControls;
|
||||
|
||||
|
||||
// Combines call feedback from both codecs if available
|
||||
InCallFeedback = new BoolFeedback(() =>
|
||||
{
|
||||
bool inAudioCall = false;
|
||||
bool inVideoCall = false;
|
||||
|
||||
if (AudioCodec != null)
|
||||
inAudioCall = AudioCodec.IsInCall;
|
||||
|
||||
if (VideoCodec != null)
|
||||
inVideoCall = VideoCodec.IsInCall;
|
||||
|
||||
if (inAudioCall || inVideoCall)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
});
|
||||
|
||||
SetupDisplays();
|
||||
|
||||
// Get Microphone Privacy object, if any MUST HAPPEN AFTER setting InCallFeedback
|
||||
this.MicrophonePrivacy = EssentialsRoomConfigHelper.GetMicrophonePrivacy(PropertiesConfig, this);
|
||||
|
||||
Debug.Console(2, this, "Microphone Privacy Config evaluated.");
|
||||
|
||||
// Get emergency object, if any
|
||||
this.Emergency = EssentialsRoomConfigHelper.GetEmergency(PropertiesConfig, this);
|
||||
|
||||
Debug.Console(2, this, "Emergency Config evaluated.");
|
||||
|
||||
|
||||
VideoCodec.CallStatusChange += (o, a) => this.InCallFeedback.FireUpdate();
|
||||
VideoCodec.IsReadyChange += (o, a) => { this.SetCodecExternalSources(); SetCodecBranding(); };
|
||||
|
||||
if (AudioCodec != null)
|
||||
AudioCodec.CallStatusChange += (o, a) => this.InCallFeedback.FireUpdate();
|
||||
|
||||
IsSharingFeedback = new BoolFeedback(() => VideoCodec.SharingContentIsOnFeedback.BoolValue);
|
||||
VideoCodec.SharingContentIsOnFeedback.OutputChange += (o, a) => this.IsSharingFeedback.FireUpdate();
|
||||
|
||||
// link privacy to VC (for now?)
|
||||
PrivacyModeIsOnFeedback = new BoolFeedback(() => VideoCodec.PrivacyModeIsOnFeedback.BoolValue);
|
||||
VideoCodec.PrivacyModeIsOnFeedback.OutputChange += (o, a) => this.PrivacyModeIsOnFeedback.FireUpdate();
|
||||
|
||||
CallTypeFeedback = new IntFeedback(() => 0);
|
||||
|
||||
SetSourceListKey();
|
||||
|
||||
EnablePowerOnToLastSource = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Console(0, this, "Error Initializing Room: {0}", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupDisplays()
|
||||
{
|
||||
//DefaultDisplay = DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultDisplayKey) as IRoutingSinkWithSwitching;
|
||||
|
||||
var destinationList = ConfigReader.ConfigObject.DestinationLists[PropertiesConfig.DestinationListKey];
|
||||
|
||||
foreach (var destination in destinationList)
|
||||
{
|
||||
var dest = destination.Value.SinkDevice as IRoutingSinkWithSwitching;
|
||||
|
||||
if (dest != null)
|
||||
{
|
||||
Displays.Add(dest);
|
||||
}
|
||||
|
||||
var display = dest as DisplayBase;
|
||||
if (display != null)
|
||||
{
|
||||
// Link power, warming, cooling to display
|
||||
var dispTwoWay = display as IHasPowerControlWithFeedback;
|
||||
if (dispTwoWay != null)
|
||||
{
|
||||
dispTwoWay.PowerIsOnFeedback.OutputChange += (o, a) =>
|
||||
{
|
||||
if (dispTwoWay.PowerIsOnFeedback.BoolValue != OnFeedback.BoolValue)
|
||||
{
|
||||
//if (!dispTwoWay.PowerIsOnFeedback.BoolValue)
|
||||
// CurrentSourceInfo = null;
|
||||
OnFeedback.FireUpdate();
|
||||
}
|
||||
if (dispTwoWay.PowerIsOnFeedback.BoolValue)
|
||||
{
|
||||
SetDefaultLevels();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
display.IsWarmingUpFeedback.OutputChange += (o, a) =>
|
||||
{
|
||||
IsWarmingUpFeedback.FireUpdate();
|
||||
if (!IsWarmingUpFeedback.BoolValue)
|
||||
(CurrentVolumeControls as IBasicVolumeWithFeedback).SetVolume(DefaultVolume);
|
||||
};
|
||||
display.IsCoolingDownFeedback.OutputChange += (o, a) =>
|
||||
{
|
||||
IsCoolingDownFeedback.FireUpdate();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetSourceListKey()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(PropertiesConfig.SourceListKey))
|
||||
{
|
||||
SetSourceListKey(PropertiesConfig.SourceListKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetSourceListKey(Key);
|
||||
}
|
||||
|
||||
SetCodecExternalSources();
|
||||
}
|
||||
|
||||
protected override void CustomSetConfig(DeviceConfig config)
|
||||
{
|
||||
var newPropertiesConfig = JsonConvert.DeserializeObject<EssentialsConferenceRoomPropertiesConfig>(config.Properties.ToString());
|
||||
|
||||
if (newPropertiesConfig != null)
|
||||
PropertiesConfig = newPropertiesConfig;
|
||||
|
||||
ConfigWriter.UpdateRoomConfig(config);
|
||||
}
|
||||
|
||||
public override bool CustomActivate()
|
||||
{
|
||||
// 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.LogoUrlLightBkgnd = PropertiesConfig.LogoLight.GetLogoUrlLight();
|
||||
this.LogoUrlDarkBkgnd = PropertiesConfig.LogoDark.GetLogoUrlDark();
|
||||
|
||||
this.DefaultSourceItem = PropertiesConfig.DefaultSourceItem;
|
||||
this.DefaultVolume = (ushort)(PropertiesConfig.Volumes.Master.Level * 65535 / 100);
|
||||
|
||||
return base.CustomActivate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected override void EndShutdown()
|
||||
{
|
||||
VideoCodec.EndAllCalls();
|
||||
|
||||
SetDefaultLevels();
|
||||
|
||||
RunDefaultPresentRoute();
|
||||
|
||||
CrestronEnvironment.Sleep(1000);
|
||||
|
||||
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Shutting down room");
|
||||
|
||||
RunRouteAction("roomOff");
|
||||
VideoCodec.StopSharing();
|
||||
VideoCodec.StandbyActivate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Routes the default source item, if any. Returns true when default route exists
|
||||
/// </summary>
|
||||
public override bool RunDefaultPresentRoute()
|
||||
{
|
||||
if (DefaultSourceItem != null)
|
||||
RunRouteAction(DefaultSourceItem);
|
||||
|
||||
return DefaultSourceItem != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets up the room when started into call mode without presenting a source
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool RunDefaultCallRoute()
|
||||
{
|
||||
RunRouteAction(DefaultCodecRouteString);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void RunRouteActionCodec(string routeKey, string sourceListKey)
|
||||
{
|
||||
_codecExternalSourceChange = true;
|
||||
RunRouteAction(routeKey, sourceListKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="routeKey"></param>
|
||||
public void RunRouteAction(string routeKey)
|
||||
{
|
||||
RunRouteAction(routeKey, new Action(() => { }));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="routeKey"></param>
|
||||
/// <param name="souceListKey"></param>
|
||||
/// <param name="successCallback"></param>
|
||||
public void RunRouteAction(string routeKey, string sourceListKey)
|
||||
{
|
||||
if (string.IsNullOrEmpty(sourceListKey))
|
||||
{
|
||||
Debug.Console(1, this, "No sourceListKey present. RunRouteAction assumes default source list.");
|
||||
RunRouteAction(routeKey, new Action(() => { }));
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Console(1, this, "sourceListKey present but not yet implemented");
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="routeKey"></param>
|
||||
/// <param name="souceListKey"></param>
|
||||
/// <param name="successCallback"></param>
|
||||
public void RunRouteAction(string routeKey, string sourceListKey, Action successCallback)
|
||||
{
|
||||
if (string.IsNullOrEmpty(sourceListKey))
|
||||
{
|
||||
RunRouteAction(routeKey, successCallback);
|
||||
}
|
||||
else
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets a source from config list SourceListKey and dynamically build and executes the
|
||||
/// route or commands
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
public void RunRouteAction(string routeKey, Action successCallback)
|
||||
{
|
||||
// Run this on a separate thread
|
||||
new CTimer(o =>
|
||||
{
|
||||
// try to prevent multiple simultaneous selections
|
||||
SourceSelectLock.TryEnter();
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to get the list item by it's string key
|
||||
if (!dict.ContainsKey(routeKey))
|
||||
{
|
||||
Debug.Console(1, this, "WARNING: No item '{0}' found on config list '{1}'",
|
||||
routeKey, SourceListKey);
|
||||
return;
|
||||
}
|
||||
|
||||
// End usage timer on last source
|
||||
if (!string.IsNullOrEmpty(LastSourceKey))
|
||||
{
|
||||
var usageLastSource = dict[LastSourceKey].SourceDevice as IUsageTracking;
|
||||
if (usageLastSource != null && usageLastSource.UsageTracker != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// There MAY have been failures in here. Protect
|
||||
usageLastSource.UsageTracker.EndDeviceUsage();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Console(1, this, "*#* EXCEPTION in end usage tracking:\r{0}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Let's run it
|
||||
var item = dict[routeKey];
|
||||
if (routeKey.ToLower() != "roomoff")
|
||||
{
|
||||
|
||||
LastSourceKey = routeKey;
|
||||
}
|
||||
else
|
||||
CurrentSourceInfoKey = null;
|
||||
|
||||
// hand off the individual routes to this helper
|
||||
foreach (var route in item.RouteList)
|
||||
DoRouteItem(route);
|
||||
|
||||
// Start usage timer on routed source
|
||||
var usageNewSource = item.SourceDevice as IUsageTracking;
|
||||
if (usageNewSource != null && usageNewSource.UsageTracker != null) // Have to make sure there is a usage tracker!
|
||||
{
|
||||
(item.SourceDevice as IUsageTracking).UsageTracker.StartDeviceUsage();
|
||||
}
|
||||
|
||||
// See if this can be moved into common, base-class method -------------
|
||||
|
||||
|
||||
// Set volume control, using default if non provided
|
||||
IBasicVolumeControls volDev = null;
|
||||
// Handle special cases for volume control
|
||||
if (string.IsNullOrEmpty(item.VolumeControlKey)
|
||||
|| item.VolumeControlKey.Equals("$defaultAudio", StringComparison.OrdinalIgnoreCase))
|
||||
volDev = DefaultVolumeControls;
|
||||
//else if (item.VolumeControlKey.Equals("$defaultDisplay", StringComparison.OrdinalIgnoreCase))
|
||||
// volDev = DefaultDisplay as IBasicVolumeControls;
|
||||
// Or a specific device, probably rarely used.
|
||||
else
|
||||
{
|
||||
var dev = DeviceManager.GetDeviceForKey(item.VolumeControlKey);
|
||||
if (dev is IBasicVolumeControls)
|
||||
volDev = dev as IBasicVolumeControls;
|
||||
else if (dev is IHasVolumeDevice)
|
||||
volDev = (dev as IHasVolumeDevice).VolumeDevice;
|
||||
}
|
||||
|
||||
if (volDev != CurrentVolumeControls)
|
||||
{
|
||||
// zero the volume on the device we are leaving.
|
||||
// Set the volume to default on device we are entering
|
||||
if (ZeroVolumeWhenSwtichingVolumeDevices && CurrentVolumeControls is IBasicVolumeWithFeedback)
|
||||
{
|
||||
var vd = CurrentVolumeControls as IBasicVolumeWithFeedback;
|
||||
SavedVolumeLevels[vd] = (uint)vd.VolumeLevelFeedback.IntValue;
|
||||
vd.SetVolume(0);
|
||||
}
|
||||
|
||||
CurrentVolumeControls = volDev;
|
||||
if (ZeroVolumeWhenSwtichingVolumeDevices && CurrentVolumeControls is IBasicVolumeWithFeedback)
|
||||
{
|
||||
var vd = CurrentVolumeControls as IBasicVolumeWithFeedback;
|
||||
ushort vol = (SavedVolumeLevels.ContainsKey(vd) ? (ushort)SavedVolumeLevels[vd] : DefaultVolume);
|
||||
vd.SetVolume(vol);
|
||||
}
|
||||
}
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// store the name and UI info for routes
|
||||
if (item.SourceKey == "$off")
|
||||
{
|
||||
CurrentSourceInfoKey = routeKey;
|
||||
CurrentSourceInfo = null;
|
||||
}
|
||||
else if (item.SourceKey != null)
|
||||
{
|
||||
CurrentSourceInfoKey = routeKey;
|
||||
CurrentSourceInfo = item;
|
||||
}
|
||||
|
||||
OnFeedback.FireUpdate();
|
||||
|
||||
if (OnFeedback.BoolValue)
|
||||
{
|
||||
if (VideoCodec.UsageTracker.InUseTracker.InUseFeedback.BoolValue)
|
||||
{
|
||||
Debug.Console(1, this, "Video Codec in use, deactivating standby on codec");
|
||||
VideoCodec.StandbyDeactivate();
|
||||
}
|
||||
|
||||
if (VideoCodec.StandbyIsOnFeedback.BoolValue)
|
||||
{
|
||||
VideoCodec.StandbyDeactivate();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Console(1, this, "Video codec not in standby. No need to wake.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Console(1, this, "Room OnFeedback state: {0}", OnFeedback.BoolValue);
|
||||
}
|
||||
|
||||
// report back when done
|
||||
if (successCallback != null)
|
||||
successCallback();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Console(1, this, "ERROR in routing: {0}", e);
|
||||
}
|
||||
|
||||
SourceSelectLock.Leave();
|
||||
}, 0); // end of CTimer
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="route"></param>
|
||||
void DoRouteItem(SourceRouteListItem route)
|
||||
{
|
||||
// if there is a $defaultAll on route, run two separate
|
||||
if (route.DestinationKey.Equals("$defaultAll", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
foreach (var display in Displays)
|
||||
{
|
||||
var tempVideo = new SourceRouteListItem
|
||||
{
|
||||
DestinationKey = display.Key,
|
||||
SourceKey = route.SourceKey,
|
||||
Type = eRoutingSignalType.Video
|
||||
};
|
||||
DoRoute(tempVideo);
|
||||
}
|
||||
}
|
||||
else
|
||||
DoRoute(route);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="route"></param>
|
||||
/// <returns></returns>
|
||||
bool DoRoute(SourceRouteListItem route)
|
||||
{
|
||||
IRoutingSink dest = null;
|
||||
|
||||
if (route.DestinationKey.Equals("$defaultaudio", StringComparison.OrdinalIgnoreCase))
|
||||
dest = DefaultAudioDevice as IRoutingSink;
|
||||
//else if (route.DestinationKey.Equals("$defaultDisplay", StringComparison.OrdinalIgnoreCase))
|
||||
// dest = DefaultDisplay;
|
||||
else
|
||||
dest = DeviceManager.GetDeviceForKey(route.DestinationKey) as IRoutingSink;
|
||||
|
||||
if (dest == null)
|
||||
{
|
||||
Debug.Console(1, this, "Cannot route, unknown destination '{0}'", route.DestinationKey);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (route.SourceKey.Equals("$off", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
dest.ReleaseRoute();
|
||||
if (dest is IHasPowerControl)
|
||||
(dest as IHasPowerControl).PowerOff();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
var source = DeviceManager.GetDeviceForKey(route.SourceKey) as IRoutingOutputs;
|
||||
if (source == null)
|
||||
{
|
||||
Debug.Console(1, this, "Cannot route unknown source '{0}' to {1}", route.SourceKey, route.DestinationKey);
|
||||
return false;
|
||||
}
|
||||
dest.ReleaseAndMakeRoute(source, route.Type);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void RoomVacatedForTimeoutPeriod(object o)
|
||||
{
|
||||
//Implement this
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does what it says
|
||||
/// </summary>
|
||||
public override void SetDefaultLevels()
|
||||
{
|
||||
Debug.Console(1, this, "Restoring default levels");
|
||||
var vc = CurrentVolumeControls as IBasicVolumeWithFeedback;
|
||||
if (vc != null)
|
||||
vc.SetVolume(DefaultVolume);
|
||||
}
|
||||
/// <summary>
|
||||
/// Will power the room on with the last-used source
|
||||
/// </summary>
|
||||
public override void PowerOnToDefaultOrLastSource()
|
||||
{
|
||||
if (!EnablePowerOnToLastSource || LastSourceKey == null)
|
||||
return;
|
||||
RunRouteAction(LastSourceKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs "roomOff" action on all rooms not set to ExcludeFromGlobalFunctions
|
||||
/// </summary>
|
||||
public static void AllRoomsOff()
|
||||
{
|
||||
var allRooms = DeviceManager.AllDevices.Where(d =>
|
||||
d is IEssentialsRoom && !(d as IEssentialsHuddleSpaceRoom).ExcludeFromGlobalFunctions);
|
||||
foreach (var room in allRooms)
|
||||
(room as IEssentialsHuddleSpaceRoom).RunRouteAction("roomOff");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Setup the external sources for the Cisco Touch 10 devices that support IHasExternalSourceSwitch
|
||||
/// </summary>
|
||||
private void SetCodecExternalSources()
|
||||
{
|
||||
var videoCodecWithExternalSwitching = VideoCodec as IHasExternalSourceSwitching;
|
||||
|
||||
if (videoCodecWithExternalSwitching == null || !videoCodecWithExternalSwitching.ExternalSourceListEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Get the tie line that the external switcher is connected to
|
||||
string codecInputConnectorName = ConfigReader.ConfigObject.TieLines.SingleOrDefault(
|
||||
x => x.DestinationKey == VideoCodec.Key && x.DestinationPort == videoCodecWithExternalSwitching.ExternalSourceInputPort).DestinationPort;
|
||||
|
||||
videoCodecWithExternalSwitching.ClearExternalSources();
|
||||
videoCodecWithExternalSwitching.RunRouteAction = RunRouteActionCodec;
|
||||
var srcList = ConfigReader.ConfigObject.SourceLists.SingleOrDefault(x => x.Key == SourceListKey).Value.OrderBy(kv => kv.Value.Order); ;
|
||||
|
||||
foreach (var kvp in srcList)
|
||||
{
|
||||
var srcConfig = kvp.Value;
|
||||
|
||||
if (kvp.Key != DefaultCodecRouteString && kvp.Key != "roomOff")
|
||||
{
|
||||
videoCodecWithExternalSwitching.AddExternalSource(codecInputConnectorName, kvp.Key, srcConfig.PreferredName, PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.eExternalSourceType.desktop);
|
||||
videoCodecWithExternalSwitching.SetExternalSourceState(kvp.Key, PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.eExternalSourceMode.Ready);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Console(2, this, "Error setting codec external sources: {0}", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetCodecBranding()
|
||||
{
|
||||
var vcWithBranding = VideoCodec as IHasBranding;
|
||||
|
||||
if (vcWithBranding == null) return;
|
||||
|
||||
Debug.Console(1, this, "Setting Codec Branding");
|
||||
vcWithBranding.InitializeBranding(Key);
|
||||
}
|
||||
|
||||
#region IPrivacy Members
|
||||
|
||||
|
||||
public void PrivacyModeOff()
|
||||
{
|
||||
VideoCodec.PrivacyModeOff();
|
||||
}
|
||||
|
||||
public void PrivacyModeOn()
|
||||
{
|
||||
VideoCodec.PrivacyModeOn();
|
||||
}
|
||||
|
||||
public void PrivacyModeToggle()
|
||||
{
|
||||
VideoCodec.PrivacyModeToggle();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,7 @@ namespace PepperDash.Essentials
|
||||
}
|
||||
}
|
||||
|
||||
public EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; private set; }
|
||||
public EssentialsConferenceRoomPropertiesConfig PropertiesConfig { get; private set; }
|
||||
|
||||
public IRoutingSinkWithSwitching DefaultDisplay { get; private set; }
|
||||
public IBasicVolumeControls DefaultAudioDevice { get; private set; }
|
||||
@@ -210,7 +210,7 @@ namespace PepperDash.Essentials
|
||||
{
|
||||
PropertiesConfig = JsonConvert.DeserializeObject<EssentialsHuddleVtc1PropertiesConfig>
|
||||
(config.Properties.ToString());
|
||||
DefaultDisplay = DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultDisplayKey) as IRoutingSinkWithSwitching;
|
||||
DefaultDisplay = DeviceManager.GetDeviceForKey((PropertiesConfig as EssentialsHuddleVtc1PropertiesConfig).DefaultDisplayKey) as IRoutingSinkWithSwitching;
|
||||
|
||||
VideoCodec = DeviceManager.GetDeviceForKey(PropertiesConfig.VideoCodecKey) as
|
||||
PepperDash.Essentials.Devices.Common.VideoCodec.VideoCodecBase;
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
|
||||
using PepperDash.Essentials.Core;
|
||||
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
|
||||
using PepperDash.Essentials.Room.Config;
|
||||
using PepperDash.Essentials.Core.Devices;
|
||||
using PepperDash.Essentials.Devices.Common.Codec;
|
||||
using PepperDash.Essentials.Devices.Common.VideoCodec;
|
||||
using PepperDash.Essentials.Devices.Common.AudioCodec;
|
||||
|
||||
|
||||
using PepperDash.Core;
|
||||
|
||||
namespace PepperDash.Essentials
|
||||
{
|
||||
public interface IEssentialsHuddleSpaceRoom : IEssentialsRoom, IHasCurrentSourceInfoChange, IRunRouteAction, IRunDefaultPresentRoute, IHasDefaultDisplay
|
||||
{
|
||||
bool ExcludeFromGlobalFunctions { get; }
|
||||
|
||||
void RunRouteAction(string routeKey);
|
||||
|
||||
EssentialsHuddleRoomPropertiesConfig PropertiesConfig { get; }
|
||||
|
||||
IBasicVolumeControls CurrentVolumeControls { get; }
|
||||
|
||||
event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
|
||||
}
|
||||
|
||||
public interface IEssentialsHuddleVtc1Room : IEssentialsRoom, IHasCurrentSourceInfoChange,
|
||||
IPrivacy, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasDefaultDisplay, IHasInCallFeedback
|
||||
{
|
||||
EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; }
|
||||
|
||||
void RunRouteAction(string routeKey);
|
||||
|
||||
IHasScheduleAwareness ScheduleSource { get; }
|
||||
|
||||
BoolFeedback InCallFeedback { get; }
|
||||
|
||||
BoolFeedback PrivacyModeIsOnFeedback { get; }
|
||||
|
||||
string DefaultCodecRouteString { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
|
||||
using PepperDash.Essentials.Core;
|
||||
using PepperDash.Essentials.Room.Config;
|
||||
|
||||
|
||||
|
||||
namespace PepperDash.Essentials
|
||||
{
|
||||
public interface IEssentialsHuddleSpaceRoom : IEssentialsRoom, IHasCurrentSourceInfoChange, IRunRouteAction, IRunDefaultPresentRoute, IHasDefaultDisplay
|
||||
{
|
||||
bool ExcludeFromGlobalFunctions { get; }
|
||||
|
||||
void RunRouteAction(string routeKey);
|
||||
|
||||
EssentialsHuddleRoomPropertiesConfig PropertiesConfig { get; }
|
||||
|
||||
IBasicVolumeControls CurrentVolumeControls { get; }
|
||||
|
||||
event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
using PepperDash.Essentials.Core;
|
||||
using PepperDash.Essentials.Room.Config;
|
||||
using PepperDash.Essentials.Devices.Common.Codec;
|
||||
using PepperDash.Essentials.Devices.Common.VideoCodec;
|
||||
using PepperDash.Essentials.Devices.Common.AudioCodec;
|
||||
|
||||
namespace PepperDash.Essentials
|
||||
{
|
||||
public interface IEssentialsHuddleVtc1Room : IEssentialsRoom, IHasCurrentSourceInfoChange,
|
||||
IPrivacy, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasDefaultDisplay, IHasInCallFeedback
|
||||
{
|
||||
EssentialsConferenceRoomPropertiesConfig PropertiesConfig { get; }
|
||||
|
||||
bool ExcludeFromGlobalFunctions { get; }
|
||||
|
||||
void RunRouteAction(string routeKey);
|
||||
|
||||
IHasScheduleAwareness ScheduleSource { get; }
|
||||
|
||||
new BoolFeedback InCallFeedback { get; }
|
||||
|
||||
new BoolFeedback PrivacyModeIsOnFeedback { get; }
|
||||
|
||||
string DefaultCodecRouteString { get; }
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,8 @@ namespace PepperDash.Essentials
|
||||
{
|
||||
public class EssentialsTouchpanelController : EssentialsDevice, IHasBasicTriListWithSmartObject
|
||||
{
|
||||
private CrestronTouchpanelPropertiesConfig _propertiesConfig;
|
||||
|
||||
public BasicTriListWithSmartObject Panel { get; private set; }
|
||||
|
||||
public PanelDriverBase PanelDriver { get; private set; }
|
||||
@@ -50,6 +52,7 @@ namespace PepperDash.Essentials
|
||||
public EssentialsTouchpanelController(string key, string name, string type, CrestronTouchpanelPropertiesConfig props, uint id)
|
||||
: base(key, name)
|
||||
{
|
||||
_propertiesConfig = props;
|
||||
|
||||
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Creating touchpanel hardware...");
|
||||
type = type.ToLower();
|
||||
@@ -124,8 +127,38 @@ namespace PepperDash.Essentials
|
||||
Panel.LoadSmartObjects(sgdName);
|
||||
Panel.SigChange += Panel_SigChange;
|
||||
|
||||
AddPostActivationAction(() =>
|
||||
{
|
||||
// Check for IEssentialsRoomCombiner in DeviceManager and if found, subscribe to its event
|
||||
|
||||
var roomCombiner = DeviceManager.AllDevices.FirstOrDefault((d) => d is IEssentialsRoomCombiner) as IEssentialsRoomCombiner;
|
||||
|
||||
if (roomCombiner != null)
|
||||
{
|
||||
roomCombiner.RoomCombinationScenarioChanged += new EventHandler<EventArgs>(roomCombiner_RoomCombinationScenarioChanged);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void roomCombiner_RoomCombinationScenarioChanged(object sender, EventArgs e)
|
||||
{
|
||||
var roomCombiner = sender as IEssentialsRoomCombiner;
|
||||
|
||||
string newRoomKey = null;
|
||||
|
||||
if (roomCombiner.CurrentScenario.UiMap.ContainsKey(Key))
|
||||
{
|
||||
newRoomKey = roomCombiner.CurrentScenario.UiMap[Key];
|
||||
}
|
||||
else if (roomCombiner.CurrentScenario.UiMap.ContainsKey(_propertiesConfig.DefaultRoomKey))
|
||||
{
|
||||
newRoomKey = roomCombiner.CurrentScenario.UiMap[_propertiesConfig.DefaultRoomKey];
|
||||
}
|
||||
|
||||
// TODO:
|
||||
}
|
||||
|
||||
public void LoadAndShowDriver(PanelDriverBase driver)
|
||||
{
|
||||
PanelDriver = driver;
|
||||
|
||||
@@ -306,7 +306,7 @@ namespace PepperDash.Essentials
|
||||
|
||||
TriList.SetSigFalseAction(UIBoolJoin.DisplayPowerTogglePress, () =>
|
||||
{
|
||||
if (CurrentRoom != null && CurrentRoom.DefaultDisplay is IHasPowerControl)
|
||||
if (CurrentRoom != null && CurrentRoom.DefaultDisplay != null && CurrentRoom.DefaultDisplay is IHasPowerControl)
|
||||
(CurrentRoom.DefaultDisplay as IHasPowerControl).PowerToggle();
|
||||
});
|
||||
|
||||
|
||||
@@ -1,326 +1,326 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharpPro.DeviceSupport;
|
||||
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharpPro.DeviceSupport;
|
||||
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials;
|
||||
using PepperDash.Essentials.Core;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
using PepperDash.Essentials.Core.SmartObjects;
|
||||
using PepperDash.Essentials.Core.Touchpanels.Keyboards;
|
||||
using PepperDash.Essentials.Devices.Displays;
|
||||
using PepperDash.Essentials.Room.Config;
|
||||
|
||||
namespace PepperDash.Essentials.UIDrivers
|
||||
{
|
||||
public class EssentialsHuddleTechPageDriver : PanelDriverBase
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
SmartObjectDynamicList MenuList;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
SubpageReferenceList StatusList;
|
||||
/// <summary>
|
||||
/// The list of display controls
|
||||
/// </summary>
|
||||
SubpageReferenceList DisplayList;
|
||||
/// <summary>
|
||||
/// References lines in the list against device instances
|
||||
/// </summary>
|
||||
Dictionary<ICommunicationMonitor, uint> StatusListDeviceIndexes;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
JoinedSigInterlock PagesInterlock;
|
||||
|
||||
/// <summary>
|
||||
/// 1
|
||||
/// </summary>
|
||||
public const uint JoinText = 1;
|
||||
|
||||
CTimer PinAuthorizedTimer;
|
||||
|
||||
EssentialsRoomTechConfig Config;
|
||||
|
||||
StringBuilder PinEntryBuilder = new StringBuilder(4);
|
||||
|
||||
bool IsAuthorized;
|
||||
|
||||
SmartObjectNumeric PinKeypad;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="trilist"></param>
|
||||
/// <param name="parent"></param>
|
||||
public EssentialsHuddleTechPageDriver(BasicTriListWithSmartObject trilist, EssentialsRoomTechConfig config)
|
||||
: base(trilist)
|
||||
{
|
||||
Config = config;
|
||||
|
||||
PagesInterlock = new JoinedSigInterlock(trilist);
|
||||
PagesInterlock.SetButDontShow(UIBoolJoin.TechSystemStatusVisible);
|
||||
|
||||
trilist.SetSigFalseAction(UIBoolJoin.TechExitButton, Hide);
|
||||
|
||||
MenuList = new SmartObjectDynamicList(trilist.SmartObjects[UISmartObjectJoin.TechMenuList],
|
||||
true, 3100);
|
||||
|
||||
MenuList.SetFeedback(1, true); // initial fb
|
||||
ushort count = 0;
|
||||
|
||||
MenuList.SetItemMainText(1, "System Status");
|
||||
MenuList.SetItemButtonAction(1, b => {
|
||||
if (b) PagesInterlock.ShowInterlocked(UIBoolJoin.TechSystemStatusVisible);
|
||||
MenuList.SetFeedback(1, true);
|
||||
});
|
||||
|
||||
MenuList.SetItemMainText(2, "Display Controls");
|
||||
MenuList.SetItemButtonAction(2, b => {
|
||||
if (b) PagesInterlock.ShowInterlocked(UIBoolJoin.TechDisplayControlsVisible);
|
||||
MenuList.SetFeedback(2, true);
|
||||
});
|
||||
|
||||
count = 2;
|
||||
|
||||
// Don't show panel setup on iPad or xpanel
|
||||
if (TriList is Crestron.SimplSharpPro.DeviceSupport.TswFt5Button)
|
||||
{
|
||||
count++;
|
||||
MenuList.SetItemMainText(count, "Panel Setup");
|
||||
MenuList.SetItemButtonAction(count, b =>
|
||||
{
|
||||
if (b) PagesInterlock.ShowInterlocked(UIBoolJoin.TechPanelSetupVisible);
|
||||
MenuList.SetFeedback(count, true);
|
||||
});
|
||||
}
|
||||
|
||||
MenuList.Count = count;
|
||||
BuildStatusList();
|
||||
BuildDisplayList();
|
||||
SetupPinModal();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override void Show()
|
||||
{
|
||||
// divert to PIN if we need auth
|
||||
if (IsAuthorized)
|
||||
{
|
||||
// Cancel the auth timer so we don't deauth after coming back in
|
||||
if (PinAuthorizedTimer != null)
|
||||
PinAuthorizedTimer.Stop();
|
||||
|
||||
TriList.SetBool(UIBoolJoin.TechCommonItemsVisbible, true);
|
||||
PagesInterlock.Show();
|
||||
base.Show();
|
||||
}
|
||||
else
|
||||
{
|
||||
TriList.SetBool(UIBoolJoin.PinDialog4DigitVisible, true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override void Hide()
|
||||
{
|
||||
// Leave it authorized for 60 seconds.
|
||||
if (IsAuthorized)
|
||||
PinAuthorizedTimer = new CTimer(o => {
|
||||
IsAuthorized = false;
|
||||
PinAuthorizedTimer = null;
|
||||
}, 60000);
|
||||
TriList.SetBool(UIBoolJoin.TechCommonItemsVisbible, false);
|
||||
PagesInterlock.Hide();
|
||||
base.Hide();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wire up the keypad and buttons
|
||||
/// </summary>
|
||||
void SetupPinModal()
|
||||
{
|
||||
TriList.SetSigFalseAction(UIBoolJoin.PinDialogCancelPress, CancelPinDialog);
|
||||
PinKeypad = new SmartObjectNumeric(TriList.SmartObjects[UISmartObjectJoin.TechPinDialogKeypad], true);
|
||||
PinKeypad.Digit0.UserObject = new Action<bool>(b => { if (b)DialPinDigit('0'); });
|
||||
PinKeypad.Digit1.UserObject = new Action<bool>(b => { if (b)DialPinDigit('1'); });
|
||||
PinKeypad.Digit2.UserObject = new Action<bool>(b => { if (b)DialPinDigit('2'); });
|
||||
PinKeypad.Digit3.UserObject = new Action<bool>(b => { if (b)DialPinDigit('3'); });
|
||||
PinKeypad.Digit4.UserObject = new Action<bool>(b => { if (b)DialPinDigit('4'); });
|
||||
PinKeypad.Digit5.UserObject = new Action<bool>(b => { if (b)DialPinDigit('5'); });
|
||||
PinKeypad.Digit6.UserObject = new Action<bool>(b => { if (b)DialPinDigit('6'); });
|
||||
PinKeypad.Digit7.UserObject = new Action<bool>(b => { if (b)DialPinDigit('7'); });
|
||||
PinKeypad.Digit8.UserObject = new Action<bool>(b => { if (b)DialPinDigit('8'); });
|
||||
PinKeypad.Digit9.UserObject = new Action<bool>(b => { if (b)DialPinDigit('9'); });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="d"></param>
|
||||
void DialPinDigit(char d)
|
||||
{
|
||||
PinEntryBuilder.Append(d);
|
||||
var len = PinEntryBuilder.Length;
|
||||
SetPinDotsFeedback(len);
|
||||
|
||||
// check it!
|
||||
if (len == 4)
|
||||
{
|
||||
if (Config.Password == PinEntryBuilder.ToString())
|
||||
{
|
||||
IsAuthorized = true;
|
||||
SetPinDotsFeedback(0);
|
||||
TriList.SetBool(UIBoolJoin.PinDialog4DigitVisible, false);
|
||||
Show();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetPinDotsFeedback(0);
|
||||
TriList.SetBool(UIBoolJoin.PinDialogErrorVisible, true);
|
||||
new CTimer(o =>
|
||||
{
|
||||
TriList.SetBool(UIBoolJoin.PinDialogErrorVisible, false);
|
||||
}, 1500);
|
||||
}
|
||||
|
||||
PinEntryBuilder.Remove(0, len); // clear it either way
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the dots as pin is entered
|
||||
/// </summary>
|
||||
/// <param name="len"></param>
|
||||
void SetPinDotsFeedback(int len)
|
||||
{
|
||||
TriList.SetBool(UIBoolJoin.PinDialogDot1, len >= 1);
|
||||
TriList.SetBool(UIBoolJoin.PinDialogDot2, len >= 2);
|
||||
TriList.SetBool(UIBoolJoin.PinDialogDot3, len >= 3);
|
||||
TriList.SetBool(UIBoolJoin.PinDialogDot4, len == 4);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does what it says
|
||||
/// </summary>
|
||||
void CancelPinDialog()
|
||||
{
|
||||
PinEntryBuilder.Remove(0, PinEntryBuilder.Length);
|
||||
TriList.SetBool(UIBoolJoin.PinDialog4DigitVisible, false);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
void BuildStatusList()
|
||||
{
|
||||
StatusList = new SubpageReferenceList(TriList, UISmartObjectJoin.TechStatusList, 3, 3, 3);
|
||||
StatusListDeviceIndexes = new Dictionary<ICommunicationMonitor, uint>();
|
||||
uint i = 0;
|
||||
foreach (var d in DeviceManager.AllDevices)
|
||||
{
|
||||
// make sure it is both ICommunicationMonitor and a Device
|
||||
var sd = d as ICommunicationMonitor;
|
||||
if (sd == null)
|
||||
continue;
|
||||
var dd = sd as Device;
|
||||
if(dd == null)
|
||||
continue;
|
||||
i++;
|
||||
StatusList.StringInputSig(i, 1).StringValue = dd.Name;
|
||||
StatusList.UShortInputSig(i, 1).UShortValue = (ushort)sd.CommunicationMonitor.Status;
|
||||
StatusListDeviceIndexes.Add(sd, i);
|
||||
sd.CommunicationMonitor.StatusChange += CommunicationMonitor_StatusChange ;
|
||||
}
|
||||
StatusList.Count = (ushort)i;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds the list of display controls
|
||||
/// </summary>
|
||||
void BuildDisplayList()
|
||||
{
|
||||
DisplayList = new SubpageReferenceList(TriList, UISmartObjectJoin.TechDisplayControlsList, 10, 3, 3);
|
||||
|
||||
var devKeys = ConfigReader.ConfigObject.Devices.Where(d =>
|
||||
d.Group.Equals("display", StringComparison.OrdinalIgnoreCase)
|
||||
|| d.Group.Equals("projector", StringComparison.OrdinalIgnoreCase))
|
||||
.Select(dd => dd.Key);
|
||||
var disps = DeviceManager.AllDevices.Where(d =>
|
||||
devKeys.Contains(d.Key));
|
||||
ushort i = 0;
|
||||
foreach (var disp in disps)
|
||||
{
|
||||
var display = disp as DisplayBase;
|
||||
if (display != null)
|
||||
{
|
||||
i++;
|
||||
DisplayList.StringInputSig(i, 1).StringValue = display.Name;
|
||||
DisplayList.GetBoolFeedbackSig(i, 1).SetSigFalseAction(display.PowerOn);
|
||||
DisplayList.GetBoolFeedbackSig(i, 2).SetSigFalseAction(display.PowerOff);
|
||||
if (display is TwoWayDisplayBase)
|
||||
{
|
||||
var powerOnSig = DisplayList.BoolInputSig(i, 1);
|
||||
(display as TwoWayDisplayBase).PowerIsOnFeedback.LinkInputSig(powerOnSig);
|
||||
|
||||
var powerOffSig = DisplayList.BoolInputSig(1, 2);
|
||||
(display as TwoWayDisplayBase).PowerIsOnFeedback.LinkComplementInputSig(powerOffSig);
|
||||
}
|
||||
DisplayList.GetBoolFeedbackSig(i, 3).SetSigFalseAction(() =>
|
||||
{ if (display is IInputHdmi1) (display as IInputHdmi1).InputHdmi1(); });
|
||||
DisplayList.GetBoolFeedbackSig(i, 4).SetSigFalseAction(() =>
|
||||
{ if (display is IInputHdmi2) (display as IInputHdmi2).InputHdmi2(); });
|
||||
DisplayList.GetBoolFeedbackSig(i, 5).SetSigFalseAction(() =>
|
||||
{ if (display is IInputHdmi3) (display as IInputHdmi3).InputHdmi3(); });
|
||||
//DisplayList.GetBoolFeedbackSig(i, 6).SetSigFalseAction(() =>
|
||||
//{ if (display is IInputHdmi4) (display as IInputHdmi4).InputHdmi4(); });
|
||||
DisplayList.GetBoolFeedbackSig(i, 6).SetSigFalseAction(() =>
|
||||
{ if (display is IInputDisplayPort1) (display as IInputDisplayPort1).InputDisplayPort1(); });
|
||||
|
||||
|
||||
// Figure out some way to provide current input feedback
|
||||
if (display is TwoWayDisplayBase)
|
||||
{
|
||||
(display as TwoWayDisplayBase).CurrentInputFeedback.OutputChange += CurrentInputFeedback_OutputChange;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
DisplayList.Count = i;
|
||||
}
|
||||
|
||||
|
||||
void CurrentInputFeedback_OutputChange(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
void CommunicationMonitor_StatusChange(object sender, MonitorStatusChangeEventArgs e)
|
||||
{
|
||||
var c = sender as ICommunicationMonitor;
|
||||
if (StatusListDeviceIndexes.ContainsKey(c))
|
||||
{
|
||||
var i = StatusListDeviceIndexes[c];
|
||||
StatusList.UShortInputSig(i, 1).UShortValue = (ushort)e.Status;
|
||||
}
|
||||
}
|
||||
}
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
using PepperDash.Essentials.Core.SmartObjects;
|
||||
using PepperDash.Essentials.Core.Touchpanels.Keyboards;
|
||||
using PepperDash.Essentials.Devices.Displays;
|
||||
using PepperDash.Essentials.Room.Config;
|
||||
|
||||
namespace PepperDash.Essentials.UIDrivers
|
||||
{
|
||||
public class EssentialsHuddleTechPageDriver : PanelDriverBase
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
SmartObjectDynamicList MenuList;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
SubpageReferenceList StatusList;
|
||||
/// <summary>
|
||||
/// The list of display controls
|
||||
/// </summary>
|
||||
SubpageReferenceList DisplayList;
|
||||
/// <summary>
|
||||
/// References lines in the list against device instances
|
||||
/// </summary>
|
||||
Dictionary<ICommunicationMonitor, uint> StatusListDeviceIndexes;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
JoinedSigInterlock PagesInterlock;
|
||||
|
||||
/// <summary>
|
||||
/// 1
|
||||
/// </summary>
|
||||
public const uint JoinText = 1;
|
||||
|
||||
CTimer PinAuthorizedTimer;
|
||||
|
||||
EssentialsRoomTechConfig Config;
|
||||
|
||||
StringBuilder PinEntryBuilder = new StringBuilder(4);
|
||||
|
||||
bool IsAuthorized;
|
||||
|
||||
SmartObjectNumeric PinKeypad;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="trilist"></param>
|
||||
/// <param name="parent"></param>
|
||||
public EssentialsHuddleTechPageDriver(BasicTriListWithSmartObject trilist, EssentialsRoomTechConfig config)
|
||||
: base(trilist)
|
||||
{
|
||||
Config = config;
|
||||
|
||||
PagesInterlock = new JoinedSigInterlock(trilist);
|
||||
PagesInterlock.SetButDontShow(UIBoolJoin.TechSystemStatusVisible);
|
||||
|
||||
trilist.SetSigFalseAction(UIBoolJoin.TechExitButton, Hide);
|
||||
|
||||
MenuList = new SmartObjectDynamicList(trilist.SmartObjects[UISmartObjectJoin.TechMenuList],
|
||||
true, 3100);
|
||||
|
||||
MenuList.SetFeedback(1, true); // initial fb
|
||||
ushort count = 0;
|
||||
|
||||
MenuList.SetItemMainText(1, "System Status");
|
||||
MenuList.SetItemButtonAction(1, b => {
|
||||
if (b) PagesInterlock.ShowInterlocked(UIBoolJoin.TechSystemStatusVisible);
|
||||
MenuList.SetFeedback(1, true);
|
||||
});
|
||||
|
||||
MenuList.SetItemMainText(2, "Display Controls");
|
||||
MenuList.SetItemButtonAction(2, b => {
|
||||
if (b) PagesInterlock.ShowInterlocked(UIBoolJoin.TechDisplayControlsVisible);
|
||||
MenuList.SetFeedback(2, true);
|
||||
});
|
||||
|
||||
count = 2;
|
||||
|
||||
// Don't show panel setup on iPad or xpanel
|
||||
if (TriList is Crestron.SimplSharpPro.DeviceSupport.TswFt5Button)
|
||||
{
|
||||
count++;
|
||||
MenuList.SetItemMainText(count, "Panel Setup");
|
||||
MenuList.SetItemButtonAction(count, b =>
|
||||
{
|
||||
if (b) PagesInterlock.ShowInterlocked(UIBoolJoin.TechPanelSetupVisible);
|
||||
MenuList.SetFeedback(count, true);
|
||||
});
|
||||
}
|
||||
|
||||
MenuList.Count = count;
|
||||
BuildStatusList();
|
||||
BuildDisplayList();
|
||||
SetupPinModal();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override void Show()
|
||||
{
|
||||
// divert to PIN if we need auth
|
||||
if (IsAuthorized)
|
||||
{
|
||||
// Cancel the auth timer so we don't deauth after coming back in
|
||||
if (PinAuthorizedTimer != null)
|
||||
PinAuthorizedTimer.Stop();
|
||||
|
||||
TriList.SetBool(UIBoolJoin.TechCommonItemsVisbible, true);
|
||||
PagesInterlock.Show();
|
||||
base.Show();
|
||||
}
|
||||
else
|
||||
{
|
||||
TriList.SetBool(UIBoolJoin.PinDialog4DigitVisible, true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override void Hide()
|
||||
{
|
||||
// Leave it authorized for 60 seconds.
|
||||
if (IsAuthorized)
|
||||
PinAuthorizedTimer = new CTimer(o => {
|
||||
IsAuthorized = false;
|
||||
PinAuthorizedTimer = null;
|
||||
}, 60000);
|
||||
TriList.SetBool(UIBoolJoin.TechCommonItemsVisbible, false);
|
||||
PagesInterlock.Hide();
|
||||
base.Hide();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wire up the keypad and buttons
|
||||
/// </summary>
|
||||
void SetupPinModal()
|
||||
{
|
||||
TriList.SetSigFalseAction(UIBoolJoin.PinDialogCancelPress, CancelPinDialog);
|
||||
PinKeypad = new SmartObjectNumeric(TriList.SmartObjects[UISmartObjectJoin.TechPinDialogKeypad], true);
|
||||
PinKeypad.Digit0.UserObject = new Action<bool>(b => { if (b)DialPinDigit('0'); });
|
||||
PinKeypad.Digit1.UserObject = new Action<bool>(b => { if (b)DialPinDigit('1'); });
|
||||
PinKeypad.Digit2.UserObject = new Action<bool>(b => { if (b)DialPinDigit('2'); });
|
||||
PinKeypad.Digit3.UserObject = new Action<bool>(b => { if (b)DialPinDigit('3'); });
|
||||
PinKeypad.Digit4.UserObject = new Action<bool>(b => { if (b)DialPinDigit('4'); });
|
||||
PinKeypad.Digit5.UserObject = new Action<bool>(b => { if (b)DialPinDigit('5'); });
|
||||
PinKeypad.Digit6.UserObject = new Action<bool>(b => { if (b)DialPinDigit('6'); });
|
||||
PinKeypad.Digit7.UserObject = new Action<bool>(b => { if (b)DialPinDigit('7'); });
|
||||
PinKeypad.Digit8.UserObject = new Action<bool>(b => { if (b)DialPinDigit('8'); });
|
||||
PinKeypad.Digit9.UserObject = new Action<bool>(b => { if (b)DialPinDigit('9'); });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="d"></param>
|
||||
void DialPinDigit(char d)
|
||||
{
|
||||
PinEntryBuilder.Append(d);
|
||||
var len = PinEntryBuilder.Length;
|
||||
SetPinDotsFeedback(len);
|
||||
|
||||
// check it!
|
||||
if (len == 4)
|
||||
{
|
||||
if (Config.Password == PinEntryBuilder.ToString())
|
||||
{
|
||||
IsAuthorized = true;
|
||||
SetPinDotsFeedback(0);
|
||||
TriList.SetBool(UIBoolJoin.PinDialog4DigitVisible, false);
|
||||
Show();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetPinDotsFeedback(0);
|
||||
TriList.SetBool(UIBoolJoin.PinDialogErrorVisible, true);
|
||||
new CTimer(o =>
|
||||
{
|
||||
TriList.SetBool(UIBoolJoin.PinDialogErrorVisible, false);
|
||||
}, 1500);
|
||||
}
|
||||
|
||||
PinEntryBuilder.Remove(0, len); // clear it either way
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the dots as pin is entered
|
||||
/// </summary>
|
||||
/// <param name="len"></param>
|
||||
void SetPinDotsFeedback(int len)
|
||||
{
|
||||
TriList.SetBool(UIBoolJoin.PinDialogDot1, len >= 1);
|
||||
TriList.SetBool(UIBoolJoin.PinDialogDot2, len >= 2);
|
||||
TriList.SetBool(UIBoolJoin.PinDialogDot3, len >= 3);
|
||||
TriList.SetBool(UIBoolJoin.PinDialogDot4, len == 4);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does what it says
|
||||
/// </summary>
|
||||
void CancelPinDialog()
|
||||
{
|
||||
PinEntryBuilder.Remove(0, PinEntryBuilder.Length);
|
||||
TriList.SetBool(UIBoolJoin.PinDialog4DigitVisible, false);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
void BuildStatusList()
|
||||
{
|
||||
StatusList = new SubpageReferenceList(TriList, UISmartObjectJoin.TechStatusList, 3, 3, 3);
|
||||
StatusListDeviceIndexes = new Dictionary<ICommunicationMonitor, uint>();
|
||||
uint i = 0;
|
||||
foreach (var d in DeviceManager.AllDevices)
|
||||
{
|
||||
// make sure it is both ICommunicationMonitor and a Device
|
||||
var sd = d as ICommunicationMonitor;
|
||||
if (sd == null)
|
||||
continue;
|
||||
var dd = sd as Device;
|
||||
if(dd == null)
|
||||
continue;
|
||||
i++;
|
||||
StatusList.StringInputSig(i, 1).StringValue = dd.Name;
|
||||
StatusList.UShortInputSig(i, 1).UShortValue = (ushort)sd.CommunicationMonitor.Status;
|
||||
StatusListDeviceIndexes.Add(sd, i);
|
||||
sd.CommunicationMonitor.StatusChange += CommunicationMonitor_StatusChange ;
|
||||
}
|
||||
StatusList.Count = (ushort)i;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds the list of display controls
|
||||
/// </summary>
|
||||
void BuildDisplayList()
|
||||
{
|
||||
DisplayList = new SubpageReferenceList(TriList, UISmartObjectJoin.TechDisplayControlsList, 10, 3, 3);
|
||||
|
||||
var devKeys = ConfigReader.ConfigObject.Devices.Where(d =>
|
||||
d.Group.Equals("display", StringComparison.OrdinalIgnoreCase)
|
||||
|| d.Group.Equals("projector", StringComparison.OrdinalIgnoreCase))
|
||||
.Select(dd => dd.Key);
|
||||
var disps = DeviceManager.AllDevices.Where(d =>
|
||||
devKeys.Contains(d.Key));
|
||||
ushort i = 0;
|
||||
foreach (var disp in disps)
|
||||
{
|
||||
var display = disp as DisplayBase;
|
||||
if (display != null)
|
||||
{
|
||||
i++;
|
||||
DisplayList.StringInputSig(i, 1).StringValue = display.Name;
|
||||
DisplayList.GetBoolFeedbackSig(i, 1).SetSigFalseAction(display.PowerOn);
|
||||
DisplayList.GetBoolFeedbackSig(i, 2).SetSigFalseAction(display.PowerOff);
|
||||
if (display is TwoWayDisplayBase)
|
||||
{
|
||||
var powerOnSig = DisplayList.BoolInputSig(i, 1);
|
||||
(display as TwoWayDisplayBase).PowerIsOnFeedback.LinkInputSig(powerOnSig);
|
||||
|
||||
var powerOffSig = DisplayList.BoolInputSig(1, 2);
|
||||
(display as TwoWayDisplayBase).PowerIsOnFeedback.LinkComplementInputSig(powerOffSig);
|
||||
}
|
||||
DisplayList.GetBoolFeedbackSig(i, 3).SetSigFalseAction(() =>
|
||||
{ if (display is IInputHdmi1) (display as IInputHdmi1).InputHdmi1(); });
|
||||
DisplayList.GetBoolFeedbackSig(i, 4).SetSigFalseAction(() =>
|
||||
{ if (display is IInputHdmi2) (display as IInputHdmi2).InputHdmi2(); });
|
||||
DisplayList.GetBoolFeedbackSig(i, 5).SetSigFalseAction(() =>
|
||||
{ if (display is IInputHdmi3) (display as IInputHdmi3).InputHdmi3(); });
|
||||
//DisplayList.GetBoolFeedbackSig(i, 6).SetSigFalseAction(() =>
|
||||
//{ if (display is IInputHdmi4) (display as IInputHdmi4).InputHdmi4(); });
|
||||
DisplayList.GetBoolFeedbackSig(i, 6).SetSigFalseAction(() =>
|
||||
{ if (display is IInputDisplayPort1) (display as IInputDisplayPort1).InputDisplayPort1(); });
|
||||
|
||||
|
||||
// Figure out some way to provide current input feedback
|
||||
if (display is TwoWayDisplayBase)
|
||||
{
|
||||
(display as TwoWayDisplayBase).CurrentInputFeedback.OutputChange += CurrentInputFeedback_OutputChange;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
DisplayList.Count = i;
|
||||
}
|
||||
|
||||
|
||||
void CurrentInputFeedback_OutputChange(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
void CommunicationMonitor_StatusChange(object sender, MonitorStatusChangeEventArgs e)
|
||||
{
|
||||
var c = sender as ICommunicationMonitor;
|
||||
if (StatusListDeviceIndexes.ContainsKey(c))
|
||||
{
|
||||
var i = StatusListDeviceIndexes[c];
|
||||
StatusList.UShortInputSig(i, 1).UShortValue = (ushort)e.Status;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -319,7 +319,7 @@ namespace PepperDash.Essentials
|
||||
|
||||
TriList.SetSigFalseAction(UIBoolJoin.DisplayPowerTogglePress, () =>
|
||||
{
|
||||
if (CurrentRoom != null && CurrentRoom.DefaultDisplay is IHasPowerControl)
|
||||
if (CurrentRoom != null && CurrentRoom.DefaultDisplay != null && CurrentRoom.DefaultDisplay is IHasPowerControl)
|
||||
(CurrentRoom.DefaultDisplay as IHasPowerControl).PowerToggle();
|
||||
});
|
||||
|
||||
@@ -448,7 +448,7 @@ namespace PepperDash.Essentials
|
||||
// and the LastMeetingDismissed != this meeting
|
||||
|
||||
var lastMeetingDismissed = meetings.FirstOrDefault(m => m.Id == LastMeetingDismissedId);
|
||||
Debug.Console(0, "*#* Room on: {0}, lastMeetingDismissedId: {1} {2} *#*",
|
||||
Debug.Console(1, "*#* Room on: {0}, lastMeetingDismissedId: {1} {2} *#*",
|
||||
CurrentRoom.OnFeedback.BoolValue,
|
||||
LastMeetingDismissedId,
|
||||
lastMeetingDismissed != null ? lastMeetingDismissed.StartTime.ToShortTimeString() : "");
|
||||
|
||||
@@ -60,6 +60,7 @@ namespace PepperDash.Essentials.Core
|
||||
DeviceCriticalSection.Enter();
|
||||
AddDeviceEnabled = false;
|
||||
// PreActivate all devices
|
||||
Debug.Console(0,"****PreActivation starting...****");
|
||||
foreach (var d in Devices.Values)
|
||||
{
|
||||
try
|
||||
@@ -69,9 +70,12 @@ namespace PepperDash.Essentials.Core
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Console(0, d, "ERROR: Device PreActivation failure:\r{0}", e);
|
||||
Debug.Console(0, d, "ERROR: Device {1} PreActivation failure: {0}", e.Message, d.Key);
|
||||
Debug.Console(1, d, "Stack Trace: {0}", e.StackTrace);
|
||||
}
|
||||
}
|
||||
Debug.Console(0, "****PreActivation complete****");
|
||||
Debug.Console(0, "****Activation starting...****");
|
||||
|
||||
// Activate all devices
|
||||
foreach (var d in Devices.Values)
|
||||
@@ -83,10 +87,14 @@ namespace PepperDash.Essentials.Core
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Console(0, d, "ERROR: Device Activation failure:\r{0}", e);
|
||||
Debug.Console(0, d, "ERROR: Device {1} Activation failure: {0}", e.Message, d.Key);
|
||||
Debug.Console(1, d, "Stack Trace: {0}", e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Console(0, "****Activation complete****");
|
||||
Debug.Console(0, "****PostActivation starting...****");
|
||||
|
||||
// PostActivate all devices
|
||||
foreach (var d in Devices.Values)
|
||||
{
|
||||
@@ -97,10 +105,13 @@ namespace PepperDash.Essentials.Core
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Console(0, d, "ERROR: Device PostActivation failure:\r{0}", e);
|
||||
Debug.Console(0, d, "ERROR: Device {1} PostActivation failure: {0}", e.Message, d.Key);
|
||||
Debug.Console(1, d, "Stack Trace: {0}", e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Console(0, "****PostActivation complete****");
|
||||
|
||||
OnAllDevicesActivated();
|
||||
}
|
||||
finally
|
||||
|
||||
@@ -62,6 +62,11 @@ namespace PepperDash.Essentials.Core
|
||||
ValueFunc = valueFunc;
|
||||
}
|
||||
|
||||
public void SetValueFunc(Func<bool> newFunc)
|
||||
{
|
||||
ValueFunc = newFunc;
|
||||
}
|
||||
|
||||
public override void FireUpdate()
|
||||
{
|
||||
bool newValue = InTestMode ? TestValue : ValueFunc.Invoke();
|
||||
|
||||
@@ -51,6 +51,12 @@ namespace PepperDash.Essentials.Core
|
||||
ValueFunc = valueFunc;
|
||||
}
|
||||
|
||||
public void SetValueFunc(Func<int> newFunc)
|
||||
{
|
||||
ValueFunc = newFunc;
|
||||
}
|
||||
|
||||
|
||||
public override void FireUpdate()
|
||||
{
|
||||
var newValue = InTestMode ? TestValue : ValueFunc.Invoke();
|
||||
|
||||
@@ -52,7 +52,10 @@ namespace PepperDash.Essentials.Core
|
||||
ValueFunc = valueFunc;
|
||||
}
|
||||
|
||||
|
||||
public void SetValueFunc(Func<string> newFunc)
|
||||
{
|
||||
ValueFunc = newFunc;
|
||||
}
|
||||
|
||||
public override void FireUpdate()
|
||||
{
|
||||
|
||||
@@ -119,9 +119,21 @@ namespace PepperDash.Essentials.Core.Fusion
|
||||
var slot = Global.ControlSystem.ProgramNumber;
|
||||
|
||||
var guidFilePath = Global.FilePathPrefix +
|
||||
string.Format(@"{0}-FusionGuids.json", InitialParametersClass.ProgramIDTag);
|
||||
string.Format(@"{0}-FusionGuids-{1:X2}.json", InitialParametersClass.ProgramIDTag, _ipId);
|
||||
|
||||
_guidFileExists = File.Exists(guidFilePath);
|
||||
var oldGuidFilePath = Global.FilePathPrefix +
|
||||
string.Format(@"{0}-FusionGuids.json", InitialParametersClass.ProgramIDTag);
|
||||
|
||||
if (File.Exists(oldGuidFilePath))
|
||||
{
|
||||
Debug.Console(0, this, "Migrating from old Fusion GUID file to new Fusion GUID File");
|
||||
|
||||
File.Copy(oldGuidFilePath, guidFilePath);
|
||||
|
||||
File.Delete(oldGuidFilePath);
|
||||
}
|
||||
|
||||
_guidFileExists = File.Exists(guidFilePath);
|
||||
|
||||
// Check if file exists
|
||||
if (!_guidFileExists)
|
||||
@@ -149,19 +161,7 @@ namespace PepperDash.Essentials.Core.Fusion
|
||||
}
|
||||
|
||||
|
||||
AddPostActivationAction(() =>
|
||||
{
|
||||
CreateSymbolAndBasicSigs(_ipId);
|
||||
SetUpSources();
|
||||
SetUpCommunitcationMonitors();
|
||||
SetUpDisplay();
|
||||
SetUpError();
|
||||
ExecuteCustomSteps();
|
||||
|
||||
FusionRVI.GenerateFileForAllFusionDevices();
|
||||
|
||||
GenerateGuidFile(guidFilePath);
|
||||
});
|
||||
AddPostActivationAction(() => PostActivate(guidFilePath));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -169,6 +169,20 @@ namespace PepperDash.Essentials.Core.Fusion
|
||||
}
|
||||
}
|
||||
|
||||
private void PostActivate(string guidFilePath)
|
||||
{
|
||||
CreateSymbolAndBasicSigs(_ipId);
|
||||
SetUpSources();
|
||||
SetUpCommunitcationMonitors();
|
||||
SetUpDisplay();
|
||||
SetUpError();
|
||||
ExecuteCustomSteps();
|
||||
|
||||
FusionRVI.GenerateFileForAllFusionDevices();
|
||||
|
||||
GenerateGuidFile(guidFilePath);
|
||||
}
|
||||
|
||||
protected string RoomGuid
|
||||
{
|
||||
get { return _guiDs.RoomGuid; }
|
||||
@@ -314,7 +328,7 @@ namespace PepperDash.Essentials.Core.Fusion
|
||||
|
||||
protected virtual void CreateSymbolAndBasicSigs(uint ipId)
|
||||
{
|
||||
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Creating Fusion Room symbol with GUID: {0}", RoomGuid);
|
||||
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Creating Fusion Room symbol with GUID: {0} and IP-ID {1:X2}", RoomGuid, ipId);
|
||||
|
||||
FusionRoom = new FusionRoom(ipId, Global.ControlSystem, Room.Name, RoomGuid);
|
||||
FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.Use();
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an abstract controller device for a partition dividing rooms that are combinable
|
||||
///
|
||||
/// In Auto mode, it can use a partition sensor to automatically determine whether the partition is present.
|
||||
///
|
||||
/// In Manual mode it accepts user input to tell it whether the partition is present.
|
||||
/// </summary>
|
||||
public class EssentialsPartitionController : IPartitionController
|
||||
{
|
||||
private IPartitionStateProvider _partitionSensor;
|
||||
|
||||
private bool isInAutoMode;
|
||||
|
||||
private bool partitionPresent;
|
||||
|
||||
public EssentialsPartitionController(string key, string name, IPartitionStateProvider sensor, bool defaultToManualMode, List<string> adjacentRoomKeys)
|
||||
{
|
||||
Key = key;
|
||||
|
||||
Name = name;
|
||||
|
||||
AdjacentRoomKeys = adjacentRoomKeys;
|
||||
|
||||
if (sensor != null)
|
||||
{
|
||||
_partitionSensor = sensor;
|
||||
|
||||
if (!defaultToManualMode)
|
||||
{
|
||||
SetAutoMode();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetManualMode();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetManualMode();
|
||||
}
|
||||
|
||||
PartitionPresentFeedback.FireUpdate();
|
||||
}
|
||||
|
||||
void PartitionPresentFeedback_OutputChange(object sender, FeedbackEventArgs e)
|
||||
{
|
||||
if (isInAutoMode)
|
||||
{
|
||||
PartitionPresentFeedback.FireUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
#region IPartitionController Members
|
||||
|
||||
public List<string> AdjacentRoomKeys { get; private set; }
|
||||
|
||||
public void SetAutoMode()
|
||||
{
|
||||
isInAutoMode = true;
|
||||
if (PartitionPresentFeedback != null)
|
||||
{
|
||||
PartitionPresentFeedback.SetValueFunc(() => _partitionSensor.PartitionPresentFeedback.BoolValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
PartitionPresentFeedback = new BoolFeedback(() => _partitionSensor.PartitionPresentFeedback.BoolValue);
|
||||
}
|
||||
|
||||
if (_partitionSensor != null)
|
||||
{
|
||||
_partitionSensor.PartitionPresentFeedback.OutputChange += PartitionPresentFeedback_OutputChange;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetManualMode()
|
||||
{
|
||||
isInAutoMode = false;
|
||||
if (PartitionPresentFeedback != null)
|
||||
{
|
||||
PartitionPresentFeedback.SetValueFunc(() => partitionPresent);
|
||||
}
|
||||
else
|
||||
{
|
||||
PartitionPresentFeedback = new BoolFeedback(() => partitionPresent);
|
||||
}
|
||||
|
||||
if (_partitionSensor != null)
|
||||
{
|
||||
_partitionSensor.PartitionPresentFeedback.OutputChange -= PartitionPresentFeedback_OutputChange;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void SetPartitionStatePresent()
|
||||
{
|
||||
if (!isInAutoMode)
|
||||
{
|
||||
partitionPresent = true;
|
||||
PartitionPresentFeedback.FireUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetPartitionStateNotPresent()
|
||||
{
|
||||
if (!isInAutoMode)
|
||||
{
|
||||
partitionPresent = false;
|
||||
PartitionPresentFeedback.FireUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public void ToggglePartitionState()
|
||||
{
|
||||
if (!isInAutoMode)
|
||||
{
|
||||
partitionPresent = !partitionPresent;
|
||||
PartitionPresentFeedback.FireUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IPartitionStateProvider Members
|
||||
|
||||
public BoolFeedback PartitionPresentFeedback { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region IKeyName Members
|
||||
|
||||
public string Name { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region IKeyed Members
|
||||
|
||||
public string Key { get; private set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -13,13 +13,13 @@ using PepperDash.Essentials.Core.Config;
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
[Description("Wrapper class for GLS Cresnet Partition Sensor")]
|
||||
public class GlsPartitionSensorController : CrestronGenericBridgeableBaseDevice
|
||||
public class GlsPartitionSensorController : CrestronGenericBridgeableBaseDevice, IPartitionStateProvider
|
||||
{
|
||||
private GlsPartCn _partitionSensor;
|
||||
|
||||
public StringFeedback NameFeedback { get; private set; }
|
||||
public BoolFeedback EnableFeedback { get; private set; }
|
||||
public BoolFeedback PartitionSensedFeedback { get; private set; }
|
||||
public BoolFeedback PartitionPresentFeedback { get; private set; }
|
||||
public BoolFeedback PartitionNotSensedFeedback { get; private set; }
|
||||
public IntFeedback SensitivityFeedback { get; private set; }
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace PepperDash.Essentials.Core
|
||||
|
||||
NameFeedback = new StringFeedback(() => Name);
|
||||
EnableFeedback = new BoolFeedback(() => _partitionSensor.EnableFeedback.BoolValue);
|
||||
PartitionSensedFeedback = new BoolFeedback(() => _partitionSensor.PartitionSensedFeedback.BoolValue);
|
||||
PartitionPresentFeedback = new BoolFeedback(() => _partitionSensor.PartitionSensedFeedback.BoolValue);
|
||||
PartitionNotSensedFeedback = new BoolFeedback(() => _partitionSensor.PartitionNotSensedFeedback.BoolValue);
|
||||
SensitivityFeedback = new IntFeedback(() => _partitionSensor.SensitivityFeedback.UShortValue);
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace PepperDash.Essentials.Core
|
||||
}
|
||||
case (GlsPartCn.PartitionSensedFeedbackEventId):
|
||||
{
|
||||
PartitionSensedFeedback.FireUpdate();
|
||||
PartitionPresentFeedback.FireUpdate();
|
||||
break;
|
||||
}
|
||||
case (GlsPartCn.PartitionNotSensedFeedbackEventId):
|
||||
@@ -186,7 +186,7 @@ namespace PepperDash.Essentials.Core
|
||||
// link output to simpl
|
||||
IsOnline.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline.JoinNumber]);
|
||||
EnableFeedback.LinkInputSig(trilist.BooleanInput[joinMap.Enable.JoinNumber]);
|
||||
PartitionSensedFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PartitionSensed.JoinNumber]);
|
||||
PartitionPresentFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PartitionSensed.JoinNumber]);
|
||||
PartitionNotSensedFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PartitionNotSensed.JoinNumber]);
|
||||
SensitivityFeedback.LinkInputSig(trilist.UShortInput[joinMap.Sensitivity.JoinNumber]);
|
||||
|
||||
@@ -216,7 +216,7 @@ namespace PepperDash.Essentials.Core
|
||||
IsOnline.FireUpdate();
|
||||
NameFeedback.FireUpdate();
|
||||
EnableFeedback.FireUpdate();
|
||||
PartitionSensedFeedback.FireUpdate();
|
||||
PartitionPresentFeedback.FireUpdate();
|
||||
PartitionNotSensedFeedback.FireUpdate();
|
||||
SensitivityFeedback.FireUpdate();
|
||||
}
|
||||
@@ -257,7 +257,7 @@ namespace PepperDash.Essentials.Core
|
||||
|
||||
public override EssentialsDevice BuildDevice(DeviceConfig dc)
|
||||
{
|
||||
Debug.Console(1, "Factory Attempting to create new C2N-RTHS Device");
|
||||
Debug.Console(1, "Factory Attempting to create new GlsPartitionSensorController Device");
|
||||
|
||||
return new GlsPartitionSensorController(dc.Key, GetGlsPartCnDevice, dc);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
|
||||
using PepperDash.Core;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes the functionality of a device that senses and provides partition state
|
||||
/// </summary>
|
||||
public interface IPartitionStateProvider : IKeyName
|
||||
{
|
||||
BoolFeedback PartitionPresentFeedback { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Describes the functionality of a device that can provide partition state either manually via user input or optionally via a sensor state
|
||||
/// </summary>
|
||||
public interface IPartitionController : IPartitionStateProvider
|
||||
{
|
||||
List<string> AdjacentRoomKeys { get; }
|
||||
|
||||
void SetPartitionStatePresent();
|
||||
|
||||
void SetPartitionStateNotPresent();
|
||||
|
||||
void ToggglePartitionState();
|
||||
|
||||
void SetManualMode();
|
||||
|
||||
void SetAutoMode();
|
||||
}
|
||||
}
|
||||
@@ -234,6 +234,8 @@
|
||||
<Compile Include="Interfaces\ILogStringsWithLevel.cs" />
|
||||
<Compile Include="Occupancy\GlsOccupancySensorPropertiesConfig.cs" />
|
||||
<Compile Include="Occupancy\GlsOirOccupancySensorController.cs" />
|
||||
<Compile Include="PartitionSensor\EssentialsPartitionController.cs" />
|
||||
<Compile Include="PartitionSensor\IPartitionStateProvider.cs" />
|
||||
<Compile Include="Occupancy\OccupancyAggregatorConfig.cs" />
|
||||
<Compile Include="Queues\ComsMessage.cs" />
|
||||
<Compile Include="Queues\ProcessStringMessage.cs" />
|
||||
@@ -289,6 +291,10 @@
|
||||
<Compile Include="Remotes\CrestronRemotePropertiesConfig.cs" />
|
||||
<Compile Include="Remotes\Hrxx0WirelessRemoteController.cs" />
|
||||
<Compile Include="Room\Behaviours\RoomOnToDefaultSourceWhenOccupied.cs" />
|
||||
<Compile Include="Room\Combining\EssentialsRoomCombiner.cs" />
|
||||
<Compile Include="Room\Combining\EssentialsRoomCombinerPropertiesConfig.cs" />
|
||||
<Compile Include="Room\Combining\IEssentialsRoomCombiner.cs" />
|
||||
<Compile Include="Room\Combining\RoomCombinationScenario.cs" />
|
||||
<Compile Include="Room\EssentialsRoomBase.cs" />
|
||||
<Compile Include="Room\Config\EssentialsRoomScheduledEventsConfig.cs" />
|
||||
<Compile Include="Room\IEssentialsRoom.cs" />
|
||||
|
||||
@@ -0,0 +1,271 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
|
||||
using PepperDash.Core;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public class EssentialsRoomCombiner : EssentialsDevice, IEssentialsRoomCombiner
|
||||
{
|
||||
private EssentialsRoomCombinerPropertiesConfig _propertiesConfig;
|
||||
|
||||
private IRoomCombinationScenario _currentScenario;
|
||||
|
||||
private List<IEssentialsRoom> _rooms;
|
||||
|
||||
private bool isInAutoMode;
|
||||
|
||||
private CTimer _scenarioChangeDebounceTimer;
|
||||
|
||||
private int _scenarioChangeDebounceTimeSeconds = 10; // default to 10s
|
||||
|
||||
public EssentialsRoomCombiner(string key, EssentialsRoomCombinerPropertiesConfig props)
|
||||
: base(key)
|
||||
{
|
||||
_propertiesConfig = props;
|
||||
|
||||
Partitions = new List<IPartitionController>();
|
||||
RoomCombinationScenarios = new List<IRoomCombinationScenario>();
|
||||
|
||||
if (_propertiesConfig.ScenarioChangeDebounceTimeSeconds > 0)
|
||||
{
|
||||
_scenarioChangeDebounceTimeSeconds = _propertiesConfig.ScenarioChangeDebounceTimeSeconds;
|
||||
}
|
||||
|
||||
IsInAutoModeFeedback = new BoolFeedback(() => isInAutoMode);
|
||||
|
||||
// default to auto mode
|
||||
isInAutoMode = true;
|
||||
|
||||
if (_propertiesConfig.defaultToManualMode)
|
||||
{
|
||||
isInAutoMode = false;
|
||||
}
|
||||
|
||||
IsInAutoModeFeedback.FireUpdate();
|
||||
|
||||
CreateScenarios();
|
||||
|
||||
AddPostActivationAction(() =>
|
||||
{
|
||||
SetupPartitionStateProviders();
|
||||
|
||||
SetRooms();
|
||||
|
||||
if (isInAutoMode)
|
||||
{
|
||||
DetermineRoomCombinationScenario();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetRoomCombinationScenario(_propertiesConfig.defaultScenarioKey);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void CreateScenarios()
|
||||
{
|
||||
foreach (var scenarioConfig in _propertiesConfig.Scenarios)
|
||||
{
|
||||
var scenario = new RoomCombinationScenario(scenarioConfig);
|
||||
RoomCombinationScenarios.Add(scenario);
|
||||
}
|
||||
}
|
||||
|
||||
void SetRooms()
|
||||
{
|
||||
_rooms = new List<IEssentialsRoom>();
|
||||
|
||||
foreach (var roomKey in _propertiesConfig.RoomKeys)
|
||||
{
|
||||
var room = DeviceManager.GetDeviceForKey(roomKey) as IEssentialsRoom;
|
||||
if (room != null)
|
||||
{
|
||||
_rooms.Add(room);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetupPartitionStateProviders()
|
||||
{
|
||||
foreach (var pConfig in _propertiesConfig.Partitions)
|
||||
{
|
||||
var sensor = DeviceManager.GetDeviceForKey(pConfig.DeviceKey) as IPartitionStateProvider;
|
||||
|
||||
var partition = new EssentialsPartitionController(pConfig.Key, pConfig.Name, sensor, _propertiesConfig.defaultToManualMode, pConfig.AdjacentRoomKeys);
|
||||
|
||||
partition.PartitionPresentFeedback.OutputChange += PartitionPresentFeedback_OutputChange;
|
||||
|
||||
Partitions.Add(partition);
|
||||
}
|
||||
}
|
||||
|
||||
void PartitionPresentFeedback_OutputChange(object sender, FeedbackEventArgs e)
|
||||
{
|
||||
StartDebounceTimer();
|
||||
}
|
||||
|
||||
void StartDebounceTimer()
|
||||
{
|
||||
var time = _scenarioChangeDebounceTimeSeconds * 1000;
|
||||
|
||||
if (_scenarioChangeDebounceTimer == null)
|
||||
{
|
||||
_scenarioChangeDebounceTimer = new CTimer((o) => DetermineRoomCombinationScenario(), time);
|
||||
}
|
||||
else
|
||||
{
|
||||
_scenarioChangeDebounceTimer.Reset(time);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the current room combination scenario based on the state of the partition sensors
|
||||
/// </summary>
|
||||
void DetermineRoomCombinationScenario()
|
||||
{
|
||||
if (_scenarioChangeDebounceTimer != null)
|
||||
{
|
||||
_scenarioChangeDebounceTimer.Dispose();
|
||||
_scenarioChangeDebounceTimer = null;
|
||||
}
|
||||
|
||||
var currentScenario = RoomCombinationScenarios.FirstOrDefault((s) =>
|
||||
{
|
||||
// iterate the partition states
|
||||
foreach (var partitionState in s.PartitionStates)
|
||||
{
|
||||
// get the partition by key
|
||||
var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionState.PartitionKey));
|
||||
|
||||
if (partition != null && partitionState.PartitionPresent != partition.PartitionPresentFeedback.BoolValue)
|
||||
{
|
||||
// the partition can't be found or the state doesn't match
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// if it hasn't returned false by now we have the matching scenario
|
||||
return true;
|
||||
});
|
||||
|
||||
if (currentScenario != null)
|
||||
{
|
||||
CurrentScenario = currentScenario;
|
||||
}
|
||||
}
|
||||
|
||||
#region IEssentialsRoomCombiner Members
|
||||
|
||||
public event EventHandler<EventArgs> RoomCombinationScenarioChanged;
|
||||
|
||||
public IRoomCombinationScenario CurrentScenario
|
||||
{
|
||||
get
|
||||
{
|
||||
return _currentScenario;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _currentScenario)
|
||||
{
|
||||
_currentScenario = value;
|
||||
Debug.Console(1, this, "Current Scenario: {0}", _currentScenario.Name);
|
||||
var handler = RoomCombinationScenarioChanged;
|
||||
if (handler != null)
|
||||
{
|
||||
handler(this, new EventArgs());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BoolFeedback IsInAutoModeFeedback { get; private set; }
|
||||
|
||||
public void SetAutoMode()
|
||||
{
|
||||
isInAutoMode = true;
|
||||
IsInAutoModeFeedback.FireUpdate();
|
||||
}
|
||||
|
||||
public void SetManualMode()
|
||||
{
|
||||
isInAutoMode = false;
|
||||
IsInAutoModeFeedback.FireUpdate();
|
||||
}
|
||||
|
||||
public void ToggleMode()
|
||||
{
|
||||
isInAutoMode = !isInAutoMode;
|
||||
IsInAutoModeFeedback.FireUpdate();
|
||||
}
|
||||
|
||||
public List<IRoomCombinationScenario> RoomCombinationScenarios { get; private set; }
|
||||
|
||||
public List<IPartitionController> Partitions { get; private set; }
|
||||
|
||||
public void TogglePartitionState(string partitionKey)
|
||||
{
|
||||
var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionKey)) as IPartitionController;
|
||||
|
||||
if (partition != null)
|
||||
{
|
||||
partition.ToggglePartitionState();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetRoomCombinationScenario(string scenarioKey)
|
||||
{
|
||||
if (isInAutoMode)
|
||||
{
|
||||
Debug.Console(0, this, "Cannot set room combination scenario when in auto mode. Set to auto mode first.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the scenario
|
||||
var scenario = RoomCombinationScenarios.FirstOrDefault((s) => s.Key.Equals(scenarioKey));
|
||||
|
||||
// Set the parition states from the scenario manually
|
||||
if (scenario != null)
|
||||
{
|
||||
foreach (var partitionState in scenario.PartitionStates)
|
||||
{
|
||||
var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionState.PartitionKey));
|
||||
|
||||
if (partition != null)
|
||||
{
|
||||
if (partitionState.PartitionPresent)
|
||||
{
|
||||
partition.SetPartitionStatePresent();
|
||||
}
|
||||
else
|
||||
{
|
||||
partition.SetPartitionStateNotPresent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class EssentialsRoomCombinerFactory : EssentialsDeviceFactory<EssentialsRoomCombiner>
|
||||
{
|
||||
public EssentialsRoomCombinerFactory()
|
||||
{
|
||||
TypeNames = new List<string> { "essentialsroomcombiner" };
|
||||
}
|
||||
|
||||
public override EssentialsDevice BuildDevice(PepperDash.Essentials.Core.Config.DeviceConfig dc)
|
||||
{
|
||||
Debug.Console(1, "Factory Attempting to create new EssentialsRoomCombiner Device");
|
||||
|
||||
var props = dc.Properties.ToObject<EssentialsRoomCombinerPropertiesConfig>();
|
||||
|
||||
return new EssentialsRoomCombiner(dc.Key, props);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
|
||||
using PepperDash.Core;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Config properties for an EssentialsRoomCombiner device
|
||||
/// </summary>
|
||||
public class EssentialsRoomCombinerPropertiesConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// The list of partitions that device the rooms
|
||||
/// </summary>
|
||||
[JsonProperty("partitions")]
|
||||
public List<PartitionConfig> Partitions {get; set;}
|
||||
|
||||
/// <summary>
|
||||
/// The list of combinations scenarios for the rooms
|
||||
/// </summary>
|
||||
[JsonProperty("scenarios")]
|
||||
public List<RoomCombinationScenarioConfig> Scenarios { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of rooms keys that can be combined
|
||||
/// </summary>
|
||||
[JsonProperty("roomKeys")]
|
||||
public List<string> RoomKeys {get; set;}
|
||||
|
||||
/// <summary>
|
||||
/// Set to true to default to manual mode
|
||||
/// </summary>
|
||||
[JsonProperty("defaultToManualMode")]
|
||||
public bool defaultToManualMode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The key of the scenario to default to at system startup if in manual mode
|
||||
/// </summary>
|
||||
[JsonProperty("defaultScenarioKey")]
|
||||
public string defaultScenarioKey { get; set; }
|
||||
|
||||
[JsonProperty("scenarioChangeDebounceTimeSeconds")]
|
||||
public int ScenarioChangeDebounceTimeSeconds { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Config properties for a partition that separates rooms
|
||||
/// </summary>
|
||||
public class PartitionConfig : IKeyName
|
||||
{
|
||||
[JsonProperty("key")]
|
||||
public string Key { get; set; }
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Key of the device that implements IPartitionStateProvider to provide the state of the partition
|
||||
/// </summary>
|
||||
[JsonProperty("deviceKey")]
|
||||
public string DeviceKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Keys of the rooms that this partion would be located between
|
||||
/// </summary>
|
||||
[JsonProperty("adjacentRoomKeys")]
|
||||
public List<string> AdjacentRoomKeys { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Config propeties for a room combination scenario
|
||||
/// </summary>
|
||||
public class RoomCombinationScenarioConfig : IKeyName
|
||||
{
|
||||
[JsonProperty("key")]
|
||||
public string Key { get; set; }
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("partitionStates")]
|
||||
public List<PartitionState> PartitionStates { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines which UI devices get mapped to which room in this scenario. The Key should be the key of the UI device and the Value should be the key of the room to map to
|
||||
/// </summary>
|
||||
[JsonProperty("uiMap")]
|
||||
public Dictionary<string, string> UiMap { get; set; }
|
||||
|
||||
[JsonProperty("activationActions")]
|
||||
public List<DeviceActionWrapper> ActivationActions { get; set; }
|
||||
|
||||
[JsonProperty("deactivationActions")]
|
||||
public List<DeviceActionWrapper> DeactivationActions { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Config properties to represent the state of a partition sensor in a RoomCombinationScenario
|
||||
/// </summary>
|
||||
public class PartitionState
|
||||
{
|
||||
[JsonProperty("partitionKey")]
|
||||
public string PartitionKey { get; set; }
|
||||
|
||||
[JsonProperty("partitionSensedState")]
|
||||
public bool PartitionPresent { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
|
||||
using PepperDash.Core;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes the functionality for an EssentailsRoomCombiner device
|
||||
/// </summary>
|
||||
public interface IEssentialsRoomCombiner : IKeyed
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that the room combination scenario has changed
|
||||
/// </summary>
|
||||
event EventHandler<EventArgs> RoomCombinationScenarioChanged;
|
||||
|
||||
/// <summary>
|
||||
/// The current room combination scenario
|
||||
/// </summary>
|
||||
IRoomCombinationScenario CurrentScenario { get; }
|
||||
|
||||
/// <summary>
|
||||
/// When true, indicates the current mode is auto mode
|
||||
/// </summary>
|
||||
BoolFeedback IsInAutoModeFeedback {get;}
|
||||
|
||||
/// <summary>
|
||||
/// Sets auto mode
|
||||
/// </summary>
|
||||
void SetAutoMode();
|
||||
|
||||
/// <summary>
|
||||
/// Sets manual mode
|
||||
/// </summary>
|
||||
void SetManualMode();
|
||||
|
||||
/// <summary>
|
||||
/// Toggles the current mode between auto and manual
|
||||
/// </summary>
|
||||
void ToggleMode();
|
||||
|
||||
/// <summary>
|
||||
/// The available room combinatino scenarios
|
||||
/// </summary>
|
||||
List<IRoomCombinationScenario> RoomCombinationScenarios { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The partition
|
||||
/// </summary>
|
||||
List<IPartitionController> Partitions { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Toggles the state of a manual partition sensor
|
||||
/// </summary>
|
||||
/// <param name="partitionKey"></param>
|
||||
void TogglePartitionState(string partitionKey);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the room combination scenario (if in manual mode)
|
||||
/// </summary>
|
||||
/// <param name="scenarioKey"></param>
|
||||
void SetRoomCombinationScenario(string scenarioKey);
|
||||
}
|
||||
|
||||
public interface IRoomCombinationScenario : IKeyName
|
||||
{
|
||||
/// <summary>
|
||||
/// When true, indicates that this room combination scenario is active
|
||||
/// </summary>
|
||||
BoolFeedback IsActiveFeedback { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Activates this room combination scenario
|
||||
/// </summary>
|
||||
void Activate();
|
||||
|
||||
/// <summary>
|
||||
/// The state of the partitions that would activate this scenario
|
||||
/// </summary>
|
||||
List<PartitionState> PartitionStates { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The mapping of UIs by key to rooms by key
|
||||
/// </summary>
|
||||
Dictionary<string, string> UiMap { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a room combination scenario
|
||||
/// </summary>
|
||||
public class RoomCombinationScenario: IRoomCombinationScenario
|
||||
{
|
||||
private RoomCombinationScenarioConfig _config;
|
||||
|
||||
public string Key { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public List<PartitionState> PartitionStates { get; private set; }
|
||||
|
||||
public Dictionary<string, string> UiMap { get; set; }
|
||||
|
||||
private bool _isActive;
|
||||
|
||||
public BoolFeedback IsActiveFeedback { get; private set; }
|
||||
|
||||
List<DeviceActionWrapper> activationActions;
|
||||
|
||||
List<DeviceActionWrapper> deactivationActions;
|
||||
|
||||
public RoomCombinationScenario(RoomCombinationScenarioConfig config)
|
||||
{
|
||||
Key = config.Key;
|
||||
|
||||
Name = config.Name;
|
||||
|
||||
PartitionStates = config.PartitionStates;
|
||||
|
||||
UiMap = config.UiMap;
|
||||
|
||||
activationActions = config.ActivationActions;
|
||||
|
||||
deactivationActions = config.DeactivationActions;
|
||||
|
||||
_config = config;
|
||||
|
||||
IsActiveFeedback = new BoolFeedback(() => _isActive);
|
||||
}
|
||||
|
||||
public void Activate()
|
||||
{
|
||||
if (activationActions != null)
|
||||
{
|
||||
foreach (var action in activationActions)
|
||||
{
|
||||
DeviceJsonApi.DoDeviceAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
_isActive = true;
|
||||
IsActiveFeedback.FireUpdate();
|
||||
}
|
||||
|
||||
public void Deactivate()
|
||||
{
|
||||
if (deactivationActions != null)
|
||||
{
|
||||
foreach (var action in deactivationActions)
|
||||
{
|
||||
DeviceJsonApi.DoDeviceAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
_isActive = false;
|
||||
IsActiveFeedback.FireUpdate();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user