Compare commits

...

37 Commits

Author SHA1 Message Date
Jason Alborough
f0d10fb1f9 Finalized IHasExternalSourceSwitching adding method for setting the ExternalSource State
Adds arguments for External Source type it the AddExternalSource()
Adds subscription and parsing for External Source events
2020-08-17 14:52:49 -04:00
Jason Alborough
aea6942a1f Update to support Cisco Codec External Sources using Essentials Room logic.
Adds new interface for Codecs IHasExternalSourceSwitching
Adds ability to set and clear External Sources in Cisco Spark device class
Adds ability to send sources from the source list to the Cisco Spark in the "EssentialsHuddleVtc1Room" room
[ ] still needs parsing when source is selected on the Cisco touch 10
2020-08-14 15:51:37 -04:00
Neil Dorin
22ff61d7f3 Merge pull request #361 from PepperDash/feature/add-qr-code-on-tsw-panels
Add Mobile Control QR code to TSW Panels for Essentials Standalone
2020-08-07 09:56:55 -06:00
Neil Dorin
f066321f3a Merge branch 'main' into feature/add-qr-code-on-tsw-panels 2020-08-07 09:41:47 -06:00
Neil Dorin
302603aa54 Updates to phone and video address logic 2020-08-07 09:29:55 -06:00
Neil Dorin
dea858e187 Updates to phone and video address logic 2020-08-07 09:11:31 -06:00
Neil Dorin
ddbee2ed04 Fixed incorrect join for dark background logo. Updates CodecInfo class to correclty poppulate values 2020-08-07 08:56:29 -06:00
Neil Dorin
b7c9677c7a Updates to finesse screen saver and get phone/video number display working correclty 2020-08-06 22:04:07 -06:00
Neil Dorin
d6581cab2e Updates to work out kinks 2020-08-06 21:16:03 -06:00
Neil Dorin
66c481e3dc Seems to work except dynamic graphics for logos and QR code 2020-08-06 19:46:12 -06:00
Neil Dorin
edd01785d5 Adds ability to get URL for both light and dark logo options 2020-08-06 18:07:23 -06:00
Neil Dorin
192aa4255c Adds ability for dark logo option 2020-08-06 15:20:24 -06:00
Neil Dorin
637ca2f312 removes parent from interfaces 2020-08-06 15:04:02 -06:00
Neil Dorin
bf7a0600f3 specified previous docker build version 2020-08-06 14:42:45 -06:00
Neil Dorin
f59654d75e working on #109 to add QR support for TSW panels 2020-08-06 13:56:42 -06:00
Andrew Welker
211665c0c4 Merge pull request #358 from PepperDash/release/1.6.0
Release/1.6.0
2020-08-06 09:21:00 -04:00
Neil Dorin
829e3eb634 Merge pull request #345 from PepperDash/release/1.6.0
Release 1.6.0
2020-08-05 13:45:04 -06:00
Andrew Welker
683f007e0b Merge pull request #357 from PepperDash/hotfix/cisco-large-directory-issues
Hotfix/cisco large directory issues
2020-08-05 12:34:36 -07:00
Neil Dorin
23bfecd870 Adds E164 and H323 fixes from release branch 2020-08-05 12:04:43 -06:00
Neil Dorin
0b485d8d96 Revert "Merge branch 'release/1.6.0' into hotfix/cisco-large-directory-issues"
This reverts commit 1d42d88c3f, reversing
changes made to ec0b2fa181.
2020-08-05 11:58:41 -06:00
Neil Dorin
1d42d88c3f Merge branch 'release/1.6.0' into hotfix/cisco-large-directory-issues 2020-08-05 11:42:47 -06:00
Neil Dorin
ec0b2fa181 Adds receive queue and thread to CiscoSparkCodec class and sets receive thread priority for ZoomRoom 2020-08-05 10:50:48 -06:00
Andrew Welker
1b621e1655 Merge branch 'main' into release/1.6.0 2020-08-04 14:32:25 -07:00
Neil Dorin
3ecadf72e9 Merge pull request #352 from PepperDash/feature/add-dmc-4kz-hdo-support-and-try-catch
Adds support for DMC-4KZ-HDO output card and adds try catch to solve …
2020-08-04 15:31:23 -06:00
Neil Dorin
744298bdb5 Adds support for DMC-4KZ-HDO output card and adds try catch to solve issue with incorrect inputSlotSupportsHdcp2 value 2020-08-04 15:13:48 -06:00
Andrew Welker
fe090113ce Merge pull request #349 from PepperDash/hotfix/ciscocodec-missing-config-options
Add null check for Cisco CE codec H323 object
2020-08-04 09:02:59 -07:00
Andrew Welker
55e50f68d3 check h323 object for null 2020-07-30 13:56:32 -06:00
Andrew Welker
8d13de0e8c Merge branch 'main' into release/1.6.0 2020-07-30 09:49:34 -07:00
Andrew Welker
41aae794b6 Merge pull request #344 from PepperDash/bugfix/essentials-huddleVtc1-routing
fix RunRouteAction methods in Huddle VTC Room
2020-07-30 09:22:04 -07:00
Andrew Welker
dbafce0aa8 fix RunRouteAction methods 2020-07-29 14:42:26 -06:00
Neil Dorin
383777c0f5 Merge pull request #342 from PepperDash/feature/push-to-nuget.org
Add push to nuget.org to workflows
2020-07-29 10:04:43 -06:00
Neil Dorin
5e24bb6cd3 Merge pull request #340 from PepperDash/hotfix/Fusion-Activation
Move some Fusion Activation steps to PostActivation action
2020-07-29 10:03:46 -06:00
Andrew Welker
35d7c23815 move method to postactivation action 2020-07-23 09:10:15 -06:00
Andrew Welker
c7e6e0c250 Move some activation steps to PostActivation 2020-07-23 08:48:05 -06:00
Andrew Welker
7c4222a598 move most init actions to PostActivationAction 2020-07-23 08:30:00 -06:00
Andrew Welker
fda888b095 fixes for activation sequence issues 2020-07-23 08:22:27 -06:00
Andrew Welker
f9b326e1e1 Merge pull request #334 from PepperDash/hotfix/fix-joinmap-constructors
Change access for constructors to enable extension and creating an instance
2020-07-22 13:22:44 -07:00
39 changed files with 4122 additions and 3503 deletions

View File

@@ -10,7 +10,7 @@ Get-ChildItem ($destination)
$exclusions = @(git submodule foreach --quiet 'echo $name')
# Trying to get any .json schema files (not currently working)
# Gets any files with the listed extensions.
Get-ChildItem -recurse -Path "$($Env:GITHUB_WORKSPACE)" -include "*.clz", "*.cpz", "*.cplz", "*.dll", "*.nuspec" | ForEach-Object {
Get-ChildItem -recurse -Path "$($Env:GITHUB_WORKSPACE)" -include "*.clz", "*.cpz", "*.cplz", "*.dll" | ForEach-Object {
$allowed = $true;
# Exclude any files in submodules
foreach ($exclude in $exclusions) {

View File

@@ -1,7 +0,0 @@
{
"workbench.colorCustomizations": {
"activityBar.background": "#332848",
"titleBar.activeBackground": "#483764",
"titleBar.activeForeground": "#FBFBFD"
}
}

View File

@@ -32,20 +32,7 @@ jobs:
uses: actions/checkout@v2
with:
fetch-depth: 0
# And any submodules
#- name: Checkout submodules
# shell: bash
# run: |
# git config --global url."https://github.com/".insteadOf "git@github.com:"
# auth_header="$(git config --local --get http.https://github.com/.extraheader)"
# git submodule sync --recursive
# git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1
- name: Add nuget.exe
uses: nuget/setup-nuget@v1
- name: Add Github Packages source
run: nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash/index.json -username Pepperdash -password ${{ secrets.GITHUB_TOKEN }}
- name: restore Nuget Packages
run: nuget install .\packages.config -OutputDirectory .\packages -ExcludeVersion
submodules: true
# Fetch all tags
- name: Fetch tags
run: git fetch --tags
@@ -71,7 +58,7 @@ jobs:
- name: Build Solution
shell: powershell
run: |
Invoke-Expression "docker run --rm --mount type=bind,source=""$($Env:GITHUB_WORKSPACE)"",target=""c:/project"" pepperdash/sspbuilder c:\cihelpers\vsidebuild.exe -Solution ""c:\project\$($Env:SOLUTION_FILE).sln"" -BuildSolutionConfiguration $($ENV:BUILD_TYPE)"
Invoke-Expression "docker run --rm --mount type=bind,source=""$($Env:GITHUB_WORKSPACE)"",target=""c:/project"" pepperdash/sspbuilder:v1.4.1 c:\cihelpers\vsidebuild.exe -Solution ""c:\project\$($Env:SOLUTION_FILE).sln"" -BuildSolutionConfiguration $($ENV:BUILD_TYPE)"
# Zip up the output files as needed
- name: Zip Build Output
shell: powershell
@@ -120,49 +107,6 @@ jobs:
asset_content_type: application/zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Push_Nuget_Package:
needs: Build_Project
runs-on: windows-latest
steps:
- name: Download Build Version Info
uses: actions/download-artifact@v1
with:
name: Version
- name: Set Version Number
shell: powershell
run: |
Get-ChildItem "./Version"
$version = Get-Content -Path ./Version/version.txt
Write-Host "Version: $version"
Write-Output "::set-env name=VERSION::$version"
Remove-Item -Path ./Version/version.txt
Remove-Item -Path ./Version
- name: Download Build output
uses: actions/download-artifact@v1
with:
name: Build
path: ./
- name: Unzip Build file
run: |
Get-ChildItem .\*.zip | Expand-Archive -DestinationPath .\
Remove-Item -Path .\*.zip
- name: Copy Files to root & delete output directory
run: |
Remove-Item -Path .\* -Include @("*.cpz","*.md","*.cplz","*.json","*.dll","*.clz")
Get-ChildItem -Path .\output\* | Copy-Item -Destination .\
Remove-Item -Path .\output -Recurse
- name: Add nuget.exe
uses: nuget/setup-nuget@v1
- name: Add Github Packages source
run: nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash/index.json -username Pepperdash -password ${{ secrets.GITHUB_TOKEN }}
- name: Add nuget.org API Key
run: nuget setApiKey ${{ secrets.NUGET_API_KEY }}
- name: Create nuget package
run: nuget pack "./PepperDash_Essentials_Core.nuspec" -version ${{ env.VERSION }}
- name: Publish nuget package to Github registry
run: nuget push **/*.nupkg -source github
- name: Publish nuget package to nuget.org
run: nuget push **/*.nupkg -Source https://api.nuget.org/v3/index.json
# This step always runs and pushes the build to the internal build rep
Internal_Push_Output:
needs: Build_Project

View File

@@ -25,19 +25,13 @@ jobs:
- name: Checkout repo
uses: actions/checkout@v2
# And any submodules
#- name: Checkout submodules
# shell: bash
# run: |
# git config --global url."https://github.com/".insteadOf "git@github.com:"
# auth_header="$(git config --local --get http.https://github.com/.extraheader)"
# git submodule sync --recursive
# git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1
- name: Add nuget.exe
uses: nuget/setup-nuget@v1
- name: Add Github Packages source
run: nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash/index.json -username Pepperdash -password ${{ secrets.GITHUB_TOKEN }}
- name: restore Nuget Packages
run: nuget install .\packages.config -OutputDirectory .\packages -ExcludeVersion
- name: Checkout submodules
shell: bash
run: |
git config --global url."https://github.com/".insteadOf "git@github.com:"
auth_header="$(git config --local --get http.https://github.com/.extraheader)"
git submodule sync --recursive
git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1
# Generate the appropriate version number
- name: Set Version Number
shell: powershell
@@ -91,49 +85,6 @@ jobs:
asset_content_type: application/zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Push_Nuget_Package:
needs: Build_Project
runs-on: windows-latest
steps:
- name: Download Build Version Info
uses: actions/download-artifact@v1
with:
name: Version
- name: Set Version Number
shell: powershell
run: |
Get-ChildItem "./Version"
$version = Get-Content -Path ./Version/version.txt
Write-Host "Version: $version"
Write-Output "::set-env name=VERSION::$version"
Remove-Item -Path ./Version/version.txt
Remove-Item -Path ./Version
- name: Download Build output
uses: actions/download-artifact@v1
with:
name: Build
path: ./
- name: Unzip Build file
run: |
Get-ChildItem .\*.zip | Expand-Archive -DestinationPath .\
Remove-Item -Path .\*.zip
- name: Copy Files to root & delete output directory
run: |
Remove-Item -Path .\* -Include @("*.cpz","*.md","*.cplz","*.json","*.dll","*.clz")
Get-ChildItem -Path .\output\* | Copy-Item -Destination .\
Remove-Item -Path .\output -Recurse
- name: Add nuget.exe
uses: nuget/setup-nuget@v1
- name: Add Github Packages source
run: nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash/index.json -username Pepperdash -password ${{ secrets.GITHUB_TOKEN }}
- name: Add nuget.org API Key
run: nuget setApiKey ${{ secrets.NUGET_API_KEY }}
- name: Create nuget package
run: nuget pack "./PepperDash_Essentials_Core.nuspec" -version ${{ env.VERSION }}
- name: Publish nuget package to Github registry
run: nuget push **/*.nupkg -source github
- name: Publish nuget package to nuget.org
run: nuget push **/*.nupkg -Source https://api.nuget.org/v3/index.json
Internal_Push_Output:
needs: Build_Project
runs-on: windows-latest

2
.gitignore vendored
View File

@@ -23,7 +23,5 @@ SIMPLSharpLogs/
*.projectinfo
essentials-framework/EssentialDMTestConfig/
output/
packages/
PepperDashEssentials-0.0.0-buildType-test.zip

View File

@@ -53,7 +53,7 @@ namespace PepperDash.Essentials
if (Debug.DoNotLoadOnNextBoot)
{
CrestronConsole.AddNewConsoleCommand(s => GoWithLoadDeferred(), "go", "Loads configuration file",
CrestronConsole.AddNewConsoleCommand(s => GoWithLoad(), "go", "Loads configuration file",
ConsoleAccessLevelEnum.AccessOperator);
}
@@ -93,18 +93,13 @@ namespace PepperDash.Essentials
if (!Debug.DoNotLoadOnNextBoot)
{
GoWithLoad(null);
GoWithLoad();
return;
}
SystemMonitor.ProgramInitialization.ProgramInitializationComplete = true;
}
private void GoWithLoadDeferred()
{
CrestronInvoke.BeginInvoke(GoWithLoad);
}
/// <summary>
/// Determines if the program is running on a processor (appliance) or server (VC-4).
///
@@ -177,7 +172,7 @@ namespace PepperDash.Essentials
/// <summary>
/// Begins the process of loading resources including plugins and configuration data
/// </summary>
public void GoWithLoad(object notUsed)
public void GoWithLoad()
{
try
{

View File

@@ -2,340 +2,340 @@
using System.Linq;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.Fusion;
using Crestron.SimplSharpPro.Fusion;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Fusion;
namespace PepperDash.Essentials.Fusion
{
public class EssentialsHuddleVtc1FusionController : EssentialsHuddleSpaceFusionSystemControllerBase
{
BooleanSigData CodecIsInCall;
public EssentialsHuddleVtc1FusionController(EssentialsHuddleVtc1Room room, uint ipId)
: base(room, ipId)
{
}
/// <summary>
/// Called in base class constructor before RVI and GUID files are built
/// </summary>
protected override void ExecuteCustomSteps()
{
SetUpCodec();
}
/// <summary>
/// Creates a static asset for the codec and maps the joins to the main room symbol
/// </summary>
void SetUpCodec()
{
try
{
var codec = (Room as EssentialsHuddleVtc1Room).VideoCodec;
if (codec == null)
{
Debug.Console(1, this, "Cannot link codec to Fusion because codec is null");
return;
}
codec.UsageTracker = new UsageTracking(codec);
codec.UsageTracker.UsageIsTracked = true;
codec.UsageTracker.DeviceUsageEnded += UsageTracker_DeviceUsageEnded;
var codecPowerOnAction = new Action<bool>(b => { if (!b) codec.StandbyDeactivate(); });
var codecPowerOffAction = new Action<bool>(b => { if (!b) codec.StandbyActivate(); });
// Map FusionRoom Attributes:
// Codec volume
var codecVolume = FusionRoom.CreateOffsetUshortSig(50, "Volume - Fader01", eSigIoMask.InputOutputSig);
codecVolume.OutputSig.UserObject = new Action<ushort>(b => (codec as IBasicVolumeWithFeedback).SetVolume(b));
(codec as IBasicVolumeWithFeedback).VolumeLevelFeedback.LinkInputSig(codecVolume.InputSig);
// In Call Status
CodecIsInCall = FusionRoom.CreateOffsetBoolSig(69, "Conf - VC 1 In Call", eSigIoMask.InputSigOnly);
codec.CallStatusChange += new EventHandler<PepperDash.Essentials.Devices.Common.Codec.CodecCallStatusItemChangeEventArgs>(codec_CallStatusChange);
// Online status
if (codec is ICommunicationMonitor)
{
var c = codec as ICommunicationMonitor;
var codecOnline = FusionRoom.CreateOffsetBoolSig(122, "Online - VC 1", eSigIoMask.InputSigOnly);
codecOnline.InputSig.BoolValue = c.CommunicationMonitor.Status == MonitorStatus.IsOk;
c.CommunicationMonitor.StatusChange += (o, a) =>
{
codecOnline.InputSig.BoolValue = a.Status == MonitorStatus.IsOk;
};
Debug.Console(0, this, "Linking '{0}' communication monitor to Fusion '{1}'", codec.Key, "Online - VC 1");
}
// Codec IP Address
bool codecHasIpInfo = false;
var codecComm = codec.Communication;
string codecIpAddress = string.Empty;
int codecIpPort = 0;
StringSigData codecIpAddressSig;
StringSigData codecIpPortSig;
if(codecComm is GenericSshClient)
{
codecIpAddress = (codecComm as GenericSshClient).Hostname;
codecIpPort = (codecComm as GenericSshClient).Port;
codecHasIpInfo = true;
}
else if (codecComm is GenericTcpIpClient)
{
codecIpAddress = (codecComm as GenericTcpIpClient).Hostname;
codecIpPort = (codecComm as GenericTcpIpClient).Port;
codecHasIpInfo = true;
}
if (codecHasIpInfo)
{
codecIpAddressSig = FusionRoom.CreateOffsetStringSig(121, "IP Address - VC", eSigIoMask.InputSigOnly);
codecIpAddressSig.InputSig.StringValue = codecIpAddress;
codecIpPortSig = FusionRoom.CreateOffsetStringSig(150, "IP Port - VC", eSigIoMask.InputSigOnly);
codecIpPortSig.InputSig.StringValue = codecIpPort.ToString();
}
var tempAsset = new FusionAsset();
var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(c => c.Key.Equals(codec.Key));
if (FusionStaticAssets.ContainsKey(deviceConfig.Uid))
{
tempAsset = FusionStaticAssets[deviceConfig.Uid];
}
else
{
// Create a new asset
tempAsset = new FusionAsset(FusionRoomGuids.GetNextAvailableAssetNumber(FusionRoom), codec.Name, "Codec", "");
FusionStaticAssets.Add(deviceConfig.Uid, tempAsset);
}
var codecAsset = FusionRoom.CreateStaticAsset(tempAsset.SlotNumber, tempAsset.Name, "Display", tempAsset.InstanceId);
codecAsset.PowerOn.OutputSig.UserObject = codecPowerOnAction;
codecAsset.PowerOff.OutputSig.UserObject = codecPowerOffAction;
codec.StandbyIsOnFeedback.LinkComplementInputSig(codecAsset.PowerOn.InputSig);
// TODO: Map relevant attributes on asset symbol
codecAsset.TrySetMakeModel(codec);
codecAsset.TryLinkAssetErrorToCommunication(codec);
}
catch (Exception e)
{
Debug.Console(1, this, "Error setting up codec in Fusion: {0}", e);
}
}
void codec_CallStatusChange(object sender, PepperDash.Essentials.Devices.Common.Codec.CodecCallStatusItemChangeEventArgs e)
{
var codec = (Room as EssentialsHuddleVtc1Room).VideoCodec;
CodecIsInCall.InputSig.BoolValue = codec.IsInCall;
}
// These methods are overridden because they access the room class which is of a different type
protected override void CreateSymbolAndBasicSigs(uint ipId)
{
Debug.Console(1, this, "Creating Fusion Room symbol with GUID: {0}", RoomGuid);
FusionRoom = new FusionRoom(ipId, Global.ControlSystem, Room.Name, RoomGuid);
FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.Use();
FusionRoom.ExtenderFusionRoomDataReservedSigs.Use();
FusionRoom.Register();
FusionRoom.FusionStateChange += FusionRoom_FusionStateChange;
FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.DeviceExtenderSigChange += FusionRoomSchedule_DeviceExtenderSigChange;
FusionRoom.ExtenderFusionRoomDataReservedSigs.DeviceExtenderSigChange += ExtenderFusionRoomDataReservedSigs_DeviceExtenderSigChange;
FusionRoom.OnlineStatusChange += FusionRoom_OnlineStatusChange;
CrestronConsole.AddNewConsoleCommand(RequestFullRoomSchedule, "FusReqRoomSchedule", "Requests schedule of the room for the next 24 hours", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(ModifyMeetingEndTimeConsoleHelper, "FusReqRoomSchMod", "Ends or extends a meeting by the specified time", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(CreateAsHocMeeting, "FusCreateMeeting", "Creates and Ad Hoc meeting for on hour or until the next meeting", ConsoleAccessLevelEnum.AccessOperator);
// Room to fusion room
Room.OnFeedback.LinkInputSig(FusionRoom.SystemPowerOn.InputSig);
// Moved to
CurrentRoomSourceNameSig = FusionRoom.CreateOffsetStringSig(84, "Display 1 - Current Source", eSigIoMask.InputSigOnly);
// Don't think we need to get current status of this as nothing should be alive yet.
(Room as EssentialsHuddleVtc1Room).CurrentSourceChange += Room_CurrentSourceInfoChange;
FusionRoom.SystemPowerOn.OutputSig.SetSigFalseAction((Room as EssentialsHuddleVtc1Room).PowerOnToDefaultOrLastSource);
FusionRoom.SystemPowerOff.OutputSig.SetSigFalseAction(() => (Room as EssentialsHuddleVtc1Room).RunRouteAction("roomOff", Room.SourceListKey));
// NO!! room.RoomIsOn.LinkComplementInputSig(FusionRoom.SystemPowerOff.InputSig);
CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler;
}
protected override void SetUpSources()
{
// Sources
var dict = ConfigReader.ConfigObject.GetSourceListForKey((Room as EssentialsHuddleVtc1Room).SourceListKey);
if (dict != null)
{
// NEW PROCESS:
// Make these lists and insert the fusion attributes by iterating these
var setTopBoxes = dict.Where(d => d.Value.SourceDevice is ISetTopBoxControls);
uint i = 1;
foreach (var kvp in setTopBoxes)
{
TryAddRouteActionSigs("Display 1 - Source TV " + i, 188 + i, kvp.Key, kvp.Value.SourceDevice);
i++;
if (i > 5) // We only have five spots
break;
}
var discPlayers = dict.Where(d => d.Value.SourceDevice is IDiscPlayerControls);
i = 1;
foreach (var kvp in discPlayers)
{
TryAddRouteActionSigs("Display 1 - Source DVD " + i, 181 + i, kvp.Key, kvp.Value.SourceDevice);
i++;
if (i > 5) // We only have five spots
break;
}
var laptops = dict.Where(d => d.Value.SourceDevice is Core.Devices.Laptop);
i = 1;
foreach (var kvp in laptops)
{
TryAddRouteActionSigs("Display 1 - Source Laptop " + i, 166 + i, kvp.Key, kvp.Value.SourceDevice);
i++;
if (i > 10) // We only have ten spots???
break;
}
foreach (var kvp in dict)
{
var usageDevice = kvp.Value.SourceDevice as IUsageTracking;
if (usageDevice != null)
{
usageDevice.UsageTracker = new UsageTracking(usageDevice as Device);
usageDevice.UsageTracker.UsageIsTracked = true;
usageDevice.UsageTracker.DeviceUsageEnded += new EventHandler<DeviceUsageEventArgs>(UsageTracker_DeviceUsageEnded);
}
}
}
else
{
Debug.Console(1, this, "WARNING: Config source list '{0}' not found for room '{1}'",
(Room as EssentialsHuddleVtc1Room).SourceListKey, Room.Key);
}
}
protected override void SetUpDisplay()
{
try
{
//Setup Display Usage Monitoring
var displays = DeviceManager.AllDevices.Where(d => d is DisplayBase);
// Consider updating this in multiple display systems
foreach (DisplayBase display in displays)
{
display.UsageTracker = new UsageTracking(display);
display.UsageTracker.UsageIsTracked = true;
display.UsageTracker.DeviceUsageEnded += new EventHandler<DeviceUsageEventArgs>(UsageTracker_DeviceUsageEnded);
}
var defaultDisplay = (Room as EssentialsHuddleVtc1Room).DefaultDisplay as DisplayBase;
if (defaultDisplay == null)
{
Debug.Console(1, this, "Cannot link null display to Fusion because default display is null");
return;
}
var dispPowerOnAction = new Action<bool>(b => { if (!b) defaultDisplay.PowerOn(); });
var dispPowerOffAction = new Action<bool>(b => { if (!b) defaultDisplay.PowerOff(); });
// Display to fusion room sigs
FusionRoom.DisplayPowerOn.OutputSig.UserObject = dispPowerOnAction;
FusionRoom.DisplayPowerOff.OutputSig.UserObject = dispPowerOffAction;
defaultDisplay.PowerIsOnFeedback.LinkInputSig(FusionRoom.DisplayPowerOn.InputSig);
if (defaultDisplay is IDisplayUsage)
(defaultDisplay as IDisplayUsage).LampHours.LinkInputSig(FusionRoom.DisplayUsage.InputSig);
MapDisplayToRoomJoins(1, 158, defaultDisplay);
var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(defaultDisplay.Key));
//Check for existing asset in GUIDs collection
var tempAsset = new FusionAsset();
if (FusionStaticAssets.ContainsKey(deviceConfig.Uid))
{
tempAsset = FusionStaticAssets[deviceConfig.Uid];
}
else
{
// Create a new asset
tempAsset = new FusionAsset(FusionRoomGuids.GetNextAvailableAssetNumber(FusionRoom), defaultDisplay.Name, "Display", "");
FusionStaticAssets.Add(deviceConfig.Uid, tempAsset);
}
var dispAsset = FusionRoom.CreateStaticAsset(tempAsset.SlotNumber, tempAsset.Name, "Display", tempAsset.InstanceId);
dispAsset.PowerOn.OutputSig.UserObject = dispPowerOnAction;
dispAsset.PowerOff.OutputSig.UserObject = dispPowerOffAction;
defaultDisplay.PowerIsOnFeedback.LinkInputSig(dispAsset.PowerOn.InputSig);
// NO!! display.PowerIsOn.LinkComplementInputSig(dispAsset.PowerOff.InputSig);
// Use extension methods
dispAsset.TrySetMakeModel(defaultDisplay);
dispAsset.TryLinkAssetErrorToCommunication(defaultDisplay);
}
catch (Exception e)
{
Debug.Console(1, this, "Error setting up display in Fusion: {0}", e);
}
}
protected override void MapDisplayToRoomJoins(int displayIndex, int joinOffset, DisplayBase display)
{
string displayName = string.Format("Display {0} - ", displayIndex);
if (display == (Room as EssentialsHuddleVtc1Room).DefaultDisplay)
{
// Power on
var defaultDisplayPowerOn = FusionRoom.CreateOffsetBoolSig((uint)joinOffset, displayName + "Power On", eSigIoMask.InputOutputSig);
defaultDisplayPowerOn.OutputSig.UserObject = new Action<bool>(b => { if (!b) display.PowerOn(); });
display.PowerIsOnFeedback.LinkInputSig(defaultDisplayPowerOn.InputSig);
// Power Off
var defaultDisplayPowerOff = FusionRoom.CreateOffsetBoolSig((uint)joinOffset + 1, displayName + "Power Off", eSigIoMask.InputOutputSig);
defaultDisplayPowerOn.OutputSig.UserObject = new Action<bool>(b => { if (!b) display.PowerOff(); }); ;
display.PowerIsOnFeedback.LinkInputSig(defaultDisplayPowerOn.InputSig);
// Current Source
var defaultDisplaySourceNone = FusionRoom.CreateOffsetBoolSig((uint)joinOffset + 8, displayName + "Source None", eSigIoMask.InputOutputSig);
defaultDisplaySourceNone.OutputSig.UserObject = new Action<bool>(b => { if (!b) (Room as EssentialsHuddleVtc1Room).RunRouteAction("roomOff", Room.SourceListKey); }); ;
}
}
}
namespace PepperDash.Essentials.Fusion
{
public class EssentialsHuddleVtc1FusionController : EssentialsHuddleSpaceFusionSystemControllerBase
{
BooleanSigData CodecIsInCall;
public EssentialsHuddleVtc1FusionController(EssentialsHuddleVtc1Room room, uint ipId)
: base(room, ipId)
{
}
/// <summary>
/// Called in base class constructor before RVI and GUID files are built
/// </summary>
protected override void ExecuteCustomSteps()
{
SetUpCodec();
}
/// <summary>
/// Creates a static asset for the codec and maps the joins to the main room symbol
/// </summary>
void SetUpCodec()
{
try
{
var codec = (Room as EssentialsHuddleVtc1Room).VideoCodec;
if (codec == null)
{
Debug.Console(1, this, "Cannot link codec to Fusion because codec is null");
return;
}
codec.UsageTracker = new UsageTracking(codec);
codec.UsageTracker.UsageIsTracked = true;
codec.UsageTracker.DeviceUsageEnded += UsageTracker_DeviceUsageEnded;
var codecPowerOnAction = new Action<bool>(b => { if (!b) codec.StandbyDeactivate(); });
var codecPowerOffAction = new Action<bool>(b => { if (!b) codec.StandbyActivate(); });
// Map FusionRoom Attributes:
// Codec volume
var codecVolume = FusionRoom.CreateOffsetUshortSig(50, "Volume - Fader01", eSigIoMask.InputOutputSig);
codecVolume.OutputSig.UserObject = new Action<ushort>(b => (codec as IBasicVolumeWithFeedback).SetVolume(b));
(codec as IBasicVolumeWithFeedback).VolumeLevelFeedback.LinkInputSig(codecVolume.InputSig);
// In Call Status
CodecIsInCall = FusionRoom.CreateOffsetBoolSig(69, "Conf - VC 1 In Call", eSigIoMask.InputSigOnly);
codec.CallStatusChange += new EventHandler<PepperDash.Essentials.Devices.Common.Codec.CodecCallStatusItemChangeEventArgs>(codec_CallStatusChange);
// Online status
if (codec is ICommunicationMonitor)
{
var c = codec as ICommunicationMonitor;
var codecOnline = FusionRoom.CreateOffsetBoolSig(122, "Online - VC 1", eSigIoMask.InputSigOnly);
codecOnline.InputSig.BoolValue = c.CommunicationMonitor.Status == MonitorStatus.IsOk;
c.CommunicationMonitor.StatusChange += (o, a) =>
{
codecOnline.InputSig.BoolValue = a.Status == MonitorStatus.IsOk;
};
Debug.Console(0, this, "Linking '{0}' communication monitor to Fusion '{1}'", codec.Key, "Online - VC 1");
}
// Codec IP Address
bool codecHasIpInfo = false;
var codecComm = codec.Communication;
string codecIpAddress = string.Empty;
int codecIpPort = 0;
StringSigData codecIpAddressSig;
StringSigData codecIpPortSig;
if(codecComm is GenericSshClient)
{
codecIpAddress = (codecComm as GenericSshClient).Hostname;
codecIpPort = (codecComm as GenericSshClient).Port;
codecHasIpInfo = true;
}
else if (codecComm is GenericTcpIpClient)
{
codecIpAddress = (codecComm as GenericTcpIpClient).Hostname;
codecIpPort = (codecComm as GenericTcpIpClient).Port;
codecHasIpInfo = true;
}
if (codecHasIpInfo)
{
codecIpAddressSig = FusionRoom.CreateOffsetStringSig(121, "IP Address - VC", eSigIoMask.InputSigOnly);
codecIpAddressSig.InputSig.StringValue = codecIpAddress;
codecIpPortSig = FusionRoom.CreateOffsetStringSig(150, "IP Port - VC", eSigIoMask.InputSigOnly);
codecIpPortSig.InputSig.StringValue = codecIpPort.ToString();
}
var tempAsset = new FusionAsset();
var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(c => c.Key.Equals(codec.Key));
if (FusionStaticAssets.ContainsKey(deviceConfig.Uid))
{
tempAsset = FusionStaticAssets[deviceConfig.Uid];
}
else
{
// Create a new asset
tempAsset = new FusionAsset(FusionRoomGuids.GetNextAvailableAssetNumber(FusionRoom), codec.Name, "Codec", "");
FusionStaticAssets.Add(deviceConfig.Uid, tempAsset);
}
var codecAsset = FusionRoom.CreateStaticAsset(tempAsset.SlotNumber, tempAsset.Name, "Display", tempAsset.InstanceId);
codecAsset.PowerOn.OutputSig.UserObject = codecPowerOnAction;
codecAsset.PowerOff.OutputSig.UserObject = codecPowerOffAction;
codec.StandbyIsOnFeedback.LinkComplementInputSig(codecAsset.PowerOn.InputSig);
// TODO: Map relevant attributes on asset symbol
codecAsset.TrySetMakeModel(codec);
codecAsset.TryLinkAssetErrorToCommunication(codec);
}
catch (Exception e)
{
Debug.Console(1, this, "Error setting up codec in Fusion: {0}", e);
}
}
void codec_CallStatusChange(object sender, PepperDash.Essentials.Devices.Common.Codec.CodecCallStatusItemChangeEventArgs e)
{
var codec = (Room as EssentialsHuddleVtc1Room).VideoCodec;
CodecIsInCall.InputSig.BoolValue = codec.IsInCall;
}
// These methods are overridden because they access the room class which is of a different type
protected override void CreateSymbolAndBasicSigs(uint ipId)
{
Debug.Console(1, this, "Creating Fusion Room symbol with GUID: {0}", RoomGuid);
FusionRoom = new FusionRoom(ipId, Global.ControlSystem, Room.Name, RoomGuid);
FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.Use();
FusionRoom.ExtenderFusionRoomDataReservedSigs.Use();
FusionRoom.Register();
FusionRoom.FusionStateChange += FusionRoom_FusionStateChange;
FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.DeviceExtenderSigChange += FusionRoomSchedule_DeviceExtenderSigChange;
FusionRoom.ExtenderFusionRoomDataReservedSigs.DeviceExtenderSigChange += ExtenderFusionRoomDataReservedSigs_DeviceExtenderSigChange;
FusionRoom.OnlineStatusChange += FusionRoom_OnlineStatusChange;
CrestronConsole.AddNewConsoleCommand(RequestFullRoomSchedule, "FusReqRoomSchedule", "Requests schedule of the room for the next 24 hours", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(ModifyMeetingEndTimeConsoleHelper, "FusReqRoomSchMod", "Ends or extends a meeting by the specified time", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(CreateAsHocMeeting, "FusCreateMeeting", "Creates and Ad Hoc meeting for on hour or until the next meeting", ConsoleAccessLevelEnum.AccessOperator);
// Room to fusion room
Room.OnFeedback.LinkInputSig(FusionRoom.SystemPowerOn.InputSig);
// Moved to
CurrentRoomSourceNameSig = FusionRoom.CreateOffsetStringSig(84, "Display 1 - Current Source", eSigIoMask.InputSigOnly);
// Don't think we need to get current status of this as nothing should be alive yet.
(Room as EssentialsHuddleVtc1Room).CurrentSourceChange += Room_CurrentSourceInfoChange;
FusionRoom.SystemPowerOn.OutputSig.SetSigFalseAction((Room as EssentialsHuddleVtc1Room).PowerOnToDefaultOrLastSource);
FusionRoom.SystemPowerOff.OutputSig.SetSigFalseAction(() => (Room as EssentialsHuddleVtc1Room).RunRouteAction("roomOff", Room.SourceListKey));
// NO!! room.RoomIsOn.LinkComplementInputSig(FusionRoom.SystemPowerOff.InputSig);
CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler;
}
protected override void SetUpSources()
{
// Sources
var dict = ConfigReader.ConfigObject.GetSourceListForKey((Room as EssentialsHuddleVtc1Room).SourceListKey);
if (dict != null)
{
// NEW PROCESS:
// Make these lists and insert the fusion attributes by iterating these
var setTopBoxes = dict.Where(d => d.Value.SourceDevice is ISetTopBoxControls);
uint i = 1;
foreach (var kvp in setTopBoxes)
{
TryAddRouteActionSigs("Display 1 - Source TV " + i, 188 + i, kvp.Key, kvp.Value.SourceDevice);
i++;
if (i > 5) // We only have five spots
break;
}
var discPlayers = dict.Where(d => d.Value.SourceDevice is IDiscPlayerControls);
i = 1;
foreach (var kvp in discPlayers)
{
TryAddRouteActionSigs("Display 1 - Source DVD " + i, 181 + i, kvp.Key, kvp.Value.SourceDevice);
i++;
if (i > 5) // We only have five spots
break;
}
var laptops = dict.Where(d => d.Value.SourceDevice is Core.Devices.Laptop);
i = 1;
foreach (var kvp in laptops)
{
TryAddRouteActionSigs("Display 1 - Source Laptop " + i, 166 + i, kvp.Key, kvp.Value.SourceDevice);
i++;
if (i > 10) // We only have ten spots???
break;
}
foreach (var kvp in dict)
{
var usageDevice = kvp.Value.SourceDevice as IUsageTracking;
if (usageDevice != null)
{
usageDevice.UsageTracker = new UsageTracking(usageDevice as Device);
usageDevice.UsageTracker.UsageIsTracked = true;
usageDevice.UsageTracker.DeviceUsageEnded += new EventHandler<DeviceUsageEventArgs>(UsageTracker_DeviceUsageEnded);
}
}
}
else
{
Debug.Console(1, this, "WARNING: Config source list '{0}' not found for room '{1}'",
(Room as EssentialsHuddleVtc1Room).SourceListKey, Room.Key);
}
}
protected override void SetUpDisplay()
{
try
{
//Setup Display Usage Monitoring
var displays = DeviceManager.AllDevices.Where(d => d is DisplayBase);
// Consider updating this in multiple display systems
foreach (DisplayBase display in displays)
{
display.UsageTracker = new UsageTracking(display);
display.UsageTracker.UsageIsTracked = true;
display.UsageTracker.DeviceUsageEnded += new EventHandler<DeviceUsageEventArgs>(UsageTracker_DeviceUsageEnded);
}
var defaultDisplay = (Room as EssentialsHuddleVtc1Room).DefaultDisplay as DisplayBase;
if (defaultDisplay == null)
{
Debug.Console(1, this, "Cannot link null display to Fusion because default display is null");
return;
}
var dispPowerOnAction = new Action<bool>(b => { if (!b) defaultDisplay.PowerOn(); });
var dispPowerOffAction = new Action<bool>(b => { if (!b) defaultDisplay.PowerOff(); });
// Display to fusion room sigs
FusionRoom.DisplayPowerOn.OutputSig.UserObject = dispPowerOnAction;
FusionRoom.DisplayPowerOff.OutputSig.UserObject = dispPowerOffAction;
defaultDisplay.PowerIsOnFeedback.LinkInputSig(FusionRoom.DisplayPowerOn.InputSig);
if (defaultDisplay is IDisplayUsage)
(defaultDisplay as IDisplayUsage).LampHours.LinkInputSig(FusionRoom.DisplayUsage.InputSig);
MapDisplayToRoomJoins(1, 158, defaultDisplay);
var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(defaultDisplay.Key));
//Check for existing asset in GUIDs collection
var tempAsset = new FusionAsset();
if (FusionStaticAssets.ContainsKey(deviceConfig.Uid))
{
tempAsset = FusionStaticAssets[deviceConfig.Uid];
}
else
{
// Create a new asset
tempAsset = new FusionAsset(FusionRoomGuids.GetNextAvailableAssetNumber(FusionRoom), defaultDisplay.Name, "Display", "");
FusionStaticAssets.Add(deviceConfig.Uid, tempAsset);
}
var dispAsset = FusionRoom.CreateStaticAsset(tempAsset.SlotNumber, tempAsset.Name, "Display", tempAsset.InstanceId);
dispAsset.PowerOn.OutputSig.UserObject = dispPowerOnAction;
dispAsset.PowerOff.OutputSig.UserObject = dispPowerOffAction;
defaultDisplay.PowerIsOnFeedback.LinkInputSig(dispAsset.PowerOn.InputSig);
// NO!! display.PowerIsOn.LinkComplementInputSig(dispAsset.PowerOff.InputSig);
// Use extension methods
dispAsset.TrySetMakeModel(defaultDisplay);
dispAsset.TryLinkAssetErrorToCommunication(defaultDisplay);
}
catch (Exception e)
{
Debug.Console(1, this, "Error setting up display in Fusion: {0}", e);
}
}
protected override void MapDisplayToRoomJoins(int displayIndex, int joinOffset, DisplayBase display)
{
string displayName = string.Format("Display {0} - ", displayIndex);
if (display == (Room as EssentialsHuddleVtc1Room).DefaultDisplay)
{
// Power on
var defaultDisplayPowerOn = FusionRoom.CreateOffsetBoolSig((uint)joinOffset, displayName + "Power On", eSigIoMask.InputOutputSig);
defaultDisplayPowerOn.OutputSig.UserObject = new Action<bool>(b => { if (!b) display.PowerOn(); });
display.PowerIsOnFeedback.LinkInputSig(defaultDisplayPowerOn.InputSig);
// Power Off
var defaultDisplayPowerOff = FusionRoom.CreateOffsetBoolSig((uint)joinOffset + 1, displayName + "Power Off", eSigIoMask.InputOutputSig);
defaultDisplayPowerOn.OutputSig.UserObject = new Action<bool>(b => { if (!b) display.PowerOff(); }); ;
display.PowerIsOnFeedback.LinkInputSig(defaultDisplayPowerOn.InputSig);
// Current Source
var defaultDisplaySourceNone = FusionRoom.CreateOffsetBoolSig((uint)joinOffset + 8, displayName + "Source None", eSigIoMask.InputOutputSig);
defaultDisplaySourceNone.OutputSig.UserObject = new Action<bool>(b => { if (!b) (Room as EssentialsHuddleVtc1Room).RunRouteAction("roomOff", Room.SourceListKey); }); ;
}
}
}
}

View File

@@ -71,9 +71,9 @@
<HintPath>..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.UI.dll</HintPath>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="PepperDash_Core, Version=1.0.39.33033, Culture=neutral, processorArchitecture=MSIL">
<Reference Include="PepperDash_Core, Version=1.0.26.30384, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\PepperDashCore\lib\net35\PepperDash_Core.dll</HintPath>
<HintPath>..\essentials-framework\pepperdashcore-builds\PepperDash_Core.dll</HintPath>
</Reference>
<Reference Include="PepperDash_Essentials_DM, Version=1.0.0.19343, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
@@ -155,6 +155,7 @@
<Compile Include="UIDrivers\Environment Drivers\EssentialsShadeDriver.cs" />
<Compile Include="UIDrivers\Essentials\EssentialsHeaderDriver.cs" />
<Compile Include="UIDrivers\JoinedSigInterlock.cs" />
<Compile Include="UIDrivers\ScreenSaverController.cs" />
<Compile Include="UIDrivers\SigInterlock.cs" />
<Compile Include="UIDrivers\EssentialsHuddleVTC\EssentialsHuddlePresentationUiDriver.cs" />
<Compile Include="UIDrivers\EssentialsHuddle\EssentialsHuddleTechPageDriver.cs" />

View File

@@ -156,7 +156,10 @@ namespace PepperDash.Essentials.Room.Config
public EssentialsEnvironmentPropertiesConfig Environment { get; set; }
[JsonProperty("logo")]
public EssentialsLogoPropertiesConfig Logo { get; set; }
public EssentialsLogoPropertiesConfig LogoLight { get; set; }
[JsonProperty("logoDark")]
public EssentialsLogoPropertiesConfig LogoDark { get; set; }
[JsonProperty("microphonePrivacy")]
public EssentialsRoomMicrophonePrivacyConfig MicrophonePrivacy { get; set; }
@@ -181,6 +184,12 @@ namespace PepperDash.Essentials.Room.Config
[JsonProperty("zeroVolumeWhenSwtichingVolumeDevices")]
public bool ZeroVolumeWhenSwtichingVolumeDevices { get; set; }
public EssentialsRoomPropertiesConfig()
{
LogoLight = new EssentialsLogoPropertiesConfig();
LogoDark = new EssentialsLogoPropertiesConfig();
}
}
public class EssentialsAvRoomPropertiesConfig : EssentialsRoomPropertiesConfig
@@ -280,7 +289,7 @@ namespace PepperDash.Essentials.Room.Config
/// <summary>
/// Gets either the custom URL, a local-to-processor URL, or null if it's a default logo
/// </summary>
public string GetUrl()
public string GetLogoUrlLight()
{
if (Type == "url")
return Url;
@@ -289,6 +298,16 @@ namespace PepperDash.Essentials.Room.Config
CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0));
return null;
}
public string GetLogoUrlDark()
{
if (Type == "url")
return Url;
if (Type == "system")
return string.Format("http://{0}:8080/logo-dark.png",
CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0));
return null;
}
}
/// <summary>

View File

@@ -327,7 +327,8 @@ namespace PepperDash.Essentials
this.SetRoomOccupancy(DeviceManager.GetDeviceForKey(PropertiesConfig.Occupancy.DeviceKey) as
IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimeoutMinutes);
this.LogoUrl = PropertiesConfig.Logo.GetUrl();
this.LogoUrlLightBkgnd = PropertiesConfig.LogoLight.GetLogoUrlLight();
this.LogoUrlDarkBkgnd = PropertiesConfig.LogoDark.GetLogoUrlDark();
this.SourceListKey = PropertiesConfig.SourceListKey;
this.DefaultSourceItem = PropertiesConfig.DefaultSourceItem;
this.DefaultVolume = (ushort)(PropertiesConfig.Volumes.Master.Level * 65535 / 100);

View File

@@ -250,7 +250,8 @@ namespace PepperDash.Essentials
this.SetRoomOccupancy(DeviceManager.GetDeviceForKey(PropertiesConfig.Occupancy.DeviceKey) as
IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimeoutMinutes);
this.LogoUrl = PropertiesConfig.Logo.GetUrl();
this.LogoUrlLightBkgnd = PropertiesConfig.LogoLight.GetLogoUrlLight();
this.LogoUrlDarkBkgnd = PropertiesConfig.LogoDark.GetLogoUrlDark();
this.SourceListKey = PropertiesConfig.SourceListKey;
this.DefaultSourceItem = PropertiesConfig.DefaultSourceItem;
this.DefaultVolume = (ushort)(PropertiesConfig.Volumes.Master.Level * 65535 / 100);

View File

@@ -50,6 +50,24 @@ namespace PepperDash.Essentials
//************************
public override string SourceListKey
{
get
{
return _SourceListKey;
}
set
{
_SourceListKey = value;
if(VideoCodec is IHasExternalSourceSwitching)
{
if((VideoCodec as IHasExternalSourceSwitching).ExternalSourceListEnabled)
{
SetCodecExternalSources();
}
}
}
}
protected override Func<bool> OnFeedbackFunc
{
@@ -206,9 +224,14 @@ namespace PepperDash.Essentials
VideoCodec = DeviceManager.GetDeviceForKey(PropertiesConfig.VideoCodecKey) as
PepperDash.Essentials.Devices.Common.VideoCodec.VideoCodecBase;
if (VideoCodec == null)
throw new ArgumentNullException("codec cannot be null");
//todo Do the thing here JTA
AudioCodec = DeviceManager.GetDeviceForKey(PropertiesConfig.AudioCodecKey) as
PepperDash.Essentials.Devices.Common.AudioCodec.AudioCodecBase;
if (AudioCodec == null)
@@ -298,6 +321,7 @@ namespace PepperDash.Essentials
VideoCodec.CallStatusChange += (o, a) => this.InCallFeedback.FireUpdate();
VideoCodec.IsReadyChange += (o, a) => this.SetCodecExternalSources();
if (AudioCodec != null)
AudioCodec.CallStatusChange += (o, a) => this.InCallFeedback.FireUpdate();
@@ -340,15 +364,16 @@ namespace PepperDash.Essentials
IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimeoutMinutes);
}
this.LogoUrl = PropertiesConfig.Logo.GetUrl();
this.LogoUrlLightBkgnd = PropertiesConfig.LogoLight.GetLogoUrlLight();
this.LogoUrlDarkBkgnd = PropertiesConfig.LogoDark.GetLogoUrlDark();
this.SourceListKey = PropertiesConfig.SourceListKey;
this.DefaultSourceItem = PropertiesConfig.DefaultSourceItem;
this.DefaultVolume = (ushort)(PropertiesConfig.Volumes.Master.Level * 65535 / 100);
return base.CustomActivate();
}
/// <summary>
///
/// </summary>
@@ -670,6 +695,35 @@ namespace PepperDash.Essentials
(room as EssentialsHuddleSpaceRoom).RunRouteAction("roomOff");
}
/// <summary>
/// Setup the external sources for the Cisco Touch 10 devices that support IHasExternalSourceSwitch
/// </summary>
private void SetCodecExternalSources()
{
string codecTieLine = "";
codecTieLine = ConfigReader.ConfigObject.TieLines.SingleOrDefault(x => x.DestinationKey == VideoCodec.Key).DestinationPort;
(VideoCodec as IHasExternalSourceSwitching).ClearExternalSources();
(VideoCodec as IHasExternalSourceSwitching).RunRouteAction = RunRouteAction;
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 != "codecOsd" && kvp.Key != "roomOff")
{
(VideoCodec as IHasExternalSourceSwitching).AddExternalSource(codecTieLine, kvp.Key, srcConfig.PreferredName, PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.eExternalSourceType.desktop);
(VideoCodec as IHasExternalSourceSwitching).SetExternalSourceState(kvp.Key, PepperDash.Essentials.Devices.Common.VideoCodec.Cisco.eExternalSourceMode.Ready);
}
}
}
#region IPrivacy Members

View File

@@ -224,6 +224,8 @@ namespace PepperDash.Essentials
var room = DeviceManager.GetDeviceForKey(props.DefaultRoomKey);
if (room is EssentialsHuddleSpaceRoom)
{
// Screen Saver Driver
mainDriver.ScreenSaverController = new ScreenSaverController(mainDriver, props);
// Header Driver
Debug.Console(0, panelController, "Adding header driver");
@@ -272,6 +274,9 @@ namespace PepperDash.Essentials
{
Debug.Console(0, panelController, "Adding huddle space VTC AV driver");
// Screen Saver Driver
mainDriver.ScreenSaverController = new ScreenSaverController(mainDriver, props);
// Header Driver
mainDriver.HeaderDriver = new EssentialsHeaderDriver(mainDriver, props);

File diff suppressed because it is too large Load Diff

View File

@@ -146,6 +146,10 @@ namespace PepperDash.Essentials
/// </summary>
public const uint RoomPhoneText = 3904;
/// <summary>
/// 3905 - Video address/number for room header
/// </summary>
public const uint RoomVideoAddressText = 3905;
/// <summary>
/// 3906 - The separator for verbose-header text on addresses
/// </summary>
public const uint RoomAddressPipeText = 3906;
@@ -154,6 +158,14 @@ namespace PepperDash.Essentials
/// </summary>
public const uint RoomUserCode = 3907;
/// <summary>
/// 3908 - The url for the mobile control server
/// </summary>
public const uint RoomMcUrl = 3908;
/// <summary>
/// 3909 - The url for the mobile control QR Code image
/// </summary>
public const uint RoomMcQrCodeUrl = 3909;
/// <summary>
/// 3911
/// </summary>
public const uint PowerOffMessage = 3911;
@@ -189,12 +201,19 @@ namespace PepperDash.Essentials
/// <summary>
/// 3923
/// </summary>
public const uint LogoUrl = 3923;
public const uint LogoUrlLightBkgnd = 3923;
/// <summary>
/// 3924 - the text on the "call help desk" button
/// </summary>
public const uint HelpPageCallButtonText = 3924;
/// <summary>
/// 3925
/// </summary>
public const uint LogoUrlDarkBkgnd = 3925;
/// <summary>
/// 3951
/// </summary>

View File

@@ -1,4 +1,5 @@
using System;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.DeviceSupport;
using Crestron.SimplSharpPro.UI;
using PepperDash.Essentials.Core;
@@ -11,6 +12,8 @@ namespace PepperDash.Essentials
/// </summary>
public class EssentialsPanelMainInterfaceDriver : PanelDriverBase
{
CTimer InactivityTimer;
/// <summary>
/// Assign the appropriate A/V driver.
/// Want to keep the AvDriver alive, because it may hold states
@@ -23,6 +26,8 @@ namespace PepperDash.Essentials
public PanelDriverBase CurrentChildDriver { get; private set; }
public ScreenSaverController ScreenSaverController { get; set; }
CrestronTouchpanelPropertiesConfig Config;
/// <summary>
@@ -35,18 +40,59 @@ namespace PepperDash.Essentials
: base(trilist)
{
Config = config;
var tsx52or60 = trilist as Tswx52ButtonVoiceControl;
if (tsx52or60 != null)
{
tsx52or60.ExtenderTouchDetectionReservedSigs.DeviceExtenderSigChange += ExtenderTouchDetectionReservedSigs_DeviceExtenderSigChange;
}
else
{
var tswx70 = trilist as TswX70Base;
if (tswx70 != null)
{
tswx70.ExtenderTouchDetectionReservedSigs.DeviceExtenderSigChange += ExtenderTouchDetectionReservedSigs_DeviceExtenderSigChange;
}
}
}
void ExtenderTouchDetectionReservedSigs_DeviceExtenderSigChange(Crestron.SimplSharpPro.DeviceExtender currentDeviceExtender, Crestron.SimplSharpPro.SigEventArgs args)
{
var timeoutMs = Config.ScreenSaverTimeoutMin * 60 * 1000;
if (args.Sig.BoolValue)
{
if (InactivityTimer != null)
{
InactivityTimer.Reset(timeoutMs);
}
else
{
InactivityTimer = new CTimer((o) => InactivityTimerExpired(), timeoutMs);
}
}
}
void InactivityTimerExpired()
{
InactivityTimer.Stop();
InactivityTimer.Dispose();
InactivityTimer = null;
ScreenSaverController.Show();
}
public override void Show()
{
CurrentChildDriver = null;
ShowSubDriver(AvDriver as PanelDriverBase);
base.Show();
base.Show();
}
public override void Hide()
{
TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = false;
TriList.BooleanInput[AvDriver.StartPageVisibleJoin].BoolValue = false;
base.Hide();
}

View File

@@ -267,7 +267,7 @@
// HideAndClearCurrentDisplayModeSigsInUse();
// tl[UIBoolJoin.TopBarHabaneroVisible].BoolValue = false;
// tl[UIBoolJoin.ActivityFooterVisible].BoolValue = false;
// tl[UIBoolJoin.StartPageVisible].BoolValue = false;
// tl[StartPageVisibleJoin].BoolValue = false;
// tl[UIBoolJoin.TapToBeginVisible].BoolValue = false;
// tl[UIBoolJoin.ToggleSharingModeVisible].BoolValue = false;
// tl[UIBoolJoin.SourceStagingBarVisible].BoolValue = false;
@@ -335,7 +335,7 @@
// }
// else
// {
// TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = true;
// TriList.BooleanInput[StartPageVisibleJoin].BoolValue = true;
// TriList.BooleanInput[UIBoolJoin.TapToBeginVisible].BoolValue = true;
// TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false;
// }
@@ -525,7 +525,7 @@
// if (!_CurrentRoom.OnFeedback.BoolValue)
// {
// ShareButtonSig.BoolValue = true;
// TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = false;
// TriList.BooleanInput[StartPageVisibleJoin].BoolValue = false;
// ShowCurrentSharingMode();
// }
// }
@@ -953,13 +953,13 @@
// if (value)
// {
// SetupActivityFooterWhenRoomOn();
// TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = false;
// TriList.BooleanInput[StartPageVisibleJoin].BoolValue = false;
// }
// else
// {
// HideCurrentSharingMode();
// SetupActivityFooterWhenRoomOff();
// TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = true;
// TriList.BooleanInput[StartPageVisibleJoin].BoolValue = true;
// if (LastSelectedSourceSig != null)
// {
// LastSelectedSourceSig.BoolValue = false;

View File

@@ -24,6 +24,9 @@ namespace PepperDash.Essentials
PresentationMode, AudioSetup
}
public uint StartPageVisibleJoin { get; private set; }
/// <summary>
/// Whether volume ramping from this panel will show the volume
/// gauge popup.
@@ -209,6 +212,7 @@ namespace PepperDash.Essentials
"Tap Share to begin";
}
/// <summary>
///
/// </summary>
@@ -225,20 +229,34 @@ namespace PepperDash.Essentials
if (Config.HeaderStyle.ToLower() == CrestronTouchpanelPropertiesConfig.Habanero)
{
TriList.SetSigFalseAction(UIBoolJoin.HeaderRoomButtonPress, () =>
PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.RoomHeaderPageVisible));
{
if (CurrentRoom.IsMobileControlEnabled)
{
Debug.Console(1, "Showing Mobile Control Header Info");
PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.RoomHeaderInfoMCPageVisible);
}
else
{
Debug.Console(1, "Showing Non Mobile Control Header Info");
PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.RoomHeaderInfoPageVisible);
}
});
}
else if (Config.HeaderStyle.ToLower() == CrestronTouchpanelPropertiesConfig.Verbose)
{
// room name on join 1, concat phone and sip on join 2, no button method
//var addr = roomConf.Addresses;
//if (addr == null) // protect from missing values by using default empties
// addr = new EssentialsRoomAddressPropertiesConfig();
//// empty string when either missing, pipe when both showing
//TriList.SetString(UIStringJoin.RoomAddressPipeText,
// (string.IsNullOrEmpty(addr.PhoneNumber.Trim())
// || string.IsNullOrEmpty(addr.SipAddress.Trim())) ? "" : " | ");
//TriList.SetString(UIStringJoin.RoomPhoneText, addr.PhoneNumber);
//TriList.SetString(UIStringJoin.RoomSipText, addr.SipAddress);
TriList.SetSigFalseAction(UIBoolJoin.HeaderRoomButtonPress, () =>
{
if (CurrentRoom.IsMobileControlEnabled)
{
Debug.Console(1, "Showing Mobile Control Header Info");
PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.RoomHeaderInfoMCPageVisible);
}
else
{
Debug.Console(1, "Showing Non Mobile Control Header Info");
PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.RoomHeaderInfoPageVisible);
}
});
}
TriList.SetBool(UIBoolJoin.DateAndTimeVisible, Config.ShowDate && Config.ShowTime);
@@ -256,7 +274,7 @@ namespace PepperDash.Essentials
}
else
{
TriList.SetBool(UIBoolJoin.StartPageVisible, true);
TriList.SetBool(StartPageVisibleJoin, true);
TriList.SetBool(UIBoolJoin.TapToBeginVisible, true);
SetupActivityFooterWhenRoomOff();
}
@@ -321,7 +339,7 @@ namespace PepperDash.Essentials
/// </summary>
void ShowLogo()
{
if (CurrentRoom.LogoUrl == null)
if (CurrentRoom.LogoUrlLightBkgnd == null)
{
TriList.SetBool(UIBoolJoin.LogoDefaultVisible, true);
TriList.SetBool(UIBoolJoin.LogoUrlVisible, false);
@@ -330,7 +348,8 @@ namespace PepperDash.Essentials
{
TriList.SetBool(UIBoolJoin.LogoDefaultVisible, false);
TriList.SetBool(UIBoolJoin.LogoUrlVisible, true);
TriList.SetString(UIStringJoin.LogoUrl, _CurrentRoom.LogoUrl);
TriList.SetString(UIStringJoin.LogoUrlLightBkgnd, _CurrentRoom.LogoUrlLightBkgnd);
TriList.SetString(UIStringJoin.LogoUrlDarkBkgnd, _CurrentRoom.LogoUrlDarkBkgnd);
}
}
@@ -351,7 +370,7 @@ namespace PepperDash.Essentials
HideAndClearCurrentDisplayModeSigsInUse();
TriList.BooleanInput[UIBoolJoin.TopBarHabaneroDynamicVisible].BoolValue = false;
TriList.BooleanInput[UIBoolJoin.ActivityFooterVisible].BoolValue = false;
TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = false;
TriList.BooleanInput[StartPageVisibleJoin].BoolValue = false;
TriList.BooleanInput[UIBoolJoin.TapToBeginVisible].BoolValue = false;
TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false;
//TriList.BooleanInput[UIBoolJoin.StagingPageVisible].BoolValue = false;
@@ -416,7 +435,7 @@ namespace PepperDash.Essentials
}
else
{
TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = true;
TriList.BooleanInput[StartPageVisibleJoin].BoolValue = true;
TriList.BooleanInput[UIBoolJoin.TapToBeginVisible].BoolValue = true;
TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false;
}
@@ -474,7 +493,7 @@ namespace PepperDash.Essentials
void ShareButtonPressed()
{
ShareButtonSig.BoolValue = true;
TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = false;
TriList.BooleanInput[StartPageVisibleJoin].BoolValue = false;
TriList.BooleanInput[UIBoolJoin.SourceStagingBarVisible].BoolValue = true;
TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = true;
// Run default source when room is off and share is pressed
@@ -778,7 +797,7 @@ namespace PepperDash.Essentials
}
// Name and logo
TriList.StringInput[UIStringJoin.CurrentRoomName].StringValue = _CurrentRoom.Name;
if (_CurrentRoom.LogoUrl == null)
if (_CurrentRoom.LogoUrlLightBkgnd == null)
{
TriList.BooleanInput[UIBoolJoin.LogoDefaultVisible].BoolValue = true;
TriList.BooleanInput[UIBoolJoin.LogoUrlVisible].BoolValue = false;
@@ -787,7 +806,9 @@ namespace PepperDash.Essentials
{
TriList.BooleanInput[UIBoolJoin.LogoDefaultVisible].BoolValue = false;
TriList.BooleanInput[UIBoolJoin.LogoUrlVisible].BoolValue = true;
TriList.StringInput[UIStringJoin.LogoUrl].StringValue = _CurrentRoom.LogoUrl;
TriList.StringInput[UIStringJoin.LogoUrlLightBkgnd].StringValue = _CurrentRoom.LogoUrlLightBkgnd;
TriList.StringInput[UIStringJoin.LogoUrlLightBkgnd].StringValue = _CurrentRoom.LogoUrlDarkBkgnd;
}
// Shutdown timer
@@ -820,12 +841,43 @@ namespace PepperDash.Essentials
if (_CurrentRoom == room) return;
// Disconnect current (probably never called)
if (_CurrentRoom != null)
_CurrentRoom.ConfigChanged -= room_ConfigChanged;
room.ConfigChanged -= room_ConfigChanged;
room.ConfigChanged += room_ConfigChanged;
if (room.IsMobileControlEnabled)
{
StartPageVisibleJoin = UIBoolJoin.StartMCPageVisible;
UpdateMCJoins(room);
if (_CurrentRoom != null)
_CurrentRoom.MobileControlRoomBridge.UserCodeChanged -= MobileControlRoomBridge_UserCodeChanged;
room.MobileControlRoomBridge.UserCodeChanged -= MobileControlRoomBridge_UserCodeChanged;
room.MobileControlRoomBridge.UserCodeChanged += MobileControlRoomBridge_UserCodeChanged;
}
else
{
StartPageVisibleJoin = UIBoolJoin.StartPageVisible;
}
RefreshCurrentRoom(room);
}
void MobileControlRoomBridge_UserCodeChanged(object sender, EventArgs e)
{
UpdateMCJoins(_CurrentRoom);
}
void UpdateMCJoins(EssentialsHuddleSpaceRoom room)
{
TriList.SetString(UIStringJoin.RoomMcUrl, room.MobileControlRoomBridge.McServerUrl);
TriList.SetString(UIStringJoin.RoomMcQrCodeUrl, room.MobileControlRoomBridge.QrCodeUrl);
TriList.SetString(UIStringJoin.RoomUserCode, room.MobileControlRoomBridge.UserCode);
}
/// <summary>
/// Fires when room config of current room has changed. Meant to refresh room values to propegate any updates to UI
/// </summary>
@@ -855,7 +907,7 @@ namespace PepperDash.Essentials
SetupActivityFooterWhenRoomOn();
TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false;
TriList.BooleanInput[UIBoolJoin.SourceStagingBarVisible].BoolValue = true;
TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = false;
TriList.BooleanInput[StartPageVisibleJoin].BoolValue = false;
TriList.BooleanInput[UIBoolJoin.VolumeSingleMute1Visible].BoolValue = true;
}
@@ -863,7 +915,7 @@ namespace PepperDash.Essentials
{
SetupActivityFooterWhenRoomOff();
ShowLogo();
TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = true;
TriList.BooleanInput[StartPageVisibleJoin].BoolValue = true;
TriList.BooleanInput[UIBoolJoin.VolumeSingleMute1Visible].BoolValue = false;
TriList.BooleanInput[UIBoolJoin.SourceStagingBarVisible].BoolValue = false;
}

View File

@@ -28,6 +28,8 @@ namespace PepperDash.Essentials
Presentation, AudioSetup, Call, Start
}
public uint StartPageVisibleJoin { get; private set; }
/// <summary>
/// Whether volume ramping from this panel will show the volume
/// gauge popup.
@@ -240,20 +242,34 @@ namespace PepperDash.Essentials
if (Config.HeaderStyle.ToLower() == CrestronTouchpanelPropertiesConfig.Habanero)
{
TriList.SetSigFalseAction(UIBoolJoin.HeaderRoomButtonPress, () =>
PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.RoomHeaderPageVisible));
{
if (CurrentRoom.IsMobileControlEnabled)
{
Debug.Console(1, "Showing Mobile Control Header Info");
PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.RoomHeaderInfoMCPageVisible);
}
else
{
Debug.Console(1, "Showing Non Mobile Control Header Info");
PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.RoomHeaderInfoPageVisible);
}
});
}
else if (Config.HeaderStyle.ToLower() == CrestronTouchpanelPropertiesConfig.Verbose)
{
// room name on join 1, concat phone and sip on join 2, no button method
//var addr = roomConf.Addresses;
//if (addr == null) // protect from missing values by using default empties
// addr = new EssentialsRoomAddressPropertiesConfig();
//// empty string when either missing, pipe when both showing
//TriList.SetString(UIStringJoin.RoomAddressPipeText,
// (string.IsNullOrEmpty(addr.PhoneNumber.Trim())
// || string.IsNullOrEmpty(addr.SipAddress.Trim())) ? "" : " | ");
//TriList.SetString(UIStringJoin.RoomPhoneText, addr.PhoneNumber);
//TriList.SetString(UIStringJoin.RoomSipText, addr.SipAddress);
TriList.SetSigFalseAction(UIBoolJoin.HeaderRoomButtonPress, () =>
{
if (CurrentRoom.IsMobileControlEnabled)
{
Debug.Console(1, "Showing Mobile Control Header Info");
PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.RoomHeaderInfoMCPageVisible);
}
else
{
Debug.Console(1, "Showing Non Mobile Control Header Info");
PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.RoomHeaderInfoPageVisible);
}
});
}
TriList.SetBool(UIBoolJoin.DateAndTimeVisible, Config.ShowDate && Config.ShowTime);
@@ -276,7 +292,7 @@ namespace PepperDash.Essentials
}
else
{
TriList.SetBool(UIBoolJoin.StartPageVisible, true);
TriList.SetBool(StartPageVisibleJoin, true);
TriList.SetBool(UIBoolJoin.TapToBeginVisible, true);
SetupActivityFooterWhenRoomOff();
}
@@ -332,7 +348,7 @@ namespace PepperDash.Essentials
/// </summary>
void ShowLogo()
{
if (CurrentRoom.LogoUrl == null)
if (CurrentRoom.LogoUrlLightBkgnd == null)
{
TriList.SetBool(UIBoolJoin.LogoDefaultVisible, true);
TriList.SetBool(UIBoolJoin.LogoUrlVisible, false);
@@ -341,7 +357,8 @@ namespace PepperDash.Essentials
{
TriList.SetBool(UIBoolJoin.LogoDefaultVisible, false);
TriList.SetBool(UIBoolJoin.LogoUrlVisible, true);
TriList.SetString(UIStringJoin.LogoUrl, _CurrentRoom.LogoUrl);
TriList.SetString(UIStringJoin.LogoUrlLightBkgnd, _CurrentRoom.LogoUrlLightBkgnd);
TriList.SetString(UIStringJoin.LogoUrlDarkBkgnd, _CurrentRoom.LogoUrlDarkBkgnd);
}
}
@@ -362,7 +379,7 @@ namespace PepperDash.Essentials
HideAndClearCurrentDisplayModeSigsInUse();
TriList.SetBool(UIBoolJoin.TopBarHabaneroDynamicVisible, false);
TriList.BooleanInput[UIBoolJoin.ActivityFooterVisible].BoolValue = false;
TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = false;
TriList.BooleanInput[StartPageVisibleJoin].BoolValue = false;
TriList.BooleanInput[UIBoolJoin.TapToBeginVisible].BoolValue = false;
TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false;
if (NextMeetingTimer != null)
@@ -606,7 +623,7 @@ namespace PepperDash.Essentials
return;
HideLogo();
HideNextMeetingPopup();
TriList.SetBool(UIBoolJoin.StartPageVisible, false);
TriList.SetBool(StartPageVisibleJoin, false);
TriList.SetBool(UIBoolJoin.SourceStagingBarVisible, false);
TriList.SetBool(UIBoolJoin.SelectASourceVisible, false);
if (CurrentSourcePageManager != null)
@@ -626,7 +643,7 @@ namespace PepperDash.Essentials
if (VCDriver.IsVisible)
VCDriver.Hide();
HideNextMeetingPopup();
TriList.SetBool(UIBoolJoin.StartPageVisible, false);
TriList.SetBool(StartPageVisibleJoin, false);
TriList.SetBool(UIBoolJoin.CallStagingBarVisible, false);
TriList.SetBool(UIBoolJoin.SourceStagingBarVisible, true);
// Run default source when room is off and share is pressed
@@ -957,12 +974,43 @@ namespace PepperDash.Essentials
if (_CurrentRoom == room) return;
// Disconnect current (probably never called)
if(_CurrentRoom != null)
_CurrentRoom.ConfigChanged -= room_ConfigChanged;
room.ConfigChanged -= room_ConfigChanged;
room.ConfigChanged += room_ConfigChanged;
if (room.IsMobileControlEnabled)
{
StartPageVisibleJoin = UIBoolJoin.StartMCPageVisible;
UpdateMCJoins(room);
if (_CurrentRoom != null)
_CurrentRoom.MobileControlRoomBridge.UserCodeChanged -= MobileControlRoomBridge_UserCodeChanged;
room.MobileControlRoomBridge.UserCodeChanged -= MobileControlRoomBridge_UserCodeChanged;
room.MobileControlRoomBridge.UserCodeChanged += MobileControlRoomBridge_UserCodeChanged;
}
else
{
StartPageVisibleJoin = UIBoolJoin.StartPageVisible;
}
RefreshCurrentRoom(room);
}
void MobileControlRoomBridge_UserCodeChanged(object sender, EventArgs e)
{
UpdateMCJoins(_CurrentRoom);
}
void UpdateMCJoins(EssentialsHuddleVtc1Room room)
{
TriList.SetString(UIStringJoin.RoomMcUrl, room.MobileControlRoomBridge.McServerUrl);
TriList.SetString(UIStringJoin.RoomMcQrCodeUrl, room.MobileControlRoomBridge.QrCodeUrl);
TriList.SetString(UIStringJoin.RoomUserCode, room.MobileControlRoomBridge.UserCode);
}
/// <summary>
/// Fires when room config of current room has changed. Meant to refresh room values to propegate any updates to UI
/// </summary>
@@ -999,12 +1047,15 @@ namespace PepperDash.Essentials
/// </summary>
void SetupSourceList()
{
var inCall = CurrentRoom.InCallFeedback.BoolValue;
var config = ConfigReader.ConfigObject.SourceLists;
if (config.ContainsKey(_CurrentRoom.SourceListKey))
{
var srcList = config[_CurrentRoom.SourceListKey].OrderBy(kv => kv.Value.Order);
// Setup sources list
SourceStagingSrl.Clear();
@@ -1028,6 +1079,8 @@ namespace PepperDash.Essentials
b => { if (!b) UiSelectSource(routeKey); });
SourceStagingSrl.AddItem(item); // add to the SRL
item.RegisterForSourceChange(_CurrentRoom);
Debug.Console(1, "**** KEY {0}", kvp.Key);
}
SourceStagingSrl.Count = (ushort)(i - 1);
}
@@ -1149,7 +1202,7 @@ namespace PepperDash.Essentials
var value = _CurrentRoom.OnFeedback.BoolValue;
TriList.BooleanInput[UIBoolJoin.RoomIsOn].BoolValue = value;
TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = !value;
TriList.BooleanInput[StartPageVisibleJoin].BoolValue = !value;
if (value) //ON
{
@@ -1381,6 +1434,7 @@ namespace PepperDash.Essentials
void ShowNotificationRibbon(string message, int timeout);
void HideNotificationRibbon();
void ShowTech();
uint StartPageVisibleJoin { get; }
}
/// <summary>

View File

@@ -0,0 +1,118 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials
{
/// <summary>
/// Driver responsible for controlling the screenshaver showing the client logo, MC connection information and QR Code. Moves the elements around to prevent screen burn in
/// </summary>
public class ScreenSaverController : PanelDriverBase
{
CTimer PositionTimer;
uint PositionTimeoutMs;
List<uint> PositionJoins;
int CurrentPositionIndex = 0;
public ScreenSaverController(EssentialsPanelMainInterfaceDriver parent, CrestronTouchpanelPropertiesConfig config)
: base(parent.TriList)
{
PositionTimeoutMs = config.ScreenSaverMovePositionIntervalMs;
TriList.SetSigFalseAction(UIBoolJoin.MCScreenSaverClosePress, () => this.Hide());
PositionJoins = new List<uint>()
{ UIBoolJoin.MCScreenSaverPosition1Visible, UIBoolJoin.MCScreenSaverPosition2Visible, UIBoolJoin.MCScreenSaverPosition3Visible, UIBoolJoin.MCScreenSaverPosition4Visible };
CrestronConsole.AddNewConsoleCommand((o) => Show(), "showscreensaver", "Shows Panel Screensaver", ConsoleAccessLevelEnum.AccessOperator);
}
public override void Show()
{
TriList.SetBool(UIBoolJoin.MCScreenSaverVisible, true);
CurrentPositionIndex = 0;
SetCurrentPosition();
StartPositionTimer();
base.Show();
}
public override void Hide()
{
PositionTimer.Stop();
PositionTimer.Dispose();
PositionTimer = null;
ClearAllPositions();
TriList.SetBool(UIBoolJoin.MCScreenSaverVisible, false);
base.Hide();
}
void StartPositionTimer()
{
if (PositionTimer == null)
{
PositionTimer = new CTimer((o) => PositionTimerExpired(), PositionTimeoutMs);
}
else
{
PositionTimer.Reset(PositionTimeoutMs);
}
}
void PositionTimerExpired()
{
IncrementPositionIndex();
SetCurrentPosition();
StartPositionTimer();
}
void IncrementPositionIndex()
{
if (CurrentPositionIndex < PositionJoins.Count - 1)
{
CurrentPositionIndex++;
}
else
{
CurrentPositionIndex = 0;
}
Debug.Console(1, "ScreenSaver Position Timer Expired: Setting new position: {0}", CurrentPositionIndex);
}
//
void SetCurrentPosition()
{
ClearAllPositions();
// Set based on current index
TriList.SetBool(PositionJoins[CurrentPositionIndex], true);
}
void ClearAllPositions()
{
foreach (var join in PositionJoins)
{
TriList.SetBool(join, false);
}
}
}
}

View File

@@ -192,22 +192,76 @@ namespace PepperDash.Essentials.UIDrivers.VC
/// <param name="e"></param>
void Codec_IsReady()
{
string roomNumberSipUri = "";
if (!string.IsNullOrEmpty(Codec.CodecInfo.SipUri)) // If both values are present, format the string with a pipe divider
roomNumberSipUri = string.Format("{0} | {1}", GetFormattedPhoneNumber(Codec.CodecInfo.SipPhoneNumber), Codec.CodecInfo.SipUri);
else // If only one value present, just show the phone number
roomNumberSipUri = Codec.CodecInfo.SipPhoneNumber;
if(string.IsNullOrEmpty(roomNumberSipUri))
roomNumberSipUri = string.Format("{0} | {1}", Codec.CodecInfo.E164Alias, Codec.CodecInfo.H323Id);
TriList.SetString(UIStringJoin.RoomPhoneText, roomNumberSipUri);
SetupAddresses();
if(HeaderDriver.HeaderButtonsAreSetUp)
HeaderDriver.ComputeHeaderCallStatus(Codec);
}
void SetupAddresses()
{
string roomContactNumbers = "";
string roomPhoneNumber = "";
string roomVideoAddress = "";
Debug.Console(1,
@"
Codec.CodecInfo.IpAddress: {0}
Codec.CodecInfo.SipUri: {1}
Codec.CodecInfo.SipPhoneNumber: {2}
Codec.CodecInfo.E164Alias: {3}
Codec.CodecInfo.H323Id: {4}
", Codec.CodecInfo.IpAddress, Codec.CodecInfo.SipUri, Codec.CodecInfo.SipPhoneNumber, Codec.CodecInfo.E164Alias, Codec.CodecInfo.H323Id);
// Populate phone number
if (!string.IsNullOrEmpty(Codec.CodecInfo.SipUri)) // If both values are present, format the string with a pipe divider
{
roomPhoneNumber = Codec.CodecInfo.SipUri;
}
else if (!string.IsNullOrEmpty(Codec.CodecInfo.SipPhoneNumber)) // If only one value present, just show the phone number
{
roomPhoneNumber = GetFormattedPhoneNumber(Codec.CodecInfo.SipPhoneNumber);
}
// Populate video number
if (!string.IsNullOrEmpty(Codec.CodecInfo.IpAddress))
{
roomVideoAddress = Codec.CodecInfo.IpAddress;
}
else if (!string.IsNullOrEmpty(Codec.CodecInfo.E164Alias))
{
roomVideoAddress = Codec.CodecInfo.E164Alias;
}
else if (!string.IsNullOrEmpty(Codec.CodecInfo.H323Id))
{
roomVideoAddress = Codec.CodecInfo.H323Id;
}
Debug.Console(1,
@" Room Contact Numbers:
Phone Number: {0}
Video Number: {1}
", roomPhoneNumber, roomVideoAddress);
if (!string.IsNullOrEmpty(roomPhoneNumber) && !string.IsNullOrEmpty(roomVideoAddress))
{
roomContactNumbers = string.Format("{0} | {1}", roomPhoneNumber, roomVideoAddress);
}
else if (!string.IsNullOrEmpty(roomPhoneNumber))
{
roomContactNumbers = roomPhoneNumber;
}
else if (!string.IsNullOrEmpty(roomVideoAddress))
{
roomContactNumbers = roomVideoAddress;
}
TriList.SetString(UIStringJoin.RoomAddressPipeText, roomContactNumbers);
TriList.SetString(UIStringJoin.RoomPhoneText, roomPhoneNumber);
TriList.SetString(UIStringJoin.RoomVideoAddressText, roomVideoAddress);
}
/// <summary>
/// Handles status changes for calls
/// </summary>

View File

@@ -1,37 +1,26 @@
# PepperDash Essentials Framework (c) 2020
## [Latest Release](https://github.com/PepperDash/Essentials/releases/latest)
## License
Provided under MIT license
## Overview
PepperDash Essentials is an open source Crestron framework that can be configured as a standalone program capable of running a wide variety of system designs and can also be utilized as a plug-in architecture to augment other Simpl# Pro and Simpl Windows programs.
Essentials Framework is a collection of C# / Simpl# Pro libraries that can be utilized in several different manners. It is currently operating as a 100% configuration-driven system, and can be extended to add different workflows and behaviors, either through the addition of further device "types" or via the plug-in mechanism. The framework is a collection of "things" that are all related and interconnected, but in general do not have dependencies on each other.
## Minimum Requirements
- Essentials Framework runs on any Crestron 3-series processor, **4-series** processor or Crestron's VC-4 platform.
- To edit and compile the source, Microsoft Visual Studio 2008 Professional with SP1 is required.
- Crestron's Simpl# Plugin is also required (must be obtained from Crestron).
## Dependencies
The [PepperDash.Core](https://github.com/PepperDash/PepperDashCore) SIMPL# library is required. It is referenced via nuget. You must have nuget.exe installed and in the `PATH` environment variable to use the following command. Nuget.exe is available at [nuget.org](https://dist.nuget.org/win-x86-commandline/latest/nuget.exe).
### Installing Dependencies
To install dependencies once nuget.exe is installed, run the following command: `nuget install .\packages.config -OutputDirectory .\packages -excludeVersion`. To verify that the packages installed correctly, open Essentials and make sure that all references are found, then try and build it.
### Installing Different versions of PepperDash Core
If you need a different version of PepperDash Core, use the command `nuget install .\packages.config -OutputDirectory .\packages -excludeVersion -Version {versionToGet}`. Omitting the `-Version` option will pull the latest release version of PepperDash Core.
The [PepperDash.Core](https://github.com/PepperDash/PepperDashCore) SIMPL# library is required. It is referenced as a submodule and will be automatically checked out when cloning this repo if set to recurse submodules. This allows different builds of the PepperDash.Core library to be referenced by checking out the desired submodule commit.
## Utilization
Essentials was originally conceptualized as a standalone application for running control system logic entirely in Simpl# Pro. It is primarily designed around accomplishing this goal, but during development, it became obvious that it could easily be leveraged to also serve as a partner application to one or more SIMPL Windows programs.
Utilization of Essentials Framework falls into the following categories:
@@ -45,13 +34,13 @@ Utilization of Essentials Framework falls into the following categories:
- Advanced logic. Some logic operations that cannot be affectively accomplished in SIMPL Windows (ex. JSON/XML serialization/deserialization, database operations, etc.) can be done in the Simpl# Pro environment and the necessary input and output bridged to a SIMPL Windows program via EISC.
3. Hybrid Application that may contain elements of both standalone control and SIMPL partner application integration.
- There may be a use case where a device can only be defined in a single application, but that device may need to be interacted with from multiple applications. The device can be defined in an Essentials application, interacted with in that application and also bridged to one or more SIMPL Windows applications.
- There may be a use case where a device can only be defined in a single application, but that device may need to be interacted with from multiple applications. The device can be defined in an Essentials application, interacted with in that application and also bridged to one or more SIMPL Windows applications.
## Documentation
For detailed documentation, see the [Wiki](https://github.com/PepperDash/EssentialsFramework/wiki).
## Documentation
For detailed documentation, see the [Wiki](https://github.com/PepperDash/EssentialsFramework/wiki).
## How-To (Getting Started)
See [Getting Started](https://github.com/PepperDash/Essentials/wiki/Get-started#how-to-get-started)

View File

@@ -1,11 +1,33 @@
using PepperDash.Core;
using System;
using PepperDash.Core;
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
{
public interface IMobileControl:IKeyed
/// <summary>
/// Describes a MobileControlSystemController
/// </summary>
public interface IMobileControl : IKeyed
{
void CreateMobileControlRoomBridge(EssentialsRoomBase room);
void LinkSystemMonitorToAppServer();
}
/// <summary>
/// Describes a MobileControl Room Bridge
/// </summary>
public interface IMobileControlRoomBridge : IKeyed
{
event EventHandler<EventArgs> UserCodeChanged;
string UserCode { get; }
string QrCodeUrl { get; }
string McServerUrl { get; }
string RoomName { get; }
}
}

View File

@@ -1,45 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using System;
using System.Collections.Generic;
using System.Linq;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.DeviceSupport;
using Newtonsoft.Json.Linq;
using PepperDash.Essentials.Core.Config;
using PepperDash.Core;
namespace PepperDash.Essentials.Core
{
/// <summary>
/// IR port wrapper. May act standalone
/// </summary>
public class IrOutputPortController : Device
{
uint IrPortUid;
IROutputPort IrPort;
public ushort StandardIrPulseTime { get; set; }
public string DriverFilepath { get; private set; }
public bool DriverIsLoaded { get; private set; }
/// <summary>
/// Constructor for IrDevice base class. If a null port is provided, this class will
/// still function without trying to talk to a port.
/// </summary>
public IrOutputPortController(string key, IROutputPort port, string irDriverFilepath)
: base(key)
{
//if (port == null) throw new ArgumentNullException("port");
IrPort = port;
if (port == null)
{
Debug.Console(0, this, "WARNING No valid IR Port assigned to controller. IR will not function");
return;
}
LoadDriver(irDriverFilepath);
using PepperDash.Essentials.Core.Config;
using PepperDash.Core;
namespace PepperDash.Essentials.Core
{
/// <summary>
/// IR port wrapper. May act standalone
/// </summary>
public class IrOutputPortController : Device
{
uint IrPortUid;
IROutputPort IrPort;
public ushort StandardIrPulseTime { get; set; }
public string DriverFilepath { get; private set; }
public bool DriverIsLoaded { get; private set; }
/// <summary>
/// Constructor for IrDevice base class. If a null port is provided, this class will
/// still function without trying to talk to a port.
/// </summary>
public IrOutputPortController(string key, IROutputPort port, string irDriverFilepath)
: base(key)
{
//if (port == null) throw new ArgumentNullException("port");
IrPort = port;
if (port == null)
{
Debug.Console(0, this, "WARNING No valid IR Port assigned to controller. IR will not function");
return;
}
LoadDriver(irDriverFilepath);
}
public IrOutputPortController(string key, Func<DeviceConfig, IROutputPort> postActivationFunc,
@@ -54,85 +54,85 @@ namespace PepperDash.Essentials.Core
/// <summary>
/// Loads the IR driver at path
/// </summary>
/// <param name="path"></param>
public void LoadDriver(string path)
{
if (string.IsNullOrEmpty(path)) path = DriverFilepath;
try
{
IrPortUid = IrPort.LoadIRDriver(path);
DriverFilepath = path;
StandardIrPulseTime = 200;
DriverIsLoaded = true;
}
catch
{
DriverIsLoaded = false;
var message = string.Format("WARNING IR Driver '{0}' failed to load", path);
Debug.Console(0, this, message);
ErrorLog.Error(message);
}
}
/// <summary>
/// Starts and stops IR command on driver. Safe for missing commands
/// </summary>
public virtual void PressRelease(string command, bool state)
{
Debug.Console(2, this, "IR:'{0}'={1}", command, state);
if (IrPort == null)
{
Debug.Console(2, this, "WARNING No IR Port assigned to controller");
return;
}
if (!DriverIsLoaded)
{
Debug.Console(2, this, "WARNING IR driver is not loaded");
return;
}
if (state)
{
if (IrPort.IsIRCommandAvailable(IrPortUid, command))
IrPort.Press(IrPortUid, command);
else
NoIrCommandError(command);
}
else
IrPort.Release();
}
/// <summary>
/// Pulses a command on driver. Safe for missing commands
/// </summary>
public virtual void Pulse(string command, ushort time)
{
if (IrPort == null)
{
Debug.Console(2, this, "WARNING No IR Port assigned to controller");
return;
}
if (!DriverIsLoaded)
{
Debug.Console(2, this, "WARNING IR driver is not loaded");
return;
}
if (IrPort.IsIRCommandAvailable(IrPortUid, command))
IrPort.PressAndRelease(IrPortUid, command, time);
else
NoIrCommandError(command);
}
/// <summary>
/// Notifies the console when a bad command is used.
/// </summary>
protected void NoIrCommandError(string command)
{
Debug.Console(2, this, "Device {0}: IR Driver {1} does not contain command {2}",
Key, IrPort.IRDriverFileNameByIRDriverId(IrPortUid), command);
/// <summary>
/// Loads the IR driver at path
/// </summary>
/// <param name="path"></param>
public void LoadDriver(string path)
{
if (string.IsNullOrEmpty(path)) path = DriverFilepath;
try
{
IrPortUid = IrPort.LoadIRDriver(path);
DriverFilepath = path;
StandardIrPulseTime = 200;
DriverIsLoaded = true;
}
catch
{
DriverIsLoaded = false;
var message = string.Format("WARNING IR Driver '{0}' failed to load", path);
Debug.Console(0, this, message);
ErrorLog.Error(message);
}
}
}
/// <summary>
/// Starts and stops IR command on driver. Safe for missing commands
/// </summary>
public virtual void PressRelease(string command, bool state)
{
Debug.Console(2, this, "IR:'{0}'={1}", command, state);
if (IrPort == null)
{
Debug.Console(2, this, "WARNING No IR Port assigned to controller");
return;
}
if (!DriverIsLoaded)
{
Debug.Console(2, this, "WARNING IR driver is not loaded");
return;
}
if (state)
{
if (IrPort.IsIRCommandAvailable(IrPortUid, command))
IrPort.Press(IrPortUid, command);
else
NoIrCommandError(command);
}
else
IrPort.Release();
}
/// <summary>
/// Pulses a command on driver. Safe for missing commands
/// </summary>
public virtual void Pulse(string command, ushort time)
{
if (IrPort == null)
{
Debug.Console(2, this, "WARNING No IR Port assigned to controller");
return;
}
if (!DriverIsLoaded)
{
Debug.Console(2, this, "WARNING IR driver is not loaded");
return;
}
if (IrPort.IsIRCommandAvailable(IrPortUid, command))
IrPort.PressAndRelease(IrPortUid, command, time);
else
NoIrCommandError(command);
}
/// <summary>
/// Notifies the console when a bad command is used.
/// </summary>
protected void NoIrCommandError(string command)
{
Debug.Console(2, this, "Device {0}: IR Driver {1} does not contain command {2}",
Key, IrPort.IRDriverFileNameByIRDriverId(IrPortUid), command);
}
}
}

View File

@@ -165,29 +165,34 @@ namespace PepperDash.Essentials.Core.Fusion
{
// Exists. Read GUIDs
ReadGuidFile(guidFilePath);
}
if (Room.RoomOccupancy != null)
{
if (Room.OccupancyStatusProviderIsRemote)
SetUpRemoteOccupancy();
else
{
SetUpLocalOccupancy();
}
}
CreateSymbolAndBasicSigs(IpId);
SetUpSources();
SetUpCommunitcationMonitors();
SetUpDisplay();
SetUpError();
ExecuteCustomSteps();
if (Room.RoomOccupancy != null)
{
if (Room.OccupancyStatusProviderIsRemote)
SetUpRemoteOccupancy();
else
{
SetUpLocalOccupancy();
}
}
AddPostActivationAction(() =>
{
CreateSymbolAndBasicSigs(IpId);
SetUpSources();
SetUpCommunitcationMonitors();
SetUpDisplay();
SetUpError();
ExecuteCustomSteps();
FusionRVI.GenerateFileForAllFusionDevices();
GenerateGuidFile(guidFilePath);
});
// Make it so!
FusionRVI.GenerateFileForAllFusionDevices();
GenerateGuidFile(guidFilePath);
}
catch (Exception e)
{

View File

@@ -83,9 +83,9 @@
<HintPath>..\..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.UI.dll</HintPath>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="PepperDash_Core, Version=1.0.39.33033, Culture=neutral, processorArchitecture=MSIL">
<Reference Include="PepperDash_Core, Version=1.0.26.30384, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\packages\PepperDashCore\lib\net35\PepperDash_Core.dll</HintPath>
<HintPath>..\..\pepperdashcore-builds\PepperDash_Core.dll</HintPath>
</Reference>
<Reference Include="SimplSharpCustomAttributesInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<package >
<metadata>
<id>PepperDashEssentials</id>
<version>1.5.6</version>
<title>PepperDash Essentials</title>
<authors>PepperDash Technologies</authors>
<owners>pepperdash</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<license type="expression">MIT</license>
<projectUrl>https://github.com/PepperDash/PepperDashCore</projectUrl>
<copyright>Copyright 2020</copyright>
<description>PepperDash Essentials is an open source Crestron framework that can be configured as a standalone program capable of running a wide variety of system designs and can also be utilized as a plug-in architecture to augment other Simpl# Pro and Simpl Windows programs. Essentials Framework is a collection of C# / Simpl# Pro libraries that can be utilized in several different manners. It is currently operating as a 100% configuration-driven system, and can be extended to add different workflows and behaviors, either through the addition of further device "types" or via the plug-in mechanism. The framework is a collection of "things" that are all related and interconnected, but in general do not have dependencies on each other.</description>
<tags>crestron 3series 4series</tags>
<repository type="git" url="https://github.com/PepperDash/Essentials"/>
<dependencies>
<dependency id="PepperDashCore" version="[1.0, 1.1)"/>
</dependencies>
</metadata>
<files>
<file src="**" target="lib\net35"/>
<file src="**" target="lib\net47"/>
</files>
</package>

View File

@@ -9,6 +9,7 @@ using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Devices;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
namespace PepperDash.Essentials.Core
{
@@ -37,10 +38,32 @@ namespace PepperDash.Essentials.Core
protected abstract Func<bool> IsWarmingFeedbackFunc { get; }
protected abstract Func<bool> IsCoolingFeedbackFunc { get; }
/// <summary>
/// Indicates if this room is Mobile Control Enabled
/// </summary>
public bool IsMobileControlEnabled { get; private set; }
/// <summary>
/// The bridge for this room if Mobile Control is enabled
/// </summary>
public IMobileControlRoomBridge MobileControlRoomBridge { get; private set; }
/// <summary>
/// The config name of the source list
/// </summary>
public string SourceListKey { get; set; }
///
protected string _SourceListKey;
public virtual string SourceListKey {
get
{
return _SourceListKey;
}
set
{
_SourceListKey = value;
}
}
/// <summary>
/// Timer used for informing the UIs of a shutdown
@@ -58,7 +81,9 @@ namespace PepperDash.Essentials.Core
public Core.Privacy.MicrophonePrivacyController MicrophonePrivacy { get; set; }
public string LogoUrl { get; set; }
public string LogoUrlLightBkgnd { get; set; }
public string LogoUrlDarkBkgnd { get; set; }
protected SecondsCountdownTimer RoomVacancyShutdownTimer { get; private set; }
@@ -128,6 +153,34 @@ namespace PepperDash.Essentials.Core
});
}
public override bool CustomActivate()
{
SetUpMobileControl();
return base.CustomActivate();
}
/// <summary>
/// If mobile control is enabled, sets the appropriate properties
/// </summary>
void SetUpMobileControl()
{
var mcBridgeKey = string.Format("mobileControlBridge-{0}", Key);
var mcBridge = DeviceManager.GetDeviceForKey(mcBridgeKey);
if (mcBridge == null)
{
Debug.Console(1, this, "*********************Mobile Control Bridge Not found for this room.");
IsMobileControlEnabled = false;
return;
}
else
{
MobileControlRoomBridge = mcBridge as IMobileControlRoomBridge;
Debug.Console(1, this, "*********************Mobile Control Bridge found and enabled for this room");
IsMobileControlEnabled = true;
}
}
void RoomVacancyShutdownPromptTimer_HasFinished(object sender, EventArgs e)
{
switch (VacancyMode)

View File

@@ -14,6 +14,8 @@
public UiSetupPropertiesConfig Setup { get; set; }
public string HeaderStyle { get; set; }
public bool IncludeInFusionRoomHealth { get; set; }
public uint ScreenSaverTimeoutMin { get; set; }
public uint ScreenSaverMovePositionIntervalMs { get; set; }
/// <summary>
@@ -26,6 +28,10 @@
{
SourcesOverflowCount = 5;
HeaderStyle = CrestronTouchpanelPropertiesConfig.Habanero;
// Default values
ScreenSaverTimeoutMin = 5;
ScreenSaverMovePositionIntervalMs = 15000;
}
/// <summary>

View File

@@ -329,56 +329,64 @@ namespace PepperDash.Essentials.DM
InputEndpointOnlineFeedbacks[tempX] = new BoolFeedback(() => { return Chassis.Inputs[tempX].EndpointOnlineFeedback; });
InputCardHdcpStateFeedbacks[tempX] = new IntFeedback(() => {
var inputCard = Chassis.Inputs[tempX];
if (inputCard.Card is DmcHd)
try
{
InputCardHdcpCapabilityTypes[tempX] = eHdcpCapabilityType.HdcpAutoSupport;
var inputCard = Chassis.Inputs[tempX];
if ((inputCard.Card as DmcHd).HdmiInput.HdcpSupportOnFeedback.BoolValue)
return 1;
return 0;
}
if (inputCard.Card is DmcHdDsp)
{
InputCardHdcpCapabilityTypes[tempX] = eHdcpCapabilityType.HdcpAutoSupport;
if ((inputCard.Card as DmcHdDsp).HdmiInput.HdcpSupportOnFeedback.BoolValue)
return 1;
return 0;
}
if (inputCard.Card is Dmc4kHdBase)
{
InputCardHdcpCapabilityTypes[tempX] = eHdcpCapabilityType.Hdcp2_2Support;
return (int)(inputCard.Card as Dmc4kHdBase).HdmiInput.HdcpReceiveCapability;
}
if (inputCard.Card is Dmc4kCBase)
{
if (PropertiesConfig.InputSlotSupportsHdcp2[tempX])
if (inputCard.Card is DmcHd)
{
InputCardHdcpCapabilityTypes[tempX] = eHdcpCapabilityType.HdcpAutoSupport;
return (int)(inputCard.Card as Dmc4kCBase).DmInput.HdcpReceiveCapability;
if ((inputCard.Card as DmcHd).HdmiInput.HdcpSupportOnFeedback.BoolValue)
return 1;
return 0;
}
if ((inputCard.Card as Dmc4kCBase).DmInput.HdcpSupportOnFeedback.BoolValue)
return 1;
return 0;
}
if (inputCard.Card is Dmc4kCDspBase)
{
if (PropertiesConfig.InputSlotSupportsHdcp2[tempX])
if (inputCard.Card is DmcHdDsp)
{
InputCardHdcpCapabilityTypes[tempX] = eHdcpCapabilityType.HdcpAutoSupport;
return (int)(inputCard.Card as Dmc4kCDspBase).DmInput.HdcpReceiveCapability;
}
if ((inputCard.Card as Dmc4kCDspBase).DmInput.HdcpSupportOnFeedback.BoolValue)
return 1;
if ((inputCard.Card as DmcHdDsp).HdmiInput.HdcpSupportOnFeedback.BoolValue)
return 1;
return 0;
}
if (inputCard.Card is Dmc4kHdBase)
{
InputCardHdcpCapabilityTypes[tempX] = eHdcpCapabilityType.Hdcp2_2Support;
return (int)(inputCard.Card as Dmc4kHdBase).HdmiInput.HdcpReceiveCapability;
}
if (inputCard.Card is Dmc4kCBase)
{
if (PropertiesConfig.InputSlotSupportsHdcp2[tempX])
{
InputCardHdcpCapabilityTypes[tempX] = eHdcpCapabilityType.HdcpAutoSupport;
return (int)(inputCard.Card as Dmc4kCBase).DmInput.HdcpReceiveCapability;
}
if ((inputCard.Card as Dmc4kCBase).DmInput.HdcpSupportOnFeedback.BoolValue)
return 1;
return 0;
}
if (inputCard.Card is Dmc4kCDspBase)
{
if (PropertiesConfig.InputSlotSupportsHdcp2[tempX])
{
InputCardHdcpCapabilityTypes[tempX] = eHdcpCapabilityType.HdcpAutoSupport;
return (int)(inputCard.Card as Dmc4kCDspBase).DmInput.HdcpReceiveCapability;
}
if ((inputCard.Card as Dmc4kCDspBase).DmInput.HdcpSupportOnFeedback.BoolValue)
return 1;
return 0;
}
return 0;
}
return 0;
catch (InvalidOperationException iopex)
{
Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "The Input Card in slot: {0} supports HDCP 2. Please update the configuration value in the inputCardSupportsHdcp2 object to true. Error: {1}", tempX, iopex);
return 0;
}
});
}
}
@@ -614,6 +622,13 @@ namespace PepperDash.Essentials.DM
var cecPort2 = outputCard.Card2.HdmiOutput;
AddDmcHdoPorts(number, cecPort1, cecPort2);
}
else if (type == "dmc4kzhdo")
{
var outputCard = new Dmc4kzHdoSingle(number, Chassis);
var cecPort1 = outputCard.Card1.HdmiOutput;
var cecPort2 = outputCard.Card2.HdmiOutput;
AddDmcHdoPorts(number, cecPort1, cecPort2);
}
else if (type == "dmchdo")
{
var outputCard = new DmcHdoSingle(number, Chassis);
@@ -800,56 +815,63 @@ namespace PepperDash.Essentials.DM
void Chassis_DMInputChange(Switch device, DMInputEventArgs args)
{
switch (args.EventId)
try
{
case DMInputEventIds.EndpointOnlineEventId:
switch (args.EventId)
{
Debug.Console(2, this, "DM Input EndpointOnlineEventId for input: {0}. State: {1}", args.Number, device.Inputs[args.Number].EndpointOnlineFeedback);
InputEndpointOnlineFeedbacks[args.Number].FireUpdate();
break;
}
case DMInputEventIds.OnlineFeedbackEventId:
{
Debug.Console(2, this, "DM Input OnlineFeedbackEventId for input: {0}. State: {1}", args.Number, device.Inputs[args.Number].EndpointOnlineFeedback);
InputEndpointOnlineFeedbacks[args.Number].FireUpdate();
break;
}
case DMInputEventIds.VideoDetectedEventId:
{
Debug.Console(2, this, "DM Input {0} VideoDetectedEventId", args.Number);
VideoInputSyncFeedbacks[args.Number].FireUpdate();
break;
}
case DMInputEventIds.InputNameEventId:
{
Debug.Console(2, this, "DM Input {0} NameFeedbackEventId", args.Number);
InputNameFeedbacks[args.Number].FireUpdate();
break;
}
case DMInputEventIds.UsbRoutedToEventId:
{
Debug.Console(2, this, "DM Input {0} UsbRoutedToEventId", args.Number);
if (UsbInputRoutedToFeebacks[args.Number] != null)
UsbInputRoutedToFeebacks[args.Number].FireUpdate();
else
Debug.Console(1, this, "No index of {0} found in UsbInputRoutedToFeedbacks");
break;
}
case DMInputEventIds.HdcpCapabilityFeedbackEventId:
{
Debug.Console(2, this, "DM Input {0} HdcpCapabilityFeedbackEventId", args.Number);
if (InputCardHdcpStateFeedbacks[args.Number] != null)
InputCardHdcpStateFeedbacks[args.Number].FireUpdate();
else
Debug.Console(1, this, "No index of {0} found in InputCardHdcpStateFeedbacks");
break;
}
default:
{
Debug.Console(2, this, "DMInputChange fired for Input {0} with Unhandled EventId: {1}", args.Number, args.EventId);
break;
case DMInputEventIds.EndpointOnlineEventId:
{
Debug.Console(2, this, "DM Input EndpointOnlineEventId for input: {0}. State: {1}", args.Number, device.Inputs[args.Number].EndpointOnlineFeedback);
InputEndpointOnlineFeedbacks[args.Number].FireUpdate();
break;
}
case DMInputEventIds.OnlineFeedbackEventId:
{
Debug.Console(2, this, "DM Input OnlineFeedbackEventId for input: {0}. State: {1}", args.Number, device.Inputs[args.Number].EndpointOnlineFeedback);
InputEndpointOnlineFeedbacks[args.Number].FireUpdate();
break;
}
case DMInputEventIds.VideoDetectedEventId:
{
Debug.Console(2, this, "DM Input {0} VideoDetectedEventId", args.Number);
VideoInputSyncFeedbacks[args.Number].FireUpdate();
break;
}
case DMInputEventIds.InputNameEventId:
{
Debug.Console(2, this, "DM Input {0} NameFeedbackEventId", args.Number);
InputNameFeedbacks[args.Number].FireUpdate();
break;
}
case DMInputEventIds.UsbRoutedToEventId:
{
Debug.Console(2, this, "DM Input {0} UsbRoutedToEventId", args.Number);
if (UsbInputRoutedToFeebacks[args.Number] != null)
UsbInputRoutedToFeebacks[args.Number].FireUpdate();
else
Debug.Console(1, this, "No index of {0} found in UsbInputRoutedToFeedbacks");
break;
}
case DMInputEventIds.HdcpCapabilityFeedbackEventId:
{
Debug.Console(2, this, "DM Input {0} HdcpCapabilityFeedbackEventId", args.Number);
if (InputCardHdcpStateFeedbacks[args.Number] != null)
InputCardHdcpStateFeedbacks[args.Number].FireUpdate();
else
Debug.Console(1, this, "No index of {0} found in InputCardHdcpCapabilityFeedbacks");
break;
}
default:
{
Debug.Console(2, this, "DMInputChange fired for Input {0} with Unhandled EventId: {1}", args.Number, args.EventId);
break;
}
}
}
catch (Exception ex)
{
Debug.Console(2, this, Debug.ErrorLogLevel.Error, "Error in Chassis_DMInputChange: {0}", ex);
}
}
///

View File

@@ -59,9 +59,9 @@
<HintPath>..\..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.UI.dll</HintPath>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="PepperDash_Core, Version=1.0.39.33033, Culture=neutral, processorArchitecture=MSIL">
<Reference Include="PepperDash_Core, Version=1.0.26.30384, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\packages\PepperDashCore\lib\net35\PepperDash_Core.dll</HintPath>
<HintPath>..\..\pepperdashcore-builds\PepperDash_Core.dll</HintPath>
</Reference>
<Reference Include="SimplSharpCustomAttributesInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>

View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Devices.Common.VideoCodec.Cisco;
namespace PepperDash.Essentials.Devices.Common.Codec
{
public interface IHasExternalSourceSwitching
{
bool ExternalSourceListEnabled { get; }
void AddExternalSource(string connectorId, string key, string name, eExternalSourceType type);
void SetExternalSourceState(string key, eExternalSourceMode mode);
void ClearExternalSources();
Action<string, string> RunRouteAction { set;}
}
}

View File

@@ -63,9 +63,9 @@
<HintPath>..\..\..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.Lighting.dll</HintPath>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="PepperDash_Core, Version=1.0.39.33033, Culture=neutral, processorArchitecture=MSIL">
<Reference Include="PepperDash_Core, Version=1.0.26.30384, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\packages\PepperDashCore\lib\net35\PepperDash_Core.dll</HintPath>
<HintPath>..\..\pepperdashcore-builds\PepperDash_Core.dll</HintPath>
</Reference>
<Reference Include="PepperDash_Essentials_Core, Version=0.0.0.22043, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
@@ -112,6 +112,7 @@
<Compile Include="Codec\eCodecCallStatus.cs" />
<Compile Include="Codec\eMeetingPrivacy.cs" />
<Compile Include="Codec\iCodecAudio.cs" />
<Compile Include="Codec\IHasExternalSourceSwitching.cs" />
<Compile Include="ImageProcessors\TVOneCorio.cs" />
<Compile Include="ImageProcessors\TVOneCorioPropertiesConfig.cs" />
<Compile Include="Power Controllers\Digitallogger.cs" />

View File

@@ -1,33 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Devices.Common.Codec
{
public class CiscoSparkCodecPropertiesConfig
{
public CommunicationMonitorConfig CommunicationMonitorProperties { get; set; }
public List<CodecActiveCallItem> Favorites { get; set; }
/// <summary>
/// Valid values: "Local" or "Corporate"
/// </summary>
public string PhonebookMode { get; set; }
public bool ShowSelfViewByDefault { get; set; }
public SharingProperties Sharing { get; set; }
}
public class SharingProperties
{
public bool AutoShareContentWhileInCall { get; set; }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Devices.Common.Codec
{
public class CiscoSparkCodecPropertiesConfig
{
[JsonProperty("communicationMonitorProperties")]
public CommunicationMonitorConfig CommunicationMonitorProperties { get; set; }
[JsonProperty("favorites")]
public List<CodecActiveCallItem> Favorites { get; set; }
/// <summary>
/// Valid values: "Local" or "Corporate"
/// </summary>
[JsonProperty("phonebookMode")]
public string PhonebookMode { get; set; }
[JsonProperty("showSelfViewByDefault")]
public bool ShowSelfViewByDefault { get; set; }
[JsonProperty("sharing")]
public SharingProperties Sharing { get; set; }
[JsonProperty("externalSourceListEnabled")]
public bool ExternalSourceListEnabled { get; set; }
/// <summary>
/// Optionsal property to set the limit of any phonebook queries for directory or searching
/// </summary>
[JsonProperty("phonebookResultsLimit")]
public uint PhonebookResultsLimit { get; set; }
}
public class SharingProperties
{
[JsonProperty("autoShareContentWhileInCall")]
public bool AutoShareContentWhileInCall { get; set; }
}
}

View File

@@ -126,11 +126,36 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public Encryption Encryption { get; set; }
public RequestedURI RequestedURI { get; set; }
public PeopleCountAverage PeopleCountAverage { get; set; }
}
}
public class UserInterface
{
public string id { get; set; }
public Presentation Presentation { get; set; }
}
public class Presentation
{
public string id { get; set; }
public ExternalSource ExternalSource { get; set; }
}
public class ExternalSource
{
public string id { get; set; }
public Selected Selected { get; set; }
}
public class Selected
{
public string id { get; set; }
public SourceIdentifier SourceIdentifier { get; set; }
}
public class SourceIdentifier
{
public string id { get; set; }
public string Value { get; set; }
}
public class Event
{
public CallDisconnect CallDisconnect { get; set; }
public CallDisconnect CallDisconnect { get; set; }
public UserInterface UserInterface { get; set; }
}
public class RootObject

View File

@@ -4,6 +4,7 @@ using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.CrestronThread;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@@ -13,7 +14,6 @@ using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Routing;
using PepperDash.Essentials.Devices.Common.Cameras;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Devices.Common.VideoCodec;
namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
@@ -171,6 +171,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
// The thread responsible for dequeuing and processing the messages
ReceiveThread = new Thread((o) => ProcessQueue(), null);
ReceiveThread.Priority = Thread.eThreadPriority.MediumPriority;
Communication = comm;
@@ -401,7 +402,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
// If the receive thread has for some reason stopped, this will restart it
if (ReceiveThread.ThreadState != Thread.eThreadStates.ThreadRunning)
{
ReceiveThread.Start();
}
}

View File

@@ -1,3 +0,0 @@
<packages>
<package id="PepperDashCore" version="1.0.38-alpha-135" targetFramework="net35" allowedVersions="[1.0,1.1)"/>
</packages>

View File

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